diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..8070c102 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,72 @@ +name: CI + +on: + push: + branches: ["**"] + pull_request: + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: -D warnings + +# Read-only by default. Nothing here publishes, comments or writes, so nothing +# here needs a token that could. +permissions: + contents: read + +# Third-party actions are pinned to commit SHAs rather than tags. A tag is a +# mutable pointer: `@v4` is whatever its owner last moved it to, and a compromised +# or retagged action runs with this workflow's token and this repository's cache. +# The version each SHA corresponds to is in the comment beside it. +jobs: + # One job running `make verify`, which is the command the README tells a reader + # to run. Splitting the host checks from the SBF build let them drift: the + # end-to-end suite needs the .so, so a job without the Solana toolchain ran + # twenty tests that could only panic, and the artifact never crossed between + # runners. If CI and the documented command are the same command, they cannot + # disagree. + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + + - name: Cache cargo + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache the Solana toolchain + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: ~/.local/share/solana + key: ${{ runner.os }}-solana-stable + + - name: Install Agave + run: | + if [ ! -x "$HOME/.local/share/solana/install/active_release/bin/solana" ]; then + sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" + fi + echo "$HOME/.local/share/solana/install/active_release/bin" >> "$GITHUB_PATH" + + - run: solana --version + + - name: make verify + run: make verify + + # The dependency tree is part of the threat surface: a compromised transitive + # crate in the proving path sees the witness and one in the client sees the + # note. Separate from `verify` because it needs no Solana toolchain and because + # a supply-chain failure should be legible as one rather than buried in a test + # log. `deny.toml` carries the policy, and every exception in it is written + # down with the reason it is an exception. + supply-chain: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1 + with: + command: check advisories bans licenses sources diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ccd7bf0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +target/ +**/target/ + +# Editor and tool state +.DS_Store +.claude/ +.idea/ +.vscode/ + +# Never +.env +keys/ +*.keypair.json +notes/ + +# Build artefacts. The one exception is the third-party program the CPI tests +# invoke: it is a fixture the suite loads, not something this repo builds. +*.so +!programs/**/fixtures/*.so + +# Vendored source, kept out of the tree +sp4/ + +# Live-run state, not deliverable. The note ledgers hold the secrets that +# release a pool's escrow, and the plan files record which validator each +# member of a run asked for. Both belong to one operator's run against one +# cluster, and neither means anything to a reader of this repository. +data/*-notes*.json +data/crowd-plan-*.json diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..048fecce --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4666 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.7", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "agave-feature-set" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4790979fc2a3c1c494c9cb84e8b514da4b8c6a992a460a077b31b07657606f8" +dependencies = [ + "ahash", + "solana-epoch-schedule", + "solana-hash", + "solana-keypair", + "solana-pubkey 4.2.0", + "solana-sha256-hasher", + "solana-svm-feature-set", +] + +[[package]] +name = "agave-reserved-account-keys" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea33710f30b13f62e6d73dbbb114117029d29539cb9439c30ef39a0736f935cc" +dependencies = [ + "agave-feature-set", + "solana-pubkey 4.2.0", + "solana-sdk-ids", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e" +dependencies = [ + "ahash", + "ark-crypto-primitives-macros", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-relations", + "ark-serialize 0.5.0", + "ark-snark", + "ark-std 0.5.0", + "blake2", + "derivative", + "digest 0.10.7", + "fnv", + "hashbrown 0.14.5", + "merlin", + "sha2 0.10.9", + "tracing", +] + +[[package]] +name = "ark-crypto-primitives-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint 0.4.8", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.8", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.8", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-groth16" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f1d0f3a534bb54188b8dcc104307db6c56cdae574ddc3212aec0625740fc7e" +dependencies = [ + "ark-crypto-primitives", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-relations", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint 0.4.8", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive 0.4.2", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.8", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.8", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-snark" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88" +dependencies = [ + "ark-ff 0.5.0", + "ark-relations", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.7", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.7", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "blst" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "borsh" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88b7ea17d208c4193f2c1e6de3c35fe71f98c96982d5ced308bdcc749ff6e1f" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f347189c62a579b8cd5f80714efa178f52e461dc2e6d701d264f5ff22e566c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65693059b6b9c588b9f62fed1cedbf0a8b805631457ea162d68f0de186f3de5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout", +] + +[[package]] +name = "clap" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "either" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-iterator" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "bitvec", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "groth16-solana" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6d1ffb18dbf5cfc60b11bd7da88474c672870247c1e5b498619bcb6ba3d8f5" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "num-bigint 0.4.8", + "solana-bn254 2.2.2", + "thiserror 1.0.69", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand 0.8.7", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.9", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.7", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ff 0.4.2", + "num-bigint 0.4.8", + "thiserror 1.0.69", +] + +[[package]] +name = "light-poseidon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a1ccadd0bb5a32c196da536fd72c59183de24a055f6bf0513bf845fefab862" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ff 0.5.0", + "num-bigint 0.4.8", + "thiserror 1.0.69", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litesvm" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c571b8f010af084d125c8968e52658eb2c5d146a0a8254681adcdac36caa3e" +dependencies = [ + "agave-feature-set", + "agave-reserved-account-keys", + "ansi_term", + "indexmap", + "itertools 0.14.0", + "log", + "serde", + "solana-account", + "solana-address 2.6.1", + "solana-address-lookup-table-interface", + "solana-builtins", + "solana-clock", + "solana-compute-budget", + "solana-compute-budget-instruction", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-fee", + "solana-fee-structure", + "solana-hash", + "solana-instruction", + "solana-instruction-error", + "solana-instructions-sysvar 4.0.0", + "solana-keypair", + "solana-last-restart-slot", + "solana-loader-v3-interface 8.0.1", + "solana-loader-v4-interface", + "solana-message", + "solana-native-token", + "solana-nonce", + "solana-nonce-account", + "solana-precompile-error", + "solana-program-error", + "solana-program-runtime", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-history", + "solana-svm-callback", + "solana-svm-log-collector", + "solana-svm-timings", + "solana-svm-transaction", + "solana-syscalls", + "solana-system-interface", + "solana-system-program", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.19", + "wincode", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mirror-circuit" +version = "0.1.0" +dependencies = [ + "ark-bn254 0.5.0", + "ark-crypto-primitives", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-groth16", + "ark-r1cs-std", + "ark-relations", + "ark-serialize 0.5.0", + "ark-snark", + "ark-std 0.5.0", + "groth16-solana", + "light-poseidon 0.4.0", + "mirror-core", + "solana-poseidon", + "thiserror 2.0.19", +] + +[[package]] +name = "mirror-cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "ark-std 0.5.0", + "base64", + "bincode", + "clap", + "hex", + "mirror-circuit", + "mirror-core", + "mirror-pool-program", + "mirror-provenance", + "serde", + "serde_json", + "sha2 0.10.9", + "solana-keypair", + "solana-message", + "solana-program", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "ureq", +] + +[[package]] +name = "mirror-core" +version = "0.1.0" +dependencies = [ + "solana-keccak-hasher", + "solana-poseidon", + "thiserror 2.0.19", +] + +[[package]] +name = "mirror-pool-program" +version = "0.1.0" +dependencies = [ + "ark-std 0.5.0", + "groth16-solana", + "hex", + "litesvm", + "mirror-circuit", + "mirror-core", + "sha2 0.10.9", + "solana-keypair", + "solana-message", + "solana-program", + "solana-signer", + "solana-system-interface", + "solana-transaction", +] + +[[package]] +name = "mirror-provenance" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "thiserror 2.0.19", + "ureq", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.23.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +dependencies = [ + "serde_core", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "solana-account" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385cad928d576683db3afef1b88d00a31a7126cc9f6f3f0c9f6b2d181437f53c" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-sysvar", +] + +[[package]] +name = "solana-account-info" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9cf16495d9eb53e3d04e72366a33bb1c20c24e78c171d8b8f5978357b63ae95" +dependencies = [ + "bincode", + "serde_core", + "solana-address 2.6.1", + "solana-program-error", + "solana-program-memory", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.6.1", +] + +[[package]] +name = "solana-address" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c93e262f671bf402e1040e4a7e40b05d81da5956c7681948c975a0997517bb" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8", + "five8_const", + "serde", + "serde_derive", + "sha2-const-stable", + "solana-atomic-u64", + "solana-define-syscall 5.1.0", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", + "wincode", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115b4f773acc4f3f3cb986b0d335e9845c0368c82b0940410935bc11ae065578" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085db4906d89324cef2a30840d59eaecf3d4231c560ec7c9f6614a93c652f501" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-bincode" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278a1a5bad62cd9da89ac8d4b7ec444e83caa8ae96aa656dfc27684b28d49a5d" +dependencies = [ + "bincode", + "serde_core", + "solana-instruction-error", +] + +[[package]] +name = "solana-blake3-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" +dependencies = [ + "blake3", + "solana-define-syscall 4.0.1", + "solana-hash", +] + +[[package]] +name = "solana-bls-signatures" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654ea8d31bbb4b0b9c28f9c545edb32691de27d4e2fc0e252c1ff47da50c5f2a" +dependencies = [ + "base64", + "blst", + "blstrs", + "cfg_eval", + "ff", + "group", + "pairing", + "rand 0.8.7", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.19", + "wincode", + "zeroize", +] + +[[package]] +name = "solana-bls12-381-syscall" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a699aa5e660203c17c18ceaef0eff78c67fd5193f4dbe90a07148e06030ab6" +dependencies = [ + "blst", + "blstrs", + "bytemuck", + "bytemuck_derive", + "group", + "pairing", +] + +[[package]] +name = "solana-bn254" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "bytemuck", + "solana-define-syscall 2.3.0", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-bn254" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ff13a8867fcc7b0f1114764e1bf6191b4551dcaf93729ddc676cd4ec6abc9f" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "bytemuck", + "solana-define-syscall 5.1.0", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-borsh" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04abbae16f57178a163125805637b8a076175bb5c0002fb04f4792bea901cf7" +dependencies = [ + "borsh", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "073e0a6555480e8f783f930299a5660c2296c8961d9b3a2adaf585561e2d59b9" +dependencies = [ + "bincode", + "qualifier_attr", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-instruction", + "solana-loader-v3-interface 7.0.0", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 4.2.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-type-overrides", + "solana-syscalls", + "solana-system-interface", + "solana-transaction-context", +] + +[[package]] +name = "solana-builtins" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e54d03edadcb2f38bdb8b6524380a858f5ad51654db1f71eccc3fb5dc4d492" +dependencies = [ + "agave-feature-set", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-hash", + "solana-program-runtime", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-system-program", + "solana-vote-program", + "solana-zk-elgamal-proof-program", + "solana-zk-token-proof-program", +] + +[[package]] +name = "solana-builtins-default-costs" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a63b9b3ae7b09c32f7f15d83e875dbf8715d0853c2354e3306316158f19d9c90" +dependencies = [ + "agave-feature-set", + "ahash", + "solana-pubkey 4.2.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-clock" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0acdace90d96e2c9e70d681465b4fe888b6bcf27c354ae9774e9f8a3b72923d" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-compute-budget" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1770e5aeba2f5ec75b2d89031780c760dcf8352a061430f5e74eab1ad9f3b132" +dependencies = [ + "solana-fee-structure", + "solana-program-runtime", +] + +[[package]] +name = "solana-compute-budget-instruction" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3ad15d715b0c4e21f6b591f126b7fa8070aadf0d75fcd89bc4c98afc9e5f8f6" +dependencies = [ + "agave-feature-set", + "solana-borsh", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-compute-budget-interface", + "solana-instruction", + "solana-packet", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-svm-transaction", + "solana-transaction-error", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8292c436b269ad23cecc8b24f7da3ab07ca111661e25e00ce0e1d22771951ab9" +dependencies = [ + "borsh", + "solana-instruction", + "solana-sdk-ids", +] + +[[package]] +name = "solana-compute-budget-program" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653943375fb64b11bcfda0c22280aa87f04902d2c25d0117e91f9788a31ed3db" +dependencies = [ + "solana-program-runtime", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.2.0", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b4d2a4bf0d0b0a86c22111917e86e8bd39a7b31420fb2c7d73eb83761fc7af" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall 5.1.0", + "subtle", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-define-syscall" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" + +[[package]] +name = "solana-define-syscall" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" + +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-define-syscall" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e14a4f604117f379840956a8fc8695e4c84f5b0ebed192f31f60d9b85d581d" + +[[package]] +name = "solana-derivation-path" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff71743072690fdbdfcdc37700ae1cb77485aaad49019473a81aee099b1e0b8c" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-rewards" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf7eb4986b0b1d6f562b21f75a836f1a6df6e00c275efcef50aab5c144dc59e" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8116e6ffa6002237d5ab5edcbda17f9ba66b6742c45a89c9fb40a94dbacd4c1d" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-program-error", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-epoch-stake" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "027e6d0b9e7daac5b2ac7c3f9ca1b727861121d9ef05084cf435ff736051e7c2" +dependencies = [ + "solana-define-syscall 5.1.0", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-example-mocks" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb265ff95e28eceda117e2e3d2d2a611ecbbfe911dfeeeecd1521814540ffab" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-instruction", + "solana-nonce", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7545e02f91da1d6996f32b18f7796aa01e0682f8f3a7434b82cd1a10448add" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-fee" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbffe004ec900267fc0bcf0c3b532c01905e6c4e3f318562718d1cdf6db939" +dependencies = [ + "agave-feature-set", + "solana-fee-structure", + "solana-svm-transaction", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef67f01cc6a0c72e99a08d0d484683f995de4c80e9568728fa77d1537f9b7e09" +dependencies = [ + "log", + "serde", + "serde_derive", + "wincode", +] + +[[package]] +name = "solana-fee-structure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" + +[[package]] +name = "solana-get-sysvar" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef3bc859fc036ed490146793557386cbfae614ebba4adc704c37d94350824ed4" +dependencies = [ + "solana-address 2.6.1", + "solana-define-syscall 5.1.0", + "solana-program-error", +] + +[[package]] +name = "solana-hash" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe51db00ac3aa9f950d1e6201a126acfa26e6d81bc4a183ba64ec02effcad883" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "five8", + "serde", + "serde_derive", + "solana-sanitize", + "wincode", +] + +[[package]] +name = "solana-hash-512" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee9c987913768643be3f4fc5f8ec667e8ec19e59e6d131688ade8d1430dafe9" + +[[package]] +name = "solana-instruction" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ebb0ffd19263051bc3f683fcc086134b8ff23af894dcb63f7563c7137b42f1" +dependencies = [ + "bincode", + "borsh", + "serde", + "serde_derive", + "solana-define-syscall 5.1.0", + "solana-instruction-error", + "solana-pubkey 4.2.0", + "wincode", +] + +[[package]] +name = "solana-instruction-error" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e7db78c122d02189619490b1fef04a2a042c389662920617c0e6381fdf8fdd" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e0732294560e88ecdb2bbc656e67383e9f88c78ec09469cef172f0d28cd1bcd" +dependencies = [ + "bitflags", + "solana-account-info", + "solana-instruction", + "solana-instruction-error", + "solana-program-error", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e38363a181313d607f7a118df2b401bb27b477a0104b09283cbf504f5f0f00cc" +dependencies = [ + "bitflags", + "solana-account-info", + "solana-instruction", + "solana-instruction-error", + "solana-program-error", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" +dependencies = [ + "sha3", + "solana-define-syscall 4.0.1", + "solana-hash", +] + +[[package]] +name = "solana-keypair" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "263d614c12aa267a3278703175fd6440552ca61bc960b5a02a4482720c53438b" +dependencies = [ + "ed25519-dalek", + "five8", + "five8_core", + "rand 0.9.5", + "solana-address 2.6.1", + "solana-seed-phrase", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22474b83d3c7c318e1c3a725784fc2d1d03b728e36369e58ce48769a61ed85e" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68029ab11d9c891d4ce23ada75745e40f983c5674af366f447b672569634231b" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 4.2.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "362b468fbde4c20521b9ff5ef743bc0d9b410455a5a92a8b29fd46954e89345f" +dependencies = [ + "solana-instruction", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-system-interface", + "wincode", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c948b33ff81fa89699911b207059e493defdba9647eaf18f23abdf3674e0fb" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-message" +version = "4.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2666e0ff38557ad1239d0fc42f4688fb9df0817fb12c041dbae90c2b2e3fa55" +dependencies = [ + "blake3", + "serde", + "serde_derive", + "solana-address 2.6.1", + "solana-hash", + "solana-instruction", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-transaction-error", + "wincode", +] + +[[package]] +name = "solana-msg" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726b7cbbc6be6f1c6f29146ac824343b9415133eee8cce156452ad1db93f8008" +dependencies = [ + "solana-define-syscall 5.1.0", +] + +[[package]] +name = "solana-native-token" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" + +[[package]] +name = "solana-nonce" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4172d5b33a0a38fcdb2af8f84406570dd51567267da96c28ad0f31fc11621c0" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey 4.2.0", + "solana-sha256-hasher", + "wincode", +] + +[[package]] +name = "solana-nonce-account" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b81bf7e2aa8c443724051507c1007d0b6d9c34b70925d3232dc78f5ca485209e" +dependencies = [ + "solana-account", + "solana-hash", + "solana-nonce", + "solana-sdk-ids", + "wincode", +] + +[[package]] +name = "solana-packet" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2a582d7863548f047f49aa3745c076cfa9e1364baa080ef0c1210f0e4ebda" +dependencies = [ + "bitflags", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-poseidon" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "737b8ab25bf4cc8e618f80f1fe40709b2ace708bc764a36b8a4c81eea8c07034" +dependencies = [ + "ark-bn254 0.4.0", + "ark-bn254 0.5.0", + "light-poseidon 0.2.0", + "light-poseidon 0.4.0", + "solana-define-syscall 4.0.1", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-precompile-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778f08fb0eaf52c9a3bef2978247f7fab0ccfddc44cfddb936d5ad9f98ede886" +dependencies = [ + "memoffset", + "solana-account-info", + "solana-big-mod-exp", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-define-syscall 5.1.0", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-epoch-stake", + "solana-example-mocks", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instruction-error", + "solana-instructions-sysvar 3.0.1", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-sysvar", + "solana-sysvar-id", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f04fa578707b3612b095f0c8e19b66a1233f7c42ca8082fcb3b745afcc0add6" +dependencies = [ + "borsh", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-program-memory" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" +dependencies = [ + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-program-option" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a88006a9b8594088cec9027ab77caaaa258a2aaa2083d3f086c44b42e50aeab" + +[[package]] +name = "solana-program-pack" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7701cb15b90667ae1c89ef4ac35a59c61e66ce58ddee13d729472af7f41d59" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-program-runtime" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0364032ca71f9be2ffab27791cd6535dbe9d2990da0e2346e99013a9bcb57f4" +dependencies = [ + "base64", + "bincode", + "cfg-if", + "itertools 0.14.0", + "log", + "percentage", + "rand 0.9.5", + "serde", + "solana-account", + "solana-account-info", + "solana-clock", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-structure", + "solana-hash", + "solana-instruction", + "solana-last-restart-slot", + "solana-loader-v3-interface 7.0.0", + "solana-program-entrypoint", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db719574990de7e8b0f55a8593ac92a5ccb42c8ce67b3e4bf05b139d5d9ee71" +dependencies = [ + "solana-address 2.6.1", +] + +[[package]] +name = "solana-rent" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f0d780bf8e8a1fe8b5b5fce1acad6b209485b86dec246e7523d5e4a8b7c7fc" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sbpf" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f84c593fa3d4131045b606dec5acf9d8eac73791bc786ca9911057aec8f43ec" +dependencies = [ + "byteorder", + "combine", + "hash32", + "libc", + "log", + "rand 0.8.7", + "rustc-demangle", + "thiserror 2.0.19", + "winapi", +] + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.6.1", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8765316242300c48242d84a41614cb3388229ec353ba464f6fe62a733e41806f" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a1ad3ed7846631c88c71c5d2f21a2ecb6b61da333d9be173b6b061b35609ae" +dependencies = [ + "k256", + "solana-define-syscall 5.1.0", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-seed-derivable" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" +dependencies = [ + "hmac", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-serde-varint" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950e5b83e839dc0f92c66afc124bb8f40e89bc90f0579e8ec5499296d27f54e3" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761357b0853c9623bf12c1d2314b3d6160a85b087b84c45224fb85766d22616b" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 4.0.1", + "solana-hash", +] + +[[package]] +name = "solana-sha512-hasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11e10e103ab5bd52af341e7bc2f4123a2f4e66bb7ba4e6ca40f1e00cd6314e02" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 5.1.0", + "solana-hash-512", +] + +[[package]] +name = "solana-short-vec" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8250a4495aad49ad20556a607da53bdcb20de78da10b65afbf918b7f1de647" +dependencies = [ + "serde_core", + "wincode", +] + +[[package]] +name = "solana-signature" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0364c7577c3c82a693ce28a1febc8d1b5d1b0a175fdc2114ae6186b69effe1e" +dependencies = [ + "ed25519-dalek", + "five8", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize", + "wincode", +] + +[[package]] +name = "solana-signer" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520bd6021163ee517f4bdc7ae03ded904f97e11320001ba0b3355f45eb14f558" +dependencies = [ + "solana-pubkey 4.2.0", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ce2b4b8911bf2db3de7b6266e67bfc21a6a9f8c566fb096d9782ca2ad16ee" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-hash", + "solana-sdk-ids", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-slot-history" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40427c04d3e808493cb5e3d1a97cef84d7c15cb6f89b15c5684d0d4027105600" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f6a291ba063a37780af29e7db14bdd3dc447584d8ba5b3fc4b88e2bbc982fa" +dependencies = [ + "solana-instruction", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-stake-history" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c736a6aa0e53b9d264d90b06589fc0996f49f882f3e71842ed754fc57ffc1a43" +dependencies = [ + "serde", + "serde_derive", + "solana-clock", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-stake-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49eb5c77484214c3484921e2cdda79d185373118b5458c1b2df0f1a04c3bc30" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.2.0", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", +] + +[[package]] +name = "solana-svm-callback" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d50ab466a202b3ec768d0d1f808c570822b4d2492801772359b9509baf1e8c6" +dependencies = [ + "solana-account", + "solana-clock", + "solana-precompile-error", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-svm-feature-set" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35320ec1b4460e2f748c9ebb6c42eb3069f8d85ec46a185ae9b5628430f3c606" + +[[package]] +name = "solana-svm-log-collector" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5ba1a825b27776f6a92fae44613d5e7f906f0c56e542bbbe1a6746eb168daff" +dependencies = [ + "log", +] + +[[package]] +name = "solana-svm-measure" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ec9c705bec0fc99b9220e62fbae9fb0a297b9a95ff411badce934103a92ec7" + +[[package]] +name = "solana-svm-timings" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b72896172acdbce474662e876fdd413092893599156500cc68840abea649441" +dependencies = [ + "eager", + "enum-iterator", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-svm-transaction" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998e6d7d1197d29a77d3701ae273cfc3e95e79978546faa4d28af637ef5211e7" +dependencies = [ + "solana-hash", + "solana-message", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-signature", + "solana-transaction", +] + +[[package]] +name = "solana-svm-type-overrides" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128cad78148dbd90e61a0bdf54706a24c356e858d85f2674dd7755eac594a4df" +dependencies = [ + "rand 0.9.5", +] + +[[package]] +name = "solana-syscalls" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2788d359af16fac879c081bc0b725e8a200702156af92e75e2c18346fcde332" +dependencies = [ + "bincode", + "libsecp256k1", + "num-traits", + "solana-account", + "solana-account-info", + "solana-big-mod-exp", + "solana-blake3-hasher", + "solana-bls12-381-syscall", + "solana-bn254 3.2.1", + "solana-clock", + "solana-cpi", + "solana-curve25519", + "solana-hash", + "solana-hash-512", + "solana-instruction", + "solana-keccak-hasher", + "solana-poseidon", + "solana-program-entrypoint", + "solana-program-runtime", + "solana-pubkey 4.2.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-sha256-hasher", + "solana-sha512-hasher", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-type-overrides", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.19", +] + +[[package]] +name = "solana-system-interface" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55b54965bf0b76fa8e2b35376583efddd4d916618cfe595bf48c7d7b55a9e628" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-address 2.6.1", + "solana-instruction", + "solana-msg", + "solana-program-error", + "wincode", +] + +[[package]] +name = "solana-system-program" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64154747d8e97a2ac1869e7633b9d5b8cac01d1ca99cf05f5910eb4b5718fbbc" +dependencies = [ + "bincode", + "log", + "solana-account", + "solana-bincode", + "solana-fee-calculator", + "solana-instruction", + "solana-nonce", + "solana-nonce-account", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 4.2.0", + "solana-sdk-ids", + "solana-svm-log-collector", + "solana-system-interface", + "solana-sysvar", + "solana-transaction-context", +] + +[[package]] +name = "solana-sysvar" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada7045bbfdd802af08fbc9c7e2b56ddabb20599d22e4c3840fcef5e7afb8324" +dependencies = [ + "base64", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall 5.1.0", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-get-sysvar", + "solana-hash", + "solana-instruction", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-history", + "solana-sysvar-id", + "wincode", +] + +[[package]] +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.6.1", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction" +version = "4.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aa9b0f8543b99e1cb7db16a7c1a392139d82db57a90d262fb0a394807337bec" +dependencies = [ + "serde", + "serde_derive", + "solana-address 2.6.1", + "solana-hash", + "solana-instruction", + "solana-instruction-error", + "solana-message", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction-error", + "wincode", +] + +[[package]] +name = "solana-transaction-context" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffd061d881fb2c182078e6ca6094fe113e50edbec224c4f8999747eb643cd02" +dependencies = [ + "bincode", + "serde", + "solana-account", + "solana-instruction", + "solana-instructions-sysvar 3.0.1", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a37cf28c58b03878d38c38411f0414d3a99a9e3b7e5ebb0f83f3317b2796d18" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction-error", + "solana-sanitize", +] + +[[package]] +name = "solana-vote-interface" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a7a204b455a53fe8c9a26a6885391a5896835e06694dbe0cf37c580f82f128" +dependencies = [ + "bincode", + "cfg_eval", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "serde_with", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] + +[[package]] +name = "solana-vote-program" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d772aa219b97b0cd9ec512c9330179714e3bb6231df4a8b81981b6c88f85f1" +dependencies = [ + "agave-feature-set", + "bincode", + "log", + "solana-account", + "solana-bincode", + "solana-bls-signatures", + "solana-clock", + "solana-epoch-schedule", + "solana-hash", + "solana-instruction", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 4.2.0", + "solana-rent", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-system-interface", + "solana-transaction-context", + "solana-vote-interface", +] + +[[package]] +name = "solana-zk-elgamal-proof-program" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d841aa9791a275535f676c9403413c66da7c1bb1c867d3575b58f4e5b881ef" +dependencies = [ + "bytemuck", + "solana-instruction", + "solana-program-runtime", + "solana-sdk-ids", + "solana-svm-log-collector", + "solana-zk-sdk", +] + +[[package]] +name = "solana-zk-sdk" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09670ff59f60e6ddc2209c2e4353992a9b9f01d4e244f3e9d67bd5146e33d388" +dependencies = [ + "aes-gcm-siv", + "base64", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "itertools 0.14.0", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.7", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-address 2.6.1", + "solana-derivation-path", + "solana-instruction", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.19", + "zeroize", +] + +[[package]] +name = "solana-zk-token-proof-program" +version = "4.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4841d6e055847c84d011d187cbad022ea4f8832c85a61a1aa220c192bd4dfd0" +dependencies = [ + "solana-program-runtime", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl 2.0.19", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.9", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wincode" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d967db7705dc29120bb6e8ce5b5a2e27734ed5976d1c904e95bd238d1c3c5a" +dependencies = [ + "bv", + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.19", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15ab90b719560d0fda79c74550ad1c948d17b118765942838055ebaf34d67071" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..4f4a2e36 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,75 @@ +[workspace] +resolver = "2" +members = [ + "crates/mirror-core", + "crates/mirror-circuit", + "crates/mirror-provenance", + "crates/mirror-cli", + "programs/mirror-pool", +] + +[workspace.package] +version = "0.1.0" +edition = "2021" +license = "MIT" +repository = "https://github.com/solanabr/mirror-pool" + +# The arkworks major must stay 0.5 across every crate: light-poseidon 0.4 is built +# against 0.5, and Fr from 0.5 and 0.6 are distinct types that will not unify. +[workspace.dependencies] +ark-bn254 = { version = "0.5", default-features = false, features = ["curve"] } +ark-ff = { version = "0.5", default-features = false } +ark-ec = { version = "0.5", default-features = false } +ark-relations = { version = "0.5", default-features = false } +ark-r1cs-std = { version = "0.5", default-features = false } +ark-groth16 = { version = "0.5", default-features = false } +ark-snark = { version = "0.5", default-features = false } +ark-serialize = { version = "0.5", default-features = false } +ark-std = { version = "0.5", default-features = false } +# solana-poseidon is deliberately the ONLY Poseidon entry point. It is cfg-gated +# upstream: the `sol_poseidon` syscall on target_os = "solana", light-poseidon 0.4 +# over ark-bn254 0.5 off-chain. That gives host/chain parity for free and keeps +# arkworks out of the .so — a pure-Rust Poseidon on SBF overflows the 4096-byte +# stack frame and costs ~1500x the syscall even when it completes. +solana-poseidon = "4.0" +# Same cfg-gating as solana-poseidon: the syscall on-chain, sha3 off-chain. +# Needed because an action payload is variable length and Poseidon is not. +# The off-chain implementation sits behind the sha3 feature; without it the +# host build compiles and then panics at first use. +solana-keccak-hasher = { version = "3.1", features = ["sha3"] } +# Host-only, and only for its published round constants, which the R1CS gadget +# reads so that in-circuit hashing provably matches the syscall. +light-poseidon = "0.4" +# 0.5 gates constraints behind `r1cs`; 0.6 renamed it to `constraints` and moved +# to ark_relations::gr1cs, which does not compose with our 0.5 pin. +ark-crypto-primitives = { version = "0.5", default-features = false, features = ["sponge", "crh", "merkle_tree", "r1cs"] } +groth16-solana = "0.2" +solana-program = "4.0" +# System instructions moved out of solana-program in 4.0. +solana-system-interface = { version = "3.0", features = ["bincode"] } +thiserror = "2" +anyhow = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +clap = { version = "4", features = ["derive"] } +sha2 = "0.10" +hex = "0.4" +# Blocking HTTP: collection is rate-limited and sequential, so an async +# runtime would add machinery without buying throughput. +ureq = { version = "2", features = ["json"] } +# Test-only: runs the built .so in a real SVM. 0.15 targets Agave 4.1.1, which is +# the toolchain the Makefile installs. +litesvm = "0.15" +solana-keypair = "3.1" +solana-signer = "3" +solana-transaction = { version = "4.1", features = ["serde", "wincode"] } +solana-message = "4.2" + +mirror-core = { path = "crates/mirror-core" } +mirror-circuit = { path = "crates/mirror-circuit" } +mirror-provenance = { path = "crates/mirror-provenance" } + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..129390a0 --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +.PHONY: all test lint fmt build-sbf clean verify + +# cargo build-sbf compiles for sbf-solana-solana, but proc-macro dependencies +# still have to be built for the host. If the shared target directory already +# holds host artifacts from `cargo test` or `cargo clippy`, cargo can hand the +# SBF rustc a host .dylib for one of those macros, which it rejects with +# "extern location ... is of an unknown type". Giving the SBF build its own +# target directory removes the collision. +# +# The program deliberately stays a member of the root workspace so that +# `cargo test --workspace` covers it. Excluding it from the workspace is the +# usual way to dodge the target-directory collision above, and it silently +# removes every on-chain test from CI: the suite still passes, because it no +# longer runs. +# +# The path must be absolute. cargo resolves a relative CARGO_TARGET_DIR against +# the manifest directory, so `target/sbf` with `--manifest-path programs/...` +# builds into programs/mirror-pool/target/sbf while cargo-build-sbf's +# post-processing looks for the artifact under the workspace root, and the build +# "succeeds" while producing no .so. +SBF_TARGET_DIR := $(CURDIR)/target/sbf + +all: verify + +fmt: + cargo fmt --all + +lint: + cargo fmt --all -- --check + cargo clippy --workspace --all-targets -- -D warnings + +test: + cargo test --workspace --all-features + +build-sbf: + CARGO_TARGET_DIR=$(SBF_TARGET_DIR) cargo build-sbf --manifest-path programs/mirror-pool/Cargo.toml + @ls -l $(SBF_TARGET_DIR)/deploy/*.so + +# Everything CI runs, in the order CI runs it. +# +# build-sbf comes before test, and the order is load-bearing: the end-to-end +# suite loads the .so this produces into a real SVM, and the artifact is +# gitignored. With test first, `make verify` fails on a fresh clone at the one +# command the README tells a reader to run. +verify: lint build-sbf test + +clean: + cargo clean + rm -rf $(SBF_TARGET_DIR) diff --git a/README.md b/README.md new file mode 100644 index 00000000..48406857 --- /dev/null +++ b/README.md @@ -0,0 +1,986 @@ +# mirror-pool + +A behavioural anonymity set for Solana — privacy for **what you do**, not for +what you hold. + +Members join a pool by depositing a fixed denomination. Later, a member proves in +zero knowledge that they own some note in the set and directs the pool to perform +an *action*: an arbitrary instruction on an arbitrary program. The pool performs +it, signed by the pool, batched with everyone else's at one timestamp. An +observer sees that a stake, a swap or a vote happened and cannot say which member +asked for it. + +Moving lamports is the degenerate case, selector zero. The interesting cases are +the other two, and the end-to-end suite runs both against a real deployed +program: four members performing one indistinguishable action in a single slot, +and the pool **signing a call as the member's authority** — which is what a stake +delegation or a governance vote needs and what a transfer cannot do. +[See below](#synchronised-actions-are-the-point). + +Rust end to end. MIT. No Anchor, no Circom, no JavaScript anywhere in the +proving path. + +**The whole work is also written up as a paper**, if you would rather read the +argument than the code: +[**A Behavioural Anonymity Set for Solana**](docs/a-behavioural-anonymity-set-for-solana.pdf) +— 39 pages, 26 references, with the protocol and the measurement argued as one +claim and every figure in it traceable to a test or a transaction in this +repository. + +## Meeting the brief + +Every row is checkable in this repository, and the right-hand column says where. + +| what is asked | how this meets it | check it | +|---|---|---| +| **Rust, end to end** | **Zero** files of any other language are tracked here. No Circom, no snarkjs, no `ethers`, no TypeScript build step, no shell scripts doing real work. The circuit is an arkworks R1CS gadget in `crates/mirror-circuit`; the prover is Rust; the verifier is the on-chain program calling the `alt_bn128` syscall. | `git ls-files '*.js' '*.ts' '*.py' '*.sol' '*.circom'` returns nothing | +| **Production-grade, tested, deployable** | 261 tests. The end-to-end suite loads the compiled `.so` into a real SVM and verifies real Groth16 proofs through the actual syscall. Negative cases assert the program's *own* error codes, not that something failed. `overflow-checks` on in release; `cargo-deny` over advisories, bans, licences and sources; CI actions pinned by commit SHA. | `make verify` | +| **Deployed and running** | Live on devnet, with every claim in this file linking to the transaction behind it. The full lifecycle — pool, deposits, proofs, batched settlement, and four rejections — is recorded with signatures. | [`docs/PROOF.md`](docs/PROOF.md) | +| **Scalable & customizable** | Adding a protocol requires no change to the on-chain program — no redeploy, no new circuit, no governance. Selector 1 invokes any program with any payload; selector 2 additionally makes the pool *sign* as the member's authority, which is what a stake delegation or a governance vote needs. The whole procedure is four steps with a worked `DelegateStake` that runs on devnet. | [`docs/INTEGRATING.md`](docs/INTEGRATING.md) | +| **Realistic** | The anonymity number is computed from live mainnet chain data, with the sample committed so the result reproduces without RPC access — and it is pointed at a pool this project neither controls nor funded, because measuring our own empty pool would be measuring nothing. | [`docs/MEASUREMENT_LOG.md`](docs/MEASUREMENT_LOG.md) | +| **Well-documented** | Eleven documents plus a 39-page paper: install path, architecture, threat model, proof of life, measurement method, and the design as decided with every departure from it recorded. | [below](#documentation) | +| **Open source, MIT** | MIT at the workspace root and on every crate. | [`LICENSE`](LICENSE) | + +## What is different here + +Six things, stated as facts about this repository rather than as comparisons. + +**Every number is taken, not modelled.** There is no simulated distribution +anywhere in the measurement path. The provenance figures come from real mainnet +funding chains; the packet and lock ceilings come from serializing the real +instruction; the compute figures come from a real SVM and a real cluster. Where a +number is derived rather than landed — the delegation ceiling through a lookup +table is the one case — the document that publishes it says so in those words. + +**The trusted setup is reproducible, and you can check it in one command.** The +seed is committed in plain sight and the proving key is derived from it rather +than withheld, so anyone can regenerate the key the deployed program verifies +against: + +``` +$ mirror verify-setup --expect b0165d5eac6fe8273b6564c78e8ba548c97e6050ae785e9142de63c81aa905b7 + +vk sha256 (regenerated): b0165d5eac6fe8273b6564c78e8ba548c97e6050ae785e9142de63c81aa905b7 +MATCH — every element of the program's verifying key is reproduced by this seed +and this circuit (4 IC points checked) +and it matches the digest you supplied +``` + +It binds the **whole** key — `alpha_g1`, `beta_g2`, `gamma_g2`, `delta_g2` and +every element of `gamma_abc_g1` — because a check that bound only `delta` would +certify a key belonging to a different circuit. `vk_drift.rs` runs the same +comparison inside `make verify`, so the compiled key and the published digest +cannot drift apart without a test going red. + +This setup is reproducible rather than *secure*, and the difference is stated +where it matters rather than here: the seed being public is exactly what makes +proofs forgeable, which is why this is on devnet and not mainnet. See +[what we do not claim](#what-we-do-not-claim). + +**The proof is verified by the chain, not by a stand-in.** `submit_spend` runs +the pairing on-chain in about 101,000 CU — half the default budget for one +instruction — through the program's own syscall. No committee, no multisig, and +no off-chain verifier standing in for one. + +**A note pays out once, ever.** The nullifier set is global rather than scoped to +an epoch, so no boundary can reopen a spend, and a test asserts the rejection +rather than assuming it. The denomination is a constant of the pool rather than a +field on the note, so the class of bug where the escrowed amount and the paid +amount disagree is not expressible. + +**Every command these documents mention exists.** `make verify` exercises the +tool the usage guide describes, and the walkthrough's output was produced by +running it against devnet rather than written by hand. + +**The measurement is turned on this project too.** `docs/CROWD.md` runs the same +metric against our own devnet crowd, where it returns the best value the metric +can produce — and then says why that number is worthless: every note in that pool +was funded by one wallet, so the partition has one class and the class is us. A +measurement apparatus that only ever points outward is one nobody has tested. + +## Getting it running + +Two prerequisites, and only two. + +**Rust.** `rust-toolchain.toml` pins 1.97.1 with `rustfmt` and `clippy`, so +[rustup](https://rustup.rs) installs the right version by itself the first time +you build — no manual step. + +**The Agave (Solana) toolchain**, for `cargo-build-sbf`. The on-chain program is +compiled to SBF and the test suite loads that `.so` into a real SVM, so without +this the suite cannot run at all: + +``` +sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" +solana --version # confirms it is on PATH +``` + +Then: + +``` +git clone https://github.com/solanabr/mirror-pool && cd mirror-pool +make verify # fmt, clippy -D warnings, build-sbf, 261 tests +``` + +Nothing in that command needs a network, an API key or an account with anybody, +and it is the whole check — there is no second suite and no optional extra. The +proving path is portable Rust with no assembly and no architecture-specific +dependency: the same suite, real Groth16 proofs included, runs on `ubuntu-latest` +x86_64 under [`.github/workflows/ci.yml`](.github/workflows/ci.yml) and on arm64 +locally, from the same source and with no feature flags between them. If you +would rather look than build, the program is live on devnet at +[`8H3cYoiAA9LM36c…`](https://explorer.solana.com/address/8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa?cluster=devnet) +and every claim below links to the transaction that backs it. + +`make verify` is the whole check, and it is the same command CI runs — see +[`.github/workflows/ci.yml`](.github/workflows/ci.yml), which invokes `make +verify` and nothing else, so the two cannot drift apart. On a cold clone it +takes a few minutes, most of it compiling arkworks. Nothing here needs a +network, a validator or a funded wallet. + +To get the member-facing tool as a binary: + +``` +cargo build --release # target/release/mirror +``` + +[`docs/USAGE.md`](docs/USAGE.md) walks the whole journey from there — creating a +note through to settling a batch — with real devnet output for every command. + +## The architecture, in one page + +Four instructions, two phases, four crates behind one program. `init_pool` +creates a denomination's pool and is permissionless; the other three are the +member's path: + +``` + deposit submit_spend settle_epoch + ─────── ──────────── ──────────── + member escrows D relay signs, member anyone signs + commitment enters never does whole batch, one + the Merkle tree Groth16 verified transaction, one + no member key on on chain, nullifier timestamp, paid + chain after this burned, nothing paid from the vault PDA +``` + +**Why two phases and not one.** Verifying `n` proofs inside one settlement would +cost `n × 101,000` CU and blow the budget at six members. Splitting them means the +expensive step is per-member and parallel, and the step that must be atomic — +the one that gives every member the same timestamp and the same ordering — is +cheap. A batch of twenty payouts settles in 35,895 CU. + +**What the proof says.** Three public inputs: the Merkle root, the nullifier, and +an action binding. The binding is a keccak digest over the selector, the target +program, the beneficiary, the relay, the relay fee, the declared account count and +the payload — recomputed on-chain from the action about to execute, never +transmitted. A relay that alters any of them produces a different binding and the +pairing fails. + +**Why the pool signs.** Actions execute from the pool's vault PDA, so the +on-chain trace of an action is identical whoever asked for it. Under +`SELECTOR_INVOKE_SIGNED` the vault is a signer of the inner call, which is how a +member delegates stake without ever being the staker authority themselves. + +| crate | what it is | +|---|---| +| `programs/mirror-pool` | The on-chain program. Four instructions, no Anchor. | +| `crates/mirror-core` | Field, Poseidon, Merkle accumulator, notes. Linked on-chain, so host and program cannot drift. | +| `crates/mirror-circuit` | The R1CS gadget, the prover, and the verifying-key export. | +| `crates/mirror-provenance` | The funding-provenance measurement, and its honesty checks. | +| `crates/mirror-cli` | `mirror` — the member's tool and the operator's. | + +[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) is the long version, with the +reason behind each decision and the alternative it was chosen over. + +## The problem this takes as its subject + +There is one channel that no deposit-based anonymity set on a public ledger +closes, and it is not something a better circuit can fix: + +> An anonymity set on a public ledger can be partitioned by **where each member's +> capital came from**. Learning a member's funding class leaves only that class to +> guess within, so what survives is the size of the class, not `k`. + +No pool controls where its users' money came from. What that channel can be is +*measured*, and measured honestly — which as far as we can tell nobody has done +against live Solana data with a published method. + +So this project claims exactly two things: + +1. **The action side is closed.** Actions execute from the pool's vault PDA, so an + action's on-chain funding trace leads to the pool and is identical for every + member. +2. **The membership side is measured**, from real mainnet data, with the method + and its limits published beside the number. + + **The pool measured is not this one.** It is Privacy Cash + (`9fhQBbumKEFuXtMBDw8AaQyAjCorLGJQiS3skWZdQyQD`), an unrelated and live Solana + mixer, because `mirror-pool` has no depositors and a measurement of our own + empty pool would be a measurement of nothing. So this is a tool pointed at + somebody else's protocol, and every number below describes theirs. + + **`ρ = 0.0955`**, inside an unresolved bracket of `0.0350 … 0.1136` and a 95% + sampling interval of `0.0848 … 0.1790`, from a clean census with **zero** + infrastructure failures and **zero** members whose funding we claim not to + exist — 54 of 83 reached a provenance class. Knowing a member's funding class + costs that pool roughly an order of magnitude of its nominal anonymity. + + **The bracket is not decoration, and a figure published without one is a + different kind of number.** Twenty-nine of those 83 members did not resolve to + a class. Counting them as one class each drives the loss factor to one end of + that range; counting them as members of the classes already seen drives it to + the other. Both are assumptions, neither is data, and the true value is + somewhere between — so the honest report is the interval. A bare `ρ` has + quietly picked one of those assumptions, which means it is partly a + measurement of how much of the graph the tracer could afford to walk rather + than of what the pool leaks. Run the tracer longer and the bare number moves; + the bracket is what stops that from looking like a finding. + + The sample's class distribution is heavy-tailed and most of it was never + observed — Good–Turing coverage 0.65, with Chao1 estimating 108 classes + against 23 seen — and that is reported as a finding rather than buried as a + caveat. One earlier run resolved ten *more* members and came back with + coverage *worse*, because the new members landed in fresh singleton classes + rather than in the observed ones. There is no budget at which this + distribution becomes well-observed. + + `docs/MEASUREMENT_LOG.md` has all eight runs, and **six of the eight end + without a publishable figure** — one that resolved nothing, one refused by the + failure gate, three refused by the informativeness gate, and one invalidated + by a defect we found in our own tracer. The two that produced a figure are + there too, including the earlier one this work superseded and the + pre-registered prediction that turned out wrong. + + **And the metric is turned on this project too.** `docs/CROWD.md` runs it + against our own devnet crowd, where it returns ρ = 1.0000 — the best value it + can produce — and then says why that number is worthless: every note in that + pool was funded by one wallet, so the partition has one class and the class is + us. A measurement that only ever points outward is a measurement nobody has + tested. + +Anything we cannot support with a measurement whose method is published, we do +not say. There is a section below of things we deliberately do not claim. + +## The three parts, and where each one stands + +A mirror-pool is asked for three things: a **coordination layer**, a **privacy +set**, and the **incentives that keep people in it**. Taking them one at a time, +including the one where the answer is partly no. + +**The coordination layer is the two-phase epoch.** `submit_spend` verifies a +proof and burns a nullifier, paying out nothing; `settle_epoch` executes the +whole batch in one transaction, so every member's action lands at one timestamp, +in one ordering, under one signature. Arrival time cannot tell the members apart, +because there is only one arrival. A settlement of **20 actions with a single +required signature** is on devnet, at the 64-account lock ceiling, and every +account in it is named through a lookup table the settler publishes and then +closes. + +**The privacy set is the note tree, and its honest size is measured rather than +asserted.** A member proves in zero knowledge that they own *some* note, never +which. What that hides on the action side is closed — actions execute from the +pool's vault, so their funding trace leads to the pool and is identical for +everyone. What it does not close is where each member's *deposit* came from, and +that channel is measured against live mainnet data with the method published +beside the number. Nominal `k` is the tree; effective `k` is smaller; this +repository publishes both and never quotes the first alone. + +**The incentives are structural, and one of them is missing.** Four are enforced +by the program rather than recommended: you cannot act until a crowd exists +(`k_floor`), waiting is never a hostage situation (the one-hour timeout), a relay +is paid out of the denomination to sign so that you never do, and a batch whose +members paid different fees is refused outright — so converging on a common fee +is a rule, not advice. + +What is **not** here is a reward for dwell — for holding a note longer than you +needed to. It was designed, and it was cut with the entry fee that would have +funded it, because a fee with no payout path is a fund trap rather than a +half-built feature. The deeper reason it stayed cut is that a reward must be paid +to somebody, and naming a member's address on chain costs that member all of +their anonymity at the exact moment they are being rewarded for protecting +everyone else's. The anonymity-preserving version — a second nullifier, claimed +under the same floor, paid to a fresh address — is specified in +[`docs/INCENTIVES.md`](docs/INCENTIVES.md) rather than sketched, and is absent +rather than half-present. + +## What is here + +| | | +|---|---| +| `programs/mirror-pool` | The on-chain program. `submit_spend`, proof and all, costs about **101,000 CU** on a real SVM — half the default budget for one instruction. | +| `crates/mirror-core` | Field, Poseidon, Merkle accumulator, notes. Linked on-chain. | +| `crates/mirror-circuit` | R1CS gadget, membership circuit, prover, key export. | +| `crates/mirror-provenance` | The funding-provenance measurement. | +| `crates/mirror-cli` | The tool. `init-pool`, `note-new`, `deposit`, `tree`, `spend`, `settle`, `disclose`, `disclose-verify` for members; `setup`, `verify-setup`, `soak`, `crowd`, `close-table` for operators; `check-endpoint`, `seeds`, `collect`, `analyze`, `compare`, `selection` for the measurement. | + +**261 tests.** The end-to-end suite loads the `.so` that `make build-sbf` +produces into a real SVM, sends real transactions, and verifies a real Groth16 +proof through the actual syscall — so a divergence between what the host believes +and what the chain does cannot pass unnoticed. + +## Using it + +``` +export P= # every command needs it; D is the pool's denomination + +mirror note-new --denomination D --out m1.json # a note is a local secret +mirror deposit --program $P --note m1.json # escrow it, join the set +mirror tree --program $P --denomination D # rebuild the accumulator +mirror spend --program $P --note m1.json \ + --to --relay relay.json # the relay signs, never you +mirror settle --program $P --denomination D # permissionless +``` + +`docs/USAGE.md` is the walkthrough, and every line of output in it was produced +by running the command against devnet. It covers three more a member may want: +`init-pool`, which anyone can run, and `disclose` / `disclose-verify`, which +prove a settled action was yours to one verifier you choose. + +The other eleven subcommands operate a pool (`setup`, `verify-setup`, `soak`, +`crowd`, `close-table`) or run the measurement (`check-endpoint`, `seeds`, +`collect`, `analyze`, `compare`, `selection`); `--help` documents each, and +`docs/MEASUREMENT_LOG.md` gives the exact invocation for every published +number. + +**No server, no indexer, no account with anybody.** The program stores only the +accumulator's frontier — enough to append a leaf, not enough to prove one is +there — so a client needs the whole leaf set. `mirror tree` recovers it from the +transaction history, rebuilds the accumulator, and checks the root against the +one the program holds: + +``` + leaves recovered 2 + pool reports 2 + rebuilt root 0c77cb909067c1a57811be8c05237aff2715c65c6250fdde764ed768096cd732 + on-chain root 0c77cb909067c1a57811be8c05237aff2715c65c6250fdde764ed768096cd732 +``` + +A matching root proves the recovered set is complete and correctly ordered, which +is the precondition a membership proof needs. It means a member can act from a +machine that has never seen the pool, carrying nothing but their note file — and +that no operator, including us, sits between a member and their own money. + +The relay signs and the member never does, so no member key appears on chain +after the deposit. Below the crowd floor, `settle` says what it is waiting for +and why rather than returning an error code. + +### Giving up your anonymity, on purpose, to one person + +Anonymity you cannot surrender deliberately is a liability rather than a feature: +at some point a member has to show an exchange or an accountant that a particular +action was theirs. The usual answer is a viewing key or an auditor role, and both +are standing capabilities somebody else holds — a compel path that exists is a +compel path that can be used. + +There is none here. `mirror disclose` writes a file the member hands to **one +verifier they chose**, and `mirror disclose-verify` checks it by recomputing +every value in it: the commitment and the nullifier from the member's secrets, +the record's address from that recomputed nullifier, the accumulator from chain +history checked against the pool's own root, and the action read out of the +record. Ten checks, each reported separately, and one that cannot be completed is +a failure rather than a silence. A file whose stated nullifier disagrees with +what the secrets produce fails on that check while the others still pass, which +tells the verifier what was tampered with rather than merely that something was. + +No on-chain component, no auditor key, no protocol path that can be made to +produce one. Two things guard the member instead: + +- **It refuses before settlement.** The disclosure carries the note's secrets, + and before the nullifier is burnt those secrets *are* the deposit — anyone + holding them can prove membership and redirect the payout. After settlement + they authorise nothing and only demonstrate the link, which is the thing being + disclosed on purpose. +- **It refuses when it would cost the others too much.** Naming one action as + yours removes you as a candidate for every other action in the pool. If that + leaves the remaining set below the pool's floor, the command stops and says + what it would cost, and the override is a flag the member has to type out. The + gate is advisory — nobody can be stopped from disclosing out of band — and it + exists so the cost is visible at the moment it is paid, by the person not + paying it. + +Thirty-one tests cover it, one per tamper case, and each asserts *which* check +failed rather than merely that verification did. `docs/USAGE.md` shows the real +thing: a member proving, after the fact, that the **stake delegation** in +`CROWD.md` was theirs — ten checks, all recomputed, against devnet. + +### How large a crowd fits in one settlement + +**First, what this number is not.** It is not the size of the anonymity set. The +set is the tree — every note the pool holds — and a member's proof says only that +they own *some* leaf of it. The accumulator is 20 levels deep, so a pool holds up +to **1,048,576 notes**, and a pool with a thousand members has an anonymity set of +a thousand whatever its settlements look like. Proving membership costs the same +at any occupancy: the Merkle path is 20 hashes whether the tree holds ten notes or +a million. + +What a settlement bounds is something narrower — how many members share *one +timestamp*. Batching is what stops arrival time from separating members the proof +has already made indistinguishable, so a larger batch is better, and a pool with +more members than one batch holds settles in several, paying for it in timestamps +rather than in set size. The ceilings below are per transaction: not per pool, not +per epoch, and not a bound on `k`. + +Two answers, and the difference between them is a transaction format rather than +anything about the program. + +**With no setup at all**, settlement is a legacy transaction that names every +account by its full 32 bytes, and the 1232-byte packet is what stops it. That +floor is measured for each shape of action, not estimated: + +| the batch | members | bytes | taken | +|---|---|---|---| +| plain payments | **10** | 1228 | settled in litesvm | +| stake delegations, everyone to the same validator | **7** | 1140 | settled in litesvm | +| stake delegations, a different validator each | **6** | 1194 | settled in litesvm **and on devnet** | + +``` +settled 10 spends in one transaction: 1228 bytes (4 to spare), 19545 CU of 200000 +11 spends: rejected by the wire at 1327 bytes, 95 over the 1232-byte limit — +while the SVM settled the same batch in 24158 CU, so compute is not the constraint +``` + +**With an address lookup table**, the same accounts are named by one byte each, +and the packet stops being the thing in the way at all. `mirror settle` publishes +a table automatically for any batch that will not fit legacy. Twenty members +settled that way on devnet: + +``` +20 spends do not fit a legacy transaction: 2218 bytes, 986 over the 1232-byte packet. +Settling through a lookup table instead. + settlement is 332 bytes of 1232, one signature +``` + +[`enxa9fztmzEHM…`](https://explorer.solana.com/tx/enxa9fztmzEHMLsvhfzJwFVRsNWha7WiSEUEeNn7UPk8KAdpnWQDzEHarGL8d4ckyBvtWrEGCkuvgW7UFgFAHzp?cluster=devnet) +— twenty payouts, `numRequiredSignatures: 1`, 2 static keys and 62 resolved +through the table, 35,895 CU. Twenty recipients and twenty relays are named in +that transaction and **not one of them signed it**. + +Nothing in the program changes for this. `settle_epoch` requires a signature from +the settler and from nobody else, and a lookup table can serve any account that +is not a signer — so the ceiling was always a property of what the client chose +to build, and ten is the floor rather than the maximum. + +**What binds instead is the account-lock limit**, and that number was taken the +hard way: a batch of 24 was refused by devnet with `TooManyAccountLocks` at 77 +accounts. `solana-transaction` exports `MAX_TX_ACCOUNT_LOCKS = 128`, but that is +the raised limit and it is not live here, so a client must plan against 64 until +it can see otherwise. Three accounts per member, three for the settler, pool and vault, and one for +the program itself — which no lookup table can resolve, because a top-level +instruction names its program in the static section — puts +twenty members at exactly 64 locks — the transaction above sits on the limit. + +Settlement adds members while the batch still fits and defers the rest, so a +settler is never handed a transaction the cluster will refuse, and `init-pool` +refuses a crowd floor higher than one settlement can carry rather than letting a +pool be created that can only ever settle on its timeout. + +**A delegation batch moves too, and by more.** Counting locks instead of bytes +for the two stake shapes gives: + +| the batch | legacy packet | through a table | +|---|---|---| +| stake delegations, everyone to the same validator | 7 | **18** | +| stake delegations, a different validator each | 6 | **13** | + +Both roughly double, and the gap between them widens from one member to five — +because a shared vote account is named once either way but *locked* once too, so +agreeing on a validator buys more under locks than it did under bytes. + +Those two figures include the `SetComputeUnitLimit` instruction, because at this +size it is not optional: thirteen delegations cost on the order of 309,000 CU at +the per-member rate `docs/CROWD.md` measured, well past the 200,000 a transaction +is given by default. Asking for more brings the compute-budget program along, and +a program is an account — so raising the budget still costs a member, forty bytes +in a legacy packet and one lock through a table. **The escape from one limit is +paid for out of the other in both regimes**, which is the result rather than the +inconvenience. + +These two are computed the way the packet ceilings are — by building the real +instruction and counting what it names — and the 64-account limit they are +measured against was itself taken from devnet. A thirteen-member delegation batch +settled through a table on a live cluster is *not* something this repository +claims, and `docs/CROWD.md` says so in the same words. + +**The table is not free, and it is taken back down.** It costs four extra +transactions, a slot of latency, and rent — and, more to the point, while it +exists it is a public durable account listing every address the settlement is +about to touch, published *before* the settlement lands. Leaving one behind per +batch would turn a one-transaction event into a permanent on-chain index of the +batch, which is a strange thing for a privacy pool to accumulate. So settlement +deactivates it immediately and `mirror close-table` reclaims the rent and removes +the list once the runtime's cooldown has passed — 15,084,280 lamports back, and +the address list gone, on the table the settlement above used. + +Under legacy, the **packet size** binds in all three rows. Each spend brings accounts nobody else +shares — its record, its beneficiary, its relay — so a payment costs about 99 +bytes a member, and a call costs more because it also names its callee and the +callee's accounts. + +The interesting row is the last one. **Actions that diverge in content cost +anonymity-set size**: a member who picks their own validator names a vote +account nobody else in the batch names, one extra key per spend, and the batch +loses a member. That is a real trade-off in the design, so it is measured from +two sides that share no code path — `a_crowd_that_agrees_on_its_validator_carries_one_more_member` +in litesvm and a live devnet run in [`docs/CROWD.md`](docs/CROWD.md) — and both +land on 1194 bytes. + +Compute is not close for payments: ten settle in under 10% of the default +instruction budget. It is much closer for delegations. On devnet the six-member +divergent batch burned 142,856 of the 200,000 CU a single instruction gets, and +`CROWD.md` reports where that leaves a settler: **at that ceiling both exits are +shut**. Asking for a larger compute budget costs a second instruction, measured +at 40 bytes against that very batch, and a legacy batch has 38 to spare — so in a +legacy transaction, raising the budget means dropping a member. A lookup table +lifts that too, and how far for a batch of delegations is unmeasured: `CROWD.md` +says so rather than assuming the legacy number carries over. + +`ten_spends_fit_in_one_settlement_and_the_packet_is_what_stops_the_eleventh` +demonstrates the payment limit from both sides: it measures the eleventh batch +at 1327 bytes *and* replays the identical batch into a second pool, where the +SVM settles it without complaint. If compute ever became the binding constraint, +that test fails rather than quietly reporting the wrong reason. +`every_account_an_action_names_costs_the_batch_a_member` does the same for the +two delegation rows, against the real Stake program. + +Every figure is a worst case, and the tests say so: a batch whose members shared +a relay would name fewer distinct keys and fit more. They are also ceilings per +transaction, not per epoch — settlement is permissionless and a busy pool +settles in several batches, at the cost of several timestamps rather than one. + +## Synchronised actions are the point + +The brief asks for an anonymity set for *behaviour*, not for funds. That +distinction is load-bearing here, so it is tested rather than asserted: + +``` +settled 4 real CPI actions in one transaction, 40251 CU +``` + +That figure moves by a few thousand between runs — the accounts are generated +fresh each time and `find_program_address` searches a different number of bumps +to derive each record's address — so what the test *asserts* is the property +rather than the number: four CPI actions and their payouts stay under 60,000 CU, +comfortably inside one instruction's default budget. + +`a_crowd_of_members_perform_a_real_protocol_action_together` seeds a pool, +loads the **real SPL Memo program** into the SVM, and has four members each +prove membership and request the identical memo. Settlement invokes Memo four +times in a single transaction, every invocation made by the pool and funded from +its vault. + +What an observer holds afterwards is four identical memos, one timestamp, one +signer, and no field anywhere in the transaction that distinguishes which member +asked for which. The actions are indistinguishable **by content** because the +payloads match, and indistinguishable **by timing** because settlement gives them +one clock. + +Three properties make this a behavioural tool rather than a mixer with a CPI +bolted on: + +- **The target is arbitrary.** Selector one invokes any program with any payload. + Memo is used in the test because it is small, real, and validates its own + account list. +- **The pool can sign as your authority.** Selector two hands the pool's vault to + the callee as a *signer*, which is what a stake delegation or a governance vote + needs and what a transfer does not: somebody must sign as the authority, and + for a member who must never appear on chain, that somebody can only be the + pool. `the_pool_signs_an_action_as_its_own_authority` proves it under + **50,000 CU** against real SPL Memo — a program that refuses any account handed to it that + has not signed, and that names its signers in its logs. The test reads that log + for the vault's own key, so the claim rests on someone else's program. Devnet + carries the case this exists for: a **real stake delegation**, with the pool as + the staker authority — [see Deployment](#deployment). +- **Moving lamports is the degenerate case.** Selector zero is a plain transfer, + kept only because expressing "pay this account" should not require a target + program. + +The two invoke selectors exist because of an ordering constraint that was +measured rather than assumed. Selector one funds the beneficiary *before* the +call, so the target sees the value; the runtime then refuses to let the vault +cross the CPI boundary, because this program has already moved its lamports by +direct mutation. Selector two pays *after*, leaving the balance untouched at the +moment of the call, which is exactly what lets the vault be a signer. Both +orderings cannot hold at once, so the member chooses, and the selector is inside +the action binding — a settler cannot obtain the pool's signature for a proof +that did not ask for it. + +The constraint turned out to be about the **batch**, not the spend, and a live +cluster is what found it. The runtime objects to any lamport this program moved +anywhere in the same instruction, so three transfers settled ahead of a signed +call are enough to break it — a case a single-spend test cannot reach. +Settlement runs every signed call first and pays everybody afterwards. +`a_signed_action_settles_inside_a_batch_of_plain_transfers` pins it, because a +signed action that could only settle alone would have to wait out the timeout +rather than join a batch, giving up the shared timestamp that is the reason to +stand in a crowd. + +A separate test passes a **non-empty account list** through the CPI, which +matters because SPL Memo requires every account handed to it to have signed. If +the program dropped an account, mislabelled a signer flag, or miscounted, Memo +rejects — so the account plumbing is load-bearing in that test rather than +decorative. + +The honest limit: the action binding commits to *how many* accounts an action +takes, not *which*. Settlement is permissionless, so a settler chooses them. For +a target whose destination lives in an account rather than in instruction data, +that is a real gap, and `docs/THREAT_MODEL.md` states it rather than working +around it. + +## Properties, and how each is checked + +**A note's value cannot disagree with its commitment.** The denomination is a +pool constant rather than a field in the note, so `vault ≥ denomination × +outstanding` is a function of two counters that nothing a prover supplies can +influence. It is re-read from the vault after lamports move rather than inferred +from the arithmetic that moved them. + +**A nullifier is spent once, ever** — never epoch-scoped. + +Those two together make a class of drain *unrepresentable* rather than merely +untested, and the class is worth naming because a shielded pool built the +obvious way lands in it. Carry the amount as a field in the note and forget to +bind it to the commitment, and a depositor of one lamport withdraws the whole +pool holding a perfectly valid proof. Scope the nullifier to an epoch — natural +if epochs are how you batch — and one deposit pays out once per epoch, forever. + +Neither is reachable here. The denomination is not in the note, so there is no +amount to bind; and the nullifier set is global, so an epoch boundary cannot +reopen a spend. Both are pinned by tests that assert the rejection rather than +assuming it. + +**A relay cannot redirect, re-price, or steal an action.** The action binding is +never transmitted — it is recomputed on-chain from the selector, the target +program, the beneficiary, the relay, the relay fee, the declared account count +and the payload, then used as the third public input, so altering any of them +changes the binding and the pairing fails. The tests tamper with that exact +input and assert the real verifier rejects it. + +The relay is in there because binding a fee without binding its recipient is +half a binding: every other field travels in clear text, so a bystander watching +an unlanded `submit_spend` could otherwise lift the proof, name themselves, and +collect. Reading the relay from the signer rather than from the instruction is +what closes it. + +It does **not** bind *which* accounts fill an action's slots, only how many. +Settlement is permissionless, so a settler chooses them; for a target whose +destination is an account rather than instruction data, that is a real limit and +`docs/THREAT_MODEL.md` states it. + +**No member key ever appears on chain** on the relay path. + +**Nothing can hold a member's escrow.** There is no `self_spend` instruction +because none is needed: a member acts as their own relay at zero fee, and +settlement is permissionless, so they settle their own batch once the timeout +passes. The cost is the expected one — their wallet signs, giving up anonymity — +and the test pins that the exit works. + +**Gadget, host and syscall compute one hash.** The gadget and the host are each +pinned to circomlib's published `poseidon([1,2])` vector rather than to each +other, so the two agreeing on a wrong answer would need circomlib's own vector to +be wrong. The syscall is then checked against the host on-chain: the end-to-end +suite asserts the root the deployed program builds equals the root the host +built. A gadget whose native and in-circuit hashes disagree is the classic +expensive failure here, because nothing catches it until proving time and the +symptom — proofs that verify nowhere — points at everything except the hash. + +## The measurement + +**Every input is somebody else's chain data.** Nothing here is simulated, and +that distinction is load-bearing rather than stylistic: an anonymity number +computed from a protocol's own parameters is a statement about arithmetic — it +comes out however the formula says it must, and a hostile reviewer can derive it +without running anything. The interesting question is what a real funding graph +does to a real anonymity set, and the only way to answer it is to go and read +one. So `mirror collect` is the one networked command, it points at pools this +project does not control, and the artifacts it produced are committed so the +analysis can be rerun offline against exactly the bytes that produced the +headline. + +Four commands, two passes, and the split is the point: + +``` +mirror seeds --program # member-weighted frame, one row per depositor +mirror collect --seeds seeds.txt # the only networked step; writes sample.json +mirror analyze --sample sample.json # pure, offline, deterministic +mirror compare --sample a.json --against b.json # is the difference real? +mirror selection --earlier lo.json --later hi.json # are the unresolved missing at random? +``` + +`data/sample-privacycash-run6.json` is the committed artifact behind the +headline. Seven samples are committed in all, and they are what make each +correction checkable rather than merely described: + +| file | run | what it is | +|---|---|---| +| `sample-smoke.json` | 1 | the size-biased frame. 12 attempted, **0 resolved** | +| `sample-privacycash.json` | 3 | member-weighted, smaller budget | +| `sample-privacycash-run4.json` | 4 | bigger budget, broken tracer | +| `sample-privacycash-run6.json` | **6** | **the headline**, tracer fixed | +| `sample-marinade.json` | 5 | the control, broken tracer | +| `sample-marinade-run7.json` | 7 | the control, tracer fixed | +| `sample-marinade-run8.json` | 8 | the control at double the page cap | + +`mirror analyze` on any of them reproduces that run's numbers offline, and +`mirror selection` on a pair reproduces the missing-at-random check. Run 1's +sample is committed too, and it is the one that resolved nothing — a failed run +is evidence about the method and is kept as such. + +**Run 2 is the one exception**: it came back above the 1% RPC-failure limit and +its sample is not committed. Saying so is part of the record. + +**Every run since Run 4 had its budget and its prediction committed to git +before the collection started**, so the parameters are declarations rather than +descriptions, and the predictions are on the record including the ones that +turned out wrong. + +### Design choices, and the failure each one exists to avoid + +Every item here is a decision that a reasonable implementation gets wrong by +default. They are listed because a provenance number is only as good as the +weakest of them, and none of them is visible in the output. + +- **Edges come from balance deltas**, not instruction parsing, which is blind to + every program that moves lamports by direct account mutation. +- **The birth edge is the oldest credit**, so the walk goes to the *start* of a + wallet's history. Reading the most recent transactions instead is the wrong end + of the record for any wallet with more than a handful, and manufactures + "unresolved" for precisely the active wallets worth resolving. +- **The oldest transaction is where that search starts, not where it ends.** An + address often appears in someone else's transaction — an ATA creation, a + multisig setup — before it is ever funded, so its oldest transaction credits it + nothing. We got this wrong: the tracer read that one transaction and reported + "no incoming edge", turning *we stopped reading* into *there is nothing there* + for wallets with eleven thousand transactions. Found while building a control + population, fixed, every affected number re-collected, and written up in + `docs/MEASUREMENT_LOG.md` rather than quietly repaired. +- **The hub threshold is decoupled from the paging cap.** Collapse them into one + number — easy to do, since both are "how many signatures do we look at" — and + "reaches an attributable origin" quietly becomes a synonym for "hit the RPC page + cap", which admits every DEX program and trading bot as an origin. +- **RPC failures are never evidence.** Counted separately, excluded from the + distribution, and above a 1% failure rate the run refuses to print a headline + rather than printing a warning above one. +- **The endpoint is checked first.** A truncated endpoint returns `null` rather + than an error for pruned history, so a collection against one looks healthy + and reports every old funding event as absent. `check-endpoint` refuses. +- **The frame is member-weighted.** Each depositor counts once. Sampling + addresses because they appear in recent blocks is size-biased toward the + highest-frequency actors. + +### Two uncertainties, and the bias that runs against us + +A `ρ` is reported with **two** intervals, because they answer different +questions and neither covers the other: + +- the **unresolved bracket** — what if the members we could not resolve had all + been one class, or all been distinct? An exact bound. +- the **sampling interval** — these depositors are a draw from a much larger + population, so how much of `ρ` is the draw? A bootstrap over members, 10,000 + replicates at a published seed, so a reader recomputes our interval and not + merely a similar one. + +And a bias that no interval fixes: plug-in entropy is biased low when classes +are many and members few, which is every run here. Since `ρ = 2^−H(C)`, that +means **every ρ we publish is biased high — the pools plausibly leak less than +we report.** It is stated because it is the direction that makes our own number +look worse, and a bias disclosed only when it flatters is not a disclosure. + +That bias is also why `compare` exists rather than a subtraction. It falls the +same way on every population measured the same way, so a *difference* survives +what neither absolute number does — and when the interval on the difference +contains zero, the tool says the two are indistinguishable and declines to rank +them. + +### The assumption underneath all of it, tested + +Dropping unresolved members is only harmless if the ones that resolve are a fair +draw of the classes present. Every bracket and every comparison rests on that, +and it is normally asserted and left alone. It is testable: collect one frame at +two budgets, split the resolved members into *cheap to trace* and *expensive to +trace*, and ask whether the two groups have the same class distribution. + +| population | pair | cheap | expensive | difference, 95% | +|---|---|---|---|---| +| privacy pool | depth 8/cap 8 → 16/24 | 39, ρ 0.1179 | 15, ρ 0.1250 | −0.1507 … +0.0704 | +| staking control | same budget, tracer fixed | 16, ρ 0.0743 | 22, ρ 0.0585 | −0.0144 … +0.0786 | + +Neither separates: at this margin, being resolvable does not pick out particular +provenance classes. + +**Only the first row is a budget margin**, and the second is weaker than it +looks. The two staking runs used identical parameters — depth 16, page cap 24 — +and differ by the tracer fix rather than by budget, so its *expensive* group is +"members the broken tracer failed on" rather than "members a smaller budget +could not reach". It is a real check on whether that bug selected for particular +classes, which is worth knowing, and it is not a second budget margin. The +manifests in `data/` carry the parameters, so this is checkable rather than +taken on trust. + +Evidence, not proof, in either case — the first row speaks for the members just +beyond a cheaper budget, not for those beyond the larger one. + +Had it separated, that would have been the more important result, and it would +have invalidated the cross-population comparison outright rather than merely +delaying it. + +### The comparison we ran, and refused + +`ρ` is the headline because it is comparable across populations, so we measured +one that is **not seeking privacy at all** — Marinade staking depositors, +identical pipeline, identical parameters — to give the number a scale. + +``` +population members rho resampled 2.5-97.5% bias +privacy pool 54 0.0955 0.0848 .. 0.1790 +0.0276 +staking control 38 0.0362 0.0463 .. 0.0708 +0.0203 + +difference: +0.0592 95% +0.0259 .. +0.1229 +``` + +The interval on the difference excludes zero, and it points the way this +project's argument wants: the privacy pool reads as the more concentrated +population. **The tool refuses to report it**, because the control resolves 42 +of 92 members and what survives is its *traceable* subset. + +The gate that refuses this did not exist when `compare` was written, and was +added after seeing the control fall on the wrong side of it. So: **we built the +check that refuses our own favourable result, after learning the result was +favourable.** Both the code and that sentence are in the repository. + +Then we spent a run trying to clear it, having predicted in advance — in the +committed log, knowing which answer suited us — that a doubled budget would get +the control above half. **It did not.** Resolution went 38 → 42 against the 46 +needed, and the prediction is on the record as wrong. + +That failed run produced the more interesting number anyway: **311 RPC calls per +additional resolved member, against 50 for the population as a whole.** The +control is not under-resolved because we were stingy. Its remaining members have +genuinely long funding chains, and the *staking* pool — where nobody wants +deniability — turns out to be markedly harder to trace than the privacy pool, +which resolved at 65% for two-thirds of the cost per member (33 RPC calls +per resolved member against 50). We do not claim to know +why, and the explanation that would flatter us is one of the two candidates, +which is exactly why we are not asserting it. + +The comparison is reported as **unachieved**. There was no further run: the +stopping rule was fixed before collection, and a stopping rule that bends when +the result is close is not one. + +### The folklore formula is inverted + +`2^H(C)` — entropy over the class-size distribution — is widely quoted as the +effective anonymity set. It is the **leakage**: it is maximised when every member +stands alone, which is total deanonymisation. The anonymity is `2^H(X|C)`. + +Our headline is the loss factor `ρ = 2^−H(C)`, because it is independent of `k` +and therefore comparable across pools. Effective-k measured at small `k` +systematically understates the steady-state loss and cannot be extrapolated +upward. + +And **"worst case is 1" is not a finding.** Under any heavy-tailed provenance +prior somebody is always alone. It describes provenance in general, not the pool +being measured. + +## Deployment + +Live on **devnet** at +[`8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa`](https://explorer.solana.com/address/8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa?cluster=devnet). +Every signature below is a link — the claims in this section are meant to be +read off the cluster rather than off this page. The whole +lifecycle ran there against a real validator — pool creation, deposits, spends +each carrying a Groth16 proof verified by the deployed program's own syscall, and +a settlement that closed the vault to its rent-exempt minimum to the lamport. + +That settlement carried five spends, and **two of them were not transfers**. One +was a memo the pool signed. The other was a **real stake delegation**: + +``` +Delegated Stake: 1.09771712 SOL, activating +Delegated Vote Account: 2f9C9AU8nFRKUub8NHToNiZzcwmYiNeipVuP8akKgRVv +Stake Authority: EwiXhCnLcg6jEaHMumo5H4tZnVyoCtBPHU5R6hE798R5 ← the pool's vault +Withdraw Authority: H9DRVAD42eiQqmXeYrX5AWwoYRr4wie4MzvJDC6Wkxmn ← the operator +``` + +`DelegateStake` requires the staker authority to sign, and no member can be that +authority without appearing on chain and undoing the point. So the pool was, and +the pool signed. That is the whole design in one transaction: an observer sees +that a delegation happened, to which validator, for how much, and **cannot say +which of the five members asked for it**. + +The withdraw authority is deliberately *not* the pool, and that is the threat +model applied rather than restated: the pool's signature is available to every +member, so an authority the vault holds is one every member holds. Delegation +survives that — the worst a member can do is re-delegate somebody's stake. +Withdrawal does not. + +Evidence never rests on our own word. Memo names its signers and named the +vault; the stake account is read back after settlement and only reaches the +`Stake` variant by being delegated. The soak checks both against the cluster and +fails the run if either is absent, so `docs/PROOF.md` cannot carry these claims +without them being true. + +That file has every signature *and* the lamports, because "closed to the +rent-exempt minimum" is the interesting part of that sentence and a list of +signatures does not show it: 100,000,115 owed against 100,000,115 paid out, and a +vault resting on its floor with a remainder of zero. The soak asserts both and +fails the run otherwise, so that table cannot record a discrepancy and still +exit successfully. + +**Not on mainnet, and that is a decision rather than an omission.** The trusted +setup here is reproducible, not secure: the seed is public, so the toxic waste is +public, so proofs are forgeable by anyone who runs the setup. A live pool with +that property would be inviting deposits it cannot protect. Publishing a threat +model that says proofs are forgeable and simultaneously advertising a mainnet +address would be incoherent. + +Devnet demonstrates everything mainnet would: same runtime, same `alt_bn128` +syscall, same verifier, same bytes. What mainnet would add is a claim about +readiness that this setup does not support yet. The prerequisite is a real +multi-party ceremony, not more SOL. + +## What we do not claim + +- Not "unlinkable", not "untraceable", not "anonymous" without a named adversary + and a stated population. +- **Not that the funding-provenance channel is closed.** It is closed on the + action side and measured on the membership side. +- Not that the trusted setup is secure. It is *reproducible*, which is a + different and lesser property: the seed is public, so the toxic waste is + public, so proofs are forgeable. `mirror verify-setup` re-derives the key from + the public seed and compares it element by element against the one compiled + into the program — expected digest + `b0165d5eac6fe8273b6564c78e8ba548c97e6050ae785e9142de63c81aa905b7`. Reproducible + and insecure is a coherent position for an unaudited protocol; the incoherent + one is a setup that is *both* insecure and unreproducible, which is what + publishing the entropy while withholding the proving key produces — nobody can + verify the key, and nobody can regenerate it either. +- The on-chain `k_floor` bounds **program-visible membership** only. That is all + a program can check. +- **Not that privacy pools attract more concentrated funding than ordinary + users.** We measured a control to find out, the point estimates say they do, + and the sample does not support saying it. `ρ`'s comparability across + populations is demonstrated as machinery and unproven as a finding. +- Not audited. + +`docs/MEASUREMENT_LOG.md` records every collection run, including the three the +tool itself refused to publish a headline from — twice on the failure gate, once +on the bracket — and the one whose pre-registered prediction turned out wrong. A +measurement project that keeps only its successful runs is selecting rather than +reporting. + +## Documentation + +| | | +|---|---| +| `docs/ARCHITECTURE.md` | The design, and why each decision is what it is. | +| `docs/PROVENANCE_METHOD.md` | Adversary model, metrics, sampling, the honest-claims analysis. | +| `docs/GROTH16_INTEGRATION.md` | The arkworks-to-Solana byte layout, verified by execution. | +| `docs/MEASUREMENT_LOG.md` | Every run. | +| `docs/THREAT_MODEL.md` | The adversary, what holds, and every place it stops. | +| `docs/INCENTIVES.md` | What keeps a member in the pool, enforced by the program — and the one reward that is deliberately absent. | +| `docs/INTEGRATING.md` | Adding a protocol: the three action shapes, a worked stake delegation, and what the proof does and does not promise. | +| [`docs/a-behavioural-anonymity-set-for-solana.pdf`](docs/a-behavioural-anonymity-set-for-solana.pdf) | **The paper.** The protocol and the measurement as one argument, with the related work, the method in full, and the eight runs. | +| `docs/PROOF.md` | Devnet signatures for every flow, and the rejections. | +| `docs/CROWD.md` | Six members delegating to six different validators in one devnet transaction, and what divergence costs. | +| `docs/USAGE.md` | The member-facing commands, end to end, with real devnet output. | +| `docs/PLAN.md` | The design as decided, and where the shipped protocol departs from it. | diff --git a/crates/mirror-circuit/Cargo.toml b/crates/mirror-circuit/Cargo.toml new file mode 100644 index 00000000..4c334728 --- /dev/null +++ b/crates/mirror-circuit/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "mirror-circuit" +version.workspace = true +edition.workspace = true +# Not published to crates.io: these crates are built from this repository, and a +# registry copy would be a second source of truth for the same code. +publish = false +license.workspace = true + +# Host-only crate: proving, key generation and the R1CS gadget. Never linked +# into the on-chain program. +[dependencies] +mirror-core.workspace = true +ark-bn254.workspace = true +ark-ff.workspace = true +ark-ec.workspace = true +ark-relations.workspace = true +ark-r1cs-std.workspace = true +ark-groth16.workspace = true +ark-snark.workspace = true +ark-serialize.workspace = true +ark-std.workspace = true +ark-crypto-primitives.workspace = true +light-poseidon.workspace = true +thiserror.workspace = true + +[dev-dependencies] +solana-poseidon.workspace = true +groth16-solana.workspace = true diff --git a/crates/mirror-circuit/src/circuit.rs b/crates/mirror-circuit/src/circuit.rs new file mode 100644 index 00000000..d1016225 --- /dev/null +++ b/crates/mirror-circuit/src/circuit.rs @@ -0,0 +1,267 @@ +//! The membership circuit. +//! +//! The statement: *I know `(k, r, denom_tag)` such that `H3(k, r, denom_tag)` +//! is a leaf of the tree with root `R`, my nullifier is `H1(k)`, and this proof +//! is bound to `action`.* +//! +//! Public inputs are exactly three, and that is a cost decision: on-chain +//! verification measures at `74,179 + 5,661 x N` compute units, so every input +//! is ~5.7k CU. Anything else we need to commit to is folded into the action +//! binding rather than added as a fourth input. +//! +//! | public input | why it cannot be a witness | +//! |---|---| +//! | `root` | the program checks it against its own root history | +//! | `nullifier` | the program records it to prevent replay | +//! | `action_binding` | the program recomputes it from the action it executes | +//! +//! `denom_tag` stays a witness: the Merkle membership already constrains it, +//! because a pool's tree only ever contains leaves committed at that pool's +//! denomination. + +use crate::poseidon_gadget::poseidon_var; +use ark_bn254::Fr; +use ark_r1cs_std::{ + alloc::AllocVar, + boolean::Boolean, + eq::EqGadget, + fields::{fp::FpVar, FieldVar}, + select::CondSelectGadget, +}; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; +use mirror_core::TREE_DEPTH; + +#[derive(Clone)] +pub struct MembershipCircuit { + // Public. + pub root: Option, + pub nullifier: Option, + pub action_binding: Option, + // Witness. + pub k: Option, + pub r: Option, + pub denom_tag: Option, + pub leaf_index: Option, + pub siblings: Option>, +} + +impl MembershipCircuit { + /// A circuit with no assignment, for key generation. + pub fn blank() -> Self { + MembershipCircuit { + root: None, + nullifier: None, + action_binding: None, + k: None, + r: None, + denom_tag: None, + leaf_index: None, + siblings: None, + } + } +} + +impl ConstraintSynthesizer for MembershipCircuit { + fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { + let missing = || SynthesisError::AssignmentMissing; + + // --- public inputs, in the order groth16-solana will receive them --- + let root = FpVar::new_input(cs.clone(), || self.root.ok_or_else(missing))?; + let nullifier = FpVar::new_input(cs.clone(), || self.nullifier.ok_or_else(missing))?; + let action_binding = + FpVar::new_input(cs.clone(), || self.action_binding.ok_or_else(missing))?; + + // --- witnesses --- + let k = FpVar::new_witness(cs.clone(), || self.k.ok_or_else(missing))?; + let r = FpVar::new_witness(cs.clone(), || self.r.ok_or_else(missing))?; + let denom_tag = FpVar::new_witness(cs.clone(), || self.denom_tag.ok_or_else(missing))?; + + // Path orientation bits. `Boolean::new_witness` enforces booleanity, so + // a prover cannot supply a non-binary direction and steer the fold. + let mut path_bits = Vec::with_capacity(TREE_DEPTH); + for level in 0..TREE_DEPTH { + let bit = Boolean::new_witness(cs.clone(), || { + let index = self.leaf_index.ok_or_else(missing)?; + Ok((index >> level) & 1 == 1) + })?; + path_bits.push(bit); + } + + let mut sibling_vars = Vec::with_capacity(TREE_DEPTH); + for level in 0..TREE_DEPTH { + let s = FpVar::new_witness(cs.clone(), || { + let siblings = self.siblings.as_ref().ok_or_else(missing)?; + siblings.get(level).copied().ok_or_else(missing) + })?; + sibling_vars.push(s); + } + + // --- the note commitment is the leaf --- + let leaf = poseidon_var(&[k.clone(), r, denom_tag])?; + + // --- fold the path to a root --- + // bit = 0 means we are a left child, so the sibling goes on the right. + let mut current = leaf; + for (bit, sibling) in path_bits.iter().zip(sibling_vars.iter()) { + let left = FpVar::conditionally_select(bit, sibling, ¤t)?; + let right = FpVar::conditionally_select(bit, ¤t, sibling)?; + current = poseidon_var(&[left, right])?; + } + current.enforce_equal(&root)?; + + // --- the nullifier is derived from the same k that opened the leaf --- + let computed_nullifier = poseidon_var(&[k])?; + computed_nullifier.enforce_equal(&nullifier)?; + + // --- bind the action --- + // A Groth16 public input participates in verification only through the + // R1CS columns that reference it. An input used in no constraint has an + // all-zero column, so its `gamma_abc` term is the identity and *any* + // value satisfies the verification equation — the input is present but + // unbound. A relay could then swap the action after proving and the + // proof would still verify. + // + // One multiplicative constraint is enough to give it a non-zero column. + // The product itself is never used; emitting the constraint is the point. + // + // This is load-bearing rather than defensive, and it is checked rather + // than assumed: `tests/onchain_layout.rs` tampers with this exact public + // input and asserts the real on-chain verifier rejects the result. If + // this line were removed, that test would fail. + let _binding_is_referenced = action_binding.square()?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::poseidon_gadget::fr_from_be; + use ark_relations::r1cs::ConstraintSystem; + use mirror_core::{Field, MerkleTree, Note}; + + fn f(v: u64) -> Field { + Field::from_u64(v) + } + + /// Builds a tree, inserts notes, and returns a fully assigned circuit for + /// the note at `target`. + fn witness_for(target: usize, count: u64) -> (MembershipCircuit, Field) { + let mut tree = MerkleTree::new().unwrap(); + let denom = f(1); + let mut notes = Vec::new(); + for i in 1..=count { + let note = Note::new(f(i * 10), f(i * 100), denom); + tree.insert(note.commitment().unwrap()).unwrap(); + notes.push(note); + } + let note = notes[target]; + let proof = tree.proof(target as u64).unwrap(); + let root = tree.root().unwrap(); + let action_binding = f(0xabcdef); + + let circuit = MembershipCircuit { + root: Some(fr_from_be(root.as_bytes())), + nullifier: Some(fr_from_be(note.nullifier().unwrap().as_bytes())), + action_binding: Some(fr_from_be(action_binding.as_bytes())), + k: Some(fr_from_be(note.k.as_bytes())), + r: Some(fr_from_be(note.r.as_bytes())), + denom_tag: Some(fr_from_be(denom.as_bytes())), + leaf_index: Some(target as u64), + siblings: Some( + proof + .siblings + .iter() + .map(|s| fr_from_be(s.as_bytes())) + .collect(), + ), + }; + (circuit, root) + } + + fn satisfied(c: MembershipCircuit) -> bool { + let cs = ConstraintSystem::::new_ref(); + c.generate_constraints(cs.clone()).unwrap(); + cs.is_satisfied().unwrap() + } + + #[test] + fn an_honest_witness_satisfies_the_circuit() { + let (circuit, _) = witness_for(3, 9); + assert!(satisfied(circuit)); + } + + #[test] + fn every_position_in_the_tree_works() { + // Left children, right children, and the boundary where the frontier + // pairs against an empty subtree. + for target in 0..7 { + let (circuit, _) = witness_for(target, 7); + assert!(satisfied(circuit), "leaf {target} failed"); + } + } + + #[test] + fn a_wrong_root_is_rejected() { + let (mut circuit, _) = witness_for(2, 5); + circuit.root = Some(Fr::from(999u64)); + assert!(!satisfied(circuit)); + } + + #[test] + fn a_wrong_nullifier_is_rejected() { + let (mut circuit, _) = witness_for(2, 5); + circuit.nullifier = Some(Fr::from(999u64)); + assert!(!satisfied(circuit)); + } + + #[test] + fn a_forged_secret_is_rejected() { + // Knowing the path is not enough; you must open the leaf. + let (mut circuit, _) = witness_for(2, 5); + circuit.k = Some(Fr::from(12345u64)); + assert!(!satisfied(circuit)); + } + + #[test] + fn a_tampered_sibling_is_rejected() { + let (mut circuit, _) = witness_for(2, 5); + let mut siblings = circuit.siblings.clone().unwrap(); + siblings[0] = Fr::from(7u64); + circuit.siblings = Some(siblings); + assert!(!satisfied(circuit)); + } + + #[test] + fn claiming_a_different_leaf_index_is_rejected() { + let (mut circuit, _) = witness_for(2, 5); + circuit.leaf_index = Some(3); + assert!(!satisfied(circuit)); + } + + #[test] + fn a_note_from_another_denomination_is_rejected() { + let (mut circuit, _) = witness_for(2, 5); + circuit.denom_tag = Some(Fr::from(2u64)); + assert!(!satisfied(circuit)); + } + + #[test] + fn the_circuit_size_is_reasonable() { + let cs = ConstraintSystem::::new_ref(); + let (circuit, _) = witness_for(1, 4); + circuit.generate_constraints(cs.clone()).unwrap(); + let n = cs.num_constraints(); + // depth 20 nodes + one commitment + one nullifier, ~243 each. + assert!( + (4_000..8_000).contains(&n), + "circuit is {n} constraints, outside the expected band" + ); + assert_eq!( + cs.num_instance_variables(), + 4, + "one plus three public inputs" + ); + } +} diff --git a/crates/mirror-circuit/src/lib.rs b/crates/mirror-circuit/src/lib.rs new file mode 100644 index 00000000..6a018a7b --- /dev/null +++ b/crates/mirror-circuit/src/lib.rs @@ -0,0 +1,14 @@ +//! Groth16 membership circuit over BN254, its key generation, the host prover, +//! and export into the byte layout the on-chain verifier consumes. +//! +//! Host-only: never linked into the on-chain program. +#![forbid(unsafe_code)] + +pub mod circuit; +pub mod poseidon_gadget; +pub mod prover; +pub mod solana; + +pub use circuit::MembershipCircuit; +pub use prover::{generate, generate_reproducible, prove, Keys, SolanaProof, Witness}; +pub use solana::{vk_to_rust_source, vk_to_solana, SolanaVerifyingKey}; diff --git a/crates/mirror-circuit/src/poseidon_gadget.rs b/crates/mirror-circuit/src/poseidon_gadget.rs new file mode 100644 index 00000000..96147c0b --- /dev/null +++ b/crates/mirror-circuit/src/poseidon_gadget.rs @@ -0,0 +1,189 @@ +//! The R1CS Poseidon gadget. +//! +//! This mirrors `light_poseidon`'s permutation instruction for instruction, +//! reading its published round constants and MDS matrix rather than +//! re-deriving them. That is the whole design: the constants have exactly one +//! source, so the gadget cannot drift from the syscall. +//! +//! Two routes were rejected: +//! +//! * `ark_crypto_primitives`' `PoseidonSponge` is a sponge with rate and +//! capacity; its squeeze does not agree with circomlib's fixed-arity +//! compression. Reading `state[0]` after one permutation does agree, but that +//! is an implementation detail of the sponge rather than part of its contract. +//! The one open Solana project that made the sponge primary later migrated off +//! it. +//! * `ark_crypto_primitives::crh::poseidon::TwoToOneCRH` is not usable here for +//! the same reason. +//! +//! Several published Solana projects get this wrong in a way that only shows up +//! at proving time: their native hash and their in-circuit hash are different +//! functions, because the gadget was configured with home-rolled constants. +//! `matches_native_over_random_inputs` below is the test that would have caught +//! it. + +use ark_bn254::Fr; +use ark_ff::PrimeField; +use ark_r1cs_std::{fields::fp::FpVar, fields::FieldVar}; +use ark_relations::r1cs::SynthesisError; +use light_poseidon::{parameters::bn254_x5::get_poseidon_parameters, PoseidonParameters}; + +/// Poseidon over `inputs`, matching `light_poseidon::Poseidon::new_circom`. +/// +/// The state is `[domain_tag, inputs...]` with `domain_tag = 0`, the width is +/// `inputs.len() + 1`, and the digest is `state[0]` after the permutation. +pub fn poseidon_var(inputs: &[FpVar]) -> Result, SynthesisError> { + let width = inputs.len() + 1; + let params: PoseidonParameters = + get_poseidon_parameters::(width as u8).map_err(|_| SynthesisError::Unsatisfiable)?; + + // state = [domain_tag = 0, inputs...] + let mut state: Vec> = Vec::with_capacity(width); + state.push(FpVar::::constant(Fr::from(0u64))); + state.extend_from_slice(inputs); + + let all_rounds = params.full_rounds + params.partial_rounds; + let half_rounds = params.full_rounds / 2; + + for round in 0..half_rounds { + apply_ark(&mut state, ¶ms, round); + apply_sbox_full(&mut state, params.alpha)?; + state = apply_mds(&state, ¶ms); + } + for round in half_rounds..half_rounds + params.partial_rounds { + apply_ark(&mut state, ¶ms, round); + state[0] = pow_alpha(&state[0], params.alpha)?; + state = apply_mds(&state, ¶ms); + } + for round in half_rounds + params.partial_rounds..all_rounds { + apply_ark(&mut state, ¶ms, round); + apply_sbox_full(&mut state, params.alpha)?; + state = apply_mds(&state, ¶ms); + } + + Ok(state[0].clone()) +} + +/// Adds this round's constants. The constants are field constants, so this is +/// a linear operation and costs no constraints. +fn apply_ark(state: &mut [FpVar], params: &PoseidonParameters, round: usize) { + for (i, slot) in state.iter_mut().enumerate() { + let c = params.ark[round * params.width + i]; + *slot += FpVar::::constant(c); + } +} + +fn apply_sbox_full(state: &mut [FpVar], alpha: u64) -> Result<(), SynthesisError> { + for slot in state.iter_mut() { + *slot = pow_alpha(slot, alpha)?; + } + Ok(()) +} + +/// `x^alpha`. Alpha is 5 for every BN254 x5 instance, computed as +/// `((x^2)^2) * x` — three constraints, which is optimal for exponent 5. +fn pow_alpha(x: &FpVar, alpha: u64) -> Result, SynthesisError> { + debug_assert_eq!(alpha, 5, "the x5 parameter sets only support alpha = 5"); + let x2 = x.square()?; + let x4 = x2.square()?; + Ok(&x4 * x) +} + +/// Multiplies the state by the MDS matrix. The matrix is constant, so each +/// output is a linear combination of the inputs and costs no constraints. +fn apply_mds(state: &[FpVar], params: &PoseidonParameters) -> Vec> { + (0..params.width) + .map(|i| { + state + .iter() + .enumerate() + .fold(FpVar::::constant(Fr::from(0u64)), |acc, (j, a)| { + acc + a * FpVar::::constant(params.mds[i][j]) + }) + }) + .collect() +} + +/// Converts a canonical big-endian 32-byte element into `Fr`. +pub fn fr_from_be(bytes: &[u8; 32]) -> Fr { + Fr::from_be_bytes_mod_order(bytes) +} + +/// Converts `Fr` into canonical big-endian 32 bytes. +pub fn fr_to_be(f: &Fr) -> [u8; 32] { + use ark_ff::BigInteger; + let mut out = [0u8; 32]; + out.copy_from_slice(&f.into_bigint().to_bytes_be()); + out +} + +#[cfg(test)] +mod tests { + use super::*; + use ark_r1cs_std::{alloc::AllocVar, R1CSVar}; + use ark_relations::r1cs::ConstraintSystem; + use ark_std::rand::{RngCore, SeedableRng}; + + fn native(inputs: &[Fr]) -> Fr { + use light_poseidon::{Poseidon, PoseidonHasher}; + let mut h = Poseidon::::new_circom(inputs.len()).unwrap(); + h.hash(inputs).unwrap() + } + + fn in_circuit(inputs: &[Fr]) -> (Fr, usize) { + let cs = ConstraintSystem::::new_ref(); + let vars: Vec> = inputs + .iter() + .map(|v| FpVar::new_witness(cs.clone(), || Ok(*v)).unwrap()) + .collect(); + let out = poseidon_var(&vars).unwrap(); + assert!(cs.is_satisfied().unwrap(), "constraint system unsatisfied"); + (out.value().unwrap(), cs.num_constraints()) + } + + /// The parity test. If this ever fails, proofs stop verifying on-chain and + /// the reason will not be obvious from the failure. + #[test] + fn matches_native_over_random_inputs() { + let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(0x6d1_7707); + for arity in 1..=4usize { + for _ in 0..8 { + let inputs: Vec = (0..arity) + .map(|_| { + let mut b = [0u8; 32]; + rng.fill_bytes(&mut b); + Fr::from_be_bytes_mod_order(&b) + }) + .collect(); + let (got, _) = in_circuit(&inputs); + assert_eq!(got, native(&inputs), "arity {arity} diverged"); + } + } + } + + /// Anchors the gadget to the same external constant `mirror-core` pins, so + /// gadget and host are each checked against circomlib rather than against each + /// other, and the syscall is checked against the host on-chain. + #[test] + fn matches_the_published_circomlib_vector() { + let (got, _) = in_circuit(&[Fr::from(1u64), Fr::from(2u64)]); + assert_eq!( + fr_to_be(&got), + [ + 0x11, 0x5c, 0xc0, 0xf5, 0xe7, 0xd6, 0x90, 0x41, 0x3d, 0xf6, 0x4c, 0x6b, 0x96, 0x62, + 0xe9, 0xcf, 0x2a, 0x36, 0x17, 0xf2, 0x74, 0x32, 0x45, 0x51, 0x9e, 0x19, 0x60, 0x7a, + 0x44, 0x17, 0x18, 0x9a, + ] + ); + } + + #[test] + fn constraint_cost_is_as_budgeted() { + let (_, n) = in_circuit(&[Fr::from(1u64), Fr::from(2u64)]); + // 8 full rounds x 3 lanes x 3 constraints + 57 partial x 3 = 243. + assert!( + (200..300).contains(&n), + "arity-2 permutation cost {n} constraints, outside the expected band" + ); + } +} diff --git a/crates/mirror-circuit/src/prover.rs b/crates/mirror-circuit/src/prover.rs new file mode 100644 index 00000000..aa0cd150 --- /dev/null +++ b/crates/mirror-circuit/src/prover.rs @@ -0,0 +1,165 @@ +//! Key generation and proving. + +use crate::{ + circuit::MembershipCircuit, + poseidon_gadget::fr_from_be, + solana::{proof_to_solana, vk_to_solana, SolanaVerifyingKey}, +}; +use ark_bn254::{Bn254, Fr}; +use ark_groth16::{Groth16, Proof, ProvingKey, VerifyingKey}; +use ark_snark::SNARK; +use ark_std::rand::{RngCore, SeedableRng}; +use mirror_core::{Field, MerkleProof, Note}; + +/// A Groth16 keypair for the membership circuit. +pub struct Keys { + pub pk: ProvingKey, + pub vk: VerifyingKey, +} + +impl Keys { + pub fn solana_vk(&self) -> SolanaVerifyingKey { + vk_to_solana(&self.vk) + } +} + +/// Generates keys from a caller-supplied RNG. +/// +/// The security of the resulting keys is exactly the security of this RNG's +/// entropy: whoever knows it can forge proofs. `generate_reproducible` below +/// makes that trade explicit rather than hiding it. +pub fn generate(rng: &mut R) -> Result { + let (pk, vk) = Groth16::::circuit_specific_setup(MembershipCircuit::blank(), rng) + .map_err(|_| SetupError::KeyGeneration)?; + Ok(Keys { pk, vk }) +} + +/// Generates keys deterministically from a public seed. +/// +/// This trades ceremony secrecy for reproducibility, deliberately and in the +/// open. Anyone can re-derive byte-identical keys from the committed seed and +/// check that the deployed program's verifying key is the one the circuit in +/// this repository produces. +/// +/// It is **not** a secure setup: the seed is public, so the toxic waste is +/// public, so proofs are forgeable. It is the honest development posture, and +/// the multi-party path that replaces it for production is a separate, +/// documented procedure. +/// +/// The reproducibility is scoped, and the scope is the committed `Cargo.lock`. +/// `StdRng` is explicitly not guaranteed portable across `rand` releases, and +/// arkworks' key generation consumes randomness in an order that is an +/// implementation detail. Re-deriving the same bytes therefore requires the same +/// locked dependency graph, which is why the lockfile is committed and why the +/// setup transcript records a digest of the resulting key rather than trusting +/// the seed alone. +/// +/// There are two ways to get this wrong, and they are opposites. Publishing the +/// entropy string *and* withholding the proving key is the worst of both: the +/// setup is insecure, because the toxic waste is public, and unreproducible, +/// because no third party can regenerate the key to check it — so nobody can +/// produce a valid proof for the deployed program at all. Running a real +/// ceremony but verifying only `delta` in the transcript is the other: the +/// process looks rigorous while certifying a key that may belong to a different +/// circuit entirely. +pub fn generate_reproducible(seed: &[u8]) -> Result { + let mut expanded = [0u8; 32]; + for (i, slot) in expanded.iter_mut().enumerate() { + *slot = seed.get(i).copied().unwrap_or(0); + } + let mut rng = ark_std::rand::rngs::StdRng::from_seed(expanded); + generate(&mut rng) +} + +/// Everything the prover needs that is not already public. +pub struct Witness<'a> { + pub note: Note, + pub merkle_proof: &'a MerkleProof, + pub root: Field, + pub action_binding: Field, +} + +/// A proof plus the public inputs it was made against, in on-chain layout. +pub struct SolanaProof { + pub proof_a: [u8; 64], + pub proof_b: [u8; 128], + pub proof_c: [u8; 64], + /// `[root, nullifier, action_binding]`, big-endian, in circuit order. + pub public_inputs: [[u8; 32]; 3], +} + +/// Builds an assigned circuit from a witness. +fn assign(w: &Witness<'_>) -> Result<(MembershipCircuit, Field), ProveError> { + let nullifier = w.note.nullifier().map_err(|_| ProveError::Hash)?; + let circuit = MembershipCircuit { + root: Some(fr_from_be(w.root.as_bytes())), + nullifier: Some(fr_from_be(nullifier.as_bytes())), + action_binding: Some(fr_from_be(w.action_binding.as_bytes())), + k: Some(fr_from_be(w.note.k.as_bytes())), + r: Some(fr_from_be(w.note.r.as_bytes())), + denom_tag: Some(fr_from_be(w.note.denom_tag.as_bytes())), + leaf_index: Some(w.merkle_proof.leaf_index), + siblings: Some( + w.merkle_proof + .siblings + .iter() + .map(|s| fr_from_be(s.as_bytes())) + .collect(), + ), + }; + Ok((circuit, nullifier)) +} + +/// Proves membership, returning the proof in on-chain layout. +pub fn prove( + keys: &Keys, + witness: &Witness<'_>, + rng: &mut R, +) -> Result { + let (circuit, nullifier) = assign(witness)?; + let proof: Proof = + Groth16::::prove(&keys.pk, circuit, rng).map_err(|_| ProveError::Proving)?; + + // Self-check before handing the proof out. A proof that does not verify + // against its own verifying key will not verify on-chain either, and + // failing here gives a diagnosable error instead of an opaque + // ProofVerificationFailed from the syscall. + let public: Vec = vec![ + fr_from_be(witness.root.as_bytes()), + fr_from_be(nullifier.as_bytes()), + fr_from_be(witness.action_binding.as_bytes()), + ]; + let ok = + Groth16::::verify(&keys.vk, &public, &proof).map_err(|_| ProveError::Proving)?; + if !ok { + return Err(ProveError::SelfCheckFailed); + } + + let (proof_a, proof_b, proof_c) = proof_to_solana(&proof); + Ok(SolanaProof { + proof_a, + proof_b, + proof_c, + public_inputs: [ + witness.root.to_bytes(), + nullifier.to_bytes(), + witness.action_binding.to_bytes(), + ], + }) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] +pub enum SetupError { + #[error("groth16 key generation failed")] + KeyGeneration, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] +pub enum ProveError { + #[error("hashing failed while assigning the witness")] + Hash, + #[error("groth16 proving failed")] + Proving, + #[error("the proof did not verify against its own verifying key")] + SelfCheckFailed, +} diff --git a/crates/mirror-circuit/src/solana.rs b/crates/mirror-circuit/src/solana.rs new file mode 100644 index 00000000..46b3a126 --- /dev/null +++ b/crates/mirror-circuit/src/solana.rs @@ -0,0 +1,167 @@ +//! Conversion from arkworks 0.5 into the byte layout `groth16-solana` accepts. +//! +//! Verified by execution against the pinned versions; see +//! `docs/GROTH16_INTEGRATION.md` for the evidence and the full pitfall list. The +//! three that matter here: +//! +//! * **G2 stores `c1` before `c0`.** The syscall reads +//! `x.c1 ‖ x.c0 ‖ y.c1 ‖ y.c0`, while arkworks serialises `Fq2` as +//! `c0 ‖ c1`. Getting this backwards produces a proof that fails to verify +//! with no diagnostic. +//! * **`proof_a` must be negated.** The verifier computes +//! `e(A,B)·e(Σic,γ)·e(C,δ)·e(α,β) == 1`, which holds only for `A = −A_proof`. +//! Nothing negates it downstream. +//! * **Serialise coordinates, never the point.** arkworks packs a y-sign flag +//! into the top bit of y's most significant byte even uncompressed, on roughly +//! half of all points. Verification tolerates it, but the bytes are +//! non-canonical, which silently breaks anything that hashes or compares them +//! — including a verifying-key commitment. + +use ark_bn254::{Bn254, Fq, Fr, G1Affine, G2Affine}; +use ark_ec::AffineRepr; +use ark_ff::{BigInteger, PrimeField}; +use ark_groth16::{Proof, VerifyingKey}; + +fn fq_to_be(f: &Fq) -> [u8; 32] { + let mut out = [0u8; 32]; + out.copy_from_slice(&f.into_bigint().to_bytes_be()); + out +} + +/// A canonical field element as the on-chain verifier expects it. +pub fn fr_to_be(f: &Fr) -> [u8; 32] { + let mut out = [0u8; 32]; + out.copy_from_slice(&f.into_bigint().to_bytes_be()); + out +} + +/// G1 as `x_be ‖ y_be`. The point at infinity encodes as all zeros. +pub fn g1_to_solana(p: &G1Affine) -> [u8; 64] { + let mut out = [0u8; 64]; + if p.infinity { + return out; + } + out[..32].copy_from_slice(&fq_to_be(&p.x)); + out[32..].copy_from_slice(&fq_to_be(&p.y)); + out +} + +/// G2 as `x.c1_be ‖ x.c0_be ‖ y.c1_be ‖ y.c0_be` — note the cross order. +pub fn g2_to_solana(p: &G2Affine) -> [u8; 128] { + let mut out = [0u8; 128]; + if p.infinity { + return out; + } + out[..32].copy_from_slice(&fq_to_be(&p.x.c1)); + out[32..64].copy_from_slice(&fq_to_be(&p.x.c0)); + out[64..96].copy_from_slice(&fq_to_be(&p.y.c1)); + out[96..].copy_from_slice(&fq_to_be(&p.y.c0)); + out +} + +/// The proof in on-chain layout. `proof_a` comes back **negated**. +pub fn proof_to_solana(proof: &Proof) -> ([u8; 64], [u8; 128], [u8; 64]) { + let neg_a: G1Affine = (-proof.a.into_group()).into(); + ( + g1_to_solana(&neg_a), + g2_to_solana(&proof.b), + g1_to_solana(&proof.c), + ) +} + +/// A verifying key in the layout `groth16_solana::groth16::Groth16Verifyingkey` +/// borrows from. `ic` has one more entry than there are public inputs. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SolanaVerifyingKey { + pub alpha_g1: [u8; 64], + pub beta_g2: [u8; 128], + pub gamma_g2: [u8; 128], + pub delta_g2: [u8; 128], + pub ic: Vec<[u8; 64]>, +} + +impl SolanaVerifyingKey { + /// Number of public inputs this key verifies. + pub fn public_input_count(&self) -> usize { + self.ic.len().saturating_sub(1) + } + + /// A stable digest over the whole key, in a fixed order. + /// + /// This is what a setup transcript must bind, and it must be the *whole* + /// key. Checking only `delta` is the tempting shortcut — it is the element a + /// contribution actually changes — but it leaves `alpha`, `beta`, `gamma` + /// and every `IC` point unconstrained, so such a verifier would happily + /// certify a transcript whose key belongs to an entirely different circuit. + pub fn digest_preimage(&self) -> Vec { + let mut buf = Vec::with_capacity(64 + 128 * 3 + self.ic.len() * 64 + 8); + buf.extend_from_slice(&self.alpha_g1); + buf.extend_from_slice(&self.beta_g2); + buf.extend_from_slice(&self.gamma_g2); + buf.extend_from_slice(&self.delta_g2); + buf.extend_from_slice(&(self.ic.len() as u64).to_be_bytes()); + for point in &self.ic { + buf.extend_from_slice(point); + } + buf + } +} + +pub fn vk_to_solana(vk: &VerifyingKey) -> SolanaVerifyingKey { + SolanaVerifyingKey { + alpha_g1: g1_to_solana(&vk.alpha_g1), + beta_g2: g2_to_solana(&vk.beta_g2), + gamma_g2: g2_to_solana(&vk.gamma_g2), + delta_g2: g2_to_solana(&vk.delta_g2), + ic: vk.gamma_abc_g1.iter().map(g1_to_solana).collect(), + } +} + +/// Renders the key as a Rust source constant for the on-chain program. +pub fn vk_to_rust_source(vk: &SolanaVerifyingKey) -> String { + use core::fmt::Write; + let mut s = String::new(); + let _ = writeln!( + s, + "//! Generated by `mirror setup`. Do not edit.\n\ + //!\n\ + //! Verifies {} public inputs: root, nullifier, action_binding.\n", + vk.public_input_count() + ); + let _ = writeln!(s, "use groth16_solana::groth16::Groth16Verifyingkey;\n"); + let emit = |s: &mut String, name: &str, bytes: &[u8]| { + let _ = writeln!(s, "pub const {name}: [u8; {}] = [", bytes.len()); + for chunk in bytes.chunks(12) { + let line: Vec = chunk.iter().map(|b| format!("{b}")).collect(); + let _ = writeln!(s, " {},", line.join(", ")); + } + let _ = writeln!(s, "];\n"); + }; + emit(&mut s, "VK_ALPHA_G1", &vk.alpha_g1); + emit(&mut s, "VK_BETA_G2", &vk.beta_g2); + emit(&mut s, "VK_GAMMA_G2", &vk.gamma_g2); + emit(&mut s, "VK_DELTA_G2", &vk.delta_g2); + let _ = writeln!(s, "pub const VK_IC: [[u8; 64]; {}] = [", vk.ic.len()); + for point in &vk.ic { + let _ = writeln!(s, " ["); + for chunk in point.chunks(12) { + let line: Vec = chunk.iter().map(|b| format!("{b}")).collect(); + let _ = writeln!(s, " {},", line.join(", ")); + } + let _ = writeln!(s, " ],"); + } + let _ = writeln!(s, "];\n"); + let _ = writeln!( + s, + "pub const VERIFYING_KEY: Groth16Verifyingkey<'static> = Groth16Verifyingkey {{\n\ + \x20 nr_pubinputs: {},\n\ + \x20 vk_alpha_g1: VK_ALPHA_G1,\n\ + \x20 vk_beta_g2: VK_BETA_G2,\n\ + \x20 vk_gamme_g2: VK_GAMMA_G2,\n\ + \x20 vk_delta_g2: VK_DELTA_G2,\n\ + \x20 vk_ic: &VK_IC,\n\ + }};", + vk.public_input_count() + ); + s +} diff --git a/crates/mirror-circuit/tests/onchain_layout.rs b/crates/mirror-circuit/tests/onchain_layout.rs new file mode 100644 index 00000000..edc20935 --- /dev/null +++ b/crates/mirror-circuit/tests/onchain_layout.rs @@ -0,0 +1,141 @@ +//! The end-to-end assertion for the proving path: a proof produced by the host +//! prover must verify under the exact verifier the on-chain program runs, using +//! the exact verifying-key bytes we will bake into it. +//! +//! `groth16-solana` compiles for the host as well as for SBF, so this exercises +//! the real verifier rather than a stand-in. If the G2 component order or the +//! `proof_a` negation were wrong, this is where it surfaces — and it surfaces +//! as a clean failure here instead of as an opaque rejection on devnet. + +use groth16_solana::groth16::{Groth16Verifier, Groth16Verifyingkey}; +use mirror_circuit::{generate_reproducible, prove, Witness}; +use mirror_core::{Field, MerkleTree, Note}; + +const SEED: &[u8] = b"mirror-pool-reproducible-dev-setup-v1"; + +struct Fixture { + keys: mirror_circuit::Keys, + tree: MerkleTree, + notes: Vec, +} + +fn fixture(count: u64) -> Fixture { + let keys = generate_reproducible(SEED).expect("key generation"); + let mut tree = MerkleTree::new().unwrap(); + let denom = Field::from_u64(1); + let mut notes = Vec::new(); + for i in 1..=count { + let note = Note::new(Field::from_u64(i * 7), Field::from_u64(i * 13), denom); + tree.insert(note.commitment().unwrap()).unwrap(); + notes.push(note); + } + Fixture { keys, tree, notes } +} + +fn verify_onchain( + svk: &mirror_circuit::SolanaVerifyingKey, + p: &mirror_circuit::SolanaProof, +) -> Result<(), groth16_solana::errors::Groth16Error> { + let vk = Groth16Verifyingkey { + nr_pubinputs: svk.public_input_count(), + vk_alpha_g1: svk.alpha_g1, + vk_beta_g2: svk.beta_g2, + vk_gamme_g2: svk.gamma_g2, + vk_delta_g2: svk.delta_g2, + vk_ic: &svk.ic, + }; + let mut verifier = + Groth16Verifier::<3>::new(&p.proof_a, &p.proof_b, &p.proof_c, &p.public_inputs, &vk)?; + verifier.verify() +} + +#[test] +fn a_host_proof_verifies_under_the_onchain_verifier() { + let f = fixture(6); + let svk = f.keys.solana_vk(); + assert_eq!(svk.public_input_count(), 3); + assert_eq!( + svk.ic.len(), + 4, + "ic carries one more entry than public inputs" + ); + + let index = 3usize; + let merkle_proof = f.tree.proof(index as u64).unwrap(); + let witness = Witness { + note: f.notes[index], + merkle_proof: &merkle_proof, + root: f.tree.root().unwrap(), + action_binding: Field::from_u64(0xfeed_beef), + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([7u8; 32]); + let proof = prove(&f.keys, &witness, &mut rng).expect("proving"); + + verify_onchain(&svk, &proof).expect("the on-chain verifier rejected an honest proof"); +} + +#[test] +fn a_tampered_public_input_is_rejected_by_the_onchain_verifier() { + let f = fixture(6); + let svk = f.keys.solana_vk(); + let merkle_proof = f.tree.proof(1).unwrap(); + let witness = Witness { + note: f.notes[1], + merkle_proof: &merkle_proof, + root: f.tree.root().unwrap(), + action_binding: Field::from_u64(1234), + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([9u8; 32]); + let mut proof = prove(&f.keys, &witness, &mut rng).expect("proving"); + + // Re-point the action binding, which is what a malicious relay would do. + // Flip a low bit so the value stays a canonical scalar and the rejection + // comes from the pairing rather than from the range check. + proof.public_inputs[2][31] ^= 1; + assert!( + verify_onchain(&svk, &proof).is_err(), + "a redirected action must not verify" + ); +} + +#[test] +fn a_non_negated_proof_a_is_rejected() { + // Guards the single easiest mistake in this integration. groth16-solana does + // not negate proof_a for you; if a future refactor drops the negation, this + // fails loudly instead of on devnet. + let f = fixture(4); + let svk = f.keys.solana_vk(); + let merkle_proof = f.tree.proof(0).unwrap(); + let witness = Witness { + note: f.notes[0], + merkle_proof: &merkle_proof, + root: f.tree.root().unwrap(), + action_binding: Field::from_u64(5), + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([3u8; 32]); + let mut proof = prove(&f.keys, &witness, &mut rng).expect("proving"); + + // Negating again returns the original, un-negated A. + let a = ark_bn254::G1Affine::new_unchecked( + ark_ff::PrimeField::from_be_bytes_mod_order(&proof.proof_a[..32]), + ark_ff::PrimeField::from_be_bytes_mod_order(&proof.proof_a[32..]), + ); + proof.proof_a = mirror_circuit::solana::g1_to_solana(&(-a)); + assert!(verify_onchain(&svk, &proof).is_err()); +} + +#[test] +fn the_setup_is_reproducible_from_its_seed() { + // Anyone can re-derive the deployed verifying key from the committed seed. + // Publishing the entropy while withholding the key is the failure this + // guards against: insecure and unreproducible at the same time. + let a = generate_reproducible(SEED).unwrap().solana_vk(); + let b = generate_reproducible(SEED).unwrap().solana_vk(); + assert_eq!(a, b); + let c = generate_reproducible(b"a different seed") + .unwrap() + .solana_vk(); + assert_ne!(a, c); +} + +use ark_std::rand::SeedableRng; diff --git a/crates/mirror-cli/Cargo.toml b/crates/mirror-cli/Cargo.toml new file mode 100644 index 00000000..43ba790c --- /dev/null +++ b/crates/mirror-cli/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "mirror-cli" +version.workspace = true +edition.workspace = true +# Not published to crates.io: these crates are built from this repository, and a +# registry copy would be a second source of truth for the same code. +publish = false +license.workspace = true + +[[bin]] +name = "mirror" +path = "src/main.rs" + +[dependencies] +mirror-core.workspace = true +mirror-circuit.workspace = true +mirror-provenance.workspace = true +mirror-pool-program = { path = "../../programs/mirror-pool", default-features = false, features = ["no-entrypoint"] } +solana-keypair.workspace = true +solana-signer.workspace = true +solana-transaction = { workspace = true, features = ["serde", "wincode"] } +solana-program.workspace = true +solana-message.workspace = true +solana-system-interface.workspace = true +ark-std.workspace = true +ureq.workspace = true +base64 = "0.22" +bincode = "1.3" +anyhow.workspace = true +clap.workspace = true +sha2.workspace = true +hex.workspace = true +serde.workspace = true +serde_json.workspace = true diff --git a/crates/mirror-cli/src/chain.rs b/crates/mirror-cli/src/chain.rs new file mode 100644 index 00000000..05a7dac9 --- /dev/null +++ b/crates/mirror-cli/src/chain.rs @@ -0,0 +1,410 @@ +//! The few RPC calls a live run needs, over the same blocking client the +//! provenance collector uses. +//! +//! `solana-client` is deliberately not a dependency. It pulls +//! `solana-transaction-status-client-types`, which sits on the far side of the +//! ecosystem's in-progress `wincode` migration and cannot coexist with the +//! version litesvm requires. Rather than fight that resolution a second time, +//! this speaks JSON-RPC directly — four methods, all of which we already needed +//! to understand. + +use anyhow::{anyhow, Result}; +use base64::Engine; +use solana_program::pubkey::Pubkey; +use solana_transaction::Transaction; + +pub struct Chain { + endpoint: String, + agent: ureq::Agent, +} + +impl Chain { + pub fn new(endpoint: impl Into) -> Self { + Chain { + endpoint: endpoint.into(), + agent: ureq::AgentBuilder::new() + .timeout(std::time::Duration::from_secs(60)) + .build(), + } + } + + /// One call, retrying through rate limits. + /// + /// The public endpoints throttle aggressively and a 429 is not a failure of + /// the thing being measured — treating it as one would abandon a run that is + /// otherwise fine. Backoff is exponential and bounded, and a persistent 429 + /// still surfaces as an error rather than as a silent default. + fn call(&self, method: &str, params: serde_json::Value) -> Result { + let body = serde_json::json!({ + "jsonrpc": "2.0", "id": 1, "method": method, "params": params, + }); + // Ten attempts with a bounded exponential backoff, which is roughly + // four minutes of patience before giving up. Seven was not enough, and + // the reason is specific rather than a matter of taste: rebuilding a + // pool's accumulator means one `getTransaction` per signature, and the + // public endpoints throttle that method far harder than they throttle a + // balance read. A client that gives up during the burst leaves a member + // unable to spend a note they own, which is the one failure this tool + // must not have. + let mut wait = std::time::Duration::from_millis(500); + let mut last: Option = None; + let mut response: Option = None; + for _ in 0..10 { + match self.agent.post(&self.endpoint).send_json(body.clone()) { + Ok(r) => { + response = Some(r.into_json()?); + break; + } + Err(ureq::Error::Status(429, _)) => { + std::thread::sleep(wait); + // Capped, because doubling ten times is over eight minutes + // of sleeping for the last attempt alone, and a member + // watching a command hang learns nothing from it. + wait = (wait * 2).min(std::time::Duration::from_secs(30)); + last = Some("rate limited".into()); + } + Err(e) => return Err(anyhow!("{method}: {e}")), + } + } + let response = response.ok_or_else(|| { + anyhow!( + "{method}: gave up after retries ({})", + last.unwrap_or_default() + ) + })?; + if let Some(err) = response.get("error") { + return Err(anyhow!("{method}: {err}")); + } + response + .get("result") + .cloned() + .ok_or_else(|| anyhow!("{method}: no result")) + } + + pub fn latest_blockhash(&self) -> Result { + let v = self.call( + "getLatestBlockhash", + serde_json::json!([{ "commitment": "confirmed" }]), + )?; + let s = v + .pointer("/value/blockhash") + .and_then(|b| b.as_str()) + .ok_or_else(|| anyhow!("blockhash missing"))?; + s.parse().map_err(|e| anyhow!("bad blockhash: {e}")) + } + + /// Sends and waits for confirmation, returning the signature. + /// + /// A failed simulation is surfaced with its logs rather than a bare error, + /// because the program's own error code is the thing worth recording. + pub fn send(&self, tx: &Transaction) -> Result { + let wire = bincode::serialize(tx)?; + let encoded = base64::engine::general_purpose::STANDARD.encode(&wire); + let sig = self.call( + "sendTransaction", + serde_json::json!([ + encoded, + { "encoding": "base64", "preflightCommitment": "confirmed" } + ]), + )?; + let sig = sig + .as_str() + .ok_or_else(|| anyhow!("signature missing"))? + .to_string(); + self.confirm(&sig)?; + Ok(sig) + } + + /// Sends a versioned transaction, which is the only kind that can resolve + /// accounts through a lookup table. + /// + /// Separate from `send` rather than generic over both, because the wire + /// encodings differ and a legacy transaction silently serialized as + /// versioned — or the reverse — produces a signature verification failure + /// with nothing in it that points at the encoding. + pub fn send_versioned( + &self, + tx: &solana_transaction::versioned::VersionedTransaction, + ) -> Result { + let wire = bincode::serialize(tx)?; + let encoded = base64::engine::general_purpose::STANDARD.encode(&wire); + let sig = self.call( + "sendTransaction", + serde_json::json!([ + encoded, + { "encoding": "base64", "preflightCommitment": "confirmed" } + ]), + )?; + let sig = sig + .as_str() + .ok_or_else(|| anyhow!("signature missing"))? + .to_string(); + self.confirm(&sig)?; + Ok(sig) + } + + /// A slot recent enough to derive a lookup table's address from, and settled + /// enough that the address lookup table program will accept it. + /// + /// **Finalized, deliberately.** A table's address is seeded with a slot, and + /// the program validates that slot against the `SlotHashes` sysvar — which + /// holds rooted slots only. A *confirmed* slot is routinely ahead of what is + /// rooted, so deriving from one produces a table address the program rejects + /// with `is not a recent slot`, an error that names the right cause and + /// sounds like the opposite of the problem: the slot was too new, not too + /// old. + pub fn recent_slot(&self) -> Result { + let v = self.call( + "getSlot", + serde_json::json!([{ "commitment": "finalized" }]), + )?; + v.as_u64().ok_or_else(|| anyhow!("slot missing")) + } + + fn confirm(&self, signature: &str) -> Result<()> { + for _ in 0..40 { + let v = self.call( + "getSignatureStatuses", + serde_json::json!([[signature], { "searchTransactionHistory": true }]), + )?; + if let Some(status) = v.pointer("/value/0") { + if !status.is_null() { + if let Some(err) = status.get("err") { + if !err.is_null() { + return Err(anyhow!("transaction failed: {err}")); + } + } + let confirmed = status + .get("confirmationStatus") + .and_then(|c| c.as_str()) + .unwrap_or(""); + if confirmed == "confirmed" || confirmed == "finalized" { + return Ok(()); + } + } + } + std::thread::sleep(std::time::Duration::from_millis(1_200)); + } + Err(anyhow!("timed out waiting for {signature}")) + } + + pub fn account_data(&self, key: &Pubkey) -> Result>> { + let v = self.call( + "getAccountInfo", + // Commitment must be stated. The default is finalized, so a read + // immediately after a confirmed write sees nothing and the caller + // concludes the account was never created. + serde_json::json!([ + key.to_string(), + { "encoding": "base64", "commitment": "confirmed" } + ]), + )?; + let value = v.get("value").unwrap_or(&serde_json::Value::Null); + if value.is_null() { + return Ok(None); + } + let b64 = value + .pointer("/data/0") + .and_then(|d| d.as_str()) + .ok_or_else(|| anyhow!("account data missing"))?; + Ok(Some(base64::engine::general_purpose::STANDARD.decode(b64)?)) + } + + /// The log lines a landed transaction produced. + /// + /// Used to read what a *callee* said about a CPI, which is the only way to + /// check a claim about the inner call from outside: the outer signature + /// proves the transaction landed and says nothing about who signed the + /// instruction the pool made inside it. + pub fn transaction_logs(&self, signature: &str) -> Result> { + let v = self.call( + "getTransaction", + serde_json::json!([ + signature, + { "commitment": "confirmed", "maxSupportedTransactionVersion": 0 } + ]), + )?; + if v.is_null() { + return Err(anyhow!( + "getTransaction: {signature} is not visible yet on this endpoint" + )); + } + let logs = v + .pointer("/meta/logMessages") + .and_then(|l| l.as_array()) + .ok_or_else(|| anyhow!("getTransaction: {signature} carries no log messages"))?; + Ok(logs + .iter() + .filter_map(|l| l.as_str().map(str::to_owned)) + .collect()) + } + + /// Every signature that touched `address`, oldest first. + /// + /// Pages until the cluster runs out. The RPC returns newest first and pages + /// backwards through `before`, so the reversal at the end is what turns this + /// into an insertion order — and insertion order is the whole point, because + /// a Merkle accumulator rebuilt in the wrong order produces a different root + /// and no proof against it will ever verify. + /// + /// Failed transactions are dropped here rather than by the caller. They + /// changed no state, so a rebuild that included them would insert leaves the + /// chain never inserted. + pub fn signatures_for_address(&self, address: &Pubkey) -> Result> { + let mut out: Vec = Vec::new(); + let mut before: Option = None; + loop { + let params = match &before { + Some(b) => serde_json::json!([ + address.to_string(), + { "limit": 1000, "before": b, "commitment": "confirmed" } + ]), + None => serde_json::json!([ + address.to_string(), + { "limit": 1000, "commitment": "confirmed" } + ]), + }; + let page = self.call("getSignaturesForAddress", params)?; + let entries = page + .as_array() + .ok_or_else(|| anyhow!("getSignaturesForAddress: not an array"))?; + if entries.is_empty() { + break; + } + for entry in entries { + let sig = entry + .get("signature") + .and_then(|s| s.as_str()) + .ok_or_else(|| anyhow!("getSignaturesForAddress: entry without signature"))?; + before = Some(sig.to_string()); + if entry.get("err").map(|e| !e.is_null()).unwrap_or(false) { + continue; + } + out.push(sig.to_string()); + } + if entries.len() < 1000 { + break; + } + } + out.reverse(); + Ok(out) + } + + /// A landed transaction, decoded. + /// + /// Asked for as base64 and deserialised here rather than read out of the + /// RPC's parsed JSON, because parsed instruction data arrives base58-encoded + /// and decoding that would mean carrying an alphabet this crate otherwise + /// has no use for. + pub fn transaction(&self, signature: &str) -> Result> { + let v = self.call( + "getTransaction", + serde_json::json!([ + signature, + { + "commitment": "confirmed", + "encoding": "base64", + "maxSupportedTransactionVersion": 0 + } + ]), + )?; + if v.is_null() { + return Ok(None); + } + let encoded = v + .pointer("/transaction/0") + .and_then(|t| t.as_str()) + .ok_or_else(|| anyhow!("getTransaction: {signature} carried no transaction"))?; + let raw = base64::engine::general_purpose::STANDARD + .decode(encoded) + .map_err(|e| anyhow!("getTransaction: {signature} is not base64: {e}"))?; + // A versioned transaction will not deserialise into this shape. Treating + // that as "not one of ours" is correct: this program is only ever called + // from legacy transactions built by this CLI, and a versioned one that + // happened to touch the pool carries nothing we need. + Ok(bincode::deserialize::(&raw).ok()) + } + + pub fn balance(&self, key: &Pubkey) -> Result { + let v = self.call( + "getBalance", + serde_json::json!([key.to_string(), { "commitment": "confirmed" }]), + )?; + v.pointer("/value") + .and_then(|b| b.as_u64()) + .ok_or_else(|| anyhow!("balance missing")) + } + + /// The rent-exempt floor for an account of `space` bytes. + /// + /// Asked of the cluster rather than computed here. The rent parameters are + /// chain state, so a constant baked into this binary would be a second + /// source of truth that is right until it is not — and the number is used + /// to assert that a vault settled to its floor exactly, which is a claim + /// worth grounding in what the cluster itself says. + pub fn rent_exempt_minimum(&self, space: usize) -> Result { + let v = self.call( + "getMinimumBalanceForRentExemption", + serde_json::json!([space, { "commitment": "confirmed" }]), + )?; + v.as_u64() + .ok_or_else(|| anyhow!("rent-exempt minimum missing")) + } + + /// Vote accounts of validators the cluster currently counts as active, + /// ordered by stake, largest first. + /// + /// Only the `current` list is read. A delinquent validator's vote account + /// still exists and `DelegateStake` would still accept it, so a run that + /// drew from `delinquent` would succeed and prove the same thing — but the + /// claim being made is about members choosing between *real* validators, and + /// a reader checking the run against the cluster should find the ones they + /// would have chosen from too. + /// + /// The order is the cluster's, made deterministic by sorting on stake and + /// then on the key, so two runs against the same epoch pick the same + /// validators and a reader can reproduce the selection instead of taking the + /// list on trust. + pub fn active_vote_accounts(&self) -> Result> { + let v = self.call( + "getVoteAccounts", + serde_json::json!([{ "commitment": "confirmed" }]), + )?; + let current = v + .get("current") + .and_then(|c| c.as_array()) + .ok_or_else(|| anyhow!("getVoteAccounts: no current validators"))?; + let mut ranked: Vec<(u64, String)> = current + .iter() + .filter_map(|entry| { + let key = entry.get("votePubkey")?.as_str()?.to_string(); + let stake = entry.get("activatedStake")?.as_u64()?; + Some((stake, key)) + }) + .collect(); + ranked.sort_by(|a, b| b.0.cmp(&a.0).then_with(|| a.1.cmp(&b.1))); + ranked + .into_iter() + .map(|(_, key)| key.parse().map_err(|e| anyhow!("vote account {key}: {e}"))) + .collect() + } + + /// What a landed transaction actually cost in compute. + /// + /// Read back from the cluster rather than simulated. A simulation runs + /// against a different slot with different account states, and the number + /// this is used for — how close a full settlement comes to the budget — is + /// only interesting if it is the number the validator metered. + pub fn compute_units(&self, signature: &str) -> Result { + let v = self.call( + "getTransaction", + serde_json::json!([ + signature, + { "commitment": "confirmed", "maxSupportedTransactionVersion": 0 } + ]), + )?; + v.pointer("/meta/computeUnitsConsumed") + .and_then(|c| c.as_u64()) + .ok_or_else(|| anyhow!("getTransaction: {signature} reports no compute units")) + } +} diff --git a/crates/mirror-cli/src/client.rs b/crates/mirror-cli/src/client.rs new file mode 100644 index 00000000..cac7ae52 --- /dev/null +++ b/crates/mirror-cli/src/client.rs @@ -0,0 +1,826 @@ +//! The member-facing half of the tool: join a pool, act through it, settle it. +//! +//! Every command here reads what it needs from the chain. Nothing depends on a +//! file this tool wrote earlier except the note itself, and nothing depends on a +//! server we run. A member who keeps their note file can act from a fresh +//! machine; a member who loses it has lost the deposit, and no operator can +//! change that in either direction. + +use crate::chain::Chain; +use crate::history::{self, History}; +use crate::lookup; +use crate::note::StoredNote; +use anyhow::{anyhow, Context, Result}; +use ark_std::rand::SeedableRng; +use mirror_pool_program::{ + instruction::Instruction as MirrorIx, + pda::{pool_address, spend_address, vault_address}, + processor::{SELECTOR_INVOKE, SELECTOR_INVOKE_SIGNED, SELECTOR_TRANSFER}, + spend::{Spend, STATUS_PENDING}, + Pool, +}; +use solana_keypair::Keypair; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; +use solana_signer::Signer; +use solana_transaction::Transaction; +use std::path::Path; + +/// What the pool account says about itself. +pub struct PoolState { + pub pool: Pubkey, + pub vault: Pubkey, + pub denomination: u64, + pub k_floor: u32, + pub deposits: u64, + pub spends: u64, + pub root: [u8; 32], +} + +pub fn read_pool(chain: &Chain, program_id: &Pubkey, denomination: u64) -> Result { + let (pool, _) = pool_address(program_id, denomination); + let (vault, _) = vault_address(program_id, &pool); + let mut data = chain.account_data(&pool)?.ok_or_else(|| { + anyhow!( + "no pool exists at {pool} for denomination {denomination}. \ + Pool creation is permissionless — `mirror init-pool` makes one." + ) + })?; + let state = + Pool::load(&mut data).map_err(|e| anyhow!("{pool} is not a pool account: {e:?}"))?; + Ok(PoolState { + pool, + vault, + denomination: state.denomination(), + k_floor: state.k_floor(), + deposits: state.deposit_count(), + spends: state.spend_count(), + root: state + .current_root() + .map_err(|e| anyhow!("{e:?}"))? + .to_bytes(), + }) +} + +fn send(chain: &Chain, ix: Instruction, signers: &[&Keypair]) -> Result { + let blockhash = chain.latest_blockhash()?; + let message = solana_message::Message::new(&[ix], Some(&signers[0].pubkey())); + let tx = Transaction::new(signers, message, blockhash); + chain.send(&tx) +} + +// --------------------------------------------------------------------------- +// init-pool + +pub fn init_pool( + chain: &Chain, + program_id: &Pubkey, + denomination: u64, + k_floor: u32, + payer: &Keypair, +) -> Result<()> { + let (pool, _) = pool_address(program_id, denomination); + let (vault, _) = vault_address(program_id, &pool); + if chain.account_data(&pool)?.is_some() { + println!("the pool for denomination {denomination} already exists at {pool}"); + println!("nothing to do — one pool per denomination is the whole point"); + return Ok(()); + } + // A floor above what one settlement can carry is a floor no crowd can ever + // satisfy. Settlement locks three accounts per member plus three for the + // pool itself, so the largest batch a transaction can hold is fixed by the + // runtime and not by this program — and a pool asking for more than that can + // only ever settle through the liveness timeout, an hour at a time, which is + // the opposite of what a high floor is chosen for. + // + // Refused rather than warned about: a pool's floor is fixed at creation, so + // by the time anyone notices, the fix is a different pool. + let settleable = (lookup::MAX_ACCOUNT_LOCKS - 3) / 3; + if k_floor as usize > settleable { + return Err(anyhow!( + "a floor of {k_floor} is higher than one settlement can carry. A transaction \ + may lock {} accounts and each member costs three, so at most {settleable} \ + members settle together — a pool with this floor would never meet it by \ + crowd, and could only ever settle on the {}s timeout. Choose {settleable} \ + or fewer.", + lookup::MAX_ACCOUNT_LOCKS, + mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS, + )); + } + let ix = Instruction::new_with_bytes( + *program_id, + &MirrorIx::InitPool { + denomination, + entry_fee: 0, + k_floor, + } + .pack(), + vec![ + AccountMeta::new(payer.pubkey(), true), + AccountMeta::new(pool, false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = send(chain, ix, &[payer])?; + println!("pool {pool}"); + println!("vault {vault}"); + println!("signature {sig}"); + Ok(()) +} + +// --------------------------------------------------------------------------- +// deposit + +pub fn deposit( + chain: &Chain, + program_id: &Pubkey, + note_path: &Path, + depositor: &Keypair, +) -> Result<()> { + let stored = StoredNote::read(note_path)?; + let note = stored.note()?; + let state = read_pool(chain, program_id, stored.denomination)?; + let commitment = stored.commitment_bytes()?; + + // Refuse a second deposit of the same note before it costs anything. The + // program allows duplicate commitments — the only party a duplicate harms is + // whoever paid for it — but a member doing it by accident is out a + // denomination for a leaf they cannot distinguish from their first. + let history = history::scan(chain, program_id, &state.pool, false)?; + if history.index_of(&commitment).is_some() { + return Err(anyhow!( + "this note's commitment is already a leaf of this pool. Depositing it \ + again would escrow a second denomination against a note you cannot \ + tell apart from the first." + )); + } + + let balance = chain.balance(&depositor.pubkey())?; + if balance < state.denomination { + return Err(anyhow!( + "{} holds {} lamports and this pool escrows {} per deposit", + depositor.pubkey(), + balance, + state.denomination + )); + } + + let ix = Instruction::new_with_bytes( + *program_id, + &MirrorIx::Deposit { commitment }.pack(), + vec![ + AccountMeta::new(depositor.pubkey(), true), + AccountMeta::new(state.pool, false), + AccountMeta::new(state.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = send(chain, ix, &[depositor])?; + println!( + "deposited {} lamports into {}", + state.denomination, state.pool + ); + println!("leaf {}", state.deposits); + println!("signature {sig}"); + println!(); + println!( + "Keep {} safe. It is the only way to spend this note,", + note_path.display() + ); + println!("and nobody — including this pool's authors — can reissue it."); + let _ = note; + Ok(()) +} + +// --------------------------------------------------------------------------- +// tree + +/// Rebuilds the accumulator from chain history and checks it against the pool. +/// +/// The check is the point. A rebuilt tree whose root matches the one the program +/// holds is proof that the history is complete and correctly ordered, which is +/// exactly the precondition a membership proof needs. A mismatch means any proof +/// built here would fail on-chain for reasons that would be very hard to read +/// backwards from the failure. +pub fn tree(chain: &Chain, program_id: &Pubkey, denomination: u64) -> Result { + let state = read_pool(chain, program_id, denomination)?; + println!("pool {}", state.pool); + println!("vault {}", state.vault); + println!("denomination {}", state.denomination); + println!("k floor {}", state.k_floor); + println!( + "notes {} deposited, {} settled, {} outstanding", + state.deposits, + state.spends, + state.deposits.saturating_sub(state.spends) + ); + println!(); + println!("rebuilding the accumulator from chain history:"); + + let history = history::scan(chain, program_id, &state.pool, true)?; + let rebuilt = history.tree()?; + let root = rebuilt.root().map_err(|e| anyhow!("{e:?}"))?; + + println!(); + println!(" leaves recovered {}", history.commitments.len()); + println!(" pool reports {}", state.deposits); + println!(" rebuilt root {}", hex::encode(root.to_bytes())); + println!(" on-chain root {}", hex::encode(state.root)); + + if history.commitments.len() as u64 != state.deposits { + return Err(anyhow!( + "recovered {} leaves but the pool has inserted {}. The history is \ + incomplete — most likely the endpoint has pruned it. `mirror \ + check-endpoint` tests for exactly that.", + history.commitments.len(), + state.deposits + )); + } + if root.to_bytes() != state.root { + return Err(anyhow!( + "the rebuilt root does not match the pool's. The leaf set or its \ + order is wrong, and any proof built against this tree would be \ + rejected on-chain." + )); + } + println!(); + println!(" the rebuilt tree matches the chain — proofs built from it will verify"); + Ok(history) +} + +// --------------------------------------------------------------------------- +// spend + +/// What a member is asking the pool to do. +pub enum Action { + /// Pay the beneficiary, no CPI. + Transfer, + /// Call `target` with `payload`. `pool_signs` picks the selector that hands + /// the vault to the callee as a signer. + Invoke { + target: Pubkey, + payload: Vec, + accounts: u8, + pool_signs: bool, + }, +} + +impl Action { + fn selector(&self) -> u64 { + match self { + Action::Transfer => SELECTOR_TRANSFER, + Action::Invoke { + pool_signs: false, .. + } => SELECTOR_INVOKE, + Action::Invoke { + pool_signs: true, .. + } => SELECTOR_INVOKE_SIGNED, + } + } + fn target(&self) -> [u8; 32] { + match self { + Action::Transfer => [0u8; 32], + Action::Invoke { target, .. } => target.to_bytes(), + } + } + fn payload(&self) -> &[u8] { + match self { + Action::Transfer => &[], + Action::Invoke { payload, .. } => payload, + } + } + fn accounts(&self) -> u8 { + match self { + Action::Transfer => 0, + Action::Invoke { accounts, .. } => *accounts, + } + } +} + +#[allow(clippy::too_many_arguments)] +pub fn spend( + chain: &Chain, + program_id: &Pubkey, + note_path: &Path, + beneficiary: &Pubkey, + relay: &Keypair, + relay_fee: u64, + action: Action, +) -> Result<()> { + let stored = StoredNote::read(note_path)?; + let note = stored.note()?; + let state = read_pool(chain, program_id, stored.denomination)?; + + if relay.pubkey() == *beneficiary { + eprintln!( + "warning: the relay and the beneficiary are the same key, which links \ + the payout to whoever paid the fee." + ); + } + if relay_fee >= state.denomination { + return Err(anyhow!( + "a relay fee of {relay_fee} is not less than the denomination {}", + state.denomination + )); + } + if state.deposits < state.k_floor as u64 { + return Err(anyhow!( + "this pool holds {} notes and its floor is {}. It refuses to act \ + below the floor, because a crowd of one is not a crowd.", + state.deposits, + state.k_floor + )); + } + + println!("rebuilding the accumulator so this note can be proved a member:"); + let history = history::scan(chain, program_id, &state.pool, true)?; + let commitment = stored.commitment_bytes()?; + let index = history.index_of(&commitment).ok_or_else(|| { + anyhow!( + "this note is not a leaf of the pool. Either it was never deposited, \ + or it belongs to a different denomination." + ) + })?; + let tree = history.tree()?; + let root = tree.root().map_err(|e| anyhow!("{e:?}"))?; + if root.to_bytes() != state.root { + return Err(anyhow!( + "the rebuilt root does not match the pool's, so a proof against it \ + would be rejected. Run `mirror tree` to see the mismatch." + )); + } + println!( + " this note is leaf {index} of {}", + history.commitments.len() + ); + + // The mistake that undoes the whole protocol, caught before it lands. + // + // The relay signs, so its key is public on the spend transaction. If that + // same key signed a deposit into this pool, an observer joins the two by + // reading two public transactions and the anonymity set collapses to one for + // this action — the proof stays sound and protects nothing. It is an easy + // mistake to make, because the obvious key to hand `--relay` is the one + // already funded, which is the one that deposited. + if history.depositors.contains(&relay.pubkey()) { + return Err(anyhow!( + "the relay {} has also deposited into this pool.\n\n\ + The relay signs this spend, so its key is public on it. A key that \ + appears on both a deposit and a spend links them, and this action's \ + anonymity set collapses to one — the proof would be sound and \ + pointless.\n\n\ + Use a key with no history with this pool, funded from somewhere that \ + does not lead back to your deposit.", + relay.pubkey() + )); + } + + let binding = mirror_core::action_binding( + action.selector(), + &action.target(), + &beneficiary.to_bytes(), + &relay.pubkey().to_bytes(), + relay_fee, + action.accounts(), + action.payload(), + ); + let merkle_proof = tree.proof(index).map_err(|e| anyhow!("{e:?}"))?; + let witness = mirror_circuit::Witness { + note, + merkle_proof: &merkle_proof, + root, + action_binding: binding, + }; + + println!("deriving the proving key from the published seed (this takes a moment)"); + let keys = crate::soak::keys()?; + println!("proving membership"); + let mut rng = ark_std::rand::rngs::StdRng::from_entropy(); + let proof = mirror_circuit::prove(&keys, &witness, &mut rng).map_err(|e| anyhow!("{e:?}"))?; + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(program_id, &state.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + *program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: action.selector(), + target_program: action.target(), + beneficiary: beneficiary.to_bytes(), + relay_fee, + action_accounts: action.accounts(), + payload: action.payload().to_vec(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(state.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = send(chain, ix, &[relay])?; + + println!(); + println!("submitted. The note is spent and the action is recorded."); + println!(" nullifier {}", hex::encode(nullifier)); + println!(" record {spend_pda}"); + println!(" signature {sig}"); + println!(); + println!("Nothing has been paid out yet — settlement executes the batch, which is"); + println!("what gives every member's action one timestamp. Run `mirror settle`, or"); + println!("wait for anyone else to."); + Ok(()) +} + +// --------------------------------------------------------------------------- +// settle + +pub fn settle( + chain: &Chain, + program_id: &Pubkey, + denomination: u64, + settler: &Keypair, + now: i64, +) -> Result<()> { + let state = read_pool(chain, program_id, denomination)?; + println!("looking for spends waiting to settle:"); + let history = history::scan(chain, program_id, &state.pool, true)?; + + let mut ready: Vec<(Pubkey, Pubkey, Pubkey, i64, u64)> = Vec::new(); + let mut skipped_actions: Vec<([u8; 32], u64, u8)> = Vec::new(); + for submitted in &history.spends { + let Some(mut data) = chain.account_data(&submitted.spend)? else { + continue; + }; + let Ok(record) = Spend::load(&mut data) else { + continue; + }; + if record.status() != STATUS_PENDING { + continue; + } + if record.selector() != SELECTOR_TRANSFER { + // A CPI action needs the account list its callee expects, which this + // command cannot infer from the chain — the record binds how many + // accounts, never which. Settling those is a caller's job. + skipped_actions.push(( + submitted.nullifier, + record.selector(), + record.action_accounts(), + )); + continue; + } + ready.push(( + submitted.spend, + Pubkey::new_from_array(record.beneficiary()), + Pubkey::new_from_array(record.relay()), + record.submitted_at(), + record.relay_fee(), + )); + } + + if !skipped_actions.is_empty() { + println!( + " {} pending action(s) left alone: a CPI needs the account list its callee", + skipped_actions.len() + ); + println!(" expects, and the record binds how many accounts, never which."); + for (nullifier, selector, accounts) in &skipped_actions { + println!( + " nullifier {} — selector {selector}, {accounts} account(s)", + hex::encode(nullifier) + ); + } + } + if ready.is_empty() { + println!(" nothing to settle"); + return Ok(()); + } + + // Members are paid `denomination - relay_fee`, and that payout is public — so + // a batch mixing fees settles into visibly different amounts and an observer + // partitions it by value. The program refuses such a batch; this picks one + // fee and settles the members who paid it, rather than assembling a + // transaction that will be rejected. + // + // The largest group goes first, because the batch that hides its members + // best is the biggest one available. + let mut by_fee: std::collections::BTreeMap> = std::collections::BTreeMap::new(); + for entry in ready { + by_fee.entry(entry.4).or_default().push(entry); + } + let fee_groups = by_fee.len(); + let (chosen_fee, mut ready) = by_fee + .into_iter() + .max_by_key(|(_, group)| group.len()) + .expect("there is at least one pending spend"); + if fee_groups > 1 { + println!(); + println!( + " the pending spends carry {fee_groups} different relay fees. Settling the {} that", + ready.len() + ); + println!( + " paid {chosen_fee}: a batch of mixed fees pays visibly different amounts, which" + ); + println!(" lets an observer partition it by value. Run again for the others."); + } + + // A lookup table takes the packet out of the way, and what takes over is the + // number of accounts a transaction may lock. Members are added while the + // batch still fits under it, so a settler is never handed a transaction the + // cluster will refuse — and never has to know the limit exists. + let base = vec![ + AccountMeta::new(settler.pubkey(), true), + AccountMeta::new(state.pool, false), + AccountMeta::new(state.vault, false), + ]; + let mut metas = base.clone(); + let mut taken = 0usize; + for (spend, beneficiary, relay, _, _) in &ready { + let mut next = metas.clone(); + next.push(AccountMeta::new(*spend, false)); + next.push(AccountMeta::new(*beneficiary, false)); + next.push(AccountMeta::new(*relay, false)); + if lookup::locks_for(&next, program_id, &settler.pubkey()) > lookup::MAX_ACCOUNT_LOCKS { + break; + } + metas = next; + taken += 1; + } + if taken == 0 { + return Err(anyhow!( + "a single spend already locks more than the {} accounts a transaction may hold", + lookup::MAX_ACCOUNT_LOCKS + )); + } + let deferred = ready.len() - taken; + if deferred > 0 { + println!(); + println!( + " {} spend(s) pending; settling {taken} of them, which is what fits under the", + ready.len() + ); + println!( + " {}-account lock limit. Run this again for the rest — the cost is a", + lookup::MAX_ACCOUNT_LOCKS + ); + println!(" second timestamp, which is a real cost to the anonymity of both halves."); + } + ready.truncate(taken); + + // The crowd rule, checked against the batch actually being sent rather than + // against everything pending. Those differ whenever the lock limit truncates + // a batch, and checking the wrong one builds a transaction the program then + // refuses with a bare error code — which is exactly what this check exists + // to spare a caller. + let crowd = ready.len() as u32 >= state.k_floor; + let timeout = mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS; + if !crowd { + let youngest = ready.iter().map(|(_, _, _, at, _)| *at).max().unwrap_or(0); + let waited = now.saturating_sub(youngest); + if waited < timeout { + println!(); + println!( + " this batch carries {} spend(s) and the pool's floor is {}.", + ready.len(), + state.k_floor + ); + if deferred > 0 { + println!( + " {} more are pending but cannot join: the floor is above what one", + deferred + ); + println!(" transaction can settle, so this pool can only settle on the timeout."); + } + println!( + " A batch below the floor may settle once every spend in it has waited {timeout}s;" + ); + println!( + " the youngest has waited {waited}s, so {}s remain.", + timeout - waited + ); + println!(); + println!(" This is a liveness guarantee rather than a restriction: nobody can"); + println!(" hold a member's funds waiting for a crowd that never arrives."); + return Ok(()); + } + + // Past the timeout the program will accept this batch whatever its size, + // and a settler about to publish an under-floor batch should be told what + // it buys the members in it — which, at one member, is nothing. The + // timeout is a solvency guarantee and it is not an anonymity one. + println!(); + println!( + " WARNING: this batch carries {} spend(s), below the pool's floor of {}.", + ready.len(), + state.k_floor + ); + println!(" It settles because every spend in it has waited out the {timeout}s timeout,"); + println!(" which is a solvency guarantee and not an anonymity one. The members in"); + if ready.len() == 1 { + println!(" this batch get an anonymity set of exactly one: the action will be"); + println!(" attributable to whoever submitted it. Wait for company if you can."); + } else { + println!( + " this batch get an anonymity set of {}, not {}.", + ready.len(), + state.k_floor + ); + } + } + + let ix = Instruction::new_with_bytes( + *program_id, + &MirrorIx::SettleEpoch { + count: ready.len() as u8, + } + .pack(), + metas, + ); + + // A legacy transaction names every account by its full 32 bytes, so a batch + // outgrows the 1232-byte packet at ten members. Rather than settle ten and + // leave the rest, a batch that does not fit is settled through a lookup + // table, which names the same accounts by one byte each. + // + // Legacy stays the default for batches that fit, and that is deliberate: a + // table costs four extra transactions, a slot of latency and rent, and none + // of it buys anything for a batch already inside the packet. + let sig = match legacy_settlement_bytes(&ix, &settler.pubkey()) { + bytes if bytes <= PACKET_DATA_SIZE => { + println!(); + println!( + "settling {} spends in one legacy transaction, {bytes} bytes", + ready.len() + ); + send(chain, ix, &[settler])? + } + bytes => { + println!(); + println!( + " {} spends do not fit a legacy transaction: {bytes} bytes, {} over the \ + {PACKET_DATA_SIZE}-byte packet.", + ready.len(), + bytes - PACKET_DATA_SIZE + ); + println!(" Settling through a lookup table instead."); + settle_through_lookup_table(chain, ix, settler)? + } + }; + println!(); + println!("settled {} spends in one transaction", ready.len()); + println!(" signature {sig}"); + println!(); + println!("Every payout in that batch shares one timestamp and one ordering, which"); + println!("is what stops arrival time from telling the members apart."); + Ok(()) +} + +/// The 1280-byte IPv6 minimum MTU, less a 40-byte IPv6 header and an 8-byte +/// fragment header. +const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; + +/// What this instruction would weigh as a legacy transaction signed by one key. +fn legacy_settlement_bytes(ix: &Instruction, payer: &Pubkey) -> usize { + let message = solana_message::Message::new(std::slice::from_ref(ix), Some(payer)); + 1 + 64 + message.serialize().len() +} + +/// Publishes a lookup table, settles through it, and then takes it back down. +/// +/// The table is the interesting part of the cost, and not only because of the +/// rent. While it exists it is a public, durable account listing every address +/// the settlement is about to touch — published *before* the settlement lands, +/// signed by the settler. Leaving it there would turn a one-transaction event +/// into a permanent on-chain index of the batch, which is a strange thing for a +/// privacy pool to leave behind. +/// +/// So it is deactivated immediately, and closing it — which returns the rent and +/// removes the list — is reported as the errand it is: the runtime enforces a +/// cooldown of roughly `DEACTIVATION_COOLDOWN_SLOTS` slots first, because a +/// transaction already in flight may still be resolving against the table. +fn settle_through_lookup_table( + chain: &Chain, + ix: Instruction, + settler: &Keypair, +) -> Result { + use solana_message::{v0, AddressLookupTableAccount, VersionedMessage}; + use solana_transaction::versioned::VersionedTransaction; + + let authority = settler.pubkey(); + let addresses = lookup::addresses_for(&ix.accounts, &ix.program_id); + + let recent_slot = chain.recent_slot()?; + let (create_ix, table) = lookup::create(&authority, &authority, recent_slot)?; + send(chain, create_ix, &[settler])?; + println!(" lookup table {table}"); + + for chunk in addresses.chunks(lookup::ADDRESSES_PER_EXTEND) { + let extend_ix = lookup::extend(&table, &authority, &authority, chunk)?; + send(chain, extend_ix, &[settler])?; + } + println!(" {} addresses published", addresses.len()); + + // A table cannot be used in the slot it was extended in: the runtime resolves + // it against a slot strictly later than the last write. Waiting for the + // cluster to move on is not politeness, it is the difference between a + // settlement that lands and one rejected for an address the table already + // holds. + let extended_at = chain.recent_slot()?; + while chain.recent_slot()? <= extended_at { + std::thread::sleep(std::time::Duration::from_millis(400)); + } + + let alt = AddressLookupTableAccount { + key: table, + addresses, + }; + let message = v0::Message::try_compile(&authority, &[ix], &[alt], chain.latest_blockhash()?) + .map_err(|e| anyhow!("compiling the settlement against the lookup table: {e}"))?; + let tx = VersionedTransaction::try_new(VersionedMessage::V0(message), &[settler]) + .map_err(|e| anyhow!("signing the settlement: {e}"))?; + let bytes = bincode::serialize(&tx)?.len(); + println!(" settlement is {bytes} bytes of {PACKET_DATA_SIZE}, one signature"); + let sig = chain.send_versioned(&tx)?; + + send(chain, lookup::deactivate(&table, &authority)?, &[settler])?; + println!( + " table deactivated. Close it after ~{} slots to reclaim the rent and remove", + lookup::DEACTIVATION_COOLDOWN_SLOTS + ); + println!(" the published address list:"); + println!(" mirror close-table --table {table}"); + Ok(sig) +} + +/// Takes a lookup table back down, returning its rent and removing the address +/// list it published. +/// +/// Separate from settling because the runtime will not allow it to be the same +/// errand: a table must sit deactivated for a cooldown before it can close, so +/// that a transaction already in flight cannot have the table pulled out from +/// under it. Deactivation happens at settlement; this is the second half. +/// +/// Running it is optional in the sense that nothing breaks if nobody does, and +/// not optional in the sense that skipping it leaves rent stranded and, more to +/// the point, leaves a permanent public list of every address that settlement +/// touched. +pub fn close_table(chain: &Chain, table: &Pubkey, authority: &Keypair) -> Result<()> { + let before = chain.balance(&authority.pubkey())?; + let ix = lookup::close(table, &authority.pubkey(), &authority.pubkey())?; + match send(chain, ix, &[authority]) { + Ok(sig) => { + let reclaimed = chain.balance(&authority.pubkey())?.saturating_sub(before); + println!("closed {table}"); + println!(" signature {sig}"); + println!(" reclaimed {reclaimed} lamports, and the published address list is gone"); + Ok(()) + } + Err(e) => { + let message = e.to_string(); + if message.contains("not been deactivated") || message.contains("still in use") { + Err(anyhow!( + "{table} is not closable yet. A deactivated table waits about {} slots \ + before it can be closed, because a transaction already in flight may \ + still be resolving against it. Try again shortly.", + lookup::DEACTIVATION_COOLDOWN_SLOTS + )) + } else { + Err(e) + } + } + } +} + +/// Creates a note and writes it, printing what to do next. +pub fn note_new(denomination: u64, path: &Path) -> Result<()> { + let note = crate::note::generate(denomination)?; + let stored = StoredNote::from_note(¬e, denomination)?; + stored.write(path)?; + println!("wrote {}", path.display()); + println!(" denomination {denomination}"); + println!(" commitment {}", stored.commitment); + println!(); + println!("This file is the note. Treat it exactly as you would a keypair:"); + println!("anyone holding it can spend the deposit, and losing it loses the"); + println!("deposit with no way back."); + println!(); + println!("Next: mirror deposit --note {}", path.display()); + Ok(()) +} + +/// The current wall clock, for the crowd-rule explanation. +pub fn now() -> Result { + Ok(std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .context("reading the clock")? + .as_secs() as i64) +} diff --git a/crates/mirror-cli/src/crowd.rs b/crates/mirror-cli/src/crowd.rs new file mode 100644 index 00000000..91459574 --- /dev/null +++ b/crates/mirror-cli/src/crowd.rs @@ -0,0 +1,1307 @@ +//! Different members, different validators, one timestamp. +//! +//! `PROOF.md` shows the pool delegating stake as a member's authority, once, in +//! a batch whose other members were making payments. That establishes the +//! capability and leaves the harder question open: a batch of *identical* +//! actions is the easy case for an anonymity set, because there is nothing to +//! tell the members apart in the first place. The question worth answering is +//! what happens when the actions **diverge in content** — when each member picks +//! a different validator, which is exactly the behavioural pattern that +//! fingerprints a staker across time. +//! +//! So this run settles N delegations to N *different* validators in one +//! transaction, and reads every stake account back off the cluster to check that +//! each member got the validator they asked for. +//! +//! It also measures what that costs, because it does cost something. A +//! transaction names each distinct account once, and a batch of divergent +//! actions names more distinct accounts than a batch of uniform ones — one extra +//! vote account per member. The 1232-byte packet is therefore reached sooner, +//! and **the anonymity set a divergent batch can hold is smaller than the one a +//! uniform batch can hold**. That is a real trade-off in the design and it is +//! better measured than left for a reader to discover. +//! +//! Nothing here is simulated. The ceiling is found by serializing real +//! instructions, and the batch at that ceiling is settled against a live +//! cluster. + +use crate::chain::Chain; +use crate::lookup::MAX_ACCOUNT_LOCKS as MAX_LOCKS; +use crate::note::StoredNote; +use crate::soak::{keys, read_keypair, Settlement, Step}; +use crate::stake; +use anyhow::{anyhow, Context, Result}; +use mirror_circuit::{prove, Keys, Witness}; +use mirror_core::{MerkleTree, Note}; +use mirror_pool_program::{ + instruction::Instruction as MirrorIx, + pda::{pool_address, spend_address, vault_address}, + processor::SELECTOR_INVOKE_SIGNED, +}; +use solana_keypair::Keypair; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; +use solana_signer::Signer; +use solana_transaction::Transaction; + +/// A pool is unique per denomination, so this constant also selects the pool. +/// Bump it for a clean run; the note ledger is keyed by it, so a new +/// denomination starts a new ledger too. +const DENOMINATION: u64 = 43_000_007; // 0.043 SOL +const ENTRY_FEE: u64 = 0; +const RELAY_FEE: u64 = 200_000; + +/// What the operator puts into each stake account before the pool delegates it. +/// +/// Devnet's minimum delegation is 1 SOL, which no sane pool denomination +/// reaches: a pool whose notes each cleared the floor would need six-plus SOL to +/// fill a single batch of this size. The operator funds the account and the +/// member's escrow is added to it. What the *pool* supplies is the authority, +/// which is the part being demonstrated. +const STAKE_FUNDING: u64 = 1_100_000_000; + +/// Enough for a relay to pay for its own `submit_spend` and stay rent-exempt. +/// It is repaid at settlement out of the denomination. +const RELAY_FUNDING: u64 = 5_000_000; + +/// The 1280-byte IPv6 minimum MTU, less a 40-byte IPv6 header and an 8-byte +/// fragment header. Written out rather than imported because the crates this +/// binary already depends on do not re-export it, and a number a reader can +/// derive is worth more than one they have to trust. +const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; + +/// What a transaction carrying a single non-budget instruction is given unless +/// it asks for more. Asking costs a second instruction, and a second instruction +/// costs bytes a full settlement has none of. +const DEFAULT_COMPUTE_BUDGET: u64 = 200_000; + +/// One member's delegation, and the validator they chose. +pub struct Member { + pub stake: Pubkey, + pub vote: Pubkey, + pub relay: Pubkey, +} + +/// What the run measured about how many members fit. +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Ceiling { + /// Members per settlement when each chooses a different validator. + pub divergent: usize, + /// Members per settlement when they all choose the same one. + pub uniform: usize, + /// Wire size of a full divergent settlement. + pub divergent_bytes: usize, + /// Wire size of one member more than fits. + pub over_bytes: usize, + /// What adding a `SetComputeUnitLimit` instruction costs in bytes. + /// + /// Measured because the two limits turn out to be coupled. Raising the + /// compute budget is the obvious answer to a settlement that runs out of it, + /// and it is paid for in the one currency a full batch has none of. + pub budget_bytes: usize, + + /// The same two ceilings when the packet is taken out of the way by a lookup + /// table, so what binds is the 64-account lock limit instead of 1232 bytes. + /// + /// A table names an account with one byte instead of thirty-two, which ends + /// the byte argument and starts a different one. These are the answer to the + /// question the earlier version of this report left open rather than + /// guessed at. + /// + /// Both figures assume the `SetComputeUnitLimit` instruction is present, + /// because for this shape it has to be: a batch large enough to be worth a + /// table costs more compute than the 200,000 a transaction is given by + /// default. That instruction brings its own program, and a program is an + /// account — so raising the budget still costs a member, just in locks now + /// rather than in bytes. + #[serde(default)] + pub divergent_through_table: usize, + #[serde(default)] + pub uniform_through_table: usize, + /// Locks held by a full divergent settlement through a table, against the 64 + /// a transaction may hold. + #[serde(default)] + pub locks_at_divergent_table: usize, +} + +/// Everything the report is rendered from. +/// +/// Written after the run succeeds and read back by `--render-only`, so that +/// improving a sentence in the report costs nothing. A document generated from a +/// live run is worth more than a hand-written one, and it is only worth more +/// while regenerating it is cheap — otherwise the prose drifts away from the +/// generator that is supposed to produce it, quietly. +/// Addresses are stored as base58 text rather than as the byte arrays a +/// `Pubkey` serializes into, because this file is meant to be read: every value +/// in it can be pasted into an explorer and checked against the cluster, which +/// is the only reason to keep it at all. +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Outcome { + pub pool: String, + pub vault: String, + pub denomination: u64, + pub ceiling: Ceiling, + pub roster: Vec, + pub signature: String, + pub bytes: usize, + pub compute_units: u64, + pub steps: Vec, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct MemberRecord { + pub stake: String, + pub vote: String, + pub relay: String, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct StepRecord { + pub name: String, + pub signature: String, + pub note: String, +} + +pub struct Crowd { + client: Chain, + program_id: Pubkey, + payer: Keypair, + pool: Pubkey, + vault: Pubkey, + pub steps: Vec, +} + +impl Crowd { + pub fn new(url: &str, program_id: Pubkey, payer: Keypair) -> Self { + let (pool, _) = pool_address(&program_id, DENOMINATION); + let (vault, _) = vault_address(&program_id, &pool); + Crowd { + client: Chain::new(url), + program_id, + payer, + pool, + vault, + steps: Vec::new(), + } + } + + pub fn pool(&self) -> Pubkey { + self.pool + } + pub fn vault(&self) -> Pubkey { + self.vault + } + + fn send(&self, ix: Instruction, signers: &[&Keypair]) -> Result { + let blockhash = self.client.latest_blockhash()?; + let message = solana_message::Message::new(&[ix], Some(&signers[0].pubkey())); + let tx = Transaction::new(signers, message, blockhash); + self.client.send(&tx) + } + + fn record(&mut self, name: &'static str, signature: String, note: String) { + println!(" {name:<28} {signature}"); + self.steps.push(Step { + name, + signature, + note, + }); + } + + fn pool_metas(&self) -> Vec { + vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ] + } + + /// Creates the pool, unless a previous run already did. + /// + /// Notes left in the pool are allowed here, and that is deliberate. A run + /// against a live cluster gets interrupted — a public endpoint times out + /// mid-confirmation and the deposits are already made — and a tool that + /// refuses to continue turns a transient network error into escrow nobody + /// releases. What must not happen is a run *reporting* a batch it did not + /// assemble, and that is checked where it can be checked properly: the + /// leftovers must number exactly what this run needs, the ledger must hold + /// their secrets, and every settled delegation is read back off the cluster + /// at the end. + pub fn init_pool(&mut self, k_floor: u32, members: usize) -> Result<()> { + if let Some(mut data) = self.client.account_data(&self.pool)? { + let pool = mirror_pool_program::Pool::load(&mut data) + .map_err(|e| anyhow!("the account at the pool address is not a pool: {e:?}"))?; + let outstanding = pool + .outstanding_notes() + .map_err(|e| anyhow!("reading the pool: {e:?}"))?; + if outstanding as usize > members { + return Err(anyhow!( + "the pool for denomination {DENOMINATION} holds {outstanding} unspent \ + note(s) and this run needs {members}, so it cannot be the remains of \ + this run. Raise DENOMINATION in crowd.rs for a clean pool — the note \ + ledger is keyed by it, so a new denomination starts a new ledger too." + )); + } + if pool.k_floor() != k_floor { + return Err(anyhow!( + "the existing pool's floor is {} and this run needs {k_floor}. \ + A pool's floor is fixed at creation, so raise DENOMINATION for a \ + fresh one.", + pool.k_floor() + )); + } + if outstanding > 0 { + println!(" pool exists and holds {outstanding} note(s) from an interrupted run"); + } else { + println!(" pool already exists and is empty, reusing it"); + } + return Ok(()); + } + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::InitPool { + denomination: DENOMINATION, + entry_fee: ENTRY_FEE, + k_floor, + } + .pack(), + self.pool_metas(), + ); + let payer = self.payer.insecure_clone(); + let sig = self.send(ix, &[&payer])?; + self.record( + "init_pool", + sig, + format!("denomination {DENOMINATION}, k_floor {k_floor}"), + ); + Ok(()) + } + + fn leaf_count(&self) -> Result { + let mut data = self + .client + .account_data(&self.pool) + .context("reading the pool account")? + .ok_or_else(|| anyhow!("the pool account does not exist"))?; + let pool = mirror_pool_program::Pool::load(&mut data).map_err(|e| anyhow!("{e:?}"))?; + Ok(pool.deposit_count()) + } + + /// Deposits until the pool holds `target` notes, returning the host tree and + /// every note in it. + /// + /// Stated as a target rather than a count so that resuming is the same code + /// path as starting: a run interrupted after four of six deposits makes two + /// more, and one interrupted after all six makes none. + /// + /// The ledger is written after every single deposit rather than at the end, + /// because the program keeps only the accumulator's frontier: a note whose + /// secrets are lost after its commitment reached the tree is escrow nobody + /// can ever release. An interrupted run must leave a file that still matches + /// the chain. + pub fn deposit( + &mut self, + target: usize, + ledger: &std::path::Path, + ) -> Result<(MerkleTree, Vec)> { + let mut tree = MerkleTree::new().map_err(|e| anyhow!("{e}"))?; + let mut notes = Vec::new(); + + let mut stored: Vec = if ledger.exists() { + serde_json::from_str(&std::fs::read_to_string(ledger)?)? + } else { + Vec::new() + }; + let on_chain = self.leaf_count()? as usize; + if stored.len() != on_chain { + return Err(anyhow!( + "the note ledger holds {} notes but the pool has {on_chain} leaves. \ + They must agree, or the host tree cannot match the program's root. \ + Use a fresh denomination, or restore the ledger.", + stored.len() + )); + } + for note in &stored { + let note = note.note()?; + tree.insert(note.commitment().map_err(|e| anyhow!("{e}"))?) + .map_err(|e| anyhow!("{e}"))?; + notes.push(note); + } + + if stored.len() > target { + return Err(anyhow!( + "the pool already holds {} notes and this run wants {target}", + stored.len() + )); + } + if let Some(parent) = ledger.parent() { + std::fs::create_dir_all(parent)?; + } + for _ in stored.len()..target { + let note = crate::note::generate(DENOMINATION)?; + let commitment = note.commitment().map_err(|e| anyhow!("{e}"))?; + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::Deposit { + commitment: commitment.to_bytes(), + } + .pack(), + self.pool_metas(), + ); + let payer = self.payer.insecure_clone(); + let sig = self.send(ix, &[&payer])?; + self.record("deposit", sig, format!("note {}", notes.len() + 1)); + tree.insert(commitment).map_err(|e| anyhow!("{e}"))?; + notes.push(note); + stored.push(StoredNote::from_note(¬e, DENOMINATION)?); + std::fs::write(ledger, serde_json::to_string(&stored)?)?; + } + Ok((tree, notes)) + } + + /// The pending spend this note already has, if an interrupted run submitted + /// one. + /// + /// Rebuilt from the chain rather than from a file, because it can be: a + /// note's nullifier is a function of the note alone, the record's address is + /// a function of the nullifier, and the record itself carries the two + /// accounts settlement has to name. A state file would be a second source of + /// truth for facts the chain already holds, and the failure it invites — a + /// file that disagrees with the cluster — is worse than the one it prevents. + /// + /// A record that is already settled returns `None`: that note is finished, + /// and re-submitting it would burn a nullifier that is already burnt. + pub fn existing_spend(&self, note: &Note) -> Result> { + let nullifier = note.nullifier().map_err(|e| anyhow!("{e}"))?.to_bytes(); + let (spend_pda, _) = spend_address(&self.program_id, &self.pool, &nullifier); + let Some(mut data) = self.client.account_data(&spend_pda)? else { + return Ok(None); + }; + let record = mirror_pool_program::spend::Spend::load(&mut data) + .map_err(|e| anyhow!("the account at {spend_pda} is not a spend record: {e:?}"))?; + if record.status() != mirror_pool_program::spend::STATUS_PENDING { + return Ok(None); + } + let beneficiary = Pubkey::new_from_array(record.beneficiary()); + Ok(Some(Settlement { + spend: spend_pda, + beneficiary, + relay: Pubkey::new_from_array(record.relay()), + target: Some(Pubkey::new_from_array(record.target_program())), + // The vote account is not recoverable from the record, because the + // proof never bound it — `DelegateStake` carries the validator in an + // account slot rather than in its instruction data. The caller + // supplies it from the plan, and the read-back after settlement is + // what turns that into a checked claim. + action_accounts: Vec::new(), + })) + } + + /// Gives a relay enough to pay for the one transaction it signs. + /// + /// Every member gets their own relay here, which is the worst case for the + /// packet and the one a settler has to plan against: a batch whose members + /// shared a relay names fewer distinct keys and fits more of them. + pub fn fund_relay(&mut self, relay: &Pubkey) -> Result<()> { + let ix = solana_system_interface::instruction::transfer( + &self.payer.pubkey(), + relay, + RELAY_FUNDING, + ); + let payer = self.payer.insecure_clone(); + self.send(ix, &[&payer])?; + Ok(()) + } + + /// A stake account whose **staker** is the pool's vault and whose + /// **withdrawer** is not. + pub fn create_stake_account(&mut self) -> Result { + let stake_kp = Keypair::new(); + let [create, initialise] = stake::create( + &self.payer.pubkey(), + &stake_kp.pubkey(), + &self.vault, + &self.payer.pubkey(), + STAKE_FUNDING, + )?; + let blockhash = self.client.latest_blockhash()?; + let message = + solana_message::Message::new(&[create, initialise], Some(&self.payer.pubkey())); + let payer = self.payer.insecure_clone(); + let tx = Transaction::new(&[&payer, &stake_kp], message, blockhash); + let sig = self.client.send(&tx)?; + self.record( + "create stake account", + sig, + format!("{STAKE_FUNDING} lamports, staker = the pool's vault"), + ); + Ok(stake_kp.pubkey()) + } + + /// Submits one member's spend: delegate `stake` to `vote`, authorised by the + /// pool, signed by a relay that is not the member. + #[allow(clippy::too_many_arguments)] + pub fn submit_delegation( + &mut self, + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + stake_account: &Pubkey, + vote: &Pubkey, + relay: &Keypair, + ) -> Result { + use ark_std::rand::SeedableRng; + let stake_program = stake::program_id()?; + let merkle_proof = tree.proof(index as u64).map_err(|e| anyhow!("{e}"))?; + // The stake account is the beneficiary, so the member's escrow lands in + // the stake they authorised rather than beside it. + // + // Note what the binding does *not* cover: the vote account. The proof + // fixes the selector, the target program, the beneficiary, the fee, the + // account *count* and the payload — and `DelegateStake` carries the + // validator in an account slot, not in its four bytes of instruction + // data. Which validator a member gets is therefore chosen at settlement. + // That is the account-slot limit `THREAT_MODEL.md` states, met head-on: + // the check below is a read-back of every stake account, because the + // proof cannot make this promise and something has to. + let binding = mirror_core::action_binding( + SELECTOR_INVOKE_SIGNED, + &stake_program.to_bytes(), + &stake_account.to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + stake::DELEGATE_ACCOUNTS, + &stake::DELEGATE_STAKE, + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().map_err(|e| anyhow!("{e}"))?, + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8 + 1; 32]); + let proof = prove(keys, &witness, &mut rng).map_err(|e| anyhow!("{e}"))?; + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&self.program_id, &self.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR_INVOKE_SIGNED, + target_program: stake_program.to_bytes(), + beneficiary: stake_account.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: stake::DELEGATE_ACCOUNTS, + payload: stake::DELEGATE_STAKE.to_vec(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = self.send(ix, &[relay])?; + self.record( + "submit_spend", + sig, + format!("note {index}, relay-signed, delegate to {vote}"), + ); + Ok(spend_pda) + } + + fn settle_ix(&self, batch: &[Settlement]) -> Instruction { + let mut metas = vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + ]; + for entry in batch { + metas.push(AccountMeta::new(entry.spend, false)); + metas.push(AccountMeta::new(entry.beneficiary, false)); + metas.push(AccountMeta::new(entry.relay, false)); + if let Some(target) = entry.target { + metas.push(AccountMeta::new_readonly(target, false)); + // The vault is among these, and it reaches the callee as a + // *signer*. The program sets that flag itself from seeds no + // settler holds, which is why the meta here says otherwise. + metas.extend(entry.action_accounts.iter().cloned()); + } + } + Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SettleEpoch { + count: batch.len() as u8, + } + .pack(), + metas, + ) + } + + /// What this settlement would weigh on the wire. + /// + /// A legacy transaction is a compact array of 64-byte signatures followed by + /// the serialized message, and `Message::serialize` is what a validator + /// receives rather than an approximation of it. Settlement is signed by the + /// settler alone, so the signature array is one entry and its length prefix + /// one byte. + pub fn settlement_bytes(&self, batch: &[Settlement]) -> usize { + let ix = self.settle_ix(batch); + let message = solana_message::Message::new(&[ix], Some(&self.payer.pubkey())); + 1 + 64 + message.serialize().len() + } + + /// What the same settlement would weigh with a `SetComputeUnitLimit` + /// instruction in front of it. + /// + /// The difference is the price of asking for more compute. It is worth a + /// number rather than an argument, because for a batch of cross-program + /// actions the compute budget and the packet stop being independent limits: + /// the escape from one is paid for out of the other. + pub fn settlement_bytes_with_budget(&self, batch: &[Settlement]) -> usize { + // `ComputeBudgetInstruction::SetComputeUnitLimit`: a u8 discriminant of + // 2 followed by a little-endian u32. The program takes no accounts, so + // what this costs is its own key plus the instruction's framing. + let budget: Pubkey = "ComputeBudget111111111111111111111111111111" + .parse() + .expect("the compute budget program id is a const"); + let mut data = vec![2u8]; + data.extend_from_slice(&u32::MAX.to_le_bytes()); + let raise = Instruction::new_with_bytes(budget, &data, vec![]); + let message = solana_message::Message::new( + &[raise, self.settle_ix(batch)], + Some(&self.payer.pubkey()), + ); + 1 + 64 + message.serialize().len() + } + + pub fn settle(&mut self, batch: &[Settlement]) -> Result<(String, usize)> { + let bytes = self.settlement_bytes(batch); + if bytes > PACKET_DATA_SIZE { + return Err(anyhow!( + "this settlement is {bytes} bytes, {} over the {PACKET_DATA_SIZE}-byte \ + packet limit, and no validator would accept it", + bytes - PACKET_DATA_SIZE + )); + } + let ix = self.settle_ix(batch); + let payer = self.payer.insecure_clone(); + let sig = self.send(ix, &[&payer])?; + self.record( + "settle_epoch", + sig.clone(), + format!( + "{} delegations to {} different validators, one transaction, {bytes} bytes", + batch.len(), + batch.len() + ), + ); + Ok((sig, bytes)) + } + + pub fn compute_units(&self, signature: &str) -> Result { + self.client.compute_units(signature) + } + + /// Reads a stake account back off the cluster and returns the validator it + /// actually backs. + pub fn delegated_voter(&self, stake_account: &Pubkey) -> Result { + let data = self + .client + .account_data(stake_account)? + .ok_or_else(|| anyhow!("the stake account {stake_account} vanished"))?; + stake::delegated_voter(&data) + } + + /// How many members fit in one settlement, found by serializing rather than + /// by arithmetic. + /// + /// Placeholder keys are legitimate here because transaction size depends on + /// how many *distinct* accounts a message names, not on which — and the real + /// batch is measured again before it is sent, so an error in that reasoning + /// surfaces as a refusal rather than as a wrong number in a document. + /// + /// Both shapes are measured because the difference between them is the + /// finding. `divergent` gives every member their own vote account; + /// `uniform` shares one across the batch, which is the same run of members + /// all choosing the same validator. + pub fn measure_ceiling(&self) -> Ceiling { + let shape = |n: usize, share_vote: bool| -> Vec { + let shared_vote = Pubkey::new_unique(); + (0..n) + .map(|_| { + let stake_account = Pubkey::new_unique(); + let vote = if share_vote { + shared_vote + } else { + Pubkey::new_unique() + }; + Settlement { + spend: Pubkey::new_unique(), + beneficiary: stake_account, + relay: Pubkey::new_unique(), + target: Some(stake::program_id().expect("the stake program id is a const")), + action_accounts: stake::delegate_accounts( + &stake_account, + &vote, + &self.vault, + ) + .expect("the delegate account list is built from consts"), + } + }) + .collect() + }; + let largest = |share_vote: bool| -> usize { + // Searched from the top down rather than counted upward, so a + // hypothetical non-monotonic encoding would be caught by the + // round-trip check against the batch that actually lands rather + // than hidden by an early exit. + (1..=32) + .rfind(|n| self.settlement_bytes(&shape(*n, share_vote)) <= PACKET_DATA_SIZE) + .unwrap_or(0) + }; + let largest_through_table = |share_vote: bool| -> usize { + (1..=64) + .rfind(|n| self.settlement_locks_with_budget(&shape(*n, share_vote)) <= MAX_LOCKS) + .unwrap_or(0) + }; + let divergent = largest(false); + let uniform = largest(true); + let full = shape(divergent, false); + let divergent_bytes = self.settlement_bytes(&full); + let divergent_through_table = largest_through_table(false); + Ceiling { + divergent, + uniform, + divergent_bytes, + over_bytes: self.settlement_bytes(&shape(divergent + 1, false)), + budget_bytes: self.settlement_bytes_with_budget(&full) - divergent_bytes, + divergent_through_table, + uniform_through_table: largest_through_table(true), + locks_at_divergent_table: self + .settlement_locks_with_budget(&shape(divergent_through_table, false)), + } + } + + /// How many accounts a settlement would lock, with the compute-budget + /// instruction counted. + /// + /// This is the limit that takes over once a lookup table ends the byte + /// argument, and it is a different kind of limit: bytes are spent per + /// account *name*, locks are held per *distinct* account. That is the whole + /// reason a crowd agreeing on one validator fits more members — the shared + /// vote account is named once and locked once, where divergent members each + /// bring one nobody else in the batch holds. + /// + /// The compute-budget program is included because it is an account like any + /// other. A batch this size cannot execute inside the default 200,000 CU, so + /// the instruction is not optional here, and neither is the lock it costs. + pub fn settlement_locks_with_budget(&self, batch: &[Settlement]) -> usize { + let ix = self.settle_ix(batch); + let mut metas = ix.accounts.clone(); + metas.push(AccountMeta::new_readonly(compute_budget_program(), false)); + crate::lookup::locks_for(&metas, &ix.program_id, &self.payer.pubkey()) + } +} + +/// The compute-budget program, which a settlement large enough to need a lookup +/// table also needs. +fn compute_budget_program() -> Pubkey { + "ComputeBudget111111111111111111111111111111" + .parse() + .expect("the compute budget program id is a const") +} + +pub fn run(program: &str, url: &str, keypair: &str, out: &std::path::Path) -> Result<()> { + let program_id: Pubkey = program + .parse() + .map_err(|e| anyhow!("bad program id: {e}"))?; + let payer = read_keypair(keypair)?; + println!("program {program_id}"); + println!("payer {}", payer.pubkey()); + println!("cluster {url}\n"); + + let mut crowd = Crowd::new(url, program_id, payer.insecure_clone()); + + // The ceiling first, before anything is spent. How many stake accounts to + // create is the answer to this question, and creating the wrong number means + // either a batch that no validator will accept or SOL left in accounts the + // run has no use for. + let ceiling = crowd.measure_ceiling(); + println!("how many members fit in one settlement, by serializing the real instruction:"); + println!( + " all delegating to the same validator {} members", + ceiling.uniform + ); + println!( + " each delegating to a different one {} members ({} bytes, {} to spare)", + ceiling.divergent, + ceiling.divergent_bytes, + PACKET_DATA_SIZE - ceiling.divergent_bytes + ); + println!( + " one more than that {} bytes, {} over the {PACKET_DATA_SIZE}-byte limit\n", + ceiling.over_bytes, + ceiling.over_bytes - PACKET_DATA_SIZE + ); + let members = ceiling.divergent; + if members < 2 { + return Err(anyhow!( + "only {members} member(s) fit, so there is no crowd to measure" + )); + } + + // Validators the cluster itself counts as active, so a reader checking this + // run finds the delegations pointing at validators they could have chosen. + // + // Fixed to a file on the first run and reused after, because the ranking + // moves between epochs and a resumed run that re-drew the list would settle + // members against validators other than the ones they asked for — silently, + // since the proof binds the account *count* and never the accounts. + let plan_path = format!("data/crowd-plan-{DENOMINATION}.json"); + let votes = crowd_votes(url, members, std::path::Path::new(&plan_path))?; + println!("validators drawn from the cluster's active set:"); + for (i, v) in votes.iter().enumerate() { + println!(" member {i} {v}"); + } + + let cost = members as u64 * (STAKE_FUNDING + DENOMINATION + RELAY_FUNDING); + println!( + "\nthis run will spend about {:.2} SOL: {members} stake accounts, {members} deposits, \ + {members} relays\n", + cost as f64 / 1e9 + ); + + println!("deriving the proving key from the published seed (this takes a moment)"); + let keys = keys()?; + + println!("\nsetting up:"); + crowd.init_pool(members as u32, members)?; + let ledger_path = format!("data/crowd-notes-{DENOMINATION}.json"); + let ledger = std::path::Path::new(&ledger_path); + let (tree, notes) = crowd.deposit(members, ledger)?; + + let mut batch = Vec::new(); + let mut roster = Vec::new(); + for (i, vote) in votes.iter().enumerate() { + // A spend this note already carries is reused rather than remade. The + // nullifier is spend-once-ever, so a second submission for the same note + // is refused by the program — which would strand the run at exactly the + // point a flaky endpoint left it. + let entry = match crowd.existing_spend(¬es[i])? { + Some(found) => { + println!(" member {i:<21} spend {} already submitted", found.spend); + Settlement { + action_accounts: stake::delegate_accounts( + &found.beneficiary, + vote, + &crowd.vault(), + )?, + ..found + } + } + None => { + let stake_account = crowd.create_stake_account()?; + let relay = Keypair::new(); + crowd.fund_relay(&relay.pubkey())?; + let spend = crowd.submit_delegation( + &keys, + &tree, + ¬es, + i, + &stake_account, + vote, + &relay, + )?; + Settlement { + spend, + beneficiary: stake_account, + relay: relay.pubkey(), + target: Some(stake::program_id()?), + action_accounts: stake::delegate_accounts( + &stake_account, + vote, + &crowd.vault(), + )?, + } + } + }; + roster.push(Member { + stake: entry.beneficiary, + vote: *vote, + relay: entry.relay, + }); + batch.push(entry); + } + + println!("\nsettling all {members} in one transaction:"); + let (signature, bytes) = crowd.settle(&batch)?; + let cu = crowd.compute_units(&signature)?; + println!(" {bytes} bytes of {PACKET_DATA_SIZE}, {cu} CU of {DEFAULT_COMPUTE_BUDGET}"); + println!( + " raising the compute budget would cost {} bytes and there are {} to spare", + ceiling.budget_bytes, + PACKET_DATA_SIZE - bytes + ); + if bytes != ceiling.divergent_bytes { + return Err(anyhow!( + "the settlement that landed was {bytes} bytes and the measurement predicted \ + {}, so the ceiling above describes a different transaction than the one sent", + ceiling.divergent_bytes + )); + } + + // The read-back. The proof binds how many accounts the call takes and never + // which, so nothing before this point can promise a member got the validator + // they asked for — the account state is the only place that answer exists. + println!("\nreading every stake account back off the cluster:"); + for (i, member) in roster.iter().enumerate() { + let voter = crowd.delegated_voter(&member.stake)?; + if voter != member.vote { + return Err(anyhow!( + "member {i} asked to delegate to {} and the stake account backs {voter}", + member.vote + )); + } + println!(" member {i} {} → {voter}", member.stake); + } + + let distinct: std::collections::HashSet<_> = roster.iter().map(|m| m.vote).collect(); + if distinct.len() != members { + return Err(anyhow!( + "the batch names {} distinct validators for {members} members, so it does not \ + demonstrate divergence", + distinct.len() + )); + } + println!( + "\n{members} members, {} distinct validators, one transaction, one timestamp.", + distinct.len() + ); + + let outcome = Outcome { + pool: crowd.pool().to_string(), + vault: crowd.vault().to_string(), + denomination: DENOMINATION, + ceiling, + roster: roster + .iter() + .map(|m| MemberRecord { + stake: m.stake.to_string(), + vote: m.vote.to_string(), + relay: m.relay.to_string(), + }) + .collect(), + signature, + bytes, + compute_units: cu, + steps: crowd + .steps + .iter() + .map(|s| StepRecord { + name: s.name.to_string(), + signature: s.signature.clone(), + note: s.note.clone(), + }) + .collect(), + }; + let result_path = format!("data/crowd-result-{DENOMINATION}.json"); + std::fs::write(&result_path, serde_json::to_string_pretty(&outcome)?)?; + write_report(&outcome, out)?; + println!("wrote {} and {result_path}", out.display()); + Ok(()) +} + +fn write_report(outcome: &Outcome, out: &std::path::Path) -> Result<()> { + if let Some(parent) = out.parent() { + std::fs::create_dir_all(parent)?; + } + std::fs::write(out, report(outcome))?; + Ok(()) +} + +/// Re-renders the report from the last run's recorded results. +/// +/// Touches no cluster and spends nothing. The numbers are exactly the ones the +/// run measured; only the sentences around them can change. +pub fn render_only(out: &std::path::Path) -> Result<()> { + let result_path = format!("data/crowd-result-{DENOMINATION}.json"); + let text = std::fs::read_to_string(&result_path).with_context(|| { + format!("{result_path} does not exist — there is no recorded run to render") + })?; + let mut outcome: Outcome = serde_json::from_str(&text)?; + + // The through-a-table ceilings are a property of the instruction's shape and + // not of the run, so they are recomputed here rather than trusted from the + // file. A record written before these fields existed deserializes them as + // zero, and rendering a zero into a published table is worse than any + // staleness this is meant to avoid: it would read as a measured result. + // + // Nothing about this touches a cluster. It builds the same instruction the + // settlement builds and counts what it names, which is what the packet + // ceilings in the same struct already are. + let derived = Crowd::new( + "http://127.0.0.1:1", + outcome + .pool + .parse() + .unwrap_or_else(|_| solana_program::pubkey::Pubkey::new_unique()), + Keypair::new(), + ) + .measure_ceiling(); + outcome.ceiling.divergent_through_table = derived.divergent_through_table; + outcome.ceiling.uniform_through_table = derived.uniform_through_table; + outcome.ceiling.locks_at_divergent_table = derived.locks_at_divergent_table; + + write_report(&outcome, out)?; + println!("rendered {} from {result_path}", out.display()); + Ok(()) +} + +/// Picks `n` distinct active validators, largest stake first, and remembers the +/// choice. +/// +/// The file is the record of what each member *asked for*. It has to exist +/// somewhere outside the chain, because the chain does not hold it: a member's +/// proof binds the number of accounts their call takes and not which accounts +/// fill the slots, so before settlement there is nothing on-chain that says +/// which validator member 3 wanted. The read-back afterwards compares the +/// cluster against this file, which is what makes it a check rather than a +/// restatement. +fn crowd_votes(url: &str, n: usize, plan: &std::path::Path) -> Result> { + if plan.exists() { + let saved: Vec = serde_json::from_str(&std::fs::read_to_string(plan)?)?; + if saved.len() != n { + return Err(anyhow!( + "{} names {} validators and this run needs {n}. It belongs to a run of a \ + different size; delete it only if no spend has been submitted against it.", + plan.display(), + saved.len() + )); + } + println!("(reusing the validator choices in {})", plan.display()); + return saved + .iter() + .map(|s| s.parse().map_err(|e| anyhow!("{s}: {e}"))) + .collect(); + } + let all = Chain::new(url).active_vote_accounts()?; + if all.len() < n { + return Err(anyhow!( + "the cluster reports {} active validators and this run needs {n}", + all.len() + )); + } + let chosen: Vec = all.into_iter().take(n).collect(); + if let Some(parent) = plan.parent() { + std::fs::create_dir_all(parent)?; + } + let names: Vec = chosen.iter().map(|v| v.to_string()).collect(); + std::fs::write(plan, serde_json::to_string_pretty(&names)?)?; + Ok(chosen) +} + +fn explorer(kind: &str, id: &str) -> String { + format!("[`{id}`](https://explorer.solana.com/{kind}/{id}?cluster=devnet)") +} + +fn report(outcome: &Outcome) -> String { + let Outcome { + ceiling, + roster, + bytes, + steps, + .. + } = outcome; + let (signature, cu) = (&outcome.signature, outcome.compute_units); + let denomination = outcome.denomination; + let bytes = *bytes; + let members = roster.len(); + let mut md = String::new(); + md.push_str("# Different members, different validators, one timestamp\n\n"); + md.push_str( + "A batch whose members all do the same thing is the easy case for an anonymity set: \ + there is nothing to tell them apart to begin with. This run does the hard one. Each \ + member delegates stake to a **different validator**, and all of it settles in a \ + single transaction.\n\n\ + Validator choice is the behavioural pattern worth hiding. It is stable, it is \ + public, and it fingerprints a staker across epochs far more reliably than an \ + amount does. What an observer gets from the transaction below is a set of \ + delegations landing at one timestamp with no way to say which member asked for \ + which.\n\n", + ); + md.push_str(&format!( + "Generated by `mirror crowd`. Pool {}, vault {}, denomination {denomination} lamports.\n\n", + explorer("address", &outcome.pool), + explorer("address", &outcome.vault) + )); + + md.push_str("## The settlement\n\n"); + md.push_str(&format!("{}\n\n", explorer("tx", signature))); + md.push_str(&format!( + "| | |\n|---|---|\n| members | {members} |\n| distinct validators | {members} |\n\ + | wire size | {bytes} of {PACKET_DATA_SIZE} bytes |\n\ + | compute | {cu} of {DEFAULT_COMPUTE_BUDGET} CU |\n\n" + )); + + md.push_str("## Who got what\n\n"); + md.push_str( + "Read back from the cluster after settlement, not assumed from what was requested. \ + A member's proof binds how many accounts their call takes and never *which*, so \ + the stake account's own state is the only place the answer exists — this table is \ + the check that limit needs, and the run fails if any row disagrees.\n\n\ + Every member has their own relay, and no relay key appears twice. That is the \ + worst case for the packet and the case a settler has to plan against: a batch \ + whose members shared a relay would name fewer distinct keys and fit more of \ + them.\n\n", + ); + md.push_str("| member | stake account | delegated to | relay |\n|---|---|---|---|\n"); + for (i, m) in roster.iter().enumerate() { + md.push_str(&format!( + "| {i} | {} | {} | {} |\n", + explorer("address", &m.stake), + explorer("address", &m.vote), + explorer("address", &m.relay) + )); + } + md.push('\n'); + + md.push_str("## What divergence costs\n\n"); + md.push_str(&format!( + "Divergence is not free, and the price is anonymity-set size. A transaction names \ + each distinct account once, so a member who picks their own validator adds a vote \ + account nobody else in the batch names. The 1232-byte packet is reached sooner.\n\n\ + | batch | members per settlement |\n|---|---|\n\ + | all delegating to the same validator | {} |\n\ + | each delegating to a different one | {} |\n\n\ + At {} members the settlement weighs {} bytes with {} to spare; one more member \ + weighs {} bytes, {} over the limit. Both figures come from serializing the real \ + instruction, and the settlement that landed above is {bytes} bytes — the same \ + number, which is what makes the measurement a prediction rather than a \ + description.\n\n", + ceiling.uniform, + ceiling.divergent, + ceiling.divergent, + ceiling.divergent_bytes, + PACKET_DATA_SIZE - ceiling.divergent_bytes, + ceiling.over_bytes, + ceiling.over_bytes - PACKET_DATA_SIZE, + )); + md.push_str("## And compute, which is closer than it is for payments\n\n"); + md.push_str(&format!( + "This settlement burned **{cu} CU of the {DEFAULT_COMPUTE_BUDGET}** a single \ + instruction gets by default — {:.0}% of the budget, for {members} payouts and \ + {members} cross-program invocations. That is a different regime from a batch of \ + plain transfers: `ten_spends_fit_in_one_settlement_and_the_packet_is_what_stops_\ + the_eleventh` settles ten of those in 19,545 CU, where compute is nowhere in the \ + conversation. A delegation costs roughly an order of magnitude more per member \ + than a payment does.\n\n\ + Each member's Groth16 proof was verified earlier, in their own `submit_spend`, \ + which costs about 101,000 CU. That is why the two phases exist: verifying \ + {members} proofs here would cost over 600,000 CU — comfortably past the 200,000 a \ + single instruction gets by default, and a large fraction of the 1.4M a whole \ + transaction may ever request.\n\n", + cu as f64 * 100.0 / DEFAULT_COMPUTE_BUDGET as f64 + )); + md.push_str(&format!( + "The packet binds first — {} members is where the bytes run out, and the budget is \ + not exhausted there — but for a **legacy** transaction the two limits are barely \ + independent, and that is worth stating plainly. The usual answer to a settlement \ + that runs out of compute is to ask for more with a `SetComputeUnitLimit` \ + instruction. Measured against this very batch, that instruction costs **{} \ + bytes**, and a full legacy settlement has {} to spare. In a legacy transaction, \ + raising the budget means dropping a member.\n\n\ + **A lookup table lifts that, and here is how far.** Naming accounts by one \ + byte each takes the packet out of the way — `mirror settle` does it \ + automatically, and a batch of twenty plain transfers settled that way on devnet \ + at 332 bytes of 1232. What takes over for *delegations* is the 64-account lock \ + limit, and it is a different kind of limit: bytes are spent naming an account, \ + locks are held per **distinct** account.\n\n\ + | batch | legacy packet | through a lookup table |\n|---|---|---|\n\ + | all delegating to the same validator | {} | **{}** |\n\ + | each delegating to a different one | {} | **{}** |\n\n\ + A full divergent batch through a table holds {} of the 64 locks a transaction \ + may take. Both ceilings roughly double, and the gap between them widens from one \ + member to {} — because a shared vote account is named once either way but locked \ + only once too, so agreeing on a validator is worth more here than it was in the \ + packet.\n\n\ + **The compute budget instruction is counted in those two figures, because at \ + this size it is not optional.** A batch of {} delegations costs on the order of \ + {} CU at the per-member rate this run measured, well past the 200,000 a \ + transaction is given by default. Asking for more brings the compute-budget \ + program along, and a program is an account — so raising the budget still costs a \ + member. In the legacy packet that cost was {} bytes; through a table it is one \ + lock. The escape from one limit is paid out of the other in both regimes, which \ + is the finding rather than the inconvenience.\n\n\ + **What kind of number these two are.** They are computed the same way the packet \ + ceilings above are — by building the real instruction and counting what it \ + names — and not by settling a batch of that size. The 64-account limit itself is \ + not a guess: it was found on devnet, where 77 accounts returned \ + `TooManyAccountLocks`, and the twenty-transfer settlement cited above landed at \ + exactly 64. What has not been done is a delegation batch of {} settled through a \ + table on a live cluster, and this document does not claim one.\n\n", + ceiling.divergent, + ceiling.budget_bytes, + PACKET_DATA_SIZE - ceiling.divergent_bytes, + ceiling.uniform, + ceiling.uniform_through_table, + ceiling.divergent, + ceiling.divergent_through_table, + ceiling.locks_at_divergent_table, + ceiling.uniform_through_table - ceiling.divergent_through_table, + ceiling.divergent_through_table, + ceiling.divergent_through_table * 23_800, + ceiling.budget_bytes, + ceiling.divergent_through_table, + )); + + md.push_str("## Every step\n\n"); + md.push_str("| step | signature | note |\n|---|---|---|\n"); + for step in steps { + md.push_str(&format!( + "| {} | {} | {} |\n", + step.name, + explorer("tx", &step.signature), + step.note + )); + } + md.push('\n'); + + md.push_str("## Reproducing this document\n\n"); + md.push_str(&format!( + "Every value above was written by the run that produced it, and the run recorded \ + them in `data/crowd-result-{denomination}.json`. `mirror crowd --render-only` \ + rebuilds this file from that record without touching a cluster, so the prose \ + around a number can be improved without re-running a measurement — and a number \ + cannot be changed without re-running one.\n\n\ + Every address and signature here is on devnet and can be checked against the \ + cluster rather than against this file.\n\n" + )); + + md.push_str("## What this run's own anonymity was, by our own metric\n\n"); + md.push_str( + "It would be easy to publish this section's numbers and let a reader take them \ + for a privacy result. They are not one, and the honest way to show that is to \ + run the measurement this repository is built around against *this run* rather \ + than only against somebody else's pool.\n\n", + ); + // Every note here was deposited by one wallet, so the funding-provenance + // partition has exactly one class. Computed by the same code that produces + // the published headline rather than asserted, because the point of the + // section is that the number comes out *good* and means nothing. + let own = mirror_provenance::Anonymity::from_class_sizes(&[members as u64]); + if let Some(a) = own { + md.push_str(&format!( + "| quantity | this run |\n|---|---|\n\ + | nominal k | {} |\n\ + | provenance classes | {} |\n\ + | ρ, the loss factor | {:.4} |\n\ + | effective k (Shannon) | {:.2} |\n\ + | effective k (min-entropy) | {:.2} |\n\n", + a.nominal_k, a.classes, a.loss_factor, a.eff_k_shannon, a.eff_k_min_entropy + )); + md.push_str(&format!( + "**ρ = {:.4} is the best value the metric can return, and it is meaningless \ + here.** Every note in this pool was deposited by the same wallet, so the \ + partition has one class holding all {} members; an adversary who learns a \ + member's funding class learns nothing, and the metric correctly reports no \ + loss *through that channel*. What it cannot report is that the single class \ + is the operator, who funded every deposit and every relay and therefore knows \ + which member is which. Against that adversary the anonymity set is **one**, \ + and no funding-provenance number will ever say so, because provenance is not \ + the channel that failed.\n\n\ + This is the shape of the tautology `PROVENANCE_METHOD.md` §9.0 warns about, \ + met head-on: a metric applied to a population constructed by the person \ + reading it returns whatever that construction implies. The published headline \ + in `README.md` avoids it by pointing at a pool this project does not control \ + and did not fund — which is the only reason that number means anything and \ + this one does not.\n\n", + a.loss_factor, a.nominal_k + )); + } + + md.push_str("## Scope\n\n"); + md.push_str( + "Devnet, and one operator. This is a functional and quantitative result, not an \ + anonymity claim about a live crowd: the relays here were funded from the same \ + wallet that made the deposits, which is exactly the linkage `USAGE.md` tells a \ + real member to avoid. What the run establishes is that a batch of *divergent* \ + actions settles as one, that every member reached the validator they chose, and \ + what such a batch costs in packet space.\n\n\ + The withdraw authority on every stake account above is the operator, never the \ + pool. The pool's signature is available to every member, so an authority the vault \ + holds is an authority every member holds: delegation is safe on those terms — the \ + worst a member can do is re-delegate somebody else's stake — and withdrawal is \ + not. That is `THREAT_MODEL.md` applied rather than repeated.\n", + ); + md +} + +#[cfg(test)] +mod tests { + use super::*; + + /// A `Crowd` with no cluster behind it. + /// + /// `measure_ceiling` never touches the network — it serializes instructions + /// and counts accounts — so the ceilings are testable without devnet, which + /// is what makes them a pinned result rather than something re-derived on + /// each run and believed. + fn offline() -> Crowd { + Crowd::new("http://127.0.0.1:1", Pubkey::new_unique(), Keypair::new()) + } + + /// The four ceilings, pinned. + /// + /// Legacy and through-a-table are different regimes and the numbers say so. + /// A change to the account shape of `settle_epoch` moves these, and moving + /// them silently is how a document comes to describe a settlement nobody can + /// send. + #[test] + fn the_table_lifts_the_delegation_ceiling_and_locks_take_over() { + let c = offline().measure_ceiling(); + + // Legacy: the 1232-byte packet binds, and divergence costs a member. + assert_eq!(c.uniform, 7, "legacy, one validator"); + assert_eq!(c.divergent, 6, "legacy, a validator each"); + + // Through a table: the packet stops mattering and the 64-account lock + // limit takes over. Both shapes roughly double. + assert_eq!(c.uniform_through_table, 18, "table, one validator"); + assert_eq!(c.divergent_through_table, 13, "table, a validator each"); + + assert!( + c.locks_at_divergent_table <= MAX_LOCKS, + "a full divergent batch holds {} locks, over the {MAX_LOCKS} limit", + c.locks_at_divergent_table + ); + } + + /// Divergence costs more under locks than under bytes, and the reason is + /// structural rather than incidental. + /// + /// Bytes are spent naming an account; locks are held per *distinct* + /// account. A shared vote account is named once either way, so agreeing on a + /// validator buys one member in a legacy packet and five through a table. + #[test] + fn agreeing_on_a_validator_buys_more_members_through_a_table_than_without() { + let c = offline().measure_ceiling(); + let legacy_gain = c.uniform - c.divergent; + let table_gain = c.uniform_through_table - c.divergent_through_table; + assert!( + table_gain > legacy_gain, + "divergence cost {legacy_gain} member(s) legacy and {table_gain} through a table; \ + the table was supposed to make the shared account matter more, not less" + ); + } +} diff --git a/crates/mirror-cli/src/disclose.rs b/crates/mirror-cli/src/disclose.rs new file mode 100644 index 00000000..172992c8 --- /dev/null +++ b/crates/mirror-cli/src/disclose.rs @@ -0,0 +1,1549 @@ +//! Voluntary disclosure: proving to one chosen verifier that a settled action +//! was yours. +//! +//! Everything about *what happened* is already public. A spend record PDA is +//! derived from the nullifier and holds, in cleartext, the beneficiary, the +//! selector, the target program, the relay fee, the payload and whether it +//! settled. The pool hides exactly one thing: **which member asked for it.** +//! +//! So a disclosure is not an audit trail, an escrow, or a key anyone else holds. +//! It is a member handing a file to a counterparty of their own choosing — an +//! exchange, a tax authority, a court, a friend — that lets that counterparty +//! recompute the link for themselves. There is no on-chain component, no +//! auditor key, and no path by which the protocol can be made to produce one. +//! That is deliberate: a compel path that exists is a compel path that can be +//! used, and a pool with one is a pool whose members are anonymous only until +//! somebody with standing asks. +//! +//! The verifier is not asked to trust the file. Every field in it is either +//! recomputed from the secrets or read off the cluster; a disclosure whose +//! stated nullifier disagrees with `H1(k)` fails rather than being believed. +//! See [`verify`]. +//! +//! ## Why this is safe after settlement and catastrophic before +//! +//! `(k, r)` is the whole authority over a note. Before the note is spent, the +//! secrets *are* the money: anyone holding them can produce the membership +//! proof and direct the payout wherever they like. Disclosing an unspent note +//! is therefore not a disclosure at all — it is handing over the deposit, and +//! the recipient can spend it before the discloser finishes explaining what the +//! file was for. +//! +//! Once the nullifier is burnt and the record is settled, `(k, r)` authorises +//! nothing. The replay guard is the *existence* of the spend record, so a second +//! spend of the same note fails at account creation and never reaches the +//! verifier. What is left in the secrets is only the ability to demonstrate the +//! link — which is the thing being disclosed on purpose. +//! +//! [`build`] refuses to write a disclosure for a note that is not settled. That +//! is not a policy check that a determined member can be talked out of; it is +//! the one mistake in this module that costs somebody their deposit. + +use crate::chain::Chain; +use crate::client; +use crate::history; +use crate::note::StoredNote; +use anyhow::{anyhow, Context, Result}; +use mirror_core::{Field, MerkleTree, Note}; +use mirror_pool_program::{ + pda::{pool_address, spend_address}, + spend::{Spend, STATUS_SETTLED}, +}; +use serde::{Deserialize, Serialize}; +use solana_program::pubkey::Pubkey; +use std::path::Path; + +/// The flag that constructs a [`DisclosureOverride`], named in one place so the +/// refusal message can tell a reader exactly what to type. +pub const ACKNOWLEDGE_FLAG: &str = "--i-accept-the-cost-to-others"; + +// --------------------------------------------------------------------------- +// The file + +/// A member's claim that one settled action was theirs, in the form a verifier +/// can check. +/// +/// Plain JSON with base58 pubkeys and hex byte strings, for the same reason the +/// note file is: it is meant to be read by the person receiving it, not only +/// parsed by this binary. A verifier who does not trust this tool should be able +/// to see what is being claimed and check it with their own code. +/// +/// It carries what a verifier needs and nothing that helps a third party. Every +/// field here is either already public on chain or is a secret that settlement +/// has already spent. +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Disclosure { + /// The pool program, base58. + pub program: String, + /// The pool account, base58. Derived from the program and the denomination, + /// and [`verify`] rederives it rather than trusting this field. + pub pool: String, + pub denomination: u64, + /// Where the note sits in the accumulator, counting from the pool's first + /// deposit. + pub leaf_index: u64, + /// `H3(k, r, denom_tag)`, 32 bytes big-endian hex. + pub commitment: String, + /// Nullifier preimage, 32 bytes big-endian hex. + /// + /// This is the secret that authorised the spend, and it is published here + /// **only because the spend already happened**. Its nullifier is burnt, the + /// spend record exists, and the record's existence is what refuses a second + /// spend — so the secret no longer moves any money. The same two lines in a + /// file written before settlement would hand the reader the deposit. + pub k: String, + /// Blinding factor, 32 bytes big-endian hex. Safe for exactly the same + /// reason `k` is, and worthless without it. + pub r: String, + /// `H1(k)`, 32 bytes big-endian hex. Already public — it was an argument to + /// the spend instruction — and repeated here so a reader can see the link + /// being claimed without running anything. + pub nullifier: String, + /// The spend record account, base58. + pub spend_record: String, + /// What the member is claiming they asked the pool to do. + pub action: ClaimedAction, +} + +/// The action a disclosure claims, field for field as the record holds it. +/// +/// Restated here rather than left implicit in "go read the record" because the +/// claim is the point: a member is asserting *this* payout was theirs, and a +/// verifier compares the assertion against the chain rather than reading the +/// chain and being told what it means. +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ClaimedAction { + /// Who received the outcome, base58. + pub beneficiary: String, + /// Which kind of action the pool executed. + pub selector: u64, + /// The program the pool invoked, base58. All zeroes for a plain transfer. + pub target_program: String, + /// Taken out of the denomination, never added to it. + pub relay_fee: u64, + /// Instruction data for the invocation, hex. Empty for a plain transfer. + pub payload: String, +} + +impl Disclosure { + pub fn read(path: &Path) -> Result { + let text = std::fs::read_to_string(path) + .with_context(|| format!("reading the disclosure at {}", path.display()))?; + serde_json::from_str(&text).with_context(|| format!("parsing {}", path.display())) + } + + /// Writes the disclosure, overwriting if one is already there. + /// + /// Unlike a note file, this is regenerable from the note at any time, so + /// refusing to overwrite would protect nothing and would strand a member who + /// ran the command twice. + pub fn write(&self, path: &Path) -> Result<()> { + let text = serde_json::to_string_pretty(self)?; + std::fs::write(path, text) + .with_context(|| format!("writing the disclosure to {}", path.display()))?; + Ok(()) + } +} + +// --------------------------------------------------------------------------- +// What the chain says + +/// The spend record as the chain holds it, reduced to the fields a disclosure +/// claims. +#[derive(Clone, Debug)] +pub struct SpendRecordView { + /// `STATUS_SETTLED`, not merely present. A pending record means the action + /// has not executed, and a member who discloses one is disclosing a note + /// whose secrets still authorise a payout. + pub settled: bool, + pub pool: [u8; 32], + pub beneficiary: [u8; 32], + pub selector: u64, + pub target_program: [u8; 32], + pub relay_fee: u64, + pub payload: Vec, +} + +/// Everything [`verify`] needs from the cluster, gathered in one place. +/// +/// Split out from the RPC so the verification logic is a pure function of a +/// value a test can construct. That is not a testing convenience: it is what +/// makes the tamper matrix below exhaustive, because every one of these fields +/// is something an attacker controls if they control the endpoint, and each one +/// must be shown to break exactly one check. +#[derive(Clone, Debug)] +pub struct ChainView { + /// The denomination the pool account reports, which is not necessarily the + /// one the disclosure claims. + pub denomination: u64, + pub k_floor: u32, + /// The pool's current accumulator root. + pub root: [u8; 32], + /// Spends the pool counts as settled. Incremented at settlement, not at + /// submission, so it is the size of the set a disclosure shrinks. + pub settled_spends: u64, + /// Commitments in insertion order, recovered from deposit instructions. + pub leaves: Vec<[u8; 32]>, + /// `None` when no account exists at the disclosed address. + pub record: Option, +} + +/// Reads the cluster into a [`ChainView`]. +/// +/// Deliberately thin, and deliberately the only part of this module that talks +/// to a network. Anything it cannot establish is an error rather than a +/// [`ChainView`] with a plausible-looking hole in it: a rebuilt accumulator that +/// is missing leaves would fail the root check and read to a member like the +/// discloser's fault rather than the endpoint's. +pub fn observe( + chain: &Chain, + program: &Pubkey, + denomination: u64, + record: &Pubkey, + verbose: bool, +) -> Result { + let state = client::read_pool(chain, program, denomination)?; + let history = history::scan(chain, program, &state.pool, verbose)?; + if history.commitments.len() as u64 != state.deposits { + return Err(anyhow!( + "recovered {} leaves but the pool has inserted {}. The history is \ + incomplete — most likely the endpoint has pruned it — and a \ + disclosure cannot be checked against a partial accumulator. \ + `mirror check-endpoint` tests for exactly that.", + history.commitments.len(), + state.deposits + )); + } + let record = match chain.account_data(record)? { + None => None, + Some(mut data) => { + let spend = Spend::load(&mut data) + .map_err(|e| anyhow!("{record} exists but is not a spend record: {e:?}"))?; + Some(SpendRecordView { + settled: spend.status() == STATUS_SETTLED, + pool: spend.pool(), + beneficiary: spend.beneficiary(), + selector: spend.selector(), + target_program: spend.target_program(), + relay_fee: spend.relay_fee(), + payload: spend.payload().to_vec(), + }) + } + }; + Ok(ChainView { + denomination: state.denomination, + k_floor: state.k_floor, + root: state.root, + settled_spends: state.spends, + leaves: history.commitments, + record, + }) +} + +// --------------------------------------------------------------------------- +// The co-participant gate + +/// What disclosing costs the members who did not. +/// +/// A pool's privacy is joint property. Every settled action is a candidate for +/// every member, and a member who names one of them as theirs removes it from +/// everyone else's cover: the remaining actions are now shared among a smaller +/// set. The discloser pays nothing for this — they have already chosen — and the +/// people who pay are not in the room. +#[derive(Clone, Copy, Debug)] +pub struct CoParticipantCost { + pub settled_spends: u64, + pub k_floor: u32, + /// Settled actions still unattributed once this one is named. + pub remaining: u64, +} + +impl CoParticipantCost { + pub fn new(settled_spends: u64, k_floor: u32) -> Self { + CoParticipantCost { + settled_spends, + k_floor, + // Saturating rather than checked: a pool with no settled spend has + // nothing to disclose, and [`build`] refuses it earlier for the + // stronger reason that the note is unspent. + remaining: settled_spends.saturating_sub(1), + } + } + + /// Whether what is left after this disclosure is still a crowd by the + /// pool's own definition. + pub fn leaves_a_crowd(&self) -> bool { + self.remaining >= self.k_floor as u64 + } +} + +/// Deliberate consent to disclose below the pool's floor. +/// +/// The gate is **advisory and cannot be otherwise**. The secrets are the +/// member's; they can publish them in a text message, and no code here or on +/// chain can stop that. What this type buys is that the cost is visible at the +/// moment it is paid, to the person paying it on someone else's behalf, rather +/// than discovered later by the members who lost cover. +/// +/// It is a constructed type instead of a `bool` parameter for the same reason +/// the staker and the withdrawer are separate arguments elsewhere in this crate: +/// a bare `true` is one keystroke and one misread signature away from being +/// passed by a caller who never considered the question. Building this requires +/// having computed the cost first. +#[derive(Clone, Copy, Debug)] +pub struct DisclosureOverride { + acknowledged: CoParticipantCost, +} + +impl DisclosureOverride { + /// Consents to the cost described, which the caller must have computed. + pub fn acknowledging(cost: CoParticipantCost) -> Self { + DisclosureOverride { acknowledged: cost } + } + + /// The cost that was consented to, for the record this prints. + pub fn cost(&self) -> CoParticipantCost { + self.acknowledged + } +} + +// --------------------------------------------------------------------------- +// Building one + +/// Assembles a disclosure for a note this pool has already settled. +/// +/// Every field is derived rather than accepted: the leaf index is found by +/// searching the recovered leaf set for the recomputed commitment, the record +/// address is the PDA of the recomputed nullifier, and the action is copied out +/// of the record the chain holds rather than out of anything the member typed. +/// A disclosure this tool would refuse to verify is never written. +pub fn build( + program: &Pubkey, + pool: &Pubkey, + stored: &StoredNote, + view: &ChainView, + consent: Option<&DisclosureOverride>, +) -> Result { + let note = stored.note()?; + if view.denomination != stored.denomination { + return Err(anyhow!( + "this note is for denomination {} and the pool at {pool} holds {}", + stored.denomination, + view.denomination + )); + } + let commitment = note.commitment().map_err(|e| anyhow!("{e:?}"))?.to_bytes(); + let leaf_index = view + .leaves + .iter() + .position(|leaf| leaf == &commitment) + .ok_or_else(|| { + anyhow!( + "this note is not a leaf of the pool at {pool}. Either it was \ + never deposited, or it belongs to a different denomination." + ) + })? as u64; + let nullifier = note.nullifier().map_err(|e| anyhow!("{e:?}"))?.to_bytes(); + let (record_address, _) = spend_address(program, pool, &nullifier); + + // The refusal that protects the discloser rather than their co-members. An + // unspent note's secrets still authorise a payout, so a "disclosure" of one + // is a transfer of the deposit to whoever reads the file. + let record = view.record.as_ref().ok_or_else(|| { + anyhow!( + "there is no spend record at {record_address}, so this note has not \ + been spent.\n\n\ + Its secrets still authorise a payout: anyone holding them can prove \ + membership and direct the money wherever they like. Disclosing an \ + unspent note does not prove what you did with it — it gives it away.\n\n\ + Spend the note first. Once it has settled, k and r authorise nothing \ + and this file proves only what it says." + ) + })?; + if !record.settled { + return Err(anyhow!( + "the spend record at {record_address} exists but has not settled.\n\n\ + The action has not executed yet, so there is nothing to prove was \ + yours, and the note's secrets are still the only thing standing \ + between the deposit and whoever holds them. Wait for settlement — \ + `mirror settle` runs it, and so does anyone else." + )); + } + if record.pool != pool.to_bytes() { + return Err(anyhow!( + "the record at {record_address} belongs to pool {}, not {pool}. \ + A disclosure naming this pool would not verify.", + Pubkey::new_from_array(record.pool) + )); + } + + let cost = CoParticipantCost::new(view.settled_spends, view.k_floor); + if !cost.leaves_a_crowd() && consent.is_none() { + return Err(anyhow!( + "REFUSING: this pool has settled {} spend(s) and its floor is {}. \ + Naming one of them as yours leaves {} unattributed, which is below \ + the floor.\n\n\ + The people that costs are not you. Every settled action is a \ + candidate for every member; removing one narrows the guess for all \ + the rest, and they did not agree to it and will not be told.\n\n\ + If you have weighed that and still want to, pass {ACKNOWLEDGE_FLAG}. \ + Nothing here can stop you disclosing out-of-band anyway — the secrets \ + are yours. This exists so the cost is visible at the moment it is \ + paid.", + cost.settled_spends, + cost.k_floor, + cost.remaining + )); + } + + Ok(Disclosure { + program: program.to_string(), + pool: pool.to_string(), + denomination: stored.denomination, + leaf_index, + commitment: hex::encode(commitment), + k: hex::encode(note.k.to_bytes()), + r: hex::encode(note.r.to_bytes()), + nullifier: hex::encode(nullifier), + spend_record: record_address.to_string(), + action: ClaimedAction { + beneficiary: Pubkey::new_from_array(record.beneficiary).to_string(), + selector: record.selector, + target_program: Pubkey::new_from_array(record.target_program).to_string(), + relay_fee: record.relay_fee, + payload: hex::encode(&record.payload), + }, + }) +} + +// --------------------------------------------------------------------------- +// Checking one + +/// One independently reported step of a verification. +/// +/// Separate variants rather than one boolean because "this disclosure is false" +/// is not a useful thing to hand somebody. A verifier needs to know whether the +/// secrets are wrong, the leaf set is incomplete, or the record says something +/// else — those are different conversations with different people. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Check { + /// `H3(k, r, denom_tag)` equals the stated commitment. + SecretsRecomputeToTheCommitment, + /// The stated pool is the PDA for the stated denomination, and the account + /// there reports that denomination. + ThePoolMatchesTheDenomination, + /// The recomputed commitment sits at the stated leaf index. + TheCommitmentIsTheStatedLeaf, + /// The accumulator rebuilt from history has the pool's on-chain root. + TheRebuiltRootMatchesTheChain, + /// `H1(k)` equals the stated nullifier. + SecretsRecomputeToTheNullifier, + /// The stated record address is the PDA of the *recomputed* nullifier. + TheRecordAddressIsTheNullifiersPda, + /// An account exists at that address. + TheRecordExistsOnChain, + /// It settled, rather than merely being submitted. + TheRecordIsSettled, + /// Its `pool` field is this pool. + TheRecordBelongsToThisPool, + /// Its beneficiary, selector, target, fee and payload are what is claimed. + TheRecordMatchesTheClaimedAction, +} + +impl Check { + /// Every check, in the order [`verify`] reports them. + pub const ALL: [Check; 10] = [ + Check::SecretsRecomputeToTheCommitment, + Check::ThePoolMatchesTheDenomination, + Check::TheCommitmentIsTheStatedLeaf, + Check::TheRebuiltRootMatchesTheChain, + Check::SecretsRecomputeToTheNullifier, + Check::TheRecordAddressIsTheNullifiersPda, + Check::TheRecordExistsOnChain, + Check::TheRecordIsSettled, + Check::TheRecordBelongsToThisPool, + Check::TheRecordMatchesTheClaimedAction, + ]; + + /// A line a verifier can read without knowing this codebase. + pub fn name(&self) -> &'static str { + match self { + Check::SecretsRecomputeToTheCommitment => "the secrets recompute to the commitment", + Check::ThePoolMatchesTheDenomination => "the pool matches the denomination", + Check::TheCommitmentIsTheStatedLeaf => "the commitment is the stated leaf", + Check::TheRebuiltRootMatchesTheChain => "the rebuilt root matches the chain", + Check::SecretsRecomputeToTheNullifier => "the secrets recompute to the nullifier", + Check::TheRecordAddressIsTheNullifiersPda => { + "the record address is the nullifier's PDA" + } + Check::TheRecordExistsOnChain => "the spend record exists on chain", + Check::TheRecordIsSettled => "the spend record is settled", + Check::TheRecordBelongsToThisPool => "the spend record belongs to this pool", + Check::TheRecordMatchesTheClaimedAction => "the record matches the claimed action", + } + } +} + +/// One check's verdict, with what was compared. +#[derive(Debug)] +pub struct Verdict { + pub check: Check, + pub passed: bool, + /// What the check saw, phrased so a failure tells the reader what to do + /// about it rather than only that something is wrong. + pub detail: String, +} + +/// Every check and its verdict. +#[derive(Debug, Default)] +pub struct Verification { + verdicts: Vec, +} + +impl Verification { + fn record(&mut self, check: Check, outcome: Result) { + let (passed, detail) = match outcome { + Ok(detail) => (true, detail), + Err(detail) => (false, detail), + }; + self.verdicts.push(Verdict { + check, + passed, + detail, + }); + } + + pub fn verdicts(&self) -> &[Verdict] { + &self.verdicts + } + + pub fn failures(&self) -> impl Iterator { + self.verdicts.iter().filter(|v| !v.passed) + } + + /// True only when every check ran and passed. There is no partial credit: + /// a disclosure that half-verifies proves nothing. + pub fn passed(&self) -> bool { + self.verdicts.len() == Check::ALL.len() && self.verdicts.iter().all(|v| v.passed) + } +} + +/// The secrets, turned back into the two values the chain published. +struct Recomputed { + commitment: [u8; 32], + nullifier: [u8; 32], +} + +/// Every field of the disclosure that has to be parsed before it can be used. +/// +/// Held as `Result`s rather than unwrapped up front so that a field this tool +/// cannot read fails the checks that depend on it instead of aborting the whole +/// verification. A verifier handed a corrupt file should still learn which parts +/// of the claim survive. +struct Parsed { + program: Result, + pool: Result, + commitment: Result<[u8; 32], String>, + nullifier: Result<[u8; 32], String>, + record_address: Result, + beneficiary: Result, + target_program: Result, + payload: Result, String>, + secrets: Result, +} + +fn parse_pubkey(s: &str, what: &str) -> Result { + s.parse() + .map_err(|e| format!("the {what} is not a base58 pubkey: {e}")) +} + +fn parse_hex32(s: &str, what: &str) -> Result<[u8; 32], String> { + let raw = hex::decode(s).map_err(|e| format!("the {what} is not hex: {e}"))?; + raw.try_into() + .map_err(|_| format!("the {what} is not 32 bytes")) +} + +fn parse_field(s: &str, what: &str) -> Result { + let bytes = parse_hex32(s, what)?; + Field::from_bytes(bytes).map_err(|e| format!("{what} is not a canonical field element: {e:?}")) +} + +/// Recomputes the commitment and the nullifier from the disclosed secrets. +/// +/// This is the recompute-first rule in one function: the two values the rest of +/// the verification compares against come from `(k, r)` and the denomination, +/// never from the fields of the file that claim them. +fn recompute(disclosure: &Disclosure) -> Result { + let k = parse_field(&disclosure.k, "k")?; + let r = parse_field(&disclosure.r, "r")?; + let note = Note::new(k, r, Field::from_u64(disclosure.denomination)); + Ok(Recomputed { + commitment: note + .commitment() + .map_err(|e| format!("hashing the commitment: {e:?}"))? + .to_bytes(), + nullifier: note + .nullifier() + .map_err(|e| format!("hashing the nullifier: {e:?}"))? + .to_bytes(), + }) +} + +/// Rebuilds the accumulator from a recovered leaf set. +/// +/// Order matters and is the whole reason this is worth checking: the same +/// leaves inserted in a different order give a different root, so a root that +/// matches the chain's is evidence the leaf set is both complete and correctly +/// ordered — which is what makes "leaf 7 is the commitment" mean anything. +fn rebuild_root(leaves: &[[u8; 32]]) -> Result<[u8; 32], String> { + let mut tree = MerkleTree::new().map_err(|e| format!("{e:?}"))?; + for (i, leaf) in leaves.iter().enumerate() { + let field = Field::from_bytes(*leaf) + .map_err(|_| format!("recovered leaf {i} is not a canonical field element"))?; + tree.insert(field).map_err(|e| format!("{e:?}"))?; + } + tree.root() + .map(|root| root.to_bytes()) + .map_err(|e| format!("{e:?}")) +} + +fn secrets_recompute_to_the_commitment(parsed: &Parsed) -> Result { + let secrets = parsed.secrets.as_ref().map_err(Clone::clone)?; + let stated = parsed.commitment.as_ref().map_err(Clone::clone)?; + if secrets.commitment != *stated { + return Err(format!( + "the secrets commit to {}, but the disclosure states {}", + hex::encode(secrets.commitment), + hex::encode(stated) + )); + } + Ok(format!( + "H3(k, r, denom_tag) = {}", + hex::encode(secrets.commitment) + )) +} + +/// The pool is a PDA of the program and the denomination, so a disclosure that +/// names all three cannot be internally consistent by accident — and the account +/// at that address must itself report the denomination the commitment was bound +/// to, or the note being disclosed belongs to a different tree. +fn the_pool_matches_the_denomination( + disclosure: &Disclosure, + view: &ChainView, + parsed: &Parsed, +) -> Result { + let program = parsed.program.as_ref().map_err(Clone::clone)?; + let pool = parsed.pool.as_ref().map_err(Clone::clone)?; + let (derived, _) = pool_address(program, disclosure.denomination); + if derived != *pool { + return Err(format!( + "denomination {} under program {program} is pool {derived}, not {pool}", + disclosure.denomination + )); + } + if view.denomination != disclosure.denomination { + return Err(format!( + "the pool at {pool} holds denomination {}, but the disclosure claims {}", + view.denomination, disclosure.denomination + )); + } + Ok(format!( + "{pool} is the pool for {} lamports", + view.denomination + )) +} + +/// Checked against the *recomputed* commitment. A file whose commitment field +/// were trusted here would let a discloser point at somebody else's leaf. +fn the_commitment_is_the_stated_leaf( + disclosure: &Disclosure, + view: &ChainView, + parsed: &Parsed, +) -> Result { + let secrets = parsed.secrets.as_ref().map_err(Clone::clone)?; + let at = view + .leaves + .get(disclosure.leaf_index as usize) + .ok_or_else(|| { + format!( + "the disclosure claims leaf {}, but the pool's history holds only {} leaves", + disclosure.leaf_index, + view.leaves.len() + ) + })?; + if *at != secrets.commitment { + let elsewhere = view + .leaves + .iter() + .position(|leaf| leaf == &secrets.commitment); + return Err(match elsewhere { + Some(i) => format!( + "the secrets commit to leaf {i}, not to leaf {}", + disclosure.leaf_index + ), + None => format!( + "the commitment these secrets produce is not in the pool's leaf \ + set at all ({} leaves recovered)", + view.leaves.len() + ), + }); + } + Ok(format!( + "leaf {} of {} is {}", + disclosure.leaf_index, + view.leaves.len(), + hex::encode(secrets.commitment) + )) +} + +/// The check that makes the leaf index mean something. +/// +/// Without it, a verifier is trusting whoever served the history. A leaf set +/// with an insertion missing, or reordered, produces a tree in which some other +/// member's note occupies the disclosed index — and every other check here would +/// still pass. Matching the on-chain root is the only available evidence that +/// the recovered set is the set the program accumulated. +fn the_rebuilt_root_matches_the_chain(view: &ChainView) -> Result { + let rebuilt = rebuild_root(&view.leaves)?; + if rebuilt != view.root { + return Err(format!( + "the accumulator rebuilt from {} recovered leaves has root {}, but \ + the pool holds {}. The leaf set or its order is wrong, so the leaf \ + index above names nothing.", + view.leaves.len(), + hex::encode(rebuilt), + hex::encode(view.root) + )); + } + Ok(format!( + "{} leaves rebuild to {}", + view.leaves.len(), + hex::encode(rebuilt) + )) +} + +fn secrets_recompute_to_the_nullifier(parsed: &Parsed) -> Result { + let secrets = parsed.secrets.as_ref().map_err(Clone::clone)?; + let stated = parsed.nullifier.as_ref().map_err(Clone::clone)?; + if secrets.nullifier != *stated { + return Err(format!( + "H1(k) is {}, but the disclosure states {}", + hex::encode(secrets.nullifier), + hex::encode(stated) + )); + } + Ok(format!("H1(k) = {}", hex::encode(secrets.nullifier))) +} + +/// Derived from the secrets, not read out of the file. +/// +/// This is what binds the record to the note. A disclosure that could name any +/// record address would be a member pointing at whichever settled action suited +/// them; the address has to fall out of `H1(k)` and the pool. +fn the_record_address_is_the_nullifiers_pda(parsed: &Parsed) -> Result { + let secrets = parsed.secrets.as_ref().map_err(Clone::clone)?; + let program = parsed.program.as_ref().map_err(Clone::clone)?; + let pool = parsed.pool.as_ref().map_err(Clone::clone)?; + let stated = parsed.record_address.as_ref().map_err(Clone::clone)?; + let (derived, _) = spend_address(program, pool, &secrets.nullifier); + if derived != *stated { + return Err(format!( + "H1(k) in this pool is record {derived}, but the disclosure names {stated}" + )); + } + Ok(format!("{derived} is the record for H1(k)")) +} + +fn the_record_exists_on_chain(view: &ChainView, parsed: &Parsed) -> Result { + let stated = parsed.record_address.as_ref().map_err(Clone::clone)?; + match &view.record { + None => Err(format!( + "no account exists at {stated}. Either the spend was never submitted, \ + or this endpoint cannot see it." + )), + Some(_) => Ok(format!("{stated} holds a spend record")), + } +} + +/// Settled, not merely submitted. +/// +/// A pending record is a burnt nullifier and an action that has not run. The +/// member has not yet done the thing they are claiming to have done, and the +/// action may still fail at settlement. +fn the_record_is_settled(view: &ChainView) -> Result { + let record = view + .record + .as_ref() + .ok_or_else(|| "there is no record to read a status from".to_string())?; + if !record.settled { + return Err( + "the record is pending: the action was authorised but has not executed, \ + so there is nothing yet to have been done" + .to_string(), + ); + } + Ok("settled".to_string()) +} + +fn the_record_belongs_to_this_pool(parsed: &Parsed, view: &ChainView) -> Result { + let pool = parsed.pool.as_ref().map_err(Clone::clone)?; + let record = view + .record + .as_ref() + .ok_or_else(|| "there is no record to read a pool from".to_string())?; + if record.pool != pool.to_bytes() { + return Err(format!( + "the record names pool {}, not {pool}", + Pubkey::new_from_array(record.pool) + )); + } + Ok(format!("the record names {pool}")) +} + +/// Every field the action binding covered, compared one at a time. +/// +/// Reported field by field rather than as a single equality because the fields +/// mean different things to a verifier: a wrong beneficiary is a different claim +/// entirely, and a wrong relay fee is an arithmetic disagreement about the same +/// one. +fn the_record_matches_the_claimed_action( + disclosure: &Disclosure, + view: &ChainView, + parsed: &Parsed, +) -> Result { + let record = view + .record + .as_ref() + .ok_or_else(|| "there is no record to compare the action against".to_string())?; + let beneficiary = parsed.beneficiary.as_ref().map_err(Clone::clone)?; + let target = parsed.target_program.as_ref().map_err(Clone::clone)?; + let payload = parsed.payload.as_ref().map_err(Clone::clone)?; + + let mut wrong: Vec = Vec::new(); + if record.beneficiary != beneficiary.to_bytes() { + wrong.push(format!( + "beneficiary: the record paid {}, the disclosure claims {beneficiary}", + Pubkey::new_from_array(record.beneficiary) + )); + } + if record.selector != disclosure.action.selector { + wrong.push(format!( + "selector: the record holds {}, the disclosure claims {}", + record.selector, disclosure.action.selector + )); + } + if record.target_program != target.to_bytes() { + wrong.push(format!( + "target program: the record invoked {}, the disclosure claims {target}", + Pubkey::new_from_array(record.target_program) + )); + } + if record.relay_fee != disclosure.action.relay_fee { + wrong.push(format!( + "relay fee: the record holds {}, the disclosure claims {}", + record.relay_fee, disclosure.action.relay_fee + )); + } + if record.payload != *payload { + wrong.push(format!( + "payload: the record holds {}, the disclosure claims {}", + hex::encode(&record.payload), + hex::encode(payload) + )); + } + if !wrong.is_empty() { + return Err(wrong.join("; ")); + } + Ok(format!( + "selector {} paid {beneficiary}, fee {}, {} payload byte(s)", + record.selector, + record.relay_fee, + record.payload.len() + )) +} + +/// Re-derives the whole claim and reports every check separately. +/// +/// Infallible by design. A malformed disclosure produces failed checks rather +/// than an error, because "this tool could not read the file" and "this tool +/// read the file and it was false" must never be distinguishable to a caller +/// that only looks at a return code — both mean the claim is not established. +/// +/// Fail-closed throughout: a check whose inputs are missing fails, and a check +/// whose prerequisite failed fails on its own terms rather than being skipped. +/// There is no path through this function that reports a pass for something it +/// did not compare. +pub fn verify(disclosure: &Disclosure, view: &ChainView) -> Verification { + let parsed = Parsed { + program: parse_pubkey(&disclosure.program, "program"), + pool: parse_pubkey(&disclosure.pool, "pool"), + commitment: parse_hex32(&disclosure.commitment, "commitment"), + nullifier: parse_hex32(&disclosure.nullifier, "nullifier"), + record_address: parse_pubkey(&disclosure.spend_record, "spend record address"), + beneficiary: parse_pubkey(&disclosure.action.beneficiary, "beneficiary"), + target_program: parse_pubkey(&disclosure.action.target_program, "target program"), + payload: hex::decode(&disclosure.action.payload) + .map_err(|e| format!("the payload is not hex: {e}")), + secrets: recompute(disclosure), + }; + + let mut result = Verification::default(); + result.record( + Check::SecretsRecomputeToTheCommitment, + secrets_recompute_to_the_commitment(&parsed), + ); + result.record( + Check::ThePoolMatchesTheDenomination, + the_pool_matches_the_denomination(disclosure, view, &parsed), + ); + result.record( + Check::TheCommitmentIsTheStatedLeaf, + the_commitment_is_the_stated_leaf(disclosure, view, &parsed), + ); + result.record( + Check::TheRebuiltRootMatchesTheChain, + the_rebuilt_root_matches_the_chain(view), + ); + result.record( + Check::SecretsRecomputeToTheNullifier, + secrets_recompute_to_the_nullifier(&parsed), + ); + result.record( + Check::TheRecordAddressIsTheNullifiersPda, + the_record_address_is_the_nullifiers_pda(&parsed), + ); + result.record( + Check::TheRecordExistsOnChain, + the_record_exists_on_chain(view, &parsed), + ); + result.record(Check::TheRecordIsSettled, the_record_is_settled(view)); + result.record( + Check::TheRecordBelongsToThisPool, + the_record_belongs_to_this_pool(&parsed, view), + ); + result.record( + Check::TheRecordMatchesTheClaimedAction, + the_record_matches_the_claimed_action(disclosure, view, &parsed), + ); + result +} + +/// Prints the checks as a table, failures included. +/// +/// Every check is printed whether it passed or not. A report that listed only +/// the failures would leave a verifier unable to tell a claim that was checked +/// thoroughly from one that was barely checked at all. +pub fn report(disclosure: &Disclosure, result: &Verification) { + println!( + "disclosure for leaf {} of {}", + disclosure.leaf_index, disclosure.pool + ); + println!(" nullifier {}", disclosure.nullifier); + println!(" record {}", disclosure.spend_record); + println!(); + for verdict in result.verdicts() { + println!( + " {:<42} {}", + verdict.check.name(), + if verdict.passed { "PASS" } else { "FAIL" } + ); + println!(" {}", verdict.detail); + } +} + +// --------------------------------------------------------------------------- +// The two commands + +/// Writes a disclosure for a settled note. +pub fn create( + chain: &Chain, + program: &Pubkey, + note_path: &Path, + out: &Path, + acknowledge_cost: bool, +) -> Result<()> { + let stored = StoredNote::read(note_path)?; + let note = stored.note()?; + let (pool, _) = pool_address(program, stored.denomination); + let nullifier = note.nullifier().map_err(|e| anyhow!("{e:?}"))?.to_bytes(); + let (record, _) = spend_address(program, &pool, &nullifier); + + println!("rebuilding the pool from chain history:"); + let view = observe(chain, program, stored.denomination, &record, true)?; + + // The flag arrives as a bool because a command-line flag is one. It becomes + // a constructed override here, at the edge, so that nothing inside this + // module can be handed a consent it never asked for. + let cost = CoParticipantCost::new(view.settled_spends, view.k_floor); + let consent = if acknowledge_cost { + Some(DisclosureOverride::acknowledging(cost)) + } else { + None + }; + let disclosure = build(program, &pool, &stored, &view, consent.as_ref())?; + + // Checked before it is written, against the same view. A disclosure that + // would not verify is a file a member would hand over and be disbelieved + // for, and they would have no way to tell why. + let result = verify(&disclosure, &view); + if !result.passed() { + report(&disclosure, &result); + return Err(anyhow!( + "refusing to write a disclosure that does not verify against the \ + chain it was built from" + )); + } + + disclosure.write(out)?; + println!(); + println!("wrote {}", out.display()); + println!(" leaf {}", disclosure.leaf_index); + println!(" nullifier {}", disclosure.nullifier); + println!(" record {}", disclosure.spend_record); + if let Some(consent) = consent { + let cost = consent.cost(); + println!(); + println!( + "You disclosed below the floor: {} settled spend(s), floor {}, {} left", + cost.settled_spends, cost.k_floor, cost.remaining + ); + println!("unattributed. That cost was paid by the other members of this pool."); + } + println!(); + println!("This file contains k and r. They authorise nothing now — the nullifier is"); + println!("burnt and the record has settled — but they identify you to whoever holds"); + println!("it, permanently and with no way to take it back. Send it to one verifier,"); + println!("over a channel you would send a passport scan over, and to nobody else."); + println!(); + println!("The verifier checks it with: mirror disclose-verify --file "); + Ok(()) +} + +/// Checks a disclosure against the cluster and prints every verdict. +pub fn check(chain: &Chain, path: &Path) -> Result<()> { + let disclosure = Disclosure::read(path)?; + // Needed before the RPC can be pointed anywhere. A file too malformed to + // name a program cannot be checked at all, which is a failure to establish + // the claim rather than a claim that failed. + let program: Pubkey = disclosure + .program + .parse() + .map_err(|e| anyhow!("the program in {} is not a pubkey: {e}", path.display()))?; + let record: Pubkey = disclosure.spend_record.parse().map_err(|e| { + anyhow!( + "the spend record address in {} is not a pubkey: {e}", + path.display() + ) + })?; + + println!("rebuilding the pool from chain history:"); + let view = observe(chain, &program, disclosure.denomination, &record, true)?; + println!(); + let result = verify(&disclosure, &view); + report(&disclosure, &result); + println!(); + + if result.passed() { + println!( + "VERIFIED. Every value in this file was recomputed from the secrets or \ + read off the\ncluster. The holder of this note is whoever asked the pool \ + for the action above." + ); + return Ok(()); + } + Err(anyhow!( + "NOT VERIFIED: {} of {} checks failed. This file does not establish that its \ + author authorised that action — it establishes nothing at all.", + result.failures().count(), + Check::ALL.len() + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + const DENOM: u64 = 100_000_000; + /// Where the disclosed note sits in the fixture's leaf set. + const LEAF: u64 = 3; + const FEE: u64 = 5_000; + const SELECTOR: u64 = 2; + + fn program() -> Pubkey { + Pubkey::new_from_array([7u8; 32]) + } + + fn beneficiary() -> Pubkey { + Pubkey::new_from_array([11u8; 32]) + } + + fn target() -> Pubkey { + Pubkey::new_from_array([13u8; 32]) + } + + fn note() -> Note { + Note::new( + Field::from_u64(1_234_567), + Field::from_u64(7_654_321), + Field::from_u64(DENOM), + ) + } + + fn root_of(leaves: &[[u8; 32]]) -> [u8; 32] { + rebuild_root(leaves).unwrap() + } + + fn leaves_with(commitment: [u8; 32]) -> Vec<[u8; 32]> { + let mut leaves: Vec<[u8; 32]> = (1..=6u64) + .map(|i| Field::from_u64(i * 977 + 13).to_bytes()) + .collect(); + leaves[LEAF as usize] = commitment; + leaves + } + + fn record_for(pool: &Pubkey) -> SpendRecordView { + SpendRecordView { + settled: true, + pool: pool.to_bytes(), + beneficiary: beneficiary().to_bytes(), + selector: SELECTOR, + target_program: target().to_bytes(), + relay_fee: FEE, + payload: b"delegate".to_vec(), + } + } + + /// A pool that has settled comfortably above its floor, holding the note. + fn honest() -> (Disclosure, ChainView) { + let program = program(); + let (pool, _) = pool_address(&program, DENOM); + let stored = StoredNote::from_note(¬e(), DENOM).unwrap(); + let leaves = leaves_with(stored.commitment_bytes().unwrap()); + let view = ChainView { + denomination: DENOM, + k_floor: 2, + root: root_of(&leaves), + settled_spends: 5, + leaves, + record: Some(record_for(&pool)), + }; + let disclosure = build(&program, &pool, &stored, &view, None).unwrap(); + (disclosure, view) + } + + fn verify_with(mutate: impl FnOnce(&mut Disclosure, &mut ChainView)) -> Verification { + let (mut disclosure, mut view) = honest(); + mutate(&mut disclosure, &mut view); + verify(&disclosure, &view) + } + + fn failed(result: &Verification) -> Vec { + result.failures().map(|v| v.check).collect() + } + + fn detail(result: &Verification, check: Check) -> String { + result + .verdicts() + .iter() + .find(|v| v.check == check) + .expect("every check is reported") + .detail + .clone() + } + + // -- the honest cases --------------------------------------------------- + + #[test] + fn an_honest_disclosure_verifies() { + let (disclosure, view) = honest(); + let result = verify(&disclosure, &view); + assert!( + result.passed(), + "an honest disclosure failed: {:?}", + failed(&result) + ); + } + + /// The claim is only as good as its coverage, so the report must show every + /// check exactly once and in a stable order — a verifier comparing two runs + /// should be comparing the same list. + #[test] + fn every_check_is_reported_exactly_once_and_in_order() { + let (disclosure, view) = honest(); + let result = verify(&disclosure, &view); + let reported: Vec = result.verdicts().iter().map(|v| v.check).collect(); + assert_eq!(reported, Check::ALL.to_vec()); + } + + #[test] + fn a_disclosure_round_trips_through_its_file_form() { + let (disclosure, view) = honest(); + let text = serde_json::to_string(&disclosure).unwrap(); + let read: Disclosure = serde_json::from_str(&text).unwrap(); + assert!(verify(&read, &view).passed()); + } + + /// The action is copied out of the record rather than out of anything the + /// member typed, so what the disclosure claims is what the chain holds. + #[test] + fn the_claimed_action_is_taken_from_the_record() { + let (disclosure, _) = honest(); + assert_eq!(disclosure.action.beneficiary, beneficiary().to_string()); + assert_eq!(disclosure.action.selector, SELECTOR); + assert_eq!(disclosure.action.target_program, target().to_string()); + assert_eq!(disclosure.action.relay_fee, FEE); + assert_eq!(disclosure.action.payload, hex::encode(b"delegate")); + } + + // -- the tamper matrix -------------------------------------------------- + + /// Wrong `k`: everything derived from the nullifier preimage moves at once. + /// The fan-out is the point — `k` is what ties the leaf, the nullifier and + /// the record address together, so a substituted one cannot satisfy any of + /// them. + #[test] + fn a_disclosure_with_the_wrong_k_fails_every_check_that_derives_from_it() { + let result = verify_with(|d, _| d.k = hex::encode(Field::from_u64(42).to_bytes())); + assert_eq!( + failed(&result), + vec![ + Check::SecretsRecomputeToTheCommitment, + Check::TheCommitmentIsTheStatedLeaf, + Check::SecretsRecomputeToTheNullifier, + Check::TheRecordAddressIsTheNullifiersPda, + ] + ); + } + + /// Wrong `r`: the commitment moves and the nullifier does not, because `r` + /// blinds the leaf and never enters `H1`. + #[test] + fn a_disclosure_with_the_wrong_r_fails_the_commitment_but_not_the_nullifier() { + let result = verify_with(|d, _| d.r = hex::encode(Field::from_u64(99).to_bytes())); + assert_eq!( + failed(&result), + vec![ + Check::SecretsRecomputeToTheCommitment, + Check::TheCommitmentIsTheStatedLeaf, + ] + ); + } + + #[test] + fn a_non_canonical_secret_is_refused_rather_than_reduced() { + let result = verify_with(|d, _| d.k = hex::encode([0xffu8; 32])); + assert!(detail(&result, Check::SecretsRecomputeToTheCommitment).contains("canonical")); + } + + /// A leaf set that is internally consistent — its root matches the chain — + /// but does not contain this note. This is the shape a member pointing at + /// somebody else's pool would produce. + #[test] + fn a_commitment_absent_from_the_recovered_leaf_set_is_refused() { + let result = verify_with(|_, view| { + view.leaves[LEAF as usize] = Field::from_u64(31_337).to_bytes(); + view.root = root_of(&view.leaves); + }); + assert_eq!(failed(&result), vec![Check::TheCommitmentIsTheStatedLeaf]); + assert!(detail(&result, Check::TheCommitmentIsTheStatedLeaf).contains("not in the pool")); + } + + /// The right note, the wrong index. Nothing else in the file changes, and + /// only the check that compares the two notices. + #[test] + fn the_right_commitment_at_the_wrong_leaf_index_is_refused() { + let result = verify_with(|d, _| d.leaf_index = 1); + assert_eq!(failed(&result), vec![Check::TheCommitmentIsTheStatedLeaf]); + assert!(detail(&result, Check::TheCommitmentIsTheStatedLeaf) + .contains(&format!("commit to leaf {LEAF}"))); + } + + #[test] + fn a_leaf_index_beyond_the_recovered_history_is_refused() { + let result = verify_with(|d, _| d.leaf_index = 4_000); + assert_eq!(failed(&result), vec![Check::TheCommitmentIsTheStatedLeaf]); + assert!(detail(&result, Check::TheCommitmentIsTheStatedLeaf).contains("only 6 leaves")); + } + + /// An incomplete or reordered history. Every other check still passes, + /// which is exactly why this one has to exist: without it a verifier would + /// be trusting whoever served the leaves. + #[test] + fn a_rebuilt_root_that_disagrees_with_the_chain_is_refused() { + let result = verify_with(|_, view| view.root = [0xAB; 32]); + assert_eq!(failed(&result), vec![Check::TheRebuiltRootMatchesTheChain]); + } + + /// The file's own nullifier field is never believed. It is compared against + /// `H1(k)`, and the record address is derived from `H1(k)` regardless — so + /// this fails the equality check and nothing else. + #[test] + fn a_nullifier_field_inconsistent_with_the_secrets_is_refused() { + let result = verify_with(|d, _| d.nullifier = hex::encode([0x01u8; 32])); + assert_eq!(failed(&result), vec![Check::SecretsRecomputeToTheNullifier]); + } + + #[test] + fn a_spend_record_address_that_is_not_the_derived_pda_is_refused() { + let result = + verify_with(|d, _| d.spend_record = Pubkey::new_from_array([9u8; 32]).to_string()); + assert_eq!( + failed(&result), + vec![Check::TheRecordAddressIsTheNullifiersPda] + ); + } + + /// Fail-closed: the three checks that need a record fail on their own terms + /// rather than being skipped, because a skipped check reads as a passed one + /// to anybody scanning the table. + #[test] + fn an_absent_spend_record_fails_every_check_that_needs_one() { + let result = verify_with(|_, view| view.record = None); + assert_eq!( + failed(&result), + vec![ + Check::TheRecordExistsOnChain, + Check::TheRecordIsSettled, + Check::TheRecordBelongsToThisPool, + Check::TheRecordMatchesTheClaimedAction, + ] + ); + } + + #[test] + fn a_record_that_is_still_pending_is_refused() { + let result = verify_with(|_, view| { + view.record.as_mut().unwrap().settled = false; + }); + assert_eq!(failed(&result), vec![Check::TheRecordIsSettled]); + assert!(detail(&result, Check::TheRecordIsSettled).contains("pending")); + } + + /// A record from another denomination's pool. The address is pool-scoped, so + /// reaching this state means the record itself was tampered with, and the + /// check that reads its `pool` field is the one that catches it. + #[test] + fn a_record_belonging_to_a_different_pool_is_refused() { + let result = verify_with(|_, view| { + view.record.as_mut().unwrap().pool = [0x55; 32]; + }); + assert_eq!(failed(&result), vec![Check::TheRecordBelongsToThisPool]); + } + + #[test] + fn a_substituted_beneficiary_is_refused() { + let result = verify_with(|d, _| { + d.action.beneficiary = Pubkey::new_from_array([0x21; 32]).to_string(); + }); + assert_eq!( + failed(&result), + vec![Check::TheRecordMatchesTheClaimedAction] + ); + assert!(detail(&result, Check::TheRecordMatchesTheClaimedAction).contains("beneficiary")); + } + + #[test] + fn a_substituted_selector_is_refused() { + let result = verify_with(|d, _| d.action.selector = SELECTOR + 1); + assert!(detail(&result, Check::TheRecordMatchesTheClaimedAction).contains("selector")); + assert_eq!( + failed(&result), + vec![Check::TheRecordMatchesTheClaimedAction] + ); + } + + #[test] + fn a_substituted_target_program_is_refused() { + let result = verify_with(|d, _| { + d.action.target_program = Pubkey::new_from_array([0x31; 32]).to_string(); + }); + assert!(detail(&result, Check::TheRecordMatchesTheClaimedAction).contains("target program")); + assert_eq!( + failed(&result), + vec![Check::TheRecordMatchesTheClaimedAction] + ); + } + + #[test] + fn a_substituted_relay_fee_is_refused() { + let result = verify_with(|d, _| d.action.relay_fee = FEE + 1); + assert!(detail(&result, Check::TheRecordMatchesTheClaimedAction).contains("relay fee")); + assert_eq!( + failed(&result), + vec![Check::TheRecordMatchesTheClaimedAction] + ); + } + + /// The payload is the action's parameters. A disclosure that understated it + /// would describe a different instruction than the one the pool executed. + #[test] + fn a_substituted_payload_is_refused() { + let result = verify_with(|d, _| d.action.payload = hex::encode(b"withdraw")); + assert!(detail(&result, Check::TheRecordMatchesTheClaimedAction).contains("payload")); + assert_eq!( + failed(&result), + vec![Check::TheRecordMatchesTheClaimedAction] + ); + } + + /// The pool the disclosure names holds a different size than it claims, so + /// the commitment it recomputes belongs to another tree entirely. + #[test] + fn a_denomination_the_pool_does_not_hold_is_refused() { + let result = verify_with(|_, view| view.denomination = DENOM + 1); + assert_eq!(failed(&result), vec![Check::ThePoolMatchesTheDenomination]); + } + + /// The pool address is a PDA of the program and the denomination, so a + /// disclosure naming some other account is refused without an RPC call. + #[test] + fn a_pool_that_is_not_the_pda_for_the_denomination_is_refused() { + let result = verify_with(|d, _| d.pool = Pubkey::new_from_array([0x41; 32]).to_string()); + // The record's own pool field no longer matches either, which is the + // record correctly disagreeing with a substituted claim. + assert_eq!( + failed(&result), + vec![ + Check::ThePoolMatchesTheDenomination, + Check::TheRecordAddressIsTheNullifiersPda, + Check::TheRecordBelongsToThisPool, + ] + ); + } + + /// A file this tool cannot parse must not verify. It is the case where a + /// bare `is_err()` would be indistinguishable from a passing claim. + #[test] + fn a_malformed_field_fails_closed_rather_than_erroring() { + let result = verify_with(|d, _| d.commitment = "not hex".to_string()); + assert!(!result.passed()); + assert!(detail(&result, Check::SecretsRecomputeToTheCommitment).contains("not hex")); + } + + // -- building ----------------------------------------------------------- + + /// The refusal that protects the discloser. An unspent note's secrets are + /// the deposit, so writing them into a file to hand somebody is not a + /// disclosure — it is a transfer. + #[test] + fn a_disclosure_for_an_unspent_note_is_refused() { + let program = program(); + let (pool, _) = pool_address(&program, DENOM); + let stored = StoredNote::from_note(¬e(), DENOM).unwrap(); + let leaves = leaves_with(stored.commitment_bytes().unwrap()); + let view = ChainView { + denomination: DENOM, + k_floor: 2, + root: root_of(&leaves), + settled_spends: 5, + leaves, + record: None, + }; + let err = build(&program, &pool, &stored, &view, None) + .unwrap_err() + .to_string(); + assert!(err.contains("has not been spent"), "{err}"); + } + + #[test] + fn a_disclosure_for_a_pending_spend_is_refused() { + let program = program(); + let (pool, _) = pool_address(&program, DENOM); + let stored = StoredNote::from_note(¬e(), DENOM).unwrap(); + let leaves = leaves_with(stored.commitment_bytes().unwrap()); + let mut record = record_for(&pool); + record.settled = false; + let view = ChainView { + denomination: DENOM, + k_floor: 2, + root: root_of(&leaves), + settled_spends: 5, + leaves, + record: Some(record), + }; + let err = build(&program, &pool, &stored, &view, None) + .unwrap_err() + .to_string(); + assert!(err.contains("has not settled"), "{err}"); + } + + #[test] + fn a_disclosure_for_a_note_the_pool_never_held_is_refused() { + let program = program(); + let (pool, _) = pool_address(&program, DENOM); + let stored = StoredNote::from_note(¬e(), DENOM).unwrap(); + let leaves: Vec<[u8; 32]> = (1..=6u64).map(|i| Field::from_u64(i).to_bytes()).collect(); + let view = ChainView { + denomination: DENOM, + k_floor: 2, + root: root_of(&leaves), + settled_spends: 5, + leaves, + record: Some(record_for(&pool)), + }; + let err = build(&program, &pool, &stored, &view, None) + .unwrap_err() + .to_string(); + assert!(err.contains("not a leaf"), "{err}"); + } + + // -- the co-participant gate -------------------------------------------- + + #[test] + fn the_gate_counts_what_is_left_for_everybody_else() { + let cost = CoParticipantCost::new(5, 2); + assert_eq!(cost.remaining, 4); + assert!(cost.leaves_a_crowd()); + // Exactly at the floor is still a crowd; one below is not. + assert!(CoParticipantCost::new(3, 2).leaves_a_crowd()); + assert!(!CoParticipantCost::new(2, 2).leaves_a_crowd()); + } + + fn view_with_settled(settled: u64, k_floor: u32) -> (Pubkey, Pubkey, StoredNote, ChainView) { + let program = program(); + let (pool, _) = pool_address(&program, DENOM); + let stored = StoredNote::from_note(¬e(), DENOM).unwrap(); + let leaves = leaves_with(stored.commitment_bytes().unwrap()); + let view = ChainView { + denomination: DENOM, + k_floor, + root: root_of(&leaves), + settled_spends: settled, + leaves, + record: Some(record_for(&pool)), + }; + (program, pool, stored, view) + } + + /// Disclosing is only free to the person doing it. Below the floor the + /// default is refusal, and the message names the people it would cost. + #[test] + fn the_gate_refuses_a_disclosure_that_leaves_the_others_below_the_floor() { + let (program, pool, stored, view) = view_with_settled(2, 2); + let err = build(&program, &pool, &stored, &view, None) + .unwrap_err() + .to_string(); + assert!(err.contains("REFUSING"), "{err}"); + assert!(err.contains(ACKNOWLEDGE_FLAG), "{err}"); + } + + #[test] + fn the_gate_permits_a_disclosure_that_leaves_a_crowd() { + let (program, pool, stored, view) = view_with_settled(3, 2); + assert!(build(&program, &pool, &stored, &view, None).is_ok()); + } + + /// The override is a value the caller has to construct out of the cost it is + /// overriding, so it cannot be produced without the number being computed. + #[test] + fn an_explicit_override_permits_a_disclosure_below_the_floor() { + let (program, pool, stored, view) = view_with_settled(2, 2); + let consent = DisclosureOverride::acknowledging(CoParticipantCost::new( + view.settled_spends, + view.k_floor, + )); + let disclosure = build(&program, &pool, &stored, &view, Some(&consent)).unwrap(); + assert!(verify(&disclosure, &view).passed()); + assert!(!consent.cost().leaves_a_crowd()); + } +} diff --git a/crates/mirror-cli/src/history.rs b/crates/mirror-cli/src/history.rs new file mode 100644 index 00000000..496a51cb --- /dev/null +++ b/crates/mirror-cli/src/history.rs @@ -0,0 +1,230 @@ +//! Rebuilding a pool's state from the chain, with no index and no local file. +//! +//! The program stores the accumulator's *frontier* — one node per level — which +//! is all it needs to append a leaf and produce a root, and is not enough to +//! prove that any particular leaf is in the tree. A member needs the whole leaf +//! set for that. +//! +//! The leaves are not lost, though: every commitment was an argument to a +//! `Deposit` instruction, so the complete set is sitting in the transaction +//! history in the order it was inserted. This module reads it back. +//! +//! That matters beyond convenience. A client that depended on a local note +//! ledger would strand a member who lost the file, and one that depended on an +//! indexer would put a server between a member and their own money. Neither is +//! acceptable for a tool whose entire premise is that you should not have to +//! trust the operator — including us. + +use crate::chain::Chain; +use anyhow::{anyhow, Result}; +use mirror_core::{Field, MerkleTree}; +use mirror_pool_program::{instruction::Instruction as MirrorIx, pda::spend_address}; +use solana_program::pubkey::Pubkey; + +/// Where the pool account sits in the account list of the two instructions this +/// module reads. Both put the signer first and the pool second. +const POOL_ACCOUNT_INDEX: usize = 1; + +/// A spend that was submitted, and where its record lives. +pub struct SubmittedSpend { + pub nullifier: [u8; 32], + pub spend: Pubkey, +} + +/// Everything a client needs that the pool account does not hold. +pub struct History { + /// Note commitments in insertion order. Index `i` is leaf `i`. + pub commitments: Vec<[u8; 32]>, + pub spends: Vec, + /// Every key that has signed a deposit into this pool. + /// + /// Collected so the tool can catch the one mistake that undoes everything: + /// relaying a spend with a key that also deposited. Depositors are public by + /// necessity — a deposit is signed — so reading them costs nothing beyond + /// the scan already being done. + pub depositors: Vec, +} + +impl History { + /// Rebuilds the host-side Merkle tree the prover needs. + pub fn tree(&self) -> Result { + let mut tree = MerkleTree::new().map_err(|e| anyhow!("{e:?}"))?; + for (i, c) in self.commitments.iter().enumerate() { + let leaf = Field::from_bytes(*c) + .map_err(|e| anyhow!("commitment {i} is not a canonical field element: {e:?}"))?; + tree.insert(leaf).map_err(|e| anyhow!("{e:?}"))?; + } + Ok(tree) + } + + /// The index of `commitment`, if this pool holds it. + pub fn index_of(&self, commitment: &[u8; 32]) -> Option { + self.commitments + .iter() + .position(|c| c == commitment) + .map(|i| i as u64) + } +} + +/// Reads every deposit and spend this pool has seen, oldest first. +/// +/// Scans the *pool* account rather than the program. A program can host one pool +/// per denomination, so scanning the program would walk every pool's history to +/// build one pool's tree, and would then have to discard most of it. The pool +/// account appears in exactly the transactions that concern it. +pub fn scan(chain: &Chain, program_id: &Pubkey, pool: &Pubkey, verbose: bool) -> Result { + let signatures = chain.signatures_for_address(pool)?; + if verbose { + println!(" {} transactions touched this pool", signatures.len()); + } + + let mut commitments = Vec::new(); + let mut spends = Vec::new(); + let mut depositors: Vec = Vec::new(); + + for (n, signature) in signatures.iter().enumerate() { + if verbose && n > 0 && n % 25 == 0 { + println!(" {n}/{} …", signatures.len()); + } + // Paced deliberately. `getTransaction` is the expensive RPC method and + // the one public endpoints throttle first, and a rebuild asks for it + // once per signature — so a pool with any history sends a burst that + // gets the client throttled partway through and fails a member who was + // only trying to spend their own note. A short pause costs seconds and + // removes the failure entirely. + if n > 0 { + std::thread::sleep(std::time::Duration::from_millis(120)); + } + let Some(tx) = chain.transaction(signature)? else { + continue; + }; + let keys = &tx.message.account_keys; + + for ix in &tx.message.instructions { + let Some(program) = keys.get(ix.program_id_index as usize) else { + continue; + }; + if program != program_id { + continue; + } + // An instruction of ours that names a different pool belongs to a + // different denomination and a different tree. + let names_this_pool = ix + .accounts + .get(POOL_ACCOUNT_INDEX) + .and_then(|i| keys.get(*i as usize)) + .map(|k| k == pool) + .unwrap_or(false); + if !names_this_pool { + continue; + } + // Anything that does not decode is not ours to interpret. The pool + // account can appear in a transaction for reasons this module has no + // opinion about. + let Ok(decoded) = MirrorIx::unpack(&ix.data) else { + continue; + }; + match decoded { + MirrorIx::Deposit { commitment } => { + commitments.push(commitment); + if let Some(who) = ix.accounts.first().and_then(|i| keys.get(*i as usize)) { + if !depositors.contains(who) { + depositors.push(*who); + } + } + } + MirrorIx::SubmitSpend { nullifier, .. } => { + let (spend, _) = spend_address(program_id, pool, &nullifier); + spends.push(SubmittedSpend { nullifier, spend }); + } + _ => {} + } + } + } + + Ok(History { + commitments, + spends, + depositors, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use mirror_core::Frontier; + + fn commitments(n: u64) -> Vec<[u8; 32]> { + (1..=n) + .map(|i| Field::from_u64(i * 1_000 + 7).to_bytes()) + .collect() + } + + /// The rebuilt tree must agree with the accumulator the program keeps. + /// + /// This is the property the whole module exists for, and it is a property of + /// the *order*: the same leaves inserted in a different order give a + /// different root, so a scan that returned them newest-first would produce a + /// tree that looks healthy and against which no proof verifies. + #[test] + fn a_rebuilt_tree_matches_the_frontier_the_program_keeps() { + let history = History { + commitments: commitments(9), + spends: Vec::new(), + depositors: Vec::new(), + }; + let mut frontier = Frontier::new().unwrap(); + for c in &history.commitments { + frontier.insert(Field::from_bytes(*c).unwrap()).unwrap(); + } + assert_eq!(history.tree().unwrap().root().unwrap(), frontier.root()); + } + + #[test] + fn the_wrong_order_produces_a_different_root() { + let forward = History { + commitments: commitments(5), + spends: Vec::new(), + depositors: Vec::new(), + }; + let mut backward = forward.commitments.clone(); + backward.reverse(); + let reversed = History { + commitments: backward, + spends: Vec::new(), + depositors: Vec::new(), + }; + assert_ne!( + forward.tree().unwrap().root().unwrap(), + reversed.tree().unwrap().root().unwrap(), + "insertion order does not affect the root, which would mean the scan \ + order does not matter — it does" + ); + } + + #[test] + fn a_commitment_is_found_at_the_index_it_was_inserted() { + let history = History { + commitments: commitments(6), + spends: Vec::new(), + depositors: Vec::new(), + }; + for (i, c) in history.commitments.clone().iter().enumerate() { + assert_eq!(history.index_of(c), Some(i as u64)); + } + assert_eq!(history.index_of(&[0xAB; 32]), None); + } + + /// A leaf the accumulator would reject must be refused while it is still a + /// bad byte string, not deep inside a Poseidon call. + #[test] + fn a_non_canonical_commitment_fails_the_rebuild_by_name() { + let history = History { + commitments: vec![[0xff; 32]], + spends: Vec::new(), + depositors: Vec::new(), + }; + let err = history.tree().unwrap_err().to_string(); + assert!(err.contains("canonical"), "{err}"); + } +} diff --git a/crates/mirror-cli/src/lookup.rs b/crates/mirror-cli/src/lookup.rs new file mode 100644 index 00000000..0f281444 --- /dev/null +++ b/crates/mirror-cli/src/lookup.rs @@ -0,0 +1,393 @@ +//! Address lookup tables, as much of them as a settlement needs. +//! +//! A legacy transaction names every account it touches by its full 32 bytes, so +//! a batch of members costs about 99 bytes each and the 1232-byte packet stops +//! it at ten. A v0 transaction may instead name accounts by a one-byte index +//! into a table published on chain, which drops the marginal cost of a member by +//! more than an order of magnitude and moves the ceiling somewhere else +//! entirely. `batch_ceiling.rs` measures the legacy number; this module is how +//! settlement stops being bound by it. +//! +//! The instruction layouts belong to somebody else's program and are written out +//! here rather than pulled in as a dependency, for the same reason `stake.rs` +//! does it: the crate that owns them drags in half the SDK, and a byte layout +//! whose derivation is written down can be checked by a reader. +//! +//! **A table is not free and it is not private.** It is a rent-paying account +//! that lists, publicly and durably, every address the settlement will touch — +//! published *before* the settlement lands. That is a real disclosure, and the +//! answer to it is `deactivate` + `close`: the rent comes back and the list +//! stops existing. A design that creates one of these per batch and never closes +//! it leaves both the lamports and the list behind, permanently, once per round. + +use anyhow::{anyhow, Result}; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; + +pub const PROGRAM: &str = "AddressLookupTab1e1111111111111111111111111"; + +/// How many addresses one `extend` can carry. +/// +/// Bounded by the packet, not by the program: the instruction carries the +/// addresses in full, so 30 of them is 960 bytes and anything much larger stops +/// fitting. Extending in chunks is the normal way to fill a table. +pub const ADDRESSES_PER_EXTEND: usize = 20; + +/// How many distinct accounts one transaction may lock. +/// +/// **Measured against devnet, not read out of the SDK.** `solana-transaction` +/// exports `MAX_TX_ACCOUNT_LOCKS = 128`, and that is the raised limit, live only +/// where the feature gate for it is active. A settlement naming 77 accounts was +/// refused by devnet with `TooManyAccountLocks`, so the number a client must +/// plan against is the older one until it can see otherwise. +/// +/// This is what actually bounds a settlement once a lookup table has taken the +/// packet out of the way. Twenty-four members through a table weigh 356 bytes of +/// 1232 — nowhere near the wire — and are refused for locking 77 accounts. +pub const MAX_ACCOUNT_LOCKS: usize = 64; + +/// Slots a table must sit deactivated before it can be closed. +/// +/// The cooldown exists because a transaction already in flight may still resolve +/// against the table, and closing it underneath such a transaction would change +/// what that transaction means. It is why reclaiming the rent is a later errand +/// rather than part of settling. +pub const DEACTIVATION_COOLDOWN_SLOTS: u64 = 513; + +fn program_id() -> Result { + PROGRAM.parse().map_err(|e| anyhow!("{PROGRAM}: {e}")) +} + +/// The address a table gets, given who owns it and which slot it was derived +/// against. +/// +/// The recent slot is part of the seed, which is what stops one authority from +/// creating the same table twice and what ties a table to a moment. The runtime +/// checks the slot is recent, so a stale one is refused rather than silently +/// producing a different address. +pub fn address(authority: &Pubkey, recent_slot: u64) -> Result<(Pubkey, u8)> { + Ok(Pubkey::find_program_address( + &[authority.as_ref(), &recent_slot.to_le_bytes()], + &program_id()?, + )) +} + +/// `CreateLookupTable { recent_slot, bump }` — discriminant 0. +pub fn create( + authority: &Pubkey, + payer: &Pubkey, + recent_slot: u64, +) -> Result<(Instruction, Pubkey)> { + let (table, bump) = address(authority, recent_slot)?; + let mut data = 0u32.to_le_bytes().to_vec(); + data.extend_from_slice(&recent_slot.to_le_bytes()); + data.push(bump); + Ok(( + Instruction::new_with_bytes( + program_id()?, + &data, + vec![ + AccountMeta::new(table, false), + AccountMeta::new_readonly(*authority, true), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ), + table, + )) +} + +/// `ExtendLookupTable { new_addresses }` — discriminant 2, then a bincode +/// sequence: a u64 length followed by the addresses. +pub fn extend( + table: &Pubkey, + authority: &Pubkey, + payer: &Pubkey, + addresses: &[Pubkey], +) -> Result { + let mut data = 2u32.to_le_bytes().to_vec(); + data.extend_from_slice(&(addresses.len() as u64).to_le_bytes()); + for a in addresses { + data.extend_from_slice(&a.to_bytes()); + } + Ok(Instruction::new_with_bytes( + program_id()?, + &data, + vec![ + AccountMeta::new(*table, false), + AccountMeta::new_readonly(*authority, true), + AccountMeta::new(*payer, true), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + )) +} + +/// `DeactivateLookupTable` — discriminant 3. Starts the cooldown; the table is +/// still usable until it elapses. +pub fn deactivate(table: &Pubkey, authority: &Pubkey) -> Result { + Ok(Instruction::new_with_bytes( + program_id()?, + &3u32.to_le_bytes(), + vec![ + AccountMeta::new(*table, false), + AccountMeta::new_readonly(*authority, true), + ], + )) +} + +/// `CloseLookupTable` — discriminant 4. Returns the rent and removes the +/// published address list. +pub fn close(table: &Pubkey, authority: &Pubkey, recipient: &Pubkey) -> Result { + Ok(Instruction::new_with_bytes( + program_id()?, + &4u32.to_le_bytes(), + vec![ + AccountMeta::new(*table, false), + AccountMeta::new_readonly(*authority, true), + AccountMeta::new(*recipient, false), + ], + )) +} + +/// The addresses a table must hold for `metas` to resolve, in first-seen order, +/// excluding those that cannot come from a table. +/// +/// Two kinds of account must stay in the transaction's static keys and so must +/// never enter the table. A **signer** cannot be served from a lookup table at +/// all — the runtime resolves the table after checking signatures. And the +/// **program being invoked** must be a static key, because the instruction +/// names it by an index into the static portion. +/// +/// Getting either wrong produces a transaction that compiles and is then +/// rejected by the cluster, so the filtering happens here, once, rather than at +/// each call site. +/// How many distinct accounts a transaction would lock for `metas`. +/// +/// The fee payer and the invoked program are locked too, so they count even +/// though neither can be served from a table. +pub fn locks_for(metas: &[AccountMeta], program: &Pubkey, payer: &Pubkey) -> usize { + let mut seen: Vec = vec![*program, *payer]; + for m in metas { + if !seen.contains(&m.pubkey) { + seen.push(m.pubkey); + } + } + seen.len() +} + +pub fn addresses_for(metas: &[AccountMeta], program: &Pubkey) -> Vec { + let mut out: Vec = Vec::new(); + for m in metas { + if m.is_signer || m.pubkey == *program || out.contains(&m.pubkey) { + continue; + } + out.push(m.pubkey); + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn create_carries_the_slot_and_the_bump_the_address_was_derived_from() { + let authority = Pubkey::new_unique(); + let slot = 305_419_896u64; + let (ix, table) = create(&authority, &authority, slot).unwrap(); + let (expected, bump) = address(&authority, slot).unwrap(); + assert_eq!(table, expected); + assert_eq!(&ix.data[..4], 0u32.to_le_bytes()); + assert_eq!(&ix.data[4..12], slot.to_le_bytes()); + assert_eq!(ix.data[12], bump, "the bump must be the derived one"); + assert_eq!(ix.data.len(), 13); + } + + /// The length prefix is a bincode `u64`, not a compact-u16. A four-byte + /// prefix would leave the program reading addresses from the wrong offset + /// and rejecting a table that was built correctly. + #[test] + fn extend_prefixes_the_addresses_with_a_u64_count() { + let table = Pubkey::new_unique(); + let authority = Pubkey::new_unique(); + let addresses: Vec = (0..3).map(|_| Pubkey::new_unique()).collect(); + let ix = extend(&table, &authority, &authority, &addresses).unwrap(); + assert_eq!(&ix.data[..4], 2u32.to_le_bytes()); + assert_eq!(&ix.data[4..12], 3u64.to_le_bytes()); + assert_eq!(ix.data.len(), 12 + 3 * 32); + for (i, a) in addresses.iter().enumerate() { + let at = 12 + i * 32; + assert_eq!(&ix.data[at..at + 32], a.to_bytes().as_slice()); + } + } + + #[test] + fn deactivate_and_close_are_bare_discriminants() { + let table = Pubkey::new_unique(); + let authority = Pubkey::new_unique(); + assert_eq!( + deactivate(&table, &authority).unwrap().data, + 3u32.to_le_bytes() + ); + assert_eq!( + close(&table, &authority, &authority).unwrap().data, + 4u32.to_le_bytes() + ); + } + + /// The rent goes back to whoever is named, which is the whole point of + /// closing rather than abandoning. + #[test] + fn close_names_the_account_the_rent_returns_to() { + let table = Pubkey::new_unique(); + let authority = Pubkey::new_unique(); + let recipient = Pubkey::new_unique(); + let ix = close(&table, &authority, &recipient).unwrap(); + assert_eq!(ix.accounts[2].pubkey, recipient); + assert!(ix.accounts[2].is_writable); + } + + /// A signer served from a lookup table makes a transaction the cluster + /// refuses. So does the program being invoked. Both are filtered, and this + /// is the test that says so. + #[test] + fn neither_a_signer_nor_the_invoked_program_enters_the_table() { + let program = Pubkey::new_unique(); + let settler = Pubkey::new_unique(); + let pool = Pubkey::new_unique(); + let metas = vec![ + AccountMeta::new(settler, true), + AccountMeta::new(pool, false), + AccountMeta::new_readonly(program, false), + ]; + let addresses = addresses_for(&metas, &program); + assert_eq!(addresses, vec![pool]); + } + + /// What a table is actually worth, measured rather than argued. + /// + /// This builds settlement-shaped instructions — a settler, a pool, a vault, + /// then three accounts nobody else shares per member — and serializes them + /// both ways. The legacy figure must reproduce what `batch_ceiling.rs` + /// settles against the real program, which is what ties this arithmetic to + /// an executed measurement; the v0 figure is the point. + /// + /// The assertion is deliberately not "the ceiling is N". Once accounts cost + /// a byte each, the packet stops being the thing in the way at any batch + /// size worth settling, and what takes over — compute, the account-lock + /// limit, the program's own heap — depends on what the members are doing. + /// Pinning a number here would be pinning the wrong constraint. + #[test] + fn a_lookup_table_takes_the_packet_out_of_the_way() { + use solana_message::{v0, AddressLookupTableAccount, VersionedMessage}; + + const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; + + // `batch_ceiling.rs` settles ten of these against the real program at + // 1228 bytes. If this model disagrees there, it is modelling something + // else and the v0 number below means nothing. + let legacy_at = |n: usize| -> usize { + let (settler, program) = (Pubkey::new_unique(), Pubkey::new_unique()); + let ix = settle_shaped(&settler, &program, n); + let msg = solana_message::Message::new(&[ix], Some(&settler)); + 1 + 64 + msg.serialize().len() + }; + assert_eq!( + legacy_at(10), + 1228, + "the legacy model no longer agrees with the executed measurement in \ + batch_ceiling.rs, so nothing else here can be trusted" + ); + assert!( + legacy_at(11) > PACKET_DATA_SIZE, + "eleven members are supposed to be over the packet" + ); + + let versioned_at = |n: usize| -> usize { + let (settler, program) = (Pubkey::new_unique(), Pubkey::new_unique()); + let ix = settle_shaped(&settler, &program, n); + let alt = AddressLookupTableAccount { + key: Pubkey::new_unique(), + addresses: addresses_for(&ix.accounts, &program), + }; + let msg = v0::Message::try_compile( + &settler, + &[ix], + &[alt], + solana_program::hash::Hash::default(), + ) + .expect("a settlement must compile against its own table"); + 1 + 64 + + bincode::serialize(&VersionedMessage::V0(msg)) + .expect("serializes") + .len() + }; + + // Sixty members is six times what the packet allows without a table and + // still nowhere near it — which is the finding, and it is a statement + // about *bytes only*. Sixty members lock 183 accounts and the cluster + // would refuse them; what a settlement can actually carry is bounded by + // MAX_ACCOUNT_LOCKS, asserted just below, and a reader who took the byte + // figure for a member count would be reading the wrong constraint. + let sixty = versioned_at(60); + assert!( + sixty < PACKET_DATA_SIZE, + "sixty members through a table weigh {sixty} bytes, over the packet" + ); + + // The limit that does bind, and the arithmetic settlement uses to stop + // short of it. Twenty members is exactly 64 locks: three per member plus + // the settler, the pool and the vault. + let payer = Pubkey::new_unique(); + let program = Pubkey::new_unique(); + let twenty = settle_shaped(&payer, &program, 20); + assert_eq!( + locks_for(&twenty.accounts, &program, &payer), + MAX_ACCOUNT_LOCKS, + "twenty members is supposed to sit exactly on the lock limit" + ); + let twenty_one = settle_shaped(&payer, &program, 21); + assert!( + locks_for(&twenty_one.accounts, &program, &payer) > MAX_ACCOUNT_LOCKS, + "twenty-one members must be over the lock limit, or settlement stops \ + one short of what it could carry" + ); + assert!( + versioned_at(10) < legacy_at(10) / 2, + "a table is supposed to cost far less per member than naming keys in full" + ); + } + + /// A settlement's account shape: three fixed, then three per member that no + /// other member shares. The same shape `batch_ceiling.rs` settles. + fn settle_shaped(settler: &Pubkey, program: &Pubkey, n: usize) -> Instruction { + let mut metas = vec![ + AccountMeta::new(*settler, true), + AccountMeta::new(Pubkey::new_unique(), false), + AccountMeta::new(Pubkey::new_unique(), false), + ]; + for _ in 0..n { + for _ in 0..3 { + metas.push(AccountMeta::new(Pubkey::new_unique(), false)); + } + } + Instruction::new_with_bytes(*program, &[4u8, n as u8], metas) + } + + /// A batch that names the same relay twice must not pay for it twice: the + /// table holds distinct addresses, and the saving is per distinct key. + #[test] + fn a_repeated_account_is_listed_once() { + let program = Pubkey::new_unique(); + let shared = Pubkey::new_unique(); + let other = Pubkey::new_unique(); + let metas = vec![ + AccountMeta::new(shared, false), + AccountMeta::new(other, false), + AccountMeta::new(shared, false), + ]; + assert_eq!(addresses_for(&metas, &program), vec![shared, other]); + } +} diff --git a/crates/mirror-cli/src/main.rs b/crates/mirror-cli/src/main.rs new file mode 100644 index 00000000..ad654ae1 --- /dev/null +++ b/crates/mirror-cli/src/main.rs @@ -0,0 +1,1243 @@ +//! `mirror` — the operator and member CLI. + +use anyhow::{Context, Result}; +use clap::{Parser, Subcommand}; +use sha2::{Digest, Sha256}; +use std::path::PathBuf; + +mod chain; +mod client; +mod crowd; +mod disclose; +mod history; +mod lookup; +mod note; +mod soak; +mod stake; + +/// The public devnet cluster, so the common case needs no flag. +const DEFAULT_URL: &str = "https://api.devnet.solana.com"; +/// Where the Solana CLI keeps its default keypair. +const DEFAULT_KEYPAIR: &str = "~/.config/solana/id.json"; + +/// The seed the committed verifying key was generated from. +/// +/// Public on purpose. It makes the setup reproducible — anyone can re-derive the +/// deployed key and check it against the circuit in this repository — and it +/// makes the setup insecure in exactly the way a public seed implies: the toxic +/// waste is public, so proofs are forgeable. That trade is stated rather than +/// hidden, and the production path is a multi-party ceremony. +/// +/// Reproducible-and-insecure is a coherent position for an unaudited tool. The +/// incoherent one is publishing the entropy *and* withholding the proving key, +/// which is insecure and unreproducible at once: the toxic waste is public, and +/// no third party can regenerate the key to produce a valid proof at all. +pub const DEV_SETUP_SEED: &str = "mirror-pool-reproducible-dev-setup-v1"; + +#[derive(Parser)] +#[command( + name = "mirror", + about = "mirror-pool: a behavioral anonymity set on Solana", + version +)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Subcommand)] +enum Command { + /// Generates the Groth16 keys and writes the verifying key as Rust source + /// for the on-chain program. + Setup { + #[arg(long, default_value = DEV_SETUP_SEED)] + seed: String, + #[arg(long, default_value = "programs/mirror-pool/src/vk.rs")] + out: PathBuf, + }, + /// Checks that an RPC endpoint can actually serve the history a provenance + /// measurement depends on, and refuses it otherwise. + /// + /// Run this before trusting any number a collection produces. A truncated + /// endpoint does not error on old data — it returns nothing — so a collector + /// pointed at one reports every old funding event as absent and produces a + /// graph that looks like a finding. + CheckEndpoint { + #[arg(long, default_value = "https://api.mainnet-beta.solana.com")] + endpoint: String, + /// Requests per second. The public endpoint sustains a measured + /// 0.28-0.55, far below its documented allowance. + #[arg(long, default_value_t = 0.4)] + rps: f64, + }, + /// Builds a member-weighted frame from a pool's depositors. + /// + /// Each depositor appears once however often they transact, and the sample + /// is spread across the pool's whole signature history rather than its most + /// recent minute. Nothing is dropped for looking hard to trace. + Seeds { + /// The pool program to enumerate depositors of. + #[arg(long)] + program: String, + /// How many distinct depositors to collect. + #[arg(long, default_value_t = 40)] + n: usize, + /// Signature pages to walk back through. More pages means a sample + /// spread over more of the pool's lifetime. + #[arg(long, default_value_t = 8)] + pages: u32, + /// Transactions to fetch in total, spread across the pages. + /// + /// Sized from the measured deposit rate rather than guessed: about one + /// program transaction in eight is a deposit, so reaching N depositors + /// costs roughly 8N fetches. + #[arg(long, default_value_t = 400)] + scan: usize, + /// Minimum lamports a payer must part with for it to count as a deposit. + #[arg(long, default_value_t = 10_000_000)] + min_deposit: u64, + #[arg(long, default_value = "seeds.txt")] + out: PathBuf, + #[arg(long, default_value = "https://api.mainnet-beta.solana.com")] + endpoint: String, + #[arg(long, default_value_t = 0.4)] + rps: f64, + }, + /// Pass one: walks each seed's funding chain and writes a sample file. + /// + /// The only step that touches the network. Everything it observes goes into + /// the sample, so the number can be recomputed later by anyone holding it. + Collect { + /// File with one seed address per line. + #[arg(long)] + seeds: PathBuf, + #[arg(long, default_value = "sample.json")] + out: PathBuf, + #[arg(long, default_value = "https://api.mainnet-beta.solana.com")] + endpoint: String, + #[arg(long, default_value_t = 0.4)] + rps: f64, + #[arg(long, default_value_t = 6)] + depth: u32, + /// Signature pages to walk before declaring an address high-activity. + /// + /// Raising it buys a better age estimate for busy funders, which is what + /// lets the volume-hub rule classify them instead of leaving them in the + /// budget bucket. + #[arg(long, default_value_t = 20)] + page_cap: u32, + }, + /// Pass two: classifies a committed sample and reports the anonymity ladder. + /// + /// Pure and offline. Given the same sample it always produces the same + /// numbers, which is what makes a published result checkable by someone who + /// does not trust our endpoint or our run. + Analyze { + #[arg(long, default_value = "sample.json")] + sample: PathBuf, + }, + /// Compares the loss factor of two populations measured the same way. + /// + /// `ρ` is the headline because it is independent of `k` and therefore + /// comparable across pools of different sizes. This is the command that + /// exercises that property rather than asserting it. + /// + /// The comparison is a bootstrap over the difference, not a subtraction of + /// two point estimates. Two samples drawn from the same underlying shape + /// will differ by *something*, and reporting that something as a finding is + /// the error this command exists to prevent: if the interval contains zero, + /// it says so and declines to rank them. + Compare { + /// The population being examined. + #[arg(long)] + sample: PathBuf, + /// The population it is measured against. + #[arg(long)] + against: PathBuf, + /// A name for each, used only in the output. + #[arg(long, default_value = "sample")] + label: String, + #[arg(long, default_value = "baseline")] + against_label: String, + }, + /// Tests whether *being resolvable* is correlated with provenance class. + /// + /// This is the assumption every unresolved bracket and every cross-population + /// comparison quietly rests on. Dropping unresolved members is only harmless + /// if the members that resolve are a fair draw of the classes present. If + /// easy-to-trace members are systematically exchange-funded and hard ones are + /// systematically something else, then the resolved subset is not the + /// population, and a difference between two such subsets can be pure + /// selection. + /// + /// Given the same frame collected at two budgets, it splits the larger run's + /// resolved members into those the smaller run also resolved and those only + /// the larger one reached, and asks whether those two groups have the same + /// class distribution. **Separation is bad news** — it is evidence that the + /// unresolved are not missing at random. + Selection { + /// The smaller-budget collection. + #[arg(long)] + earlier: PathBuf, + /// The larger-budget collection of the same frame. + #[arg(long)] + later: PathBuf, + }, + /// Runs the whole lifecycle against a live cluster and prints every + /// signature, so the result is checkable rather than asserted. + Soak { + #[arg(long)] + program: String, + #[arg(long, default_value = "https://api.devnet.solana.com")] + url: String, + /// Payer and settler keypair. + #[arg(long, default_value = "~/.config/solana/id.json")] + keypair: String, + /// Where to write the evidence. + #[arg(long, default_value = "docs/PROOF.md")] + out: PathBuf, + }, + /// Settles a batch of stake delegations to *different* validators, and + /// measures what that divergence costs in packet space. + /// + /// The claim `Soak` makes is that the pool can be a member's authority. This + /// one asks the harder question: whether a crowd survives its members + /// wanting different things. + Crowd { + #[arg(long)] + program: String, + #[arg(long, default_value = "https://api.devnet.solana.com")] + url: String, + /// Payer and settler keypair. + #[arg(long, default_value = "~/.config/solana/id.json")] + keypair: String, + /// Where to write the evidence. + #[arg(long, default_value = "docs/CROWD.md")] + out: PathBuf, + /// Re-render the report from the last run's recorded results, without + /// touching the cluster. For fixing the prose around numbers that were + /// already measured. + #[arg(long)] + render_only: bool, + }, + /// Proves to a verifier of your choosing that a settled action was yours. + /// + /// Nothing on chain changes and nobody else learns anything: a disclosure is + /// a file handed to one counterparty, not a key anybody holds. It carries + /// the note's secrets, which authorise nothing once the nullifier is burnt — + /// and which would hand over the deposit if the note were still unspent, + /// which is why this refuses to write one for a note that has not settled. + Disclose { + #[arg(long)] + program: String, + #[arg(long)] + note: PathBuf, + /// Where to write the disclosure. Overwrites: unlike a note, it can be + /// regenerated from the note at any time. + #[arg(long, default_value = "disclosure.json")] + out: PathBuf, + /// Disclose even though doing so leaves the pool's remaining settled + /// actions below its floor. The cover that costs is the other members', + /// and they are neither asked nor told. + #[arg(long)] + i_accept_the_cost_to_others: bool, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + }, + /// Checks a disclosure against the chain, recomputing every value in it. + /// + /// Nothing in the file is taken on trust. The commitment and the nullifier + /// are rederived from the secrets, the spend record's address is derived + /// from that nullifier, the accumulator is rebuilt from history and checked + /// against the pool's own root, and the action is read out of the record. + /// Every check is reported separately, and any check that cannot be + /// completed is a failure rather than a silence. + DiscloseVerify { + #[arg(long)] + file: PathBuf, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + }, + /// Reclaims a settlement's lookup table once its cooldown has passed. + /// + /// A large settlement publishes a table naming every account it touches. + /// This returns the rent and removes that list. + CloseTable { + #[arg(long)] + table: String, + #[arg(long, default_value = "https://api.devnet.solana.com")] + url: String, + #[arg(long, default_value = "~/.config/solana/id.json")] + keypair: String, + }, + /// Recomputes the verifying key from a seed and reports its digest. + /// + /// This is the check a third party runs. It binds the *whole* key — alpha, + /// beta, gamma, delta and every IC point — not just delta, so a transcript + /// carrying a key belonging to a different circuit cannot pass. Verifying + /// delta alone is the common shortcut and it would certify exactly that. + VerifySetup { + #[arg(long, default_value = DEV_SETUP_SEED)] + seed: String, + /// Expected digest, as printed by `setup`. + #[arg(long)] + expect: Option, + }, + + /// Creates a pool for a denomination. Permissionless, and one per size. + InitPool { + #[arg(long)] + program: String, + /// Lamports each deposit escrows. This also names the pool. + #[arg(long)] + denomination: u64, + /// Notes the pool must hold before it will act. + #[arg(long, default_value_t = 2)] + k_floor: u32, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + #[arg(long, default_value = DEFAULT_KEYPAIR)] + keypair: String, + }, + + /// Draws a fresh note and writes its secret to a file. + /// + /// The file is the deposit. Nobody can reissue it, which is the same + /// property that means nobody can freeze it. + NoteNew { + /// The pool this note will join, named by its denomination. + #[arg(long)] + denomination: u64, + /// Where to write it. Refuses to overwrite. + #[arg(long, default_value = "note.json")] + out: PathBuf, + }, + + /// Escrows a denomination and adds the note to the anonymity set. + Deposit { + #[arg(long)] + program: String, + #[arg(long)] + note: PathBuf, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + #[arg(long, default_value = DEFAULT_KEYPAIR)] + keypair: String, + }, + + /// Rebuilds the accumulator from chain history and checks it against the pool. + /// + /// Needs no indexer and no local file. The check is what makes a membership + /// proof trustworthy: a rebuilt root that matches the chain's is proof the + /// recovered leaf set is complete and correctly ordered. + Tree { + #[arg(long)] + program: String, + #[arg(long)] + denomination: u64, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + }, + + /// Proves membership and records an action, signed by a relay. + /// + /// The relay signs so the member never does. A member who signs their own + /// spend has published the link this pool exists to break. + Spend { + #[arg(long)] + program: String, + #[arg(long)] + note: PathBuf, + /// Who receives the payout. + #[arg(long)] + to: String, + /// The relay's keypair. Must not be the member's wallet. + #[arg(long)] + relay: String, + /// Taken out of the denomination, never added to it. + #[arg(long, default_value_t = 0)] + relay_fee: u64, + /// Call this program instead of paying the beneficiary directly. + #[arg(long)] + invoke: Option, + /// Instruction data for --invoke, hex. + #[arg(long, default_value = "")] + payload: String, + /// How many accounts the invoked instruction takes. Bound into the proof. + #[arg(long, default_value_t = 0)] + accounts: u8, + /// Hand the pool's vault to the callee as a signer, so the pool acts as + /// the authority. This is what a stake delegation needs. + #[arg(long)] + pool_signs: bool, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + }, + + /// Executes every pending transfer in one transaction. Permissionless. + Settle { + #[arg(long)] + program: String, + #[arg(long)] + denomination: u64, + #[arg(long, default_value = DEFAULT_URL)] + url: String, + #[arg(long, default_value = DEFAULT_KEYPAIR)] + keypair: String, + }, +} + +fn parse_program(s: &str) -> Result { + s.parse() + .map_err(|e| anyhow::anyhow!("--program is not a pubkey: {e}")) +} + +fn vk_digest(vk: &mirror_circuit::SolanaVerifyingKey) -> String { + let mut hasher = Sha256::new(); + hasher.update(vk.digest_preimage()); + hex::encode(hasher.finalize()) +} + +/// Loads a committed sample and returns each seed's class label, where it +/// reached one. +/// +/// Keyed by seed rather than flattened, so two collections of the same frame can +/// be aligned member by member. +fn labels_by_seed(path: &std::path::Path) -> Result> { + let text = + std::fs::read_to_string(path).with_context(|| format!("reading {}", path.display()))?; + let sample = mirror_provenance::Sample::from_json(&text)?; + let (results, _) = mirror_provenance::classify_sample( + &sample, + &mirror_provenance::AnchorSet::default(), + &mirror_provenance::Thresholds::default(), + sample.manifest.collected_at, + ); + Ok(results + .into_iter() + .filter_map(|(seed, o)| o.label().map(|l| (seed, l.to_string()))) + .collect()) +} + +/// Loads a committed sample and returns one class label per resolved member. +/// +/// Applies the same failure gate `analyze` does. A comparison drawn from a run +/// whose unresolved bucket is substantially our own infrastructure would be +/// comparing endpoints rather than populations, and it would do so invisibly — +/// the difference between two pools and the difference between two collection +/// runs look identical in the output. +fn resolved_labels(path: &std::path::Path) -> Result<(Vec, u64)> { + let text = + std::fs::read_to_string(path).with_context(|| format!("reading {}", path.display()))?; + let sample = mirror_provenance::Sample::from_json(&text)?; + let (results, census) = mirror_provenance::classify_sample( + &sample, + &mirror_provenance::AnchorSet::default(), + &mirror_provenance::Thresholds::default(), + sample.manifest.collected_at, + ); + if !census.may_publish() { + anyhow::bail!( + "{}: the RPC failure rate is {:.2}%, above the 1% limit. This sample yields no \ + headline on its own and cannot be one side of a comparison.", + path.display(), + census.failure_rate() * 100.0 + ); + } + let labels: Vec = results + .iter() + .filter_map(|(_, o)| o.label().map(|s| s.to_string())) + .collect(); + // Unresolved excluding our own RPC failures, which belong to neither side. + let unresolved = census.measurable() - census.resolved; + Ok((labels, unresolved)) +} + +fn main() -> Result<()> { + match Cli::parse().command { + Command::Setup { seed, out } => { + eprintln!("generating keys from seed {seed:?} (this takes a moment)"); + let keys = mirror_circuit::generate_reproducible(seed.as_bytes()) + .map_err(|e| anyhow::anyhow!("{e}"))?; + let svk = keys.solana_vk(); + let source = mirror_circuit::vk_to_rust_source(&svk); + if let Some(parent) = out.parent() { + std::fs::create_dir_all(parent).ok(); + } + std::fs::write(&out, source).with_context(|| format!("writing {}", out.display()))?; + println!("wrote {}", out.display()); + println!("public inputs: {}", svk.public_input_count()); + println!("vk sha256: {}", vk_digest(&svk)); + Ok(()) + } + Command::CheckEndpoint { endpoint, rps } => { + let mut client = mirror_provenance::RpcClient::new(&endpoint, rps); + match client.check_preconditions() { + Ok(check) => { + println!("endpoint {}", check.endpoint); + println!("first available block {}", check.first_available_block); + println!( + "archival probe slot {} ok", + mirror_provenance::rpc::ARCHIVAL_PROBE_SLOT + ); + println!("\nUSABLE — this endpoint serves history to genesis."); + Ok(()) + } + Err(e) => { + eprintln!("REFUSED: {e}"); + eprintln!( + "\nA measurement taken here would report old funding events as \ + absent and the resulting unresolved bucket would be an artifact." + ); + std::process::exit(2); + } + } + } + Command::Seeds { + program, + n, + pages, + scan, + min_deposit, + out, + endpoint, + rps, + } => { + let mut client = mirror_provenance::RpcClient::new(&endpoint, rps); + let check = client + .check_preconditions() + .map_err(|e| anyhow::anyhow!("endpoint refused: {e}"))?; + eprintln!( + "endpoint ok (first available block {})", + check.first_available_block + ); + + let mut seeds: Vec = Vec::new(); + let mut seen = std::collections::BTreeSet::new(); + let mut before: Option = None; + let mut scanned = 0usize; + let mut slots: Vec = Vec::new(); + + 'paging: for page in 0..pages { + let batch = client + .signatures_for_address(&program, before.as_deref(), 1_000) + .map_err(|e| anyhow::anyhow!("listing program signatures: {e}"))?; + if batch.is_empty() { + break; + } + before = Some(batch.last().expect("non-empty").signature.clone()); + eprintln!( + "page {page}: {} signatures, {} depositors so far", + batch.len(), + seeds.len() + ); + + // Spread the scan budget evenly over the pages, and stride + // within each page so the sample spans its time range instead of + // clustering at its head. + let scan_this_page = (scan / pages as usize).max(1); + let stride = (batch.len() / scan_this_page).max(1); + for info in batch.iter().step_by(stride) { + if info.err { + continue; + } + scanned += 1; + let tx = match client.transaction(&info.signature) { + Ok(t) => t, + // A failure here drops one candidate; it never becomes a + // claim about the pool. + Err(_) => continue, + }; + if let Some(d) = mirror_provenance::depositor_of(&tx, min_deposit) { + if seen.insert(d.clone()) { + slots.push(tx.slot); + seeds.push(d); + if seeds.len() >= n { + break 'paging; + } + } + } + } + } + + anyhow::ensure!(!seeds.is_empty(), "no depositors found for {program}"); + std::fs::write(&out, format!("{}\n", seeds.join("\n"))) + .with_context(|| format!("writing {}", out.display()))?; + + let span = match (slots.iter().min(), slots.iter().max()) { + (Some(lo), Some(hi)) => hi - lo, + _ => 0, + }; + println!( + "wrote {} ({} distinct depositors)", + out.display(), + seeds.len() + ); + println!( + "scanned {scanned} transactions, {} rpc calls", + client.calls_made() + ); + println!( + "sample spans {span} slots (~{:.1} hours of chain time)", + span as f64 * 0.4 / 3600.0 + ); + Ok(()) + } + Command::Collect { + seeds, + out, + endpoint, + rps, + depth, + page_cap, + } => { + let text = std::fs::read_to_string(&seeds) + .with_context(|| format!("reading {}", seeds.display()))?; + let seed_list: Vec = text + .lines() + .map(|l| l.trim().to_string()) + .filter(|l| !l.is_empty() && !l.starts_with('#')) + .collect(); + anyhow::ensure!(!seed_list.is_empty(), "no seeds in {}", seeds.display()); + + let mut client = mirror_provenance::RpcClient::new(&endpoint, rps); + let check = client + .check_preconditions() + .map_err(|e| anyhow::anyhow!("endpoint refused: {e}"))?; + eprintln!( + "endpoint ok (first available block {}), collecting {} seeds", + check.first_available_block, + seed_list.len() + ); + + let config = mirror_provenance::CollectionConfig { + depth_max: depth, + sig_page_cap: page_cap, + ..Default::default() + }; + let thresholds = mirror_provenance::Thresholds::default(); + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH)? + .as_secs() as i64; + + let collector = mirror_provenance::Collector::new(&mut client, config); + let started = std::time::Instant::now(); + let sample = + collector.collect_with_progress(&seed_list, &check, &thresholds, now, |p| { + // Rate is the useful number here: it tells the operator + // whether the run is progressing or the endpoint has + // started throttling. + let elapsed = started.elapsed().as_secs_f64().max(0.001); + eprintln!( + " [{:>3}/{}] {}… {} hops, {:?} ({} calls, {:.1}/s, {:.0}s elapsed){}", + p.done, + p.total, + &p.seed[..p.seed.len().min(8)], + p.hops, + p.stop, + p.rpc_calls, + p.rpc_calls as f64 / elapsed, + elapsed, + p.error + .as_deref() + .map(|e| format!("\n -> {}", &e[..e.len().min(160)])) + .unwrap_or_default(), + ); + }); + + std::fs::write(&out, sample.to_json()?) + .with_context(|| format!("writing {}", out.display()))?; + println!( + "wrote {} ({} rpc calls)", + out.display(), + sample.manifest.rpc_calls + ); + if !sample.manifest.excluded_non_wallet.is_empty() { + println!( + "excluded {} seeds that are not wallets (program, PDA, token account, \ + or closed): a definitional frame criterion, not a difficulty one", + sample.manifest.excluded_non_wallet.len() + ); + } + println!( + "ambiguous attribution rate: {:.1}%", + sample.manifest.ambiguous_attribution_rate * 100.0 + ); + Ok(()) + } + Command::Analyze { sample } => { + let text = std::fs::read_to_string(&sample) + .with_context(|| format!("reading {}", sample.display()))?; + let sample = mirror_provenance::Sample::from_json(&text)?; + let thresholds = mirror_provenance::Thresholds::default(); + let anchors = mirror_provenance::AnchorSet::default(); + + let (results, census) = mirror_provenance::classify_sample( + &sample, + &anchors, + &thresholds, + sample.manifest.collected_at, + ); + + println!("endpoint {}", sample.manifest.endpoint); + println!("scope {:?}", sample.manifest.config.scope); + println!("census {}", census.summary()); + println!( + "frame {} seeds excluded as non-wallets before tracing", + sample.manifest.excluded_non_wallet.len() + ); + println!(); + + if !census.may_publish() { + eprintln!( + "REFUSING to report a headline: the RPC failure rate is {:.2}%, above the \ + 1% limit. Above that threshold the unresolved bucket is substantially our \ + own making and any effective-k computed from it would be measuring our \ + infrastructure rather than the pool.", + census.failure_rate() * 100.0 + ); + std::process::exit(3); + } + + let labels: Vec = results + .iter() + .filter_map(|(_, o)| o.label().map(|s| s.to_string())) + .collect(); + + // Members that reached no class, excluding our own failures: those + // belong to neither reading of the bracket. + let unresolved = census.measurable() - census.resolved; + + match mirror_provenance::Anonymity::from_labels(&labels) { + None => { + println!("no member resolved to a class; nothing to report"); + } + Some(a) => { + println!("resolved members {}", a.nominal_k); + println!("provenance classes {}", a.classes); + println!(); + println!( + "loss factor rho {:.4} <- headline, independent of k", + a.loss_factor + ); + println!("effective-k Shannon {:.4}", a.eff_k_shannon); + println!("effective-k min-ent {:.4}", a.eff_k_min_entropy); + println!("leakage Shannon {:.4} bits", a.leakage_shannon_bits); + println!( + "leakage min-entropy {:.4} bits", + a.leakage_min_entropy_bits + ); + println!("guessing entropy {:.2}", a.guessing_entropy); + println!("Good-Turing coverage {:.4}", a.good_turing_coverage); + println!("Chao1 richness {:.2}", a.chao1); + println!( + "worst-case class {}{}", + a.worst_case, + if a.worst_case_is_informative() { + "" + } else { + " (not informative: under any heavy-tailed prior somebody is always alone)" + } + ); + println!(); + println!("class-size CCDF (share of members in a class of at most t):"); + for (t, share) in &a.class_size_ccdf { + println!(" t={t:<4} {:.4}", share); + } + + // Sampling error, which the bracket below does not cover. + // These depositors are a draw from a larger population, and + // without an interval over that draw a reader cannot tell a + // real difference between two pools from a lucky sample. + if let Some(i) = mirror_provenance::loss_factor_interval( + &labels, + mirror_provenance::bootstrap::DEFAULT_REPLICATES, + mirror_provenance::bootstrap::DEFAULT_SEED, + ) { + println!(); + println!( + "rho under resampling {:.4} .. {:.4} (2.5-97.5%, {} replicates)", + i.lo, i.hi, i.replicates + ); + println!( + " resampling bias {:+.4} (mean {:.4} against a point estimate \ + of {:.4})", + i.resampling_bias(), + i.mean, + i.point + ); + if !i.contains_point() { + println!( + " The range does not contain the point estimate, and that is a \ + property of this\n population rather than an error. Resampling \ + leaves about 37% of members unpicked,\n so single-member classes \ + vanish from most replicates; fewer classes means lower\n H(C) \ + and therefore higher rho. The size of that gap is a tail \ + diagnostic." + ); + } + println!( + " This is the spread of the estimator, not its distance from the \ + truth. Plug-in\n entropy is biased low at small n, so rho is biased \ + HIGH: the real loss factor is\n plausibly below all of this, and \ + equally so for any population measured this way." + ); + } + + // The bracket. A point estimate alone would not say whether + // the number is driven by what was measured or by what was + // not. + let mut sizes: std::collections::BTreeMap<&str, u64> = + std::collections::BTreeMap::new(); + for l in &labels { + *sizes.entry(l.as_str()).or_insert(0) += 1; + } + let resolved_sizes: Vec = sizes.into_values().collect(); + if let Some(b) = mirror_provenance::Bracket::new(&resolved_sizes, unresolved) { + println!(); + println!( + "unresolved bracket ({} resolved, {} unresolved):", + b.resolved, b.unresolved + ); + println!( + " rho {:.4} .. {:.4}", + b.lower.loss_factor, b.upper.loss_factor + ); + println!( + " effective-k {:.4} .. {:.4}", + b.lower.eff_k_shannon, b.upper.eff_k_shannon + ); + if !b.is_informative() { + println!(); + println!( + " NOT INFORMATIVE: fewer than half the members reached a class, so \ + the two readings\n diverge and either one quoted alone would \ + describe the sampling budget rather than\n the pool. The point \ + estimate above is reported for completeness, not as a result." + ); + } + } + + if a.good_turing_coverage < 0.8 { + println!(); + println!( + " UNDER-SAMPLED: Good-Turing coverage {:.2} and Chao1 estimates {:.0} \ + classes against\n {} observed, so most of the class distribution \ + was never seen. Effective-k measured at\n small k understates the \ + steady-state loss and does not extrapolate upward.", + a.good_turing_coverage, a.chao1, a.classes + ); + } + } + } + Ok(()) + } + Command::Compare { + sample, + against, + label, + against_label, + } => { + let (a, a_unresolved) = resolved_labels(&sample)?; + let (b, b_unresolved) = resolved_labels(&against)?; + + let reps = mirror_provenance::bootstrap::DEFAULT_REPLICATES; + let seed = mirror_provenance::bootstrap::DEFAULT_SEED; + + let ia = mirror_provenance::loss_factor_interval(&a, reps, seed) + .ok_or_else(|| anyhow::anyhow!("{label}: no member resolved to a class"))?; + let ib = mirror_provenance::loss_factor_interval(&b, reps, seed) + .ok_or_else(|| anyhow::anyhow!("{against_label}: no member resolved to a class"))?; + + let width = label.len().max(against_label.len()).max(10); + println!( + "{:7} {:.4} {:.4} .. {:.4} {:+.4}", + labels.len(), + i.point, + i.lo, + i.hi, + i.resampling_bias() + ); + } + + let d = mirror_provenance::difference_interval(&a, &b, reps, seed) + .ok_or_else(|| anyhow::anyhow!("nothing to compare"))?; + println!(); + println!( + "difference ({label} − {against_label}): {:+.4} 95% {:+.4} .. {:+.4}", + d.point, d.lo, d.hi + ); + println!(); + + // The same informativeness gate `analyze` applies to a single + // headline, applied to each side. It matters *more* here, not less. + // + // Comparing two populations of which one is mostly unresolved is + // comparing their traceable subsets, and traceability is not + // independent of provenance class: a wallet funded by an exchange + // resolves in one hop, and one funded through a chain of fresh + // intermediaries exhausts the budget. So the unresolved members are + // plausibly drawn from different classes than the resolved ones, and + // a difference between the two subsets can be manufactured entirely + // by that selection. + let under = |labels: &[String], unresolved: u64| -> bool { + let total = labels.len() as u64 + unresolved; + total > 0 && (labels.len() as u64) * 2 < total + }; + let a_under = under(&a, a_unresolved); + let b_under = under(&b, b_unresolved); + if a_under || b_under { + let who = match (a_under, b_under) { + (true, true) => format!("{label} and {against_label} both resolve"), + (true, false) => format!("{label} resolves"), + _ => format!("{against_label} resolves"), + }; + println!( + "REFUSING to rank these populations: {who} fewer than half its members.\n\n\ + What is left after the unresolved are dropped is each population's\n\ + *traceable* subset, and traceability is not independent of provenance\n\ + class — a wallet funded straight from an exchange resolves in one hop,\n\ + one funded through fresh intermediaries exhausts the budget. A difference\n\ + between two such subsets can be produced entirely by that selection, and\n\ + nothing in the numbers above would show it.\n\n\ + The figures are printed for completeness, not as a comparison. Closing\n\ + this needs resolution above half on both sides, which is a bigger\n\ + traversal budget rather than a different metric." + ); + return Ok(()); + } + + if d.excludes_zero() { + let (more, less) = if d.point > 0.0 { + (&label, &against_label) + } else { + (&against_label, &label) + }; + println!( + "SEPARATED. The interval on the difference excludes zero, so at these sample\n\ + sizes {more} is the more provenance-concentrated population of the two —\n\ + a member's funding class narrows the guess further there than in {less}." + ); + } else { + println!( + "NOT SEPARATED. The interval on the difference contains zero, so these two\n\ + populations are indistinguishable at these sample sizes. The point estimates\n\ + differ, and that difference is not evidence: quoting it as one would be\n\ + reporting the draw." + ); + } + println!(); + println!( + "Both estimates share the same downward bias in entropy, so both rho values are\n\ + biased high by roughly the same amount. That is why the comparison survives a\n\ + bias that neither individual number does." + ); + Ok(()) + } + Command::Selection { earlier, later } => { + let before = labels_by_seed(&earlier)?; + let after = labels_by_seed(&later)?; + + // Members the larger budget reached, split by whether the smaller + // one reached them too. + let mut easy: Vec = Vec::new(); + let mut hard: Vec = Vec::new(); + for (seed, label) in &after { + if before.contains_key(seed) { + easy.push(label.clone()); + } else { + hard.push(label.clone()); + } + } + + println!("earlier {} resolved", before.len()); + println!( + "later {} resolved ({} of them newly)", + after.len(), + hard.len() + ); + println!(); + + if hard.len() < 5 { + println!( + "Only {} members were newly resolved. That is too few to say anything \ + about\nwhether resolvability selects on class, and this check reports \ + nothing rather\nthan reporting a number computed from it.", + hard.len() + ); + return Ok(()); + } + + let reps = mirror_provenance::bootstrap::DEFAULT_REPLICATES; + let seed = mirror_provenance::bootstrap::DEFAULT_SEED; + let ie = mirror_provenance::loss_factor_interval(&easy, reps, seed) + .ok_or_else(|| anyhow::anyhow!("no easily-resolved members"))?; + let ih = mirror_provenance::loss_factor_interval(&hard, reps, seed) + .ok_or_else(|| anyhow::anyhow!("no newly-resolved members"))?; + + println!("group members rho resampled 2.5-97.5%"); + println!( + "resolved at both budgets {:>7} {:.4} {:.4} .. {:.4}", + easy.len(), + ie.point, + ie.lo, + ie.hi + ); + println!( + "only at the larger {:>7} {:.4} {:.4} .. {:.4}", + hard.len(), + ih.point, + ih.lo, + ih.hi + ); + + let d = mirror_provenance::difference_interval(&easy, &hard, reps, seed) + .ok_or_else(|| anyhow::anyhow!("nothing to compare"))?; + println!(); + println!( + "difference (easy − hard): {:+.4} 95% {:+.4} .. {:+.4}", + d.point, d.lo, d.hi + ); + println!(); + + if d.excludes_zero() { + println!( + "SELECTION DETECTED. Members that only a larger budget reaches have a\n\ + measurably different class distribution from those any budget reaches.\n\n\ + The unresolved are therefore NOT missing at random, and dropping them is\n\ + not neutral: the resolved subset of a population is biased toward whichever\n\ + classes happen to be cheap to trace. Every unresolved bracket in this\n\ + project is still a valid bound, but no comparison between two populations\n\ + at different resolution rates can be trusted, and more budget does not fix\n\ + that — it moves the boundary without removing it." + ); + } else { + println!( + "NO SELECTION DETECTED at this margin. The members that needed a larger\n\ + budget carry a class distribution indistinguishable from those that did\n\ + not, so at this margin resolvability is not picking out particular\n\ + provenance classes.\n\n\ + This is evidence, not proof. It says the members just beyond the cheaper\n\ + budget look like the ones inside it; it cannot speak for members beyond\n\ + the larger budget too, and a heavier tail could still be hiding there." + ); + } + Ok(()) + } + Command::Soak { + program, + url, + keypair, + out, + } => soak::run(&program, &url, &keypair, &out), + Command::Disclose { + program, + note, + out, + i_accept_the_cost_to_others, + url, + } => { + let chain = chain::Chain::new(&url); + disclose::create( + &chain, + &parse_program(&program)?, + ¬e, + &out, + i_accept_the_cost_to_others, + ) + } + Command::DiscloseVerify { file, url } => { + let chain = chain::Chain::new(&url); + disclose::check(&chain, &file) + } + Command::CloseTable { + table, + url, + keypair, + } => { + let authority = soak::read_keypair(&keypair)?; + let table: solana_program::pubkey::Pubkey = table + .parse() + .map_err(|e| anyhow::anyhow!("bad table address: {e}"))?; + client::close_table(&chain::Chain::new(&url), &table, &authority) + } + Command::Crowd { + program, + url, + keypair, + out, + render_only, + } => { + if render_only { + crowd::render_only(&out) + } else { + crowd::run(&program, &url, &keypair, &out) + } + } + + Command::InitPool { + program, + denomination, + k_floor, + url, + keypair, + } => { + let chain = chain::Chain::new(&url); + let payer = soak::read_keypair(&keypair)?; + client::init_pool( + &chain, + &parse_program(&program)?, + denomination, + k_floor, + &payer, + ) + } + + Command::NoteNew { denomination, out } => client::note_new(denomination, &out), + + Command::Deposit { + program, + note, + url, + keypair, + } => { + let chain = chain::Chain::new(&url); + let depositor = soak::read_keypair(&keypair)?; + client::deposit(&chain, &parse_program(&program)?, ¬e, &depositor) + } + + Command::Tree { + program, + denomination, + url, + } => { + let chain = chain::Chain::new(&url); + client::tree(&chain, &parse_program(&program)?, denomination).map(|_| ()) + } + + Command::Spend { + program, + note, + to, + relay, + relay_fee, + invoke, + payload, + accounts, + pool_signs, + url, + } => { + let chain = chain::Chain::new(&url); + let relay = soak::read_keypair(&relay)?; + let beneficiary: solana_program::pubkey::Pubkey = to + .parse() + .map_err(|e| anyhow::anyhow!("--to is not a pubkey: {e}"))?; + let action = match invoke { + None => client::Action::Transfer, + Some(target) => client::Action::Invoke { + target: target + .parse() + .map_err(|e| anyhow::anyhow!("--invoke is not a pubkey: {e}"))?, + payload: hex::decode(payload.trim_start_matches("0x")) + .context("--payload is not hex")?, + accounts, + pool_signs, + }, + }; + client::spend( + &chain, + &parse_program(&program)?, + ¬e, + &beneficiary, + &relay, + relay_fee, + action, + ) + } + + Command::Settle { + program, + denomination, + url, + keypair, + } => { + let chain = chain::Chain::new(&url); + let settler = soak::read_keypair(&keypair)?; + let now = client::now()?; + client::settle( + &chain, + &parse_program(&program)?, + denomination, + &settler, + now, + ) + } + Command::VerifySetup { seed, expect } => { + let keys = mirror_circuit::generate_reproducible(seed.as_bytes()) + .map_err(|e| anyhow::anyhow!("{e}"))?; + let regenerated = keys.solana_vk(); + let digest = vk_digest(®enerated); + println!("vk sha256 (regenerated): {digest}"); + + // Compare against the key actually compiled into the program, not + // only against a digest the caller supplies. Printing a hash and + // exiting zero verifies nothing; the point of a reproducible setup + // is that a third party can confirm the *deployed* key is the one + // this circuit and this seed produce. + let baked = mirror_pool_program::vk::VERIFYING_KEY; + let mut mismatches: Vec<&str> = Vec::new(); + if regenerated.alpha_g1 != baked.vk_alpha_g1 { + mismatches.push("alpha_g1"); + } + if regenerated.beta_g2 != baked.vk_beta_g2 { + mismatches.push("beta_g2"); + } + if regenerated.gamma_g2 != baked.vk_gamme_g2 { + mismatches.push("gamma_g2"); + } + if regenerated.delta_g2 != baked.vk_delta_g2 { + mismatches.push("delta_g2"); + } + if regenerated.ic.len() != baked.vk_ic.len() + || regenerated.ic.iter().zip(baked.vk_ic).any(|(a, b)| a != b) + { + mismatches.push("ic"); + } + + if mismatches.is_empty() { + println!( + "MATCH — every element of the program's verifying key is reproduced \ + by this seed and this circuit ({} IC points checked)", + regenerated.ic.len() + ); + } else { + eprintln!( + "MISMATCH against the program's baked key: {}", + mismatches.join(", ") + ); + eprintln!( + "The deployed program does not verify proofs from this circuit. \ + A ceremony verifier that checked only delta would have passed this." + ); + std::process::exit(1); + } + + match expect { + Some(want) if want.eq_ignore_ascii_case(&digest) => { + println!("and it matches the digest you supplied"); + Ok(()) + } + Some(want) => { + eprintln!("but the digest you supplied was {want}"); + std::process::exit(1); + } + None => Ok(()), + } + } + } +} diff --git a/crates/mirror-cli/src/note.rs b/crates/mirror-cli/src/note.rs new file mode 100644 index 00000000..a4a454f7 --- /dev/null +++ b/crates/mirror-cli/src/note.rs @@ -0,0 +1,196 @@ +//! A member's note, on disk. +//! +//! The secret is two field elements. Losing them loses the deposit — there is no +//! authority that can reissue a note, which is the same property that means no +//! authority can freeze one. So the file is deliberately boring: plain JSON, one +//! note per file, readable by anything, with the commitment stored alongside so +//! a member can check what they hold without a prover. +//! +//! It is not encrypted. Encrypting it would put a password between a member and +//! their funds and imply a security property this crate cannot deliver on its +//! own — the file is as sensitive as a keypair and wants the same handling. + +use anyhow::{anyhow, Context, Result}; +use mirror_core::{Field, Note}; +use serde::{Deserialize, Serialize}; +use std::path::Path; + +#[derive(Serialize, Deserialize)] +pub struct StoredNote { + /// The pool this note belongs to. A note is only spendable in the pool whose + /// denomination it was committed at. + pub denomination: u64, + /// Nullifier preimage, 32 bytes big-endian hex. + pub k: String, + /// Blinding factor, 32 bytes big-endian hex. + pub r: String, + /// Stored so a member can verify a deposit landed without running a prover. + pub commitment: String, +} + +impl StoredNote { + pub fn from_note(note: &Note, denomination: u64) -> Result { + Ok(StoredNote { + denomination, + k: hex::encode(note.k.to_bytes()), + r: hex::encode(note.r.to_bytes()), + commitment: hex::encode(note.commitment().map_err(|e| anyhow!("{e:?}"))?.to_bytes()), + }) + } + + pub fn note(&self) -> Result { + let k = field_from_hex(&self.k, "k")?; + let r = field_from_hex(&self.r, "r")?; + let note = Note::new(k, r, Field::from_u64(self.denomination)); + // A file whose commitment disagrees with its secrets has been edited or + // corrupted, and spending it would burn a nullifier for a leaf that is + // not in the tree. Caught here, where it is still only a bad file. + let recomputed = hex::encode(note.commitment().map_err(|e| anyhow!("{e:?}"))?.to_bytes()); + if recomputed != self.commitment.to_lowercase() { + return Err(anyhow!( + "this note file is inconsistent: its secrets commit to {recomputed}, \ + but the file records {}", + self.commitment + )); + } + Ok(note) + } + + pub fn commitment_bytes(&self) -> Result<[u8; 32]> { + let raw = hex::decode(&self.commitment).context("the commitment is not hex")?; + raw.try_into() + .map_err(|_| anyhow!("the commitment is not 32 bytes")) + } + + pub fn read(path: &Path) -> Result { + let text = std::fs::read_to_string(path) + .with_context(|| format!("reading the note at {}", path.display()))?; + serde_json::from_str(&text).with_context(|| format!("parsing {}", path.display())) + } + + /// Writes the note, refusing to overwrite. + /// + /// An overwrite here destroys a deposit, so the safe default is the only + /// default: there is no `--force`. + pub fn write(&self, path: &Path) -> Result<()> { + if path.exists() { + return Err(anyhow!( + "{} already exists. A note file is the only copy of a deposit's \ + secret, so this will not overwrite one — choose another path.", + path.display() + )); + } + let text = serde_json::to_string_pretty(self)?; + std::fs::write(path, text) + .with_context(|| format!("writing the note to {}", path.display()))?; + Ok(()) + } +} + +fn field_from_hex(s: &str, what: &str) -> Result { + let raw = hex::decode(s).with_context(|| format!("{what} is not hex"))?; + let arr: [u8; 32] = raw + .try_into() + .map_err(|_| anyhow!("{what} is not 32 bytes"))?; + Field::from_bytes(arr).map_err(|e| anyhow!("{what} is not a canonical field element: {e:?}")) +} + +/// Draws a fresh note from a CSPRNG seeded by the operating system. +/// +/// Rejection sampling rather than reduction: a reduced value would make some +/// field elements twice as likely as others, and while that is not exploitable +/// at this size it is free to avoid. A draw at or above the modulus is redrawn. +pub fn generate(denomination: u64) -> Result { + use ark_std::rand::{RngCore, SeedableRng}; + let mut rng = ark_std::rand::rngs::StdRng::from_entropy(); + let mut draw = || -> Field { + loop { + let mut bytes = [0u8; 32]; + rng.fill_bytes(&mut bytes); + // Clearing the top byte would bias the distribution; redrawing does + // not, and the expected number of redraws is under one in ten. + if let Ok(f) = Field::from_bytes(bytes) { + return f; + } + } + }; + Ok(Note::new(draw(), draw(), Field::from_u64(denomination))) +} + +#[cfg(test)] +mod tests { + use super::*; + + const DENOM: u64 = 20_000_019; + + #[test] + fn a_generated_note_round_trips_through_its_file_form() { + let note = generate(DENOM).unwrap(); + let stored = StoredNote::from_note(¬e, DENOM).unwrap(); + let text = serde_json::to_string(&stored).unwrap(); + let read: StoredNote = serde_json::from_str(&text).unwrap(); + assert_eq!(read.note().unwrap(), note); + } + + /// A note file whose commitment no longer matches its secrets must not be + /// spendable. Spending it would burn a nullifier against a leaf the tree + /// does not hold, which costs the member the deposit and tells them nothing + /// about why. + #[test] + fn a_note_whose_commitment_disagrees_with_its_secrets_is_refused() { + let note = generate(DENOM).unwrap(); + let mut stored = StoredNote::from_note(¬e, DENOM).unwrap(); + stored.commitment = hex::encode([0u8; 32]); + let err = stored.note().unwrap_err().to_string(); + assert!(err.contains("inconsistent"), "{err}"); + } + + /// The denomination is part of the commitment, so a file that claims the + /// wrong pool cannot silently be spent in it. + #[test] + fn changing_the_denomination_invalidates_the_note() { + let note = generate(DENOM).unwrap(); + let mut stored = StoredNote::from_note(¬e, DENOM).unwrap(); + stored.denomination = DENOM + 1; + assert!(stored.note().is_err()); + } + + #[test] + fn a_non_canonical_secret_is_refused_rather_than_reduced() { + let note = generate(DENOM).unwrap(); + let mut stored = StoredNote::from_note(¬e, DENOM).unwrap(); + stored.k = hex::encode([0xffu8; 32]); + assert!(stored.note().is_err()); + } + + /// Writing over an existing note destroys a deposit, so there is no path + /// that does it — not even an explicit one. + #[test] + fn writing_refuses_to_overwrite_an_existing_note() { + let dir = std::env::temp_dir().join(format!("mirror-note-test-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let path = dir.join("note.json"); + let _ = std::fs::remove_file(&path); + + let first = StoredNote::from_note(&generate(DENOM).unwrap(), DENOM).unwrap(); + first.write(&path).unwrap(); + let second = StoredNote::from_note(&generate(DENOM).unwrap(), DENOM).unwrap(); + let err = second.write(&path).unwrap_err().to_string(); + assert!(err.contains("already exists"), "{err}"); + + // The file on disk is still the first note, not the second. + assert_eq!( + StoredNote::read(&path).unwrap().commitment, + first.commitment + ); + std::fs::remove_file(&path).unwrap(); + } + + #[test] + fn two_draws_differ() { + let a = generate(DENOM).unwrap(); + let b = generate(DENOM).unwrap(); + assert_ne!(a.k, b.k); + assert_ne!(a.r, b.r); + } +} diff --git a/crates/mirror-cli/src/soak.rs b/crates/mirror-cli/src/soak.rs new file mode 100644 index 00000000..591af227 --- /dev/null +++ b/crates/mirror-cli/src/soak.rs @@ -0,0 +1,1228 @@ +//! A live-cluster soak: the whole lifecycle against a real validator. +//! +//! Every assertion is a transaction that either landed or did not, and every +//! signature is printed so a third party can look it up. Nothing here is +//! simulated — the proof is generated by the host prover and verified by the +//! deployed program's own Groth16 syscall. + +use crate::chain::Chain; +use anyhow::{anyhow, Context, Result}; +use mirror_circuit::{generate_reproducible, prove, Keys, Witness}; +use mirror_core::{Field, MerkleTree, Note}; +use mirror_pool_program::{ + instruction::Instruction as MirrorIx, + pda::{pool_address, spend_address, vault_address}, + processor::{SELECTOR_INVOKE_SIGNED, SELECTOR_TRANSFER}, +}; +use solana_keypair::Keypair; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; +use solana_signer::Signer; +use solana_transaction::Transaction; + +// A pool is unique per denomination, so this constant is also what selects the +// pool. Changing it starts a clean one, which is how the evidence run gets to +// record its own `init_pool` rather than reusing a pool an earlier run created +// and leaving the creation step undocumented. +const DENOMINATION: u64 = 20_000_023; // 0.02 SOL +const ENTRY_FEE: u64 = 0; +const K_FLOOR: u32 = 4; +/// Members in the evidence batch. Above `K_FLOOR` so the crowd rule is satisfied +/// by the crowd rather than by the timeout, and large enough to hold three +/// plain transfers beside the two actions the pool signs. +const BATCH: u64 = 5; +const RELAY_FEE: u64 = 200_000; + +/// The SPL Memo program, at the same address on every cluster. +/// +/// Used as the live-cluster CPI target for the same reason the end-to-end suite +/// uses it: it is somebody else's program, it is small, and it **refuses any +/// account handed to it that has not signed**. A memo whose only account is the +/// pool's vault therefore cannot succeed unless the pool really signed, which +/// makes the transaction itself the evidence rather than a claim about it. +const MEMO_PROGRAM: &str = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"; + +/// What the member asks the pool to say on their behalf. +const MEMO_PAYLOAD: &[u8] = b"mirror-pool: signed by the pool, for a member"; + +/// A devnet validator with a large active stake, so the delegation has somewhere +/// real to go. +/// +/// One validator is enough for the claim this run makes, which is that the pool +/// can be a member's *authority*. Whether a batch survives its members choosing +/// **different** validators is a separate claim with a separate cost, and +/// `crowd.rs` measures it against the same cluster. +const VOTE_ACCOUNT: &str = "2f9C9AU8nFRKUub8NHToNiZzcwmYiNeipVuP8akKgRVv"; + +/// What the operator puts into the stake account before the pool delegates it. +/// +/// Devnet's minimum delegation is 1 SOL and this pool's denomination is 0.02, so +/// the escrow of one member cannot reach the floor by itself — a pool whose +/// denomination cleared it would need five-plus SOL to fill a single batch. The +/// operator funds the account and the member's escrow is added to it; what the +/// *pool* supplies is the authority, which is the part being demonstrated. +const STAKE_FUNDING: u64 = 1_100_000_000; + +/// One member's pending spend, as settlement needs to see it. +pub struct Settlement { + pub spend: Pubkey, + pub beneficiary: Pubkey, + pub relay: Pubkey, + /// The CPI target, when this member's action is a call rather than a + /// transfer. + pub target: Option, + /// The accounts that action takes, in the order the callee expects them. + pub action_accounts: Vec, +} + +/// One recorded step of the run. +pub struct Step { + pub name: &'static str, + pub signature: String, + pub note: String, +} + +/// What the vault actually held, so the solvency claim is checkable from this +/// artifact instead of from a sentence asserting it. +/// +/// Saying "the vault closed to its rent-exempt minimum to the lamport" and then +/// publishing an evidence file containing only signatures asks a reader to take +/// the interesting part on trust. These are the numbers that sentence is about. +pub struct Accounting { + pub denomination: u64, + pub notes_settled: u64, + pub relay_fee: u64, + pub vault_before_settle: u64, + pub vault_after_settle: u64, + pub vault_rent_exempt_minimum: u64, +} + +impl Accounting { + /// What settlement was obliged to disburse: the full denomination for each + /// note, which the relay fee is taken out of rather than added to. + pub fn expected_payout(&self) -> u64 { + self.denomination.saturating_mul(self.notes_settled) + } + + pub fn observed_payout(&self) -> u64 { + self.vault_before_settle + .saturating_sub(self.vault_after_settle) + } + + /// Whether the vault came to rest exactly on its rent-exempt floor, with + /// every note paid and not one lamport more. + pub fn closed_exactly(&self) -> bool { + self.observed_payout() == self.expected_payout() + && self.vault_after_settle == self.vault_rent_exempt_minimum + } +} + +pub struct Soak { + client: Chain, + program_id: Pubkey, + payer: Keypair, + pool: Pubkey, + vault: Pubkey, + pub steps: Vec, + /// Case name, the program's own error code, and what the rejection proves. + pub negatives: Vec<(String, String, String)>, + pub accounting: Option, + /// The callee's own log line naming the pool's vault as a signer. + pub signed_action: Option, + /// The stake account the pool delegated, and the validator it now backs. + pub delegation: Option<(Pubkey, Pubkey)>, +} + +impl Soak { + pub fn new(url: &str, program_id: Pubkey, payer: Keypair) -> Self { + let (pool, _) = pool_address(&program_id, DENOMINATION); + let (vault, _) = vault_address(&program_id, &pool); + Soak { + client: Chain::new(url), + program_id, + payer, + pool, + vault, + steps: Vec::new(), + negatives: Vec::new(), + accounting: None, + signed_action: None, + delegation: None, + } + } + + fn send(&self, ix: Instruction, signers: &[&Keypair]) -> Result { + let blockhash = self.client.latest_blockhash()?; + let message = solana_message::Message::new(&[ix], Some(&signers[0].pubkey())); + let tx = Transaction::new(signers, message, blockhash); + self.client.send(&tx) + } + + fn record(&mut self, name: &'static str, signature: String, note: String) { + println!(" {name:<28} {signature}"); + self.steps.push(Step { + name, + signature, + note, + }); + } + + fn record_negative(&mut self, name: &str, proves: &str, err: String) { + // Only the program's own error code matters here; the rest is noise. + // Take only the hex code. The RPC embeds the error inside a JSON blob, + // so splitting on whitespace drags the rest of the payload along and the + // evidence table fills with noise instead of a code a reader can check. + let code = err + .split("custom program error: ") + .nth(1) + .map(|s| { + s.chars() + .take_while(|c| c.is_ascii_hexdigit() || *c == 'x') + .collect::() + }) + .filter(|s| !s.is_empty()) + .unwrap_or_else(|| "(no custom code)".to_string()); + println!(" {name:<28} rejected with {code}"); + self.negatives + .push((name.to_string(), code, proves.to_string())); + } + + fn account_meta_pool(&self) -> Vec { + vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ] + } + + /// Creates the pool, unless a previous run already did. + /// + /// Reusing a pool is allowed only while it is empty. The accounting claim + /// this run publishes — that the vault came to rest on its rent-exempt floor + /// with a remainder of zero — is a statement about a pool whose every + /// deposit this run also settles. A pool carrying notes from an earlier run + /// cannot satisfy it, and finding that out at the assertion means having + /// already spent the deposits to get there. It is checked before the money + /// moves instead. + pub fn init_pool(&mut self) -> Result<()> { + if let Some(data) = self.client.account_data(&self.pool)? { + let mut data = data; + let pool = mirror_pool_program::Pool::load(&mut data) + .map_err(|e| anyhow!("the account at the pool address is not a pool: {e:?}"))?; + let outstanding = pool + .outstanding_notes() + .map_err(|e| anyhow!("reading the pool: {e:?}"))?; + if outstanding > 0 { + return Err(anyhow!( + "the pool for denomination {DENOMINATION} already holds {outstanding} \ + unspent note(s), so this run cannot close its vault to the rent-exempt \ + floor and the accounting table would be a different claim than the one \ + it makes. Raise DENOMINATION in soak.rs for a clean pool — the note \ + ledger is keyed by it, so a new denomination starts a new ledger too." + )); + } + println!(" pool already exists and is empty, reusing it"); + return Ok(()); + } + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::InitPool { + denomination: DENOMINATION, + entry_fee: ENTRY_FEE, + k_floor: K_FLOOR, + } + .pack(), + self.account_meta_pool(), + ); + let payer = self.payer.insecure_clone(); + let sig = self.send(ix, &[&payer])?; + self.record( + "init_pool", + sig, + format!("denomination {DENOMINATION}, k_floor {K_FLOOR}"), + ); + Ok(()) + } + + /// Deposits `count` notes and returns the host tree plus every note in it. + /// + /// Notes are persisted, not derived from a formula. The program stores only + /// the accumulator frontier, so the host cannot reconstruct past leaves from + /// the chain — and a formula only works if every deposit ever made used the + /// same one. A rerun that guessed wrong would build a root the program has + /// never held and every proof would fail with an unrelated error. + pub fn deposit( + &mut self, + count: u64, + ledger: &std::path::Path, + ) -> Result<(MerkleTree, Vec)> { + let denom_tag = Field::from_u64(DENOMINATION); + let mut tree = MerkleTree::new().map_err(|e| anyhow!("{e}"))?; + let mut notes = Vec::new(); + + let mut secrets: Vec<(u64, u64)> = if ledger.exists() { + serde_json::from_str(&std::fs::read_to_string(ledger)?)? + } else { + Vec::new() + }; + let on_chain = self.leaf_count()? as usize; + if secrets.len() != on_chain { + return Err(anyhow!( + "the note ledger holds {} notes but the pool has {on_chain} leaves. \ + They must agree, or the host tree cannot match the program's root. \ + Use a fresh denomination, or restore the ledger.", + secrets.len() + )); + } + for (k, r) in &secrets { + let note = Note::new(Field::from_u64(*k), Field::from_u64(*r), denom_tag); + tree.insert(note.commitment().map_err(|e| anyhow!("{e}"))?) + .map_err(|e| anyhow!("{e}"))?; + notes.push(note); + } + + let base = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH)? + .as_secs(); + for j in 0..count { + let k = base.wrapping_mul(1_000_003).wrapping_add(j * 7 + 1); + let r = base.wrapping_mul(7_919).wrapping_add(j * 13 + 1); + let note = Note::new(Field::from_u64(k), Field::from_u64(r), denom_tag); + let commitment = note.commitment().map_err(|e| anyhow!("{e}"))?; + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::Deposit { + commitment: commitment.to_bytes(), + } + .pack(), + self.account_meta_pool(), + ); + let payer = self.payer.insecure_clone(); + let sig = self.send(ix, &[&payer])?; + self.record("deposit", sig, format!("note {}", notes.len() + 1)); + tree.insert(commitment).map_err(|e| anyhow!("{e}"))?; + notes.push(note); + secrets.push((k, r)); + // Written after every deposit, so an interrupted run leaves a ledger + // that still matches the chain. + std::fs::write(ledger, serde_json::to_string(&secrets)?)?; + } + Ok((tree, notes)) + } + + fn leaf_count(&self) -> Result { + let mut data = self + .client + .account_data(&self.pool) + .context("reading the pool account")? + .ok_or_else(|| anyhow!("the pool account does not exist"))?; + let pool = mirror_pool_program::Pool::load(&mut data).map_err(|e| anyhow!("{e:?}"))?; + Ok(pool.deposit_count()) + } + + /// Submits a spend for `index`, with a real proof, relay-signed. + #[allow(clippy::too_many_arguments)] + pub fn submit_spend( + &mut self, + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + beneficiary: &Pubkey, + relay: &Keypair, + label: &'static str, + ) -> Result<(Pubkey, [u8; 32])> { + use ark_std::rand::SeedableRng; + let merkle_proof = tree.proof(index as u64).map_err(|e| anyhow!("{e}"))?; + let binding = mirror_core::action_binding( + SELECTOR_TRANSFER, + &[0u8; 32], + &beneficiary.to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + 0, + &[], + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().map_err(|e| anyhow!("{e}"))?, + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8 + 1; 32]); + let proof = prove(keys, &witness, &mut rng).map_err(|e| anyhow!("{e}"))?; + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&self.program_id, &self.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR_TRANSFER, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = self.send(ix, &[relay])?; + self.record(label, sig, format!("note {index}, relay-signed")); + Ok((spend_pda, nullifier)) + } + + /// Submits a spend whose action is a **CPI the pool signs**, not a transfer. + /// + /// The action declares one account, and settlement will fill that slot with + /// the vault. The count is inside the action binding, so a settler cannot + /// add or drop a slot; the selector is inside it too, so the pool's signature + /// is something the member proved they wanted and not something settlement + /// can help itself to. + #[allow(clippy::too_many_arguments)] + pub fn submit_signed_action( + &mut self, + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + beneficiary: &Pubkey, + relay: &Keypair, + target: &Pubkey, + ) -> Result<(Pubkey, [u8; 32])> { + use ark_std::rand::SeedableRng; + let merkle_proof = tree.proof(index as u64).map_err(|e| anyhow!("{e}"))?; + let binding = mirror_core::action_binding( + SELECTOR_INVOKE_SIGNED, + &target.to_bytes(), + &beneficiary.to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + 1, + MEMO_PAYLOAD, + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().map_err(|e| anyhow!("{e}"))?, + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8 + 1; 32]); + let proof = prove(keys, &witness, &mut rng).map_err(|e| anyhow!("{e}"))?; + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&self.program_id, &self.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR_INVOKE_SIGNED, + target_program: target.to_bytes(), + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 1, + payload: MEMO_PAYLOAD.to_vec(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = self.send(ix, &[relay])?; + self.record( + "submit_spend", + sig, + format!("note {index}, relay-signed, action: pool-signed CPI to SPL Memo"), + ); + Ok((spend_pda, nullifier)) + } + + /// Creates a stake account whose **staker** is the pool's vault. + /// + /// The withdraw authority is deliberately *not* the vault, and that is the + /// threat model applied rather than restated: the pool's signature is + /// available to every member, so an authority held by the vault is an + /// authority every member holds. Staking is safe to delegate that way + /// because the worst a member can do with it is delegate somebody else's + /// stake to a different validator. Withdrawal is not, so it stays with the + /// operator. + pub fn create_stake_account(&mut self) -> Result { + let stake = Keypair::new(); + let [create, initialise] = crate::stake::create( + &self.payer.pubkey(), + &stake.pubkey(), + &self.vault, + &self.payer.pubkey(), + STAKE_FUNDING, + )?; + + let blockhash = self.client.latest_blockhash()?; + let message = + solana_message::Message::new(&[create, initialise], Some(&self.payer.pubkey())); + let payer = self.payer.insecure_clone(); + let tx = Transaction::new(&[&payer, &stake], message, blockhash); + let sig = self.client.send(&tx)?; + self.record( + "create stake account", + sig, + format!( + "{} lamports, staker = the pool's vault, withdrawer = the operator", + STAKE_FUNDING + ), + ); + Ok(stake.pubkey()) + } + + fn delegate_accounts(&self, stake: &Pubkey) -> Result> { + let vote: Pubkey = VOTE_ACCOUNT + .parse() + .map_err(|e| anyhow!("{VOTE_ACCOUNT}: {e}"))?; + crate::stake::delegate_accounts(stake, &vote, &self.vault) + } + + /// Submits a spend whose action is a real stake delegation, authorised by + /// the pool. + #[allow(clippy::too_many_arguments)] + pub fn submit_stake_delegation( + &mut self, + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + stake: &Pubkey, + relay: &Keypair, + ) -> Result<(Pubkey, [u8; 32])> { + use ark_std::rand::SeedableRng; + let stake_program = crate::stake::program_id()?; + let merkle_proof = tree.proof(index as u64).map_err(|e| anyhow!("{e}"))?; + // The stake account is the beneficiary, so the member's escrow lands in + // the stake they authorised rather than beside it. + let binding = mirror_core::action_binding( + SELECTOR_INVOKE_SIGNED, + &stake_program.to_bytes(), + &stake.to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + crate::stake::DELEGATE_ACCOUNTS, + &crate::stake::DELEGATE_STAKE, + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().map_err(|e| anyhow!("{e}"))?, + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8 + 1; 32]); + let proof = prove(keys, &witness, &mut rng).map_err(|e| anyhow!("{e}"))?; + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&self.program_id, &self.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR_INVOKE_SIGNED, + target_program: stake_program.to_bytes(), + beneficiary: stake.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: crate::stake::DELEGATE_ACCOUNTS, + payload: crate::stake::DELEGATE_STAKE.to_vec(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let sig = self.send(ix, &[relay])?; + self.record( + "submit_spend", + sig, + format!("note {index}, relay-signed, action: pool-signed stake delegation"), + ); + Ok((spend_pda, nullifier)) + } + + /// Reads the stake account back off the cluster and reports which validator + /// it now backs. + /// + /// The read is the evidence, not the signature. A landed transaction says + /// the instruction executed; only the account state says the delegation took + /// — `crate::stake::delegated_voter` is where that distinction is drawn. + pub fn confirm_delegated(&mut self, stake: &Pubkey) -> Result<()> { + let data = self + .client + .account_data(stake)? + .ok_or_else(|| anyhow!("the stake account {stake} vanished"))?; + let voter = crate::stake::delegated_voter(&data)?; + println!(" stake account delegated to {voter}"); + self.delegation = Some((*stake, voter)); + Ok(()) + } + + /// Submits a spend expected to fail, recording the program's error code. + #[allow(clippy::too_many_arguments)] + pub fn expect_rejection( + &mut self, + name: &str, + proves: &str, + ix: Instruction, + signers: &[&Keypair], + ) -> Result<()> { + match self.send(ix, signers) { + Ok(sig) => Err(anyhow!("{name} was accepted: {sig}")), + Err(e) => { + self.record_negative(name, proves, e.to_string()); + Ok(()) + } + } + } + + /// Reads the callee's own logs to confirm the pool signed the inner call. + /// + /// The settle signature proves a transaction landed. It says nothing about + /// who signed the instruction the pool made *inside* it, and that is the + /// claim worth checking, so this asks the cluster for the logs and looks for + /// what SPL Memo says. Memo names every signer it was given and refuses any + /// account that has not signed, so its own words are the evidence — and if + /// they are absent the run fails here rather than publishing the claim. + pub fn confirm_pool_signed(&mut self, signature: &str) -> Result<()> { + let logs = self.client.transaction_logs(signature)?; + let vault = self.vault.to_string(); + let line = logs + .iter() + .find(|l| l.contains("Signed by") && l.contains(&vault)) + .ok_or_else(|| { + anyhow!( + "settlement landed but SPL Memo did not report the pool's vault \ + ({vault}) as a signer, so the pool did not actually sign. Logs:\n{}", + logs.join("\n") + ) + })? + .clone(); + println!(" the callee's own log: {}", line.trim()); + self.signed_action = Some(line); + Ok(()) + } + + /// Settles a batch. An entry carrying a target program is a CPI action, and + /// the vault follows it as that action's one account. + pub fn settle(&mut self, batch: &[Settlement]) -> Result { + let mut metas = vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + ]; + let mut actions = 0usize; + for entry in batch { + metas.push(AccountMeta::new(entry.spend, false)); + metas.push(AccountMeta::new(entry.beneficiary, false)); + metas.push(AccountMeta::new(entry.relay, false)); + if let Some(target) = entry.target { + actions += 1; + metas.push(AccountMeta::new_readonly(target, false)); + // The action's own accounts, in the callee's order. Where one of + // them is the vault it reaches the callee as a *signer* — the + // program sets that flag itself, from seeds no settler holds, + // which is why the meta here says otherwise. + metas.extend(entry.action_accounts.iter().cloned()); + } + } + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SettleEpoch { + count: batch.len() as u8, + } + .pack(), + metas, + ); + let payer = self.payer.insecure_clone(); + let sig = self.send(ix, &[&payer])?; + let note = if actions == 0 { + format!("{} spends", batch.len()) + } else { + format!( + "{} spends in one transaction, {actions} of them a CPI the pool signed", + batch.len() + ) + }; + self.record("settle_epoch", sig.clone(), note); + Ok(sig) + } + + pub fn pool(&self) -> Pubkey { + self.pool + } + pub fn vault(&self) -> Pubkey { + self.vault + } + pub fn balance(&self, key: &Pubkey) -> Result { + self.client.balance(key) + } + + pub fn rent_exempt_minimum(&self, space: usize) -> Result { + self.client.rent_exempt_minimum(space) + } + pub fn program_id(&self) -> Pubkey { + self.program_id + } + pub fn spend_ix_for( + &self, + nullifier: [u8; 32], + proof: &mirror_circuit::SolanaProof, + beneficiary: &Pubkey, + relay: &Pubkey, + relay_fee: u64, + ) -> Instruction { + let (spend_pda, _) = spend_address(&self.program_id, &self.pool, &nullifier); + Instruction::new_with_bytes( + self.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR_TRANSFER, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(*relay, true), + AccountMeta::new(self.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ) + } +} + +/// The setup keys, derived from the committed public seed. +pub fn keys() -> Result { + generate_reproducible(crate::DEV_SETUP_SEED.as_bytes()).map_err(|e| anyhow!("{e}")) +} + +pub fn read_keypair(path: &str) -> Result { + let expanded = if let Some(rest) = path.strip_prefix("~/") { + format!("{}/{rest}", std::env::var("HOME")?) + } else { + path.to_string() + }; + let bytes: Vec = serde_json::from_str(&std::fs::read_to_string(&expanded)?)?; + Keypair::try_from(&bytes[..]).map_err(|e| anyhow!("reading {expanded}: {e}")) +} + +/// Proves membership of one note, bound to one beneficiary and one relay fee. +/// +/// Kept separate so a negative case can prove an honest statement and then send +/// a *different* one. That is the whole shape of the redirect attack: the proof +/// is genuine, and what the relay changes is the instruction around it. +fn proof_for_note( + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + beneficiary: &Pubkey, + relay: &Pubkey, + relay_fee: u64, +) -> Result { + use ark_std::rand::SeedableRng; + let merkle_proof = tree.proof(index as u64).map_err(|e| anyhow!("{e}"))?; + let binding = mirror_core::action_binding( + SELECTOR_TRANSFER, + &[0u8; 32], + &beneficiary.to_bytes(), + &relay.to_bytes(), + relay_fee, + 0, + &[], + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().map_err(|e| anyhow!("{e}"))?, + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8 + 1; 32]); + prove(keys, &witness, &mut rng).map_err(|e| anyhow!("{e}")) +} + +/// The full lifecycle, on a live cluster, with every signature recorded. +pub fn run(program: &str, url: &str, keypair: &str, out: &std::path::Path) -> Result<()> { + let program_id: Pubkey = program + .parse() + .map_err(|e| anyhow!("bad program id: {e}"))?; + let payer = read_keypair(keypair)?; + println!("program {program_id}"); + println!("payer {}", payer.pubkey()); + println!("cluster {url}\n"); + + let mut soak = Soak::new(url, program_id, payer.insecure_clone()); + println!("keys: deriving from the committed public seed (this takes a moment)"); + let keys = keys()?; + + println!("\npositive path:"); + soak.init_pool()?; + + // The ledger is scoped to the denomination because the pool is. `deposit` + // refuses to run when the ledger and the chain disagree on how many leaves + // exist, and tells you to use a fresh denomination — advice that a single + // shared ledger file would make impossible to follow, since the fresh pool + // starts empty and the old notes are still in the file. + let ledger_path = format!("data/soak-notes-{DENOMINATION}.json"); + let ledger = std::path::Path::new(&ledger_path); + let (tree, notes) = soak.deposit(BATCH, ledger)?; + + // Spend the notes this run deposited, not the earliest ones. A rerun + // against a pool that already holds spent notes would otherwise replay a + // burnt nullifier and stop. + let first_fresh = notes.len() - BATCH as usize; + + // One relay and one beneficiary per member: no member key appears anywhere. + // + // The last member asks for something different from the rest — a CPI the + // pool signs — and it settles in the *same* transaction as the transfers. + // That is the design's own claim about itself: an observer sees one + // timestamp, one signer and a batch of actions, with nothing separating the + // member who staked from the members who merely moved value. + let memo: Pubkey = MEMO_PROGRAM.parse().map_err(|e| anyhow!("memo id: {e}"))?; + let stake_program = crate::stake::program_id()?; + + // The stake account exists before any member asks for anything, and who + // created it is public. What the pool supplies is the authority to delegate + // it, and which member asked for that is what the anonymity set hides. + let stake = soak.create_stake_account()?; + + let memo_note = first_fresh + BATCH as usize - 2; + let stake_note = first_fresh + BATCH as usize - 1; + let mut batch = Vec::new(); + for i in first_fresh..first_fresh + BATCH as usize { + let relay = payer.insecure_clone(); + let entry = if i == stake_note { + let (spend, _) = + soak.submit_stake_delegation(&keys, &tree, ¬es, i, &stake, &relay)?; + Settlement { + spend, + // The stake account is the beneficiary, so this member's escrow + // ends up inside the stake they authorised. + beneficiary: stake, + relay: relay.pubkey(), + target: Some(stake_program), + action_accounts: soak.delegate_accounts(&stake)?, + } + } else if i == memo_note { + let beneficiary = Keypair::new().pubkey(); + let (spend, _) = + soak.submit_signed_action(&keys, &tree, ¬es, i, &beneficiary, &relay, &memo)?; + Settlement { + spend, + beneficiary, + relay: relay.pubkey(), + target: Some(memo), + action_accounts: vec![AccountMeta::new(soak.vault(), false)], + } + } else { + let beneficiary = Keypair::new().pubkey(); + let (spend, _) = soak.submit_spend( + &keys, + &tree, + ¬es, + i, + &beneficiary, + &relay, + "submit_spend", + )?; + Settlement { + spend, + beneficiary, + relay: relay.pubkey(), + target: None, + action_accounts: Vec::new(), + } + }; + batch.push(entry); + } + + let vault_before = soak.balance(&soak.vault())?; + let settle_sig = soak.settle(&batch)?; + soak.confirm_pool_signed(&settle_sig)?; + soak.confirm_delegated(&stake)?; + let vault_after = soak.balance(&soak.vault())?; + // The vault carries no data, so its floor is the rent-exempt minimum for a + // zero-byte account — asked of the cluster rather than assumed. + let vault_floor = soak.rent_exempt_minimum(0)?; + let accounting = Accounting { + denomination: DENOMINATION, + notes_settled: BATCH, + relay_fee: RELAY_FEE, + vault_before_settle: vault_before, + vault_after_settle: vault_after, + vault_rent_exempt_minimum: vault_floor, + }; + println!( + " vault {vault_before} -> {vault_after} (paid out {}, expected {}, floor {vault_floor})", + accounting.observed_payout(), + accounting.expected_payout(), + ); + // Assert it here rather than only reporting it. A soak that prints an + // unexpected number and exits zero is a soak that proves nothing. + if !accounting.closed_exactly() { + return Err(anyhow!( + "vault did not close cleanly: paid out {} against an expected {}, \ + and came to rest at {} against a rent-exempt floor of {vault_floor}", + accounting.observed_payout(), + accounting.expected_payout(), + accounting.vault_after_settle, + )); + } + println!(" vault closed to its rent-exempt floor exactly"); + soak.accounting = Some(accounting); + + println!("\nnegative path:"); + + // One more note, deposited only now. Two of the three negatives below need + // a *live* note: a rejection against an already-spent one proves the replay + // guard fired first and says nothing about the check under test. It is + // deposited after settlement so the accounting above still describes a + // vault that emptied to its floor rather than one holding a spare. + let (tree, notes) = soak.deposit(1, ledger)?; + let spare = notes.len() - 1; + + // A replayed proof: honest in every respect, against a note already spent. + { + let beneficiary = Keypair::new().pubkey(); + let proof = proof_for_note( + &keys, + &tree, + ¬es, + first_fresh, + &beneficiary, + &payer.pubkey(), + RELAY_FEE, + )?; + let ix = soak.spend_ix_for( + proof.public_inputs[1], + &proof, + &beneficiary, + &payer.pubkey(), + RELAY_FEE, + ); + soak.expect_rejection( + "replayed nullifier", + "a nullifier is spent once, ever -- not once per epoch", + ix, + &[&payer], + )?; + } + + // A relay redirecting a payout. The proof is genuine and the note is live; + // the relay simply names a different beneficiary in the instruction. The + // binding is recomputed on-chain from what the instruction says, so it no + // longer matches the one inside the proof and the pairing fails. + { + let member_chose = Keypair::new().pubkey(); + let relay_prefers = Keypair::new().pubkey(); + let proof = proof_for_note( + &keys, + &tree, + ¬es, + spare, + &member_chose, + &payer.pubkey(), + RELAY_FEE, + )?; + let ix = soak.spend_ix_for( + proof.public_inputs[1], + &proof, + &relay_prefers, + &payer.pubkey(), + RELAY_FEE, + ); + soak.expect_rejection( + "redirected beneficiary", + "a relay cannot send a member's payout somewhere the member did not choose", + ix, + &[&payer], + )?; + } + + // The other half of the same claim: a relay re-pricing its own fee. Same + // live note, same genuine proof, and the only change is the fee the + // instruction declares. + { + let beneficiary = Keypair::new().pubkey(); + let proof = proof_for_note( + &keys, + &tree, + ¬es, + spare, + &beneficiary, + &payer.pubkey(), + RELAY_FEE, + )?; + let ix = soak.spend_ix_for( + proof.public_inputs[1], + &proof, + &beneficiary, + &payer.pubkey(), + RELAY_FEE * 10, + ); + soak.expect_rejection( + "inflated relay fee", + "a relay cannot re-price the work after the member authorised it", + ix, + &[&payer], + )?; + } + + // The front-run. Everything the member authorised is left intact — same + // beneficiary, same fee, same genuine proof — and the only difference is who + // submits it. + // + // This is the one attack the other three do not cover, because the attacker + // alters nothing. They lift the proof out of a transaction they saw and land + // it first under their own key. The fee is bound to the relay the member + // named, so the binding recomputed from the signer is not the one inside the + // proof, and the pairing fails before the nullifier can burn. + { + let beneficiary = Keypair::new().pubkey(); + let member_named = Keypair::new().pubkey(); + let proof = proof_for_note( + &keys, + &tree, + ¬es, + spare, + &beneficiary, + &member_named, + RELAY_FEE, + )?; + // `payer` signs, so `payer` is the relay the program sees. + let ix = soak.spend_ix_for( + proof.public_inputs[1], + &proof, + &beneficiary, + &payer.pubkey(), + RELAY_FEE, + ); + soak.expect_rejection( + "front-run relay", + "a proof is spendable only by the relay the member made it for", + ix, + &[&payer], + )?; + } + + write_proof(&soak, url, out)?; + println!("\nwrote {}", out.display()); + Ok(()) +} + +fn write_proof(soak: &Soak, url: &str, out: &std::path::Path) -> Result<()> { + let cluster = if url.contains("devnet") { + "devnet" + } else if url.contains("mainnet") { + "mainnet-beta" + } else { + "custom" + }; + let mut md = String::new(); + md.push_str("# Live-cluster evidence\n\n"); + md.push_str( + "Every line here is a transaction that landed. Nothing is simulated: the \ + proof is produced by the host prover and verified by the deployed \ + program's own Groth16 syscall.\n\n", + ); + md.push_str(&format!("- cluster: `{cluster}`\n")); + md.push_str(&format!("- program: `{}`\n", soak.program_id())); + md.push_str(&format!("- pool: `{}`\n", soak.pool())); + md.push_str(&format!("- vault: `{}`\n\n", soak.vault())); + + md.push_str("## Flows\n\n| step | signature | note |\n|---|---|---|\n"); + for s in &soak.steps { + md.push_str(&format!( + "| {} | [`{}`](https://explorer.solana.com/tx/{}?cluster={cluster}) | {} |\n", + s.name, s.signature, s.signature, s.note + )); + } + + if let Some(a) = &soak.accounting { + md.push_str("\n## Vault accounting\n\n"); + md.push_str( + "The accounting invariant is a statement about the vault's lamports, so \ + here are the lamports. The vault holds escrow and carries no data, which \ + is what makes its floor the rent-exempt minimum for a zero-byte account \ + — read from the cluster during the run, not assumed.\n\n", + ); + md.push_str("| quantity | lamports |\n|---|---|\n"); + md.push_str(&format!("| denomination | {} |\n", a.denomination)); + md.push_str(&format!("| notes settled | {} |\n", a.notes_settled)); + md.push_str(&format!( + "| relay fee (taken out of the denomination, not added) | {} |\n", + a.relay_fee + )); + md.push_str(&format!( + "| vault before settlement | {} |\n", + a.vault_before_settle + )); + md.push_str(&format!( + "| vault after settlement | {} |\n", + a.vault_after_settle + )); + md.push_str(&format!( + "| rent-exempt minimum, 0 bytes | {} |\n", + a.vault_rent_exempt_minimum + )); + md.push_str(&format!("| **paid out** | **{}** |\n", a.observed_payout())); + md.push_str(&format!( + "| **owed** (denomination × notes) | **{}** |\n\n", + a.expected_payout() + )); + md.push_str(&format!( + "Paid out equals owed, and the vault came to rest on its floor with a \ + remainder of {} lamports. The soak asserts both and fails the run \ + otherwise, so this table cannot record a discrepancy and still exit \ + successfully.\n", + a.vault_after_settle + .saturating_sub(a.vault_rent_exempt_minimum) + )); + } + + if let Some(line) = &soak.signed_action { + md.push_str("\n## The pool signed an action, and the callee said so\n\n"); + // Derived, not asserted. The batch size and the number of signed actions + // are both run parameters, and a sentence that hardcodes them goes stale + // the first time either changes -- which is exactly what happened when + // the stake delegation joined the batch. + let settled = soak + .accounting + .as_ref() + .map(|a| a.notes_settled) + .unwrap_or(0); + let signed = u64::from(soak.signed_action.is_some()) + u64::from(soak.delegation.is_some()); + md.push_str(&format!( + "The settlement above carried {settled} spends, and {signed} of them {} not a \ + transfer: the pool invoked SPL Memo as one member's **authority**, in the same \ + transaction as the other {}. That is the capability a stake delegation or a \ + governance vote needs and a payment does not.\n\n", + if signed == 1 { "was" } else { "were" }, + settled.saturating_sub(1), + )); + md.push_str( + "A signature only proves the transaction landed. It says nothing about who \ + signed the instruction the pool made *inside* it, so the evidence has to come \ + from the callee. SPL Memo refuses any account handed to it that has not signed, \ + and names the ones that did:\n\n", + ); + md.push_str(&format!("```\n{}\n```\n\n", line.trim())); + md.push_str(&format!( + "That is the pool's vault, `{}`, which has no private key — it signed through \ + seeds only the program holds. The soak reads this line back from the cluster \ + and fails the run if it is absent, so this section cannot appear without the \ + callee having said it.\n", + soak.vault() + )); + } + + if let Some((stake, voter)) = &soak.delegation { + md.push_str("\n## The pool delegated stake, as a member's authority\n\n"); + md.push_str(&format!( + "The same settlement carried a second signed action, and this one is the case \ + the design exists for: a **real stake delegation**. Stake account \ + [`{stake}`](https://explorer.solana.com/address/{stake}?cluster=devnet) is now \ + delegated to validator \ + [`{voter}`](https://explorer.solana.com/address/{voter}?cluster=devnet).\n\n" + )); + md.push_str( + "`DelegateStake` requires the **staker authority** to sign. No member can be that \ + authority without appearing on chain and undoing the point, so the pool is, and \ + the pool signed. The account state is read back after settlement: a stake \ + account only reaches the `Stake` variant by being delegated — an initialised but \ + undelegated one is a different variant — so the check distinguishes \"the \ + instruction landed\" from \"the delegation took\", and the validator's key is \ + read out of the account rather than assumed from what was requested.\n\n", + ); + md.push_str( + "**The withdraw authority is deliberately not the pool.** The pool's signature is \ + available to every member, so an authority the vault holds is an authority every \ + member holds. Delegation is safe on those terms — the worst a member can do is \ + re-delegate to another validator. Withdrawal is not, and it stays with the \ + operator. That is `docs/THREAT_MODEL.md` applied rather than repeated.\n\n", + ); + md.push_str(&format!( + "What is hidden here is precisely one thing: **which member asked**. The stake \ + account, the validator, the amount and the timing are all public, and the \ + anonymity set is the {BATCH} members who settled together. What an observer \ + cannot recover is which of them authorised this delegation rather than one of \ + the plain transfers beside it.\n" + )); + } + + md.push_str("\n## Rejections\n\n"); + md.push_str( + "A negative case is only evidence if the program's own error code is what \ + rejected it. A bare runtime failure proves nothing about this program.\n\n", + ); + md.push_str("| case | error code | what the rejection establishes |\n|---|---|---|\n"); + for (name, code, proves) in &soak.negatives { + md.push_str(&format!("| {name} | `{code}` | {proves} |\n")); + } + // Derived, not written by hand. Every negative but the replay case attacks a + // live note, so adding one silently turned "the last two" into a false + // sentence sitting under a correct table — the failure mode this file has + // already been bitten by once. + let live_note_cases = soak.negatives.len().saturating_sub(1); + let counted = match live_note_cases { + 1 => "The last one attacks".to_string(), + 2 => "The last two attack".to_string(), + 3 => "The last three attack".to_string(), + n => format!("The last {n} attack"), + }; + md.push_str(&format!( + "\n{counted} a note that is still live, deposited after settlement \ + precisely so that they would have to. Against an already-spent note the \ + replay guard fires first and the rejection would say nothing about the \ + check under test — which is how a negative case comes to pass for the \ + wrong reason.\n" + )); + + md.push_str("\n## Scope\n\n"); + md.push_str( + "Devnet is devnet. This is a live-cluster functional proof, not a claim of \ + mainnet operation or of an anonymity crowd: the run is scripted by one \ + operator with a handful of notes. What it establishes is that the circuit, \ + the prover, the byte layout and the deployed program agree on a real \ + validator.\n", + ); + std::fs::write(out, md)?; + Ok(()) +} diff --git a/crates/mirror-cli/src/stake.rs b/crates/mirror-cli/src/stake.rs new file mode 100644 index 00000000..a4f3f7f2 --- /dev/null +++ b/crates/mirror-cli/src/stake.rs @@ -0,0 +1,221 @@ +//! The native Stake program, as much of it as a pool needs. +//! +//! Delegation is the case the pool's signature exists for. A member cannot be a +//! stake account's staker authority without appearing on chain and undoing the +//! point, so the pool is that authority and the pool signs — which is a +//! capability a payment never needs. +//! +//! Everything here is a byte layout belonging to somebody else's program, and +//! getting one wrong is not a compile error and rarely a clear runtime one: an +//! account list in the wrong order makes the stake program read the config +//! account as the authority and report a missing signature, which sends the +//! reader looking in the wrong place entirely. So the layouts live in one place +//! with the derivation written out, rather than in each caller that needs them. + +use anyhow::{anyhow, Result}; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; + +pub const PROGRAM: &str = "Stake11111111111111111111111111111111111111"; +/// Still in `DelegateStake`'s account list, deprecated but not removed. +pub const CONFIG: &str = "StakeConfig11111111111111111111111111111111"; +pub const SYSVAR_CLOCK: &str = "SysvarC1ock11111111111111111111111111111111"; +pub const SYSVAR_STAKE_HISTORY: &str = "SysvarStakeHistory1111111111111111111111111"; +pub const SYSVAR_RENT: &str = "SysvarRent111111111111111111111111111111111"; + +/// `StakeInstruction::DelegateStake`, a bare u32 discriminant. +pub const DELEGATE_STAKE: [u8; 4] = [2, 0, 0, 0]; + +/// How many accounts `DelegateStake` takes. Bound into the member's proof, so a +/// settler can neither add one nor drop one. +pub const DELEGATE_ACCOUNTS: u8 = 6; + +/// `StakeStateV2` is 200 bytes whatever variant it holds. +pub const ACCOUNT_LEN: usize = 200; + +/// The variant a stake account only reaches by being delegated. +/// +/// An initialised but undelegated account is variant 1, so the discriminant +/// alone separates "the instruction landed" from "the delegation took" — which +/// is the difference between a signature and a result. +const STATE_STAKE: u32 = 2; + +/// Where `Delegation.voter_pubkey` sits inside a serialized `StakeStateV2`. +/// +/// Bincode, no padding: a u32 discriminant, then `Meta` — 8 bytes of rent +/// reserve, two 32-byte authorities, and a 48-byte `Lockup` of an i64, a u64 and +/// a 32-byte custodian — and then `Stake`, whose first field is `Delegation`, +/// whose first field is the vote account. 4 + 8 + 64 + 48 = 124. +const VOTER_OFFSET: usize = 124; + +pub fn program_id() -> Result { + parse(PROGRAM) +} + +fn parse(s: &str) -> Result { + s.parse().map_err(|e| anyhow!("{s}: {e}")) +} + +/// Creates a stake account and initialises its two authorities. +/// +/// The pair belongs together: an account created into the stake program and left +/// uninitialised is rent paid for nothing, and both halves fit in one +/// transaction, so they are returned as one unit rather than as two steps a +/// caller could interleave. +/// +/// The **staker** and the **withdrawer** are separate arguments and are meant to +/// be different keys. The pool's signature is available to every member, so an +/// authority the vault holds is an authority every member holds: delegation is +/// safe on those terms — the worst a member can do is re-delegate to another +/// validator — and withdrawal is not. +pub fn create( + payer: &Pubkey, + stake: &Pubkey, + staker: &Pubkey, + withdrawer: &Pubkey, + lamports: u64, +) -> Result<[Instruction; 2]> { + let program = program_id()?; + let create = solana_system_interface::instruction::create_account( + payer, + stake, + lamports, + ACCOUNT_LEN as u64, + &program, + ); + + // `StakeInstruction::Initialize { Authorized, Lockup }`: a u32 discriminant, + // the two authorities, then a zero lockup. + let mut data = 0u32.to_le_bytes().to_vec(); + data.extend_from_slice(&staker.to_bytes()); + data.extend_from_slice(&withdrawer.to_bytes()); + data.extend_from_slice(&0i64.to_le_bytes()); // lockup.unix_timestamp + data.extend_from_slice(&0u64.to_le_bytes()); // lockup.epoch + data.extend_from_slice(&[0u8; 32]); // lockup.custodian + let initialise = Instruction::new_with_bytes( + program, + &data, + vec![ + AccountMeta::new(*stake, false), + AccountMeta::new_readonly(parse(SYSVAR_RENT)?, false), + ], + ); + Ok([create, initialise]) +} + +/// The account list `DelegateStake` expects, in the callee's own order. +/// +/// Taken from what the `solana` CLI builds rather than from memory. The +/// authority sits in the last slot and the deprecated config account is still in +/// the list; a list that omits it puts the authority one slot early and the +/// stake program reports a missing signature for an account that did sign. +pub fn delegate_accounts( + stake: &Pubkey, + vote: &Pubkey, + authority: &Pubkey, +) -> Result> { + Ok(vec![ + AccountMeta::new(*stake, false), + AccountMeta::new_readonly(*vote, false), + AccountMeta::new_readonly(parse(SYSVAR_CLOCK)?, false), + AccountMeta::new_readonly(parse(SYSVAR_STAKE_HISTORY)?, false), + AccountMeta::new_readonly(parse(CONFIG)?, false), + AccountMeta::new_readonly(*authority, false), + ]) +} + +/// Which validator a stake account currently backs. +/// +/// Reads the answer out of the account rather than assuming it from what was +/// requested, so a delegation that landed against a different validator than the +/// member asked for is a caught error rather than an unnoticed one. +pub fn delegated_voter(data: &[u8]) -> Result { + if data.len() < VOTER_OFFSET + 32 { + return Err(anyhow!( + "the stake account is {} bytes, too short to be a stake state", + data.len() + )); + } + let discriminant = u32::from_le_bytes([data[0], data[1], data[2], data[3]]); + if discriminant != STATE_STAKE { + return Err(anyhow!( + "the stake account is in state {discriminant}, not Stake({STATE_STAKE}): \ + the delegation did not take" + )); + } + Ok(Pubkey::new_from_array( + data[VOTER_OFFSET..VOTER_OFFSET + 32] + .try_into() + .map_err(|_| anyhow!("reading the vote account"))?, + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn state(discriminant: u32, voter: &Pubkey) -> Vec { + let mut data = vec![0u8; ACCOUNT_LEN]; + data[..4].copy_from_slice(&discriminant.to_le_bytes()); + data[VOTER_OFFSET..VOTER_OFFSET + 32].copy_from_slice(&voter.to_bytes()); + data + } + + #[test] + fn a_delegated_account_reports_the_validator_it_backs() { + let voter = Pubkey::new_unique(); + assert_eq!(delegated_voter(&state(STATE_STAKE, &voter)).unwrap(), voter); + } + + /// The check that separates a signature from a result. An initialised but + /// undelegated account carries a plausible-looking key at the voter offset — + /// zeroes, here — and reading it without checking the variant would report a + /// delegation that never happened. + #[test] + fn an_initialised_but_undelegated_account_is_not_read_as_delegated() { + let err = delegated_voter(&state(1, &Pubkey::new_unique())) + .unwrap_err() + .to_string(); + assert!(err.contains("did not take"), "{err}"); + } + + #[test] + fn an_account_too_short_to_hold_a_delegation_is_refused() { + assert!(delegated_voter(&[0u8; 64]).is_err()); + } + + /// The order is the whole point of the function, and it is the one thing a + /// reader cannot check by looking at the callee from here. + #[test] + fn the_authority_is_the_last_account_and_the_vote_account_the_second() { + let stake = Pubkey::new_unique(); + let vote = Pubkey::new_unique(); + let authority = Pubkey::new_unique(); + let metas = delegate_accounts(&stake, &vote, &authority).unwrap(); + assert_eq!(metas.len(), DELEGATE_ACCOUNTS as usize); + assert_eq!(metas[0].pubkey, stake); + assert!(metas[0].is_writable, "the stake account is written"); + assert_eq!(metas[1].pubkey, vote); + assert_eq!(metas[5].pubkey, authority); + assert!( + metas[1..].iter().all(|m| !m.is_writable), + "only the stake account is written" + ); + } + + /// The authority the pool holds must not be the authority that can take the + /// money out. Asserted on the instruction this crate builds, because the + /// argument order is the only thing standing between the two. + #[test] + fn the_staker_and_the_withdrawer_are_written_to_different_slots() { + let payer = Pubkey::new_unique(); + let stake = Pubkey::new_unique(); + let staker = Pubkey::new_unique(); + let withdrawer = Pubkey::new_unique(); + let [_, initialise] = create(&payer, &stake, &staker, &withdrawer, 1_000_000).unwrap(); + assert_eq!(&initialise.data[4..36], staker.to_bytes().as_slice()); + assert_eq!(&initialise.data[36..68], withdrawer.to_bytes().as_slice()); + } +} diff --git a/crates/mirror-core/Cargo.toml b/crates/mirror-core/Cargo.toml new file mode 100644 index 00000000..213f467a --- /dev/null +++ b/crates/mirror-core/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "mirror-core" +version.workspace = true +edition.workspace = true +# Not published to crates.io: these crates are built from this repository, and a +# registry copy would be a second source of truth for the same code. +publish = false +license.workspace = true + +# No arkworks here. mirror-core is linked into the on-chain program, and every +# byte of arkworks in the .so is a stack frame we cannot afford. Field elements +# cross this boundary as canonical 32-byte big-endian arrays. +[dependencies] +solana-poseidon.workspace = true +solana-keccak-hasher.workspace = true +thiserror.workspace = true diff --git a/crates/mirror-core/src/field.rs b/crates/mirror-core/src/field.rs new file mode 100644 index 00000000..a4dbb86b --- /dev/null +++ b/crates/mirror-core/src/field.rs @@ -0,0 +1,155 @@ +//! Canonical BN254 scalar field elements. +//! +//! Everything that crosses the boundary between the circuit, the host and the +//! on-chain program is a `Field`: exactly 32 bytes, big-endian, strictly less +//! than the BN254 scalar modulus `r`. +//! +//! The canonicality check is not decoration. SIMD-0359 made the Poseidon +//! syscall reject inputs that are not full field elements, and the on-chain +//! Groth16 verifier rejects public inputs greater than or equal to `r`. Values +//! that fail either check must be rejected where they enter the system, not +//! silently reduced — reducing would let two distinct byte strings denote one +//! nullifier, which is a double-spend. + +use crate::MirrorError; + +/// The BN254 scalar field modulus `r`, big-endian. +/// +/// 21888242871839275222246405745257275088548364400416034343698204186575808495617 +pub const MODULUS_BE: [u8; 32] = [ + 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, 0x58, 0x5d, + 0x28, 0x33, 0xe8, 0x48, 0x79, 0xb9, 0x70, 0x91, 0x43, 0xe1, 0xf5, 0x93, 0xf0, 0x00, 0x00, 0x01, +]; + +/// A canonical BN254 scalar, stored big-endian. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct Field([u8; 32]); + +impl Field { + /// Additive identity. + pub const ZERO: Field = Field([0u8; 32]); + + /// Wraps 32 big-endian bytes, rejecting anything at or above the modulus. + pub fn from_bytes(bytes: [u8; 32]) -> Result { + if !is_canonical(&bytes) { + return Err(MirrorError::NonCanonicalField); + } + Ok(Field(bytes)) + } + + /// Wraps a small integer, which is always canonical. + pub fn from_u64(v: u64) -> Self { + let mut bytes = [0u8; 32]; + bytes[24..].copy_from_slice(&v.to_be_bytes()); + Field(bytes) + } + + /// Reads a canonical element from a slice of exactly 32 bytes. + pub fn from_slice(bytes: &[u8]) -> Result { + let arr: [u8; 32] = bytes.try_into().map_err(|_| MirrorError::BadFieldLength)?; + Self::from_bytes(arr) + } + + pub const fn to_bytes(self) -> [u8; 32] { + self.0 + } + + pub const fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + pub fn is_zero(&self) -> bool { + self.0 == [0u8; 32] + } +} + +/// Constant-time-ish big-endian comparison against the modulus. +/// +/// This runs on values that are already public (roots, nullifiers, bindings), so +/// timing is not a concern; the loop is written for clarity and to avoid pulling +/// a bignum dependency into the on-chain binary. +fn is_canonical(bytes: &[u8; 32]) -> bool { + for i in 0..32 { + match bytes[i].cmp(&MODULUS_BE[i]) { + core::cmp::Ordering::Less => return true, + core::cmp::Ordering::Greater => return false, + core::cmp::Ordering::Equal => continue, + } + } + // Exactly equal to the modulus is not a canonical field element. + false +} + +impl core::fmt::Debug for Field { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Field(0x")?; + for b in self.0 { + write!(f, "{b:02x}")?; + } + write!(f, ")") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn zero_and_small_values_are_canonical() { + assert!(Field::from_bytes([0u8; 32]).is_ok()); + assert_eq!(Field::from_u64(0), Field::ZERO); + assert_eq!(Field::from_u64(1).to_bytes()[31], 1); + } + + #[test] + fn the_modulus_itself_is_rejected() { + // r is not a member of the field; only 0..r-1 are. + assert!(matches!( + Field::from_bytes(MODULUS_BE), + Err(MirrorError::NonCanonicalField) + )); + } + + #[test] + fn one_below_the_modulus_is_accepted_and_one_above_is_not() { + let mut below = MODULUS_BE; + below[31] -= 1; + assert!(Field::from_bytes(below).is_ok()); + + let mut above = MODULUS_BE; + above[31] += 1; + assert!(Field::from_bytes(above).is_err()); + } + + #[test] + fn all_ones_is_rejected() { + // The classic non-canonical input an attacker reaches for first. + assert!(Field::from_bytes([0xff; 32]).is_err()); + } + + #[test] + fn a_wrong_length_slice_is_rejected_rather_than_padded() { + assert!(matches!( + Field::from_slice(&[1u8; 31]), + Err(MirrorError::BadFieldLength) + )); + assert!(matches!( + Field::from_slice(&[1u8; 33]), + Err(MirrorError::BadFieldLength) + )); + } + + #[test] + fn high_byte_boundary_is_respected() { + // Differs from the modulus only in the first byte, one below: canonical. + let mut b = MODULUS_BE; + b[0] -= 1; + assert!(Field::from_bytes(b).is_ok()); + + // One above in the first byte: not canonical, even though later bytes are small. + let mut b = MODULUS_BE; + b[0] += 1; + b[31] = 0; + assert!(Field::from_bytes(b).is_err()); + } +} diff --git a/crates/mirror-core/src/hash.rs b/crates/mirror-core/src/hash.rs new file mode 100644 index 00000000..3b9d7432 --- /dev/null +++ b/crates/mirror-core/src/hash.rs @@ -0,0 +1,380 @@ +//! Poseidon over BN254, with domain separation by arity. +//! +//! `solana-poseidon` is the only entry point, deliberately. Upstream it is +//! cfg-gated to the `sol_poseidon` syscall on-chain and to light-poseidon over +//! ark-bn254 off-chain, so the host and the program compute the same function by +//! construction rather than by our own careful duplication. The R1CS gadget in +//! `mirror-circuit` is checked against this, which closes the three-way parity: +//! gadget == host == syscall. +//! +//! ## Domain separation +//! +//! Poseidon instances of different width are different permutations, so arity is +//! itself a domain separator — and it is a free one. Each hashed value in the +//! protocol uses a distinct arity, so no preimage of one can ever be reread as a +//! preimage of another: +//! +//! | value | arity | preimage | +//! |---|---|---| +//! | nullifier | 1 | `(k)` | +//! | Merkle node | 2 | `(left, right)` | +//! | note commitment | 3 | `(k, r, denom_tag)` | +//! +//! The action binding is not in this table: its payload is variable length, so +//! it is a keccak digest rather than a Poseidon compression. See +//! [`action_binding`]. +//! +//! An explicit integer tag was the first design here and it was wrong: with a +//! small tag constant, a Merkle node whose left child equals the tag collides +//! with a nullifier. Reaching that state requires a Poseidon preimage and so is +//! not practically exploitable, but arity separation removes the question +//! entirely at no cost. +//! +//! Hashing Merkle nodes, nullifiers and action bindings with one untagged +//! arity-2 function is the shortcut this avoids: it works, right up until a +//! value from one domain is accepted where another was meant. + +use crate::{Field, MirrorError}; +use solana_poseidon::{hashv, Endianness, Parameters}; + +fn digest(inputs: &[&[u8]]) -> Result { + let out = hashv(Parameters::Bn254X5, Endianness::BigEndian, inputs) + .map_err(|_| MirrorError::Poseidon)?; + // The syscall reduces into the field, so this cannot fail. We still go + // through the checked constructor rather than assume it. + Field::from_bytes(out.to_bytes()) +} + +/// Arity-1 Poseidon. +pub fn poseidon1(a: Field) -> Result { + digest(&[a.as_bytes()]) +} + +/// Arity-2 Poseidon. +pub fn poseidon2(a: Field, b: Field) -> Result { + digest(&[a.as_bytes(), b.as_bytes()]) +} + +/// Arity-3 Poseidon. +pub fn poseidon3(a: Field, b: Field, c: Field) -> Result { + digest(&[a.as_bytes(), b.as_bytes(), c.as_bytes()]) +} + +/// Merkle internal node: `H2(left, right)`. +pub fn hash_node(left: Field, right: Field) -> Result { + poseidon2(left, right) +} + +/// Note commitment: `H3(k, r, denom_tag)`. +/// +/// `k` is the nullifier preimage, `r` the blinding factor. `denom_tag` pins the +/// commitment to the pool's denomination so a note can never be replayed into a +/// pool of a different size even if the two share an accumulator. +pub fn commitment(k: Field, r: Field, denom_tag: Field) -> Result { + poseidon3(k, r, denom_tag) +} + +/// Nullifier: `H1(k)`. +/// +/// Deliberately not scoped to an epoch. Scoping a nullifier to the epoch is the +/// natural move once epochs are how batches form — and against a value-bearing +/// payout it is a drain, because a single deposit then pays out once per epoch, +/// forever. This one is spent once, ever. +pub fn nullifier(k: Field) -> Result { + poseidon1(k) +} + +/// Domain tag for the action binding preimage. +/// +/// Bumped to `v2` when `relay` joined the preimage. The digest would differ +/// regardless — a new field guarantees that — but the version says *why* it +/// differs. A prover left on the old shape produces a binding the program does +/// not recompute, and the failure surfaces as a rejected pairing; the tag is +/// what makes that a version mismatch rather than a mystery. +pub const ACTION_DOMAIN: &[u8] = b"mirror-pool:action:v2"; + +/// Reduces a 256-bit digest to a canonical BN254 scalar. +/// +/// The top byte is cleared, so the value is below `2^248` and therefore +/// unconditionally below the modulus. Masking rather than reducing keeps the map +/// deterministic and total — a modular reduction would need a bignum in the +/// program, and rejecting out-of-range digests would make the binding fail for +/// one preimage in roughly forty. +/// +/// Eight bits are lost from 256. What remains is far beyond what collision +/// resistance needs here: forging a binding still requires a keccak collision. +pub fn field_from_digest(digest: [u8; 32]) -> Field { + let mut bytes = digest; + bytes[0] = 0; + Field::from_bytes(bytes).expect("cleared top byte is always canonical") +} + +/// Action binding: a keccak digest over everything a relay could alter. +/// +/// This is the circuit's third public input and the value the program recomputes +/// from the action it is about to execute. It lives here, shared by host and +/// program, so the two cannot drift. +/// +/// The preimage covers every field with economic or behavioural meaning: +/// +/// | field | what altering it would let a relay do | +/// |---|---| +/// | `selector` | run a different kind of action | +/// | `target_program` | invoke a different program entirely | +/// | `beneficiary` | redirect the outcome | +/// | `relay` | collect another relay's fee | +/// | `relay_fee` | inflate its own cut | +/// | `payload` | change the action's parameters | +/// | `action_accounts` | declare a count settlement cannot satisfy | +/// +/// `relay` is here because binding the fee without binding its recipient is only +/// half a binding. Every other field in this preimage travels in clear text in +/// the instruction data, so anyone watching an unlanded `submit_spend` can lift +/// the proof, substitute their own key as the relay, and land it first: the +/// digest is unchanged, the pairing succeeds, the nullifier burns, and the fee +/// settles to them. The member's payout is never at risk — `beneficiary` and the +/// amount are bound — so this is theft from the relay, not from the member. +/// +/// It is not a profitable theft. Whoever lands the transaction funds the spend +/// record's rent, and that record is never closed because it *is* the replay +/// guard, so the attacker sinks far more than any sane fee is worth. The reason +/// to close it anyway is that an attacker need not be paid to be effective: a +/// relay whose fee can be sniped at will is a relay nobody runs, and a pool with +/// no relays is one where members submit from their own funded wallets. That +/// undoes the anonymity this whole design exists to provide — not by breaking +/// the pool, but by making the honest path uneconomic. +/// +/// `action_accounts` is here because leaving it out was a live griefing vector: +/// it is relay-supplied, it is written verbatim into the spend record, and +/// settlement refuses any spend whose declared count does not match its +/// selector. A relay handed a valid transfer proof could submit it with +/// `action_accounts = 1`, burn the nullifier, and leave a note that can never +/// settle and can never be refunded — for free, and undetectably until +/// settlement. +/// +/// Keccak rather than Poseidon because the payload is variable length and +/// Poseidon is a fixed-arity compression. The circuit never computes this — it +/// takes the result as an opaque public input — so the choice costs no +/// constraints. +#[allow(clippy::too_many_arguments)] +pub fn action_binding( + selector: u64, + target_program: &[u8; 32], + beneficiary: &[u8; 32], + relay: &[u8; 32], + relay_fee: u64, + action_accounts: u8, + payload: &[u8], +) -> Field { + let digest = solana_keccak_hasher::hashv(&[ + ACTION_DOMAIN, + &selector.to_le_bytes(), + target_program, + beneficiary, + relay, + &relay_fee.to_le_bytes(), + &[action_accounts], + payload, + ]); + field_from_digest(digest.to_bytes()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn f(v: u64) -> Field { + Field::from_u64(v) + } + + #[test] + fn hashing_is_deterministic() { + assert_eq!( + poseidon2(f(1), f(2)).unwrap(), + poseidon2(f(1), f(2)).unwrap() + ); + } + + #[test] + fn hashing_is_order_sensitive() { + assert_ne!( + poseidon2(f(1), f(2)).unwrap(), + poseidon2(f(2), f(1)).unwrap() + ); + } + + #[test] + fn arities_are_distinct_domains() { + // The whole point of separating by arity: padding one preimage with + // zeros must not reproduce another's digest. + let a1 = poseidon1(f(7)).unwrap(); + let a2 = poseidon2(f(7), Field::ZERO).unwrap(); + let a3 = poseidon3(f(7), Field::ZERO, Field::ZERO).unwrap(); + assert_ne!(a1, a2); + assert_ne!(a2, a3); + assert_ne!(a1, a3); + } + + #[test] + fn a_nullifier_cannot_be_confused_with_a_merkle_node() { + // Different arity, so no choice of children reproduces a nullifier by + // construction rather than by preimage hardness. + let k = f(42); + let null = nullifier(k).unwrap(); + assert_ne!(null, hash_node(Field::ZERO, k).unwrap()); + assert_ne!(null, hash_node(k, Field::ZERO).unwrap()); + } + + #[test] + fn a_commitment_is_bound_to_its_denomination() { + let (k, r) = (f(11), f(22)); + assert_ne!( + commitment(k, r, f(1)).unwrap(), + commitment(k, r, f(2)).unwrap(), + "the same note under two denominations must not share a commitment" + ); + } + + const PROG: [u8; 32] = [3u8; 32]; + const RELAY: [u8; 32] = [5u8; 32]; + + #[test] + fn the_action_binding_covers_every_field_a_relay_could_change() { + let bob = [7u8; 32]; + let payload = b"stake 0.1".as_slice(); + let base = action_binding(1, &PROG, &bob, &RELAY, 5_000, 0, payload); + + let mut carol = [7u8; 32]; + carol[31] = 8; + let mut other_prog = PROG; + other_prog[0] = 4; + + assert_ne!( + base, + action_binding(2, &PROG, &bob, &RELAY, 5_000, 0, payload), + "selector" + ); + assert_ne!( + base, + action_binding(1, &other_prog, &bob, &RELAY, 5_000, 0, payload), + "target program" + ); + assert_ne!( + base, + action_binding(1, &PROG, &carol, &RELAY, 5_000, 0, payload), + "beneficiary" + ); + assert_ne!( + base, + action_binding(1, &PROG, &bob, &RELAY, 6_000, 0, payload), + "relay fee" + ); + assert_ne!( + base, + action_binding(1, &PROG, &bob, &RELAY, 5_000, 0, b"stake 1.0"), + "payload" + ); + } + + /// The front-running case, stated on its own rather than as one row above. + /// + /// Every other field in the preimage is chosen by the member. This one is + /// whoever signs, so it is the only field an attacker can change *without* + /// altering what the member asked for — which is exactly why leaving it out + /// made the proof transferable to a different payee at no cost. + #[test] + fn two_relays_carrying_the_same_action_do_not_share_a_binding() { + let bob = [7u8; 32]; + let thief = [6u8; 32]; + assert_ne!( + action_binding(1, &PROG, &bob, &RELAY, 5_000, 0, b"stake 0.1"), + action_binding(1, &PROG, &bob, &thief, 5_000, 0, b"stake 0.1"), + "a proof must not verify for a relay the member did not name" + ); + } + + #[test] + fn the_binding_is_deterministic_and_lands_in_the_field() { + let a = action_binding(1, &PROG, &[9u8; 32], &RELAY, 1, 0, b"x"); + let b = action_binding(1, &PROG, &[9u8; 32], &RELAY, 1, 0, b"x"); + assert_eq!(a, b); + // Canonical by construction: the top byte is cleared. + assert_eq!(a.to_bytes()[0], 0); + assert!(Field::from_bytes(a.to_bytes()).is_ok()); + } + + #[test] + fn an_empty_payload_is_a_distinct_action_from_a_zero_byte_one() { + assert_ne!( + action_binding(1, &PROG, &[1u8; 32], &RELAY, 0, 0, b""), + action_binding(1, &PROG, &[1u8; 32], &RELAY, 0, 0, b"\0"), + ); + } + + #[test] + fn field_masking_is_total_over_every_digest() { + // Including a digest that would otherwise exceed the modulus. A binding + // that failed for some preimages would be a liveness bug that only + // appeared for one action in forty. + for probe in [[0xffu8; 32], [0u8; 32], crate::MODULUS_BE] { + let f = field_from_digest(probe); + assert_eq!(f.to_bytes()[0], 0); + } + } + + #[test] + fn the_domain_tag_separates_bindings_from_raw_hashes() { + // Without the tag, a preimage assembled elsewhere could collide with a + // binding. With it, an attacker must also control the tag. + let with_tag = action_binding(0, &[0u8; 32], &[0u8; 32], &[0u8; 32], 0, 0, b""); + let raw = field_from_digest( + solana_keccak_hasher::hashv(&[ + &0u64.to_le_bytes(), + &[0u8; 32], + &[0u8; 32], + &[0u8; 32], + &0u64.to_le_bytes(), + ]) + .to_bytes(), + ); + assert_ne!(with_tag, raw); + } + + /// The anchor for the three-way parity. + /// + /// `poseidon([1, 2])` under circomlib's BN254 x5 instance is the published + /// constant + /// `7853200120776062878684798364095072458815029376092732009249414926327459813530`. + /// Pinning it here means the host and the R1CS gadget in `mirror-circuit` are + /// each checked against an external published value rather than against each + /// other. The syscall is then checked against the host on-chain, by the + /// end-to-end suite asserting the deployed program's root equals the host's. + #[test] + fn poseidon2_matches_the_published_circomlib_vector() { + const CIRCOMLIB_1_2: [u8; 32] = [ + 0x11, 0x5c, 0xc0, 0xf5, 0xe7, 0xd6, 0x90, 0x41, 0x3d, 0xf6, 0x4c, 0x6b, 0x96, 0x62, + 0xe9, 0xcf, 0x2a, 0x36, 0x17, 0xf2, 0x74, 0x32, 0x45, 0x51, 0x9e, 0x19, 0x60, 0x7a, + 0x44, 0x17, 0x18, 0x9a, + ]; + assert_eq!(poseidon2(f(1), f(2)).unwrap().to_bytes(), CIRCOMLIB_1_2); + } + + /// Regression vectors for the other arities we rely on. These are ours, not + /// external, and exist so that an accidental change of parameters or + /// endianness is caught rather than silently re-baselined. + #[test] + fn arity_vectors_are_stable() { + const P1_1: [u8; 32] = [ + 0x29, 0x17, 0x61, 0x00, 0xea, 0xa9, 0x62, 0xbd, 0xc1, 0xfe, 0x6c, 0x65, 0x4d, 0x6a, + 0x3c, 0x13, 0x0e, 0x96, 0xa4, 0xd1, 0x16, 0x8b, 0x33, 0x84, 0x8b, 0x89, 0x7d, 0xc5, + 0x02, 0x82, 0x01, 0x33, + ]; + const P3_123: [u8; 32] = [ + 0x0e, 0x77, 0x32, 0xd8, 0x9e, 0x69, 0x39, 0xc0, 0xff, 0x03, 0xd5, 0xe5, 0x8d, 0xab, + 0x63, 0x02, 0xf3, 0x23, 0x0e, 0x26, 0x9d, 0xc5, 0xb9, 0x68, 0xf7, 0x25, 0xdf, 0x34, + 0xab, 0x36, 0xd7, 0x32, + ]; + assert_eq!(poseidon1(f(1)).unwrap().to_bytes(), P1_1); + assert_eq!(poseidon3(f(1), f(2), f(3)).unwrap().to_bytes(), P3_123); + } +} diff --git a/crates/mirror-core/src/lib.rs b/crates/mirror-core/src/lib.rs new file mode 100644 index 00000000..aecc06c3 --- /dev/null +++ b/crates/mirror-core/src/lib.rs @@ -0,0 +1,42 @@ +//! Field primitives shared by the circuit, the on-chain program and the host +//! tooling: canonical BN254 scalars, Poseidon hashing with domain separation by +//! arity, the incremental Merkle accumulator, and the note model. +//! +//! This crate is linked into the on-chain program, so it carries no arkworks. +//! Field elements cross every boundary as canonical 32-byte big-endian arrays. +#![forbid(unsafe_code)] + +mod field; +mod hash; +mod merkle; +mod note; + +pub use field::{Field, MODULUS_BE}; +pub use hash::{ + action_binding, commitment, field_from_digest, hash_node, nullifier, poseidon1, poseidon2, + poseidon3, ACTION_DOMAIN, +}; +pub use merkle::{ + baked_ladder, zero_ladder, Frontier, MerkleProof, MerkleTree, TREE_DEPTH, ZERO_LADDER, +}; +pub use note::Note; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] +pub enum MirrorError { + #[error("field element is not canonical: at or above the BN254 scalar modulus")] + NonCanonicalField, + #[error("field element must be exactly 32 bytes")] + BadFieldLength, + #[error("poseidon hashing failed")] + Poseidon, + #[error("the accumulator is full")] + TreeFull, + // There is no `BadPathLength`. A `MerkleProof` carries + // `siblings: [Field; TREE_DEPTH]`, a fixed-size array, so a path of the + // wrong length is not constructible and the check has nothing to reject. + // The property is enforced by the type rather than by a runtime branch, and + // carrying an error variant for it would advertise a check that does not + // exist. + #[error("leaf index is outside the tree")] + LeafIndexOutOfRange, +} diff --git a/crates/mirror-core/src/merkle.rs b/crates/mirror-core/src/merkle.rs new file mode 100644 index 00000000..bb2ce206 --- /dev/null +++ b/crates/mirror-core/src/merkle.rs @@ -0,0 +1,456 @@ +//! The incremental Poseidon Merkle accumulator. +//! +//! Two views of one structure: +//! +//! * [`Frontier`] is what the on-chain program keeps — `O(depth)` state and an +//! `O(depth)` append. It can produce the current root and nothing else. +//! * [`MerkleTree`] is the host-side full tree used to build the membership +//! paths that go into a proof. +//! +//! They must agree, and the tests here assert that they do over real insertion +//! sequences. That assertion is the point of this module. It is easy to test +//! each half separately and never connect them — proving against an injected +//! fixture root rather than one the on-chain accumulator actually produced — and +//! a suite built that way stays green while the two implementations drift. + +use crate::{hash_node, Field, MirrorError}; + +/// Tree depth. 2^20 leaves is roughly a million notes, which is far beyond any +/// anonymity set this protocol will realistically hold, and a depth-20 path +/// costs about 17k compute units to fold on-chain. +pub const TREE_DEPTH: usize = 20; + +/// Precomputed empty-subtree roots: `ZERO_LADDER[i]` is the root of an empty +/// subtree of height `i`. +/// +/// Baked rather than computed because the on-chain program needs the ladder on +/// every deposit, and recomputing it would cost about 17k compute units per +/// instruction. `the_baked_ladder_matches_the_computed_one` asserts the two +/// agree, so a change to the hash function cannot silently desynchronise them. +pub const ZERO_LADDER: [[u8; 32]; TREE_DEPTH + 1] = [ + // level 0 + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ], + // level 1 + [ + 32, 152, 245, 251, 158, 35, 158, 171, 60, 234, 195, 242, 123, 129, 228, 129, 220, 49, 36, + 213, 95, 254, 213, 35, 168, 57, 238, 132, 70, 182, 72, 100, + ], + // level 2 + [ + 16, 105, 103, 61, 205, 177, 34, 99, 223, 48, 26, 111, 245, 132, 167, 236, 38, 26, 68, 203, + 157, 198, 141, 240, 103, 164, 119, 68, 96, 177, 241, 225, + ], + // level 3 + [ + 24, 244, 51, 49, 83, 126, 226, 175, 46, 61, 117, 141, 80, 247, 33, 6, 70, 124, 110, 234, + 80, 55, 29, 213, 40, 213, 126, 178, 184, 86, 210, 56, + ], + // level 4 + [ + 7, 249, 216, 55, 203, 23, 176, 211, 99, 32, 255, 233, 59, 165, 35, 69, 241, 183, 40, 87, + 26, 86, 130, 101, 202, 172, 151, 85, 157, 188, 149, 42, + ], + // level 5 + [ + 43, 148, 207, 94, 135, 70, 179, 245, 201, 99, 31, 76, 93, 243, 41, 7, 166, 153, 197, 140, + 148, 178, 173, 77, 123, 92, 236, 22, 57, 24, 63, 85, + ], + // level 6 + [ + 45, 238, 147, 197, 166, 102, 69, 150, 70, 234, 125, 34, 204, 169, 225, 188, 254, 215, 30, + 105, 81, 185, 83, 97, 29, 17, 221, 163, 46, 160, 157, 120, + ], + // level 7 + [ + 7, 130, 149, 229, 162, 43, 132, 233, 130, 207, 96, 30, 182, 57, 89, 123, 139, 5, 21, 168, + 140, 181, 172, 127, 168, 164, 170, 190, 60, 135, 52, 157, + ], + // level 8 + [ + 47, 165, 229, 241, 143, 96, 39, 166, 80, 27, 236, 134, 69, 100, 71, 42, 97, 107, 46, 39, + 74, 65, 33, 26, 68, 76, 190, 58, 153, 243, 204, 97, + ], + // level 9 + [ + 14, 136, 67, 118, 208, 216, 253, 33, 236, 183, 128, 56, 158, 148, 31, 102, 228, 94, 122, + 204, 227, 226, 40, 171, 62, 33, 86, 166, 20, 252, 215, 71, + ], + // level 10 + [ + 27, 114, 1, 218, 114, 73, 79, 30, 40, 113, 122, 209, 165, 46, 180, 105, 249, 88, 146, 249, + 87, 113, 53, 51, 222, 97, 117, 229, 218, 25, 10, 242, + ], + // level 11 + [ + 31, 141, 136, 34, 114, 94, 54, 56, 82, 0, 192, 178, 1, 36, 152, 25, 166, 230, 225, 228, + 101, 8, 8, 181, 190, 188, 107, 250, 206, 125, 118, 54, + ], + // level 12 + [ + 44, 93, 130, 246, 108, 145, 75, 175, 185, 112, 21, 137, 186, 140, 252, 251, 97, 98, 176, + 161, 42, 207, 136, 168, 208, 135, 154, 4, 113, 181, 248, 90, + ], + // level 13 + [ + 20, 197, 65, 72, 160, 148, 11, 184, 32, 149, 127, 90, 223, 63, 161, 19, 78, 245, 196, 170, + 161, 19, 244, 100, 100, 88, 242, 112, 224, 191, 191, 208, + ], + // level 14 + [ + 25, 13, 51, 177, 47, 152, 111, 150, 30, 16, 192, 238, 68, 216, 185, 175, 17, 190, 37, 88, + 140, 173, 137, 212, 22, 17, 142, 75, 244, 235, 232, 12, + ], + // level 15 + [ + 34, 249, 138, 169, 206, 112, 65, 82, 172, 23, 53, 73, 20, 173, 115, 237, 17, 103, 174, 101, + 150, 175, 81, 10, 165, 179, 100, 147, 37, 224, 108, 146, + ], + // level 16 + [ + 42, 124, 124, 155, 108, 229, 136, 11, 159, 111, 34, 141, 114, 191, 106, 87, 90, 82, 111, + 41, 198, 110, 204, 238, 248, 183, 83, 211, 139, 186, 115, 35, + ], + // level 17 + [ + 46, 129, 134, 229, 88, 105, 142, 193, 198, 122, 249, 193, 77, 70, 63, 252, 71, 0, 67, 201, + 194, 152, 139, 149, 77, 117, 221, 100, 63, 54, 185, 146, + ], + // level 18 + [ + 15, 87, 197, 87, 30, 154, 78, 171, 73, 226, 200, 207, 5, 13, 174, 148, 138, 239, 110, 173, + 100, 115, 146, 39, 53, 70, 36, 157, 28, 31, 241, 15, + ], + // level 19 + [ + 24, 48, 238, 103, 181, 251, 85, 74, 213, 246, 61, 67, 136, 128, 14, 28, 254, 120, 227, 16, + 105, 125, 70, 228, 60, 156, 227, 97, 52, 247, 44, 202, + ], + // level 20 + [ + 33, 52, 231, 106, 197, 210, 26, 171, 24, 108, 43, 225, 221, 143, 132, 238, 136, 10, 30, 70, + 234, 247, 18, 249, 211, 113, 182, 223, 34, 25, 31, 62, + ], +]; + +/// Derives the ladder from the hash function. +/// +/// This is the reference implementation and the source `ZERO_LADDER` was +/// generated from. Nothing on the hot path calls it — the on-chain program and +/// both accumulator views read the baked constant instead — but it is what +/// `the_baked_ladder_matches_the_computed_one` checks that constant against, and +/// it is how the constant is regenerated if the hash ever changes. +pub fn zero_ladder() -> Result<[Field; TREE_DEPTH + 1], MirrorError> { + let mut z = [Field::ZERO; TREE_DEPTH + 1]; + for i in 1..=TREE_DEPTH { + z[i] = hash_node(z[i - 1], z[i - 1])?; + } + Ok(z) +} + +/// The baked ladder as `Field`s, validating canonicality on the way through. +/// +/// Costs no hashing, which is why the on-chain deposit path can afford it. +pub fn baked_ladder() -> Result<[Field; TREE_DEPTH + 1], MirrorError> { + let mut z = [Field::ZERO; TREE_DEPTH + 1]; + for (slot, bytes) in z.iter_mut().zip(ZERO_LADDER.iter()) { + *slot = Field::from_bytes(*bytes)?; + } + Ok(z) +} + +/// Insert-only accumulator holding one node per level. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Frontier { + filled: [Field; TREE_DEPTH], + zeros: [Field; TREE_DEPTH + 1], + next_index: u64, + root: Field, +} + +impl Frontier { + pub fn new() -> Result { + let zeros = baked_ladder()?; + Ok(Frontier { + filled: [Field::ZERO; TREE_DEPTH], + zeros, + next_index: 0, + root: zeros[TREE_DEPTH], + }) + } + + /// Number of leaves inserted so far. + pub fn len(&self) -> u64 { + self.next_index + } + + pub fn is_empty(&self) -> bool { + self.next_index == 0 + } + + pub fn root(&self) -> Field { + self.root + } + + /// Appends a leaf and returns its index. + pub fn insert(&mut self, leaf: Field) -> Result { + if self.next_index >= 1u64 << TREE_DEPTH { + return Err(MirrorError::TreeFull); + } + let index = self.next_index; + let mut current = leaf; + let mut path = index; + + for level in 0..TREE_DEPTH { + if path & 1 == 0 { + // We are a left child: remember this node and pair with the + // empty subtree to its right. + self.filled[level] = current; + current = hash_node(current, self.zeros[level])?; + } else { + // We are a right child: our left sibling is already known. + current = hash_node(self.filled[level], current)?; + } + path >>= 1; + } + + self.root = current; + self.next_index += 1; + Ok(index) + } +} + +/// A membership path: the sibling at each level, plus the leaf index whose bits +/// give the left/right orientation. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MerkleProof { + pub leaf_index: u64, + pub siblings: [Field; TREE_DEPTH], +} + +impl MerkleProof { + /// Folds the path to a root. The circuit performs exactly this computation + /// under constraints; this is the native reference it must agree with. + pub fn fold(&self, leaf: Field) -> Result { + let mut current = leaf; + let mut path = self.leaf_index; + for sibling in self.siblings.iter() { + current = if path & 1 == 0 { + hash_node(current, *sibling)? + } else { + hash_node(*sibling, current)? + }; + path >>= 1; + } + Ok(current) + } +} + +/// Host-side full tree. Stores every inserted leaf so it can rebuild any path. +#[derive(Clone, Debug)] +pub struct MerkleTree { + leaves: Vec, + zeros: [Field; TREE_DEPTH + 1], +} + +impl MerkleTree { + pub fn new() -> Result { + Ok(MerkleTree { + leaves: Vec::new(), + zeros: baked_ladder()?, + }) + } + + pub fn len(&self) -> usize { + self.leaves.len() + } + + pub fn is_empty(&self) -> bool { + self.leaves.is_empty() + } + + pub fn insert(&mut self, leaf: Field) -> Result { + if self.leaves.len() as u64 >= 1u64 << TREE_DEPTH { + return Err(MirrorError::TreeFull); + } + self.leaves.push(leaf); + Ok(self.leaves.len() as u64 - 1) + } + + /// The node at `(level, index)`, materialising empty subtrees from the + /// zero ladder rather than storing them. + fn node(&self, level: usize, index: usize) -> Result { + if level == 0 { + return Ok(self.leaves.get(index).copied().unwrap_or(self.zeros[0])); + } + let span = 1usize << level; + if index * span >= self.leaves.len() { + return Ok(self.zeros[level]); + } + let left = self.node(level - 1, index * 2)?; + let right = self.node(level - 1, index * 2 + 1)?; + hash_node(left, right) + } + + pub fn root(&self) -> Result { + self.node(TREE_DEPTH, 0) + } + + /// Builds the membership path for a previously inserted leaf. + pub fn proof(&self, leaf_index: u64) -> Result { + if leaf_index as usize >= self.leaves.len() { + return Err(MirrorError::LeafIndexOutOfRange); + } + let mut siblings = [Field::ZERO; TREE_DEPTH]; + let mut index = leaf_index as usize; + for (level, slot) in siblings.iter_mut().enumerate() { + *slot = self.node(level, index ^ 1)?; + index >>= 1; + } + Ok(MerkleProof { + leaf_index, + siblings, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn f(v: u64) -> Field { + Field::from_u64(v) + } + + #[test] + fn an_empty_frontier_and_an_empty_tree_share_a_root() { + let frontier = Frontier::new().unwrap(); + let tree = MerkleTree::new().unwrap(); + assert_eq!(frontier.root(), tree.root().unwrap()); + assert_eq!(frontier.root(), zero_ladder().unwrap()[TREE_DEPTH]); + } + + /// The constant is only safe because of this test. If the hash function, + /// its parameters, or the endianness ever change, the baked ladder becomes + /// silently wrong — every root would be computed against empty subtrees that + /// no longer exist, and deposits would still succeed while no proof could + /// ever verify. This catches that at build time instead. + #[test] + fn the_baked_ladder_matches_the_computed_one() { + let computed = zero_ladder().unwrap(); + let baked = baked_ladder().unwrap(); + for level in 0..=TREE_DEPTH { + assert_eq!( + computed[level], baked[level], + "ZERO_LADDER is stale at level {level}; regenerate it" + ); + } + } + + #[test] + fn the_baked_ladder_entries_are_canonical_field_elements() { + // A non-canonical constant would be rejected by the Poseidon syscall at + // runtime, on-chain, with no useful diagnostic. + for (level, bytes) in ZERO_LADDER.iter().enumerate() { + assert!( + Field::from_bytes(*bytes).is_ok(), + "ZERO_LADDER[{level}] is not a canonical field element" + ); + } + } + + #[test] + fn the_zero_ladder_climbs() { + let z = zero_ladder().unwrap(); + assert_eq!(z[0], Field::ZERO); + for i in 1..=TREE_DEPTH { + assert_eq!(z[i], hash_node(z[i - 1], z[i - 1]).unwrap()); + assert_ne!(z[i], z[i - 1], "level {i} collapsed"); + } + } + + /// The assertion that connects the two halves: the on-chain accumulator and + /// a host-generated proof must agree after a real sequence of deposits, not + /// after a fixture root is injected. Without this test the two can drift + /// apart indefinitely with every other test still passing. + #[test] + fn the_frontier_root_accepts_a_host_generated_proof() { + let mut frontier = Frontier::new().unwrap(); + let mut tree = MerkleTree::new().unwrap(); + + let leaves: Vec = (1..=9u64).map(f).collect(); + for leaf in &leaves { + let a = frontier.insert(*leaf).unwrap(); + let b = tree.insert(*leaf).unwrap(); + assert_eq!(a, b, "the two views disagree on leaf index"); + assert_eq!( + frontier.root(), + tree.root().unwrap(), + "roots diverged after {} insertions", + a + 1 + ); + } + + // Every leaf's path must fold to the accumulator's current root. + for (i, leaf) in leaves.iter().enumerate() { + let proof = tree.proof(i as u64).unwrap(); + assert_eq!( + proof.fold(*leaf).unwrap(), + frontier.root(), + "path for leaf {i} does not reach the on-chain root" + ); + } + } + + #[test] + fn a_path_folded_against_the_wrong_leaf_misses_the_root() { + let mut frontier = Frontier::new().unwrap(); + let mut tree = MerkleTree::new().unwrap(); + for v in 1..=4u64 { + frontier.insert(f(v)).unwrap(); + tree.insert(f(v)).unwrap(); + } + let proof = tree.proof(2).unwrap(); + assert_eq!(proof.fold(f(3)).unwrap(), frontier.root()); + assert_ne!( + proof.fold(f(99)).unwrap(), + frontier.root(), + "a forged leaf must not reach the root" + ); + } + + #[test] + fn insertion_order_changes_the_root() { + let mut a = Frontier::new().unwrap(); + let mut b = Frontier::new().unwrap(); + a.insert(f(1)).unwrap(); + a.insert(f(2)).unwrap(); + b.insert(f(2)).unwrap(); + b.insert(f(1)).unwrap(); + assert_ne!(a.root(), b.root()); + } + + #[test] + fn a_proof_for_an_uninserted_leaf_is_refused() { + let tree = MerkleTree::new().unwrap(); + assert!(matches!( + tree.proof(0), + Err(MirrorError::LeafIndexOutOfRange) + )); + } + + #[test] + fn the_root_advances_on_every_insertion() { + let mut frontier = Frontier::new().unwrap(); + let mut seen = vec![frontier.root()]; + for v in 1..=8u64 { + frontier.insert(f(v)).unwrap(); + let root = frontier.root(); + assert!(!seen.contains(&root), "root repeated after inserting {v}"); + seen.push(root); + } + assert_eq!(frontier.len(), 8); + } +} diff --git a/crates/mirror-core/src/note.rs b/crates/mirror-core/src/note.rs new file mode 100644 index 00000000..4e0322a8 --- /dev/null +++ b/crates/mirror-core/src/note.rs @@ -0,0 +1,77 @@ +//! The note model. +//! +//! A note is the unit of membership. Depositing escrows exactly the pool's +//! denomination and inserts `commitment(k, r, denom_tag)` as a leaf. Spending +//! proves knowledge of `(k, r)` for some leaf and publishes `nullifier(k)`, +//! which the program records permanently. +//! +//! The denomination is a pool constant rather than a field inside the note, so +//! the escrowed lamports and the hidden commitment cannot disagree. Carrying the +//! amount inside the note is the obvious alternative and it is a trap: unless +//! the amount is bound into the commitment *and* checked against the escrow, a +//! depositor of one lamport withdraws the whole pool holding an entirely valid +//! proof. Here that state is not representable rather than merely rejected. + +use crate::{commitment, nullifier, Field, MirrorError}; + +/// A note's secret material. `k` is the nullifier preimage; `r` blinds the +/// commitment so that two notes with the same `k` are still distinct leaves. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Note { + pub k: Field, + pub r: Field, + pub denom_tag: Field, +} + +impl Note { + pub fn new(k: Field, r: Field, denom_tag: Field) -> Self { + Note { k, r, denom_tag } + } + + /// The Merkle leaf for this note. + pub fn commitment(&self) -> Result { + commitment(self.k, self.r, self.denom_tag) + } + + /// The nullifier published when this note is spent. + pub fn nullifier(&self) -> Result { + nullifier(self.k) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn f(v: u64) -> Field { + Field::from_u64(v) + } + + #[test] + fn blinding_makes_two_notes_with_one_nullifier_preimage_distinct_leaves() { + let a = Note::new(f(1), f(10), f(100)); + let b = Note::new(f(1), f(11), f(100)); + assert_ne!(a.commitment().unwrap(), b.commitment().unwrap()); + // ...but they share a nullifier, so only one of them is ever spendable. + // That is the depositor's own mistake to make, and it costs them a note + // rather than costing the pool anything. + assert_eq!(a.nullifier().unwrap(), b.nullifier().unwrap()); + } + + #[test] + fn the_nullifier_does_not_reveal_the_commitment() { + let n = Note::new(f(7), f(8), f(9)); + assert_ne!(n.nullifier().unwrap(), n.commitment().unwrap()); + } + + #[test] + fn a_note_is_bound_to_one_denomination() { + let a = Note::new(f(1), f(2), f(1)); + let b = Note::new(f(1), f(2), f(2)); + assert_ne!( + a.commitment().unwrap(), + b.commitment().unwrap(), + "a note minted in the 0.1 SOL pool must not be a valid leaf in the 10 SOL pool" + ); + } +} diff --git a/crates/mirror-provenance/Cargo.toml b/crates/mirror-provenance/Cargo.toml new file mode 100644 index 00000000..5b8be849 --- /dev/null +++ b/crates/mirror-provenance/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "mirror-provenance" +version.workspace = true +edition.workspace = true +# Not published to crates.io: these crates are built from this repository, and a +# registry copy would be a second source of truth for the same code. +publish = false +license.workspace = true + +[dependencies] +anyhow.workspace = true +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +ureq.workspace = true diff --git a/crates/mirror-provenance/src/bootstrap.rs b/crates/mirror-provenance/src/bootstrap.rs new file mode 100644 index 00000000..f0705961 --- /dev/null +++ b/crates/mirror-provenance/src/bootstrap.rs @@ -0,0 +1,440 @@ +//! Sampling error for `ρ`, by bootstrap over members. +//! +//! Every run so far has reported `ρ` as a point estimate with an *unresolved +//! bracket* beside it. Those are two different uncertainties, and only one of +//! them was quantified. +//! +//! * The **bracket** answers: what if the members we could not resolve had +//! landed in one class, or in classes of their own? It is a bound, not a +//! distribution, and it is computed exactly. +//! * The **bootstrap here** answers: we drew *these* depositors out of a much +//! larger population — how much of `ρ` is the draw? Resampling the resolved +//! members with replacement and recomputing `ρ` each time gives a percentile +//! interval for that. +//! +//! Both are needed and neither substitutes for the other. Comparing two +//! populations without the second one is eyeballing two numbers and calling the +//! larger one larger, which is precisely the move this project criticises +//! elsewhere. +//! +//! ## What this does not fix +//! +//! **Plug-in entropy is biased downward at small `n`.** Estimating `H(C)` by +//! counting is a maximum-likelihood estimate, and it systematically understates +//! entropy when classes are many and members are few — which is exactly the +//! regime every run here operates in. A bootstrap resamples the same estimator, +//! so its interval is centred on the *biased* value: it measures the spread of +//! the estimate, not its distance from the truth. Since `ρ = 2^{−H(C)}`, +//! understated entropy means **overstated ρ**, so the true loss factor is +//! plausibly smaller than any number reported here. +//! +//! Correcting that needs a different estimator — Miller–Madow, or one of the +//! coverage-adjusted families — and this crate does not implement one. The +//! consequence is stated wherever a `ρ` appears rather than left for a reader to +//! infer, and it applies **in the same direction to every population measured**, +//! which is what keeps a comparison between two of them meaningful even while +//! each is individually biased. + +use crate::metrics::Anonymity; +use std::collections::BTreeMap; + +/// A deterministic splitmix64. +/// +/// Deliberately not an external RNG. `analyze` is a pure, offline, reproducible +/// pass: anyone holding a committed sample must be able to recompute every +/// published figure and get the same bytes, and that includes the interval. A +/// seeded generator implemented here is reproducible across platforms and +/// dependency versions in a way that "whatever `rand` does this year" is not. +struct SplitMix64 { + state: u64, +} + +impl SplitMix64 { + fn new(seed: u64) -> Self { + SplitMix64 { state: seed } + } + + fn next_u64(&mut self) -> u64 { + self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15); + let mut z = self.state; + z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + z ^ (z >> 31) + } + + /// Uniform on `0..n`, rejecting the biased tail rather than taking a modulus + /// over it. + fn below(&mut self, n: u64) -> u64 { + debug_assert!(n > 0); + let zone = u64::MAX - (u64::MAX % n); + loop { + let v = self.next_u64(); + if v < zone { + return v % n; + } + } + } +} + +/// The spread of the resampled estimator, and the estimate it was resampled +/// from. +/// +/// **This is not a confidence interval around `point`, and it is not guaranteed +/// to contain it.** It is the 2.5th-to-97.5th percentile range of `ρ̂` computed +/// over bootstrap replicates. For a statistic that is biased under resampling — +/// and `ρ` badly is, see [`Interval::resampling_bias`] — the whole range can sit +/// to one side of the original estimate. Reading it as "ρ is somewhere in here" +/// is wrong; it says "an estimate computed this way, from a sample like this one, +/// lands in here". +#[derive(Debug, Clone, PartialEq)] +pub struct Interval { + /// The estimate computed from the sample as drawn. + pub point: f64, + pub lo: f64, + pub hi: f64, + /// Mean of the bootstrap replicates. Its distance from `point` is the + /// resampling bias. + pub mean: f64, + pub replicates: usize, +} + +impl Interval { + /// Whether the interval excludes zero, for a difference between two + /// populations. + /// + /// Meaningless for a single `ρ`, which is positive by construction. + pub fn excludes_zero(&self) -> bool { + self.lo > 0.0 || self.hi < 0.0 + } + + pub fn width(&self) -> f64 { + self.hi - self.lo + } + + /// How far resampling moves the estimator, `mean − point`. + /// + /// For `ρ` this is systematically **positive** under a heavy tail, and the + /// mechanism is worth understanding because it is not noise. Resampling `n` + /// members with replacement leaves roughly `1/e` of them unpicked, so classes + /// represented by a single member vanish from a replicate about 37% of the + /// time. Fewer classes means lower `H(C)` means higher `ρ = 2^{−H(C)}`. + /// + /// The size of this bias is therefore a **tail diagnostic**: a population + /// whose classes are mostly singletons shows a large one, and a population + /// with a few crowded classes shows almost none. + pub fn resampling_bias(&self) -> f64 { + self.mean - self.point + } + + /// Whether the original estimate falls inside the resampled range at all. + /// + /// False is not an error. It means the resampling bias exceeds the spread, + /// which is a real and reportable property of a heavy-tailed population — + /// not a sign that the interval was computed wrongly. + pub fn contains_point(&self) -> bool { + self.lo <= self.point && self.point <= self.hi + } +} + +/// Default replicate count. Enough that the 2.5th and 97.5th percentiles are +/// stable to about three decimals, and cheap: each replicate is O(n). +pub const DEFAULT_REPLICATES: usize = 10_000; + +/// The fixed seed every published interval is computed at. +/// +/// Published rather than arbitrary, so a reader recomputing the number gets our +/// number and not merely a similar one. +pub const DEFAULT_SEED: u64 = 0x6D69_7272_6F72_0501; + +fn class_indices(labels: &[L]) -> Vec { + let mut index: BTreeMap = BTreeMap::new(); + let mut out = Vec::with_capacity(labels.len()); + for l in labels { + let next = index.len(); + let id = *index.entry(l.clone()).or_insert(next); + out.push(id); + } + out +} + +/// One bootstrap replicate: resample `n` members with replacement and recompute +/// the loss factor. +fn replicate(members: &[usize], classes: usize, rng: &mut SplitMix64) -> Option { + let n = members.len(); + let mut counts = vec![0u64; classes]; + for _ in 0..n { + let pick = members[rng.below(n as u64) as usize]; + counts[pick] += 1; + } + // A class that no resampled member landed in is absent from this replicate, + // not a class of size zero. `Anonymity` rejects a zero, correctly. + let sizes: Vec = counts.into_iter().filter(|&c| c > 0).collect(); + Anonymity::from_class_sizes(&sizes).map(|a| a.loss_factor) +} + +fn percentile(sorted: &[f64], q: f64) -> f64 { + if sorted.is_empty() { + return f64::NAN; + } + let idx = (q * (sorted.len() - 1) as f64).round() as usize; + sorted[idx.min(sorted.len() - 1)] +} + +/// A 95% percentile interval for `ρ` over the draw of members. +/// +/// `labels` is one class label per **resolved** member. Unresolved members are +/// not represented: they are the bracket's business, not this one's. +pub fn loss_factor_interval( + labels: &[L], + replicates: usize, + seed: u64, +) -> Option { + let point = Anonymity::from_labels(labels)?.loss_factor; + let members = class_indices(labels); + let classes = members.iter().copied().max().map(|m| m + 1)?; + + let mut rng = SplitMix64::new(seed); + let mut draws: Vec = Vec::with_capacity(replicates); + for _ in 0..replicates { + if let Some(r) = replicate(&members, classes, &mut rng) { + draws.push(r); + } + } + if draws.is_empty() { + return None; + } + draws.sort_by(|a, b| a.partial_cmp(b).expect("no NaN in a loss factor")); + + let mean = draws.iter().sum::() / draws.len() as f64; + Some(Interval { + point, + lo: percentile(&draws, 0.025), + hi: percentile(&draws, 0.975), + mean, + replicates: draws.len(), + }) +} + +/// The resampled spread of `ρ(a) − ρ(b)`. +/// +/// Each population is resampled independently within a replicate, which is the +/// right structure here: the two frames are drawn from different populations and +/// share no members. +/// +/// If the interval contains zero, the two are **not** distinguishable at this +/// sample size, and reporting one as more concentrated than the other would be +/// reporting noise. +pub fn difference_interval( + a: &[L], + b: &[L], + replicates: usize, + seed: u64, +) -> Option { + let point = Anonymity::from_labels(a)?.loss_factor - Anonymity::from_labels(b)?.loss_factor; + + let ma = class_indices(a); + let mb = class_indices(b); + let ca = ma.iter().copied().max().map(|m| m + 1)?; + let cb = mb.iter().copied().max().map(|m| m + 1)?; + + // One generator, drawn from alternately, so the pairing is reproducible and + // the two populations cannot accidentally share a stream position. + let mut rng = SplitMix64::new(seed); + let mut draws: Vec = Vec::with_capacity(replicates); + for _ in 0..replicates { + let ra = replicate(&ma, ca, &mut rng); + let rb = replicate(&mb, cb, &mut rng); + if let (Some(x), Some(y)) = (ra, rb) { + draws.push(x - y); + } + } + if draws.is_empty() { + return None; + } + draws.sort_by(|a, b| a.partial_cmp(b).expect("no NaN in a loss factor")); + + let mean = draws.iter().sum::() / draws.len() as f64; + Some(Interval { + point, + lo: percentile(&draws, 0.025), + hi: percentile(&draws, 0.975), + mean, + replicates: draws.len(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn labels(spec: &[(&str, usize)]) -> Vec { + let mut out = Vec::new(); + for (name, n) in spec { + for _ in 0..*n { + out.push((*name).to_string()); + } + } + out + } + + /// One class means no uncertainty: every resample is the same population, + /// so the interval must collapse onto the point. + #[test] + fn a_single_class_has_no_sampling_spread() { + let l = labels(&[("cex:binance", 40)]); + let i = loss_factor_interval(&l, 500, DEFAULT_SEED).unwrap(); + assert_eq!(i.point, 1.0); + assert_eq!(i.lo, 1.0); + assert_eq!(i.hi, 1.0); + } + + /// With crowded classes, resampling barely moves the estimator and the + /// range does contain it. + #[test] + fn a_crowded_population_resamples_around_its_estimate() { + let l = labels(&[("a", 20), ("b", 10), ("c", 5), ("d", 5)]); + let i = loss_factor_interval(&l, 2_000, DEFAULT_SEED).unwrap(); + assert!( + i.contains_point(), + "point {} outside [{}, {}]", + i.point, + i.lo, + i.hi + ); + assert!( + i.resampling_bias().abs() < 0.05, + "crowded classes should barely shift: bias {}", + i.resampling_bias() + ); + } + + /// The case that caught a false assumption of ours, kept as a test so it + /// cannot be re-assumed. + /// + /// An earlier version asserted that the range always contains the point + /// estimate. It does not, and the reason is not a bug: under a heavy tail, + /// resampling drops singleton classes about 37% of the time, which lowers + /// `H(C)` and therefore raises `ρ` in nearly every replicate. The whole + /// range then sits *above* the original estimate. + /// + /// This is why the type is documented as the spread of the resampled + /// estimator rather than as a confidence interval, and why the bias is + /// reported next to it instead of being hidden inside it. + #[test] + fn a_heavy_tail_shifts_the_whole_range_above_the_estimate() { + // Thirty members, almost all alone: the regime every real run is in. + let mut spec: Vec<(String, usize)> = vec![("crowd".to_string(), 6)]; + for i in 0..24 { + spec.push((format!("solo{i}"), 1)); + } + let l: Vec = spec + .iter() + .flat_map(|(n, c)| std::iter::repeat_n(n.clone(), *c)) + .collect(); + + let i = loss_factor_interval(&l, 4_000, DEFAULT_SEED).unwrap(); + assert!( + i.resampling_bias() > 0.0, + "a heavy tail must bias rho upward under resampling, got {}", + i.resampling_bias() + ); + assert!( + !i.contains_point(), + "expected the range to sit off the point under this tail: \ + point {} in [{}, {}]", + i.point, + i.lo, + i.hi + ); + } + + /// `analyze` is a pure pass and its output is a published number. The same + /// sample and the same seed must produce the same interval, byte for byte. + #[test] + fn the_interval_is_reproducible_from_its_seed() { + let l = labels(&[("a", 12), ("b", 9), ("c", 4), ("d", 1)]); + let x = loss_factor_interval(&l, 1_000, DEFAULT_SEED).unwrap(); + let y = loss_factor_interval(&l, 1_000, DEFAULT_SEED).unwrap(); + assert_eq!(x, y); + let z = loss_factor_interval(&l, 1_000, DEFAULT_SEED ^ 1).unwrap(); + assert_ne!(x.lo, z.lo, "a different seed must actually resample"); + } + + /// Fewer members must mean a wider interval. If this ever inverts, the + /// resampling is not resampling. + #[test] + fn a_smaller_sample_gives_a_wider_interval() { + let big = labels(&[("a", 40), ("b", 30), ("c", 20), ("d", 10)]); + let small = labels(&[("a", 4), ("b", 3), ("c", 2), ("d", 1)]); + let wide = loss_factor_interval(&small, 4_000, DEFAULT_SEED).unwrap(); + let tight = loss_factor_interval(&big, 4_000, DEFAULT_SEED).unwrap(); + assert!( + wide.width() > tight.width(), + "small sample width {} not wider than large sample width {}", + wide.width(), + tight.width() + ); + } + + /// Two populations that differ starkly must separate; the interval on the + /// difference must exclude zero. + #[test] + fn a_stark_difference_separates() { + // One concentrated population and one spread population. + let concentrated = labels(&[("a", 38), ("b", 1), ("c", 1)]); + let spread = labels(&[("a", 8), ("b", 8), ("c", 8), ("d", 8), ("e", 8)]); + let d = difference_interval(&concentrated, &spread, 4_000, DEFAULT_SEED).unwrap(); + assert!( + d.point > 0.0, + "concentrated must have the higher loss factor" + ); + assert!( + d.excludes_zero(), + "a stark difference must separate: [{}, {}]", + d.lo, + d.hi + ); + } + + /// The case that matters most, and the one a careless comparison gets + /// wrong: two samples drawn from the *same* shape must NOT separate. + /// + /// Without this the tool would report every pair of populations as + /// different, which is the failure mode of comparing point estimates. + #[test] + fn two_samples_of_the_same_shape_do_not_separate() { + let a = labels(&[("a", 10), ("b", 6), ("c", 3), ("d", 1)]); + let b = labels(&[("w", 10), ("x", 6), ("y", 3), ("z", 1)]); + let d = difference_interval(&a, &b, 4_000, DEFAULT_SEED).unwrap(); + assert!( + !d.excludes_zero(), + "identically shaped populations must not separate: [{}, {}]", + d.lo, + d.hi + ); + } + + /// The generator must be uniform enough that it does not itself bias the + /// interval. A modulus over the full range would fail this at large n. + #[test] + fn the_generator_is_uniform_over_its_range() { + let mut rng = SplitMix64::new(DEFAULT_SEED); + let buckets = 7u64; + let draws = 70_000; + let mut counts = vec![0usize; buckets as usize]; + for _ in 0..draws { + counts[rng.below(buckets) as usize] += 1; + } + let expected = draws as f64 / buckets as f64; + for (i, &c) in counts.iter().enumerate() { + let dev = (c as f64 - expected).abs() / expected; + assert!(dev < 0.05, "bucket {i} deviates {:.3} from uniform", dev); + } + } + + #[test] + fn an_empty_population_yields_nothing() { + let empty: Vec = Vec::new(); + assert!(loss_factor_interval(&empty, 100, DEFAULT_SEED).is_none()); + } +} diff --git a/crates/mirror-provenance/src/classify.rs b/crates/mirror-provenance/src/classify.rs new file mode 100644 index 00000000..226f31e0 --- /dev/null +++ b/crates/mirror-provenance/src/classify.rs @@ -0,0 +1,503 @@ +//! The five terminal rules, applied over a complete fact set. +//! +//! Order is R1, R2, R3, R5, R4 — and R4 is deliberately last rather than fourth +//! as the methodology table lists it. R4 is the only rule that does not name +//! anything: it produces `busy-unlabelled`, which the methodology is explicit is +//! **not an attributable origin**. So any rule that can name an entity must get +//! the chance first, and R4 is the residual for "busy, and we could not say +//! what". Evaluating it before R5 would relabel a demonstrable distributor as an +//! anonymous hub, discarding information we already paid for. +//! +//! The rule that fired is carried in the outcome, so each can be ablated in a +//! sensitivity table rather than trusted as a block. + +use crate::{ + facts::AddressFacts, + outcome::{Outcome, TerminalRule}, + rpc::SYSTEM_PROGRAM, +}; +use std::collections::{BTreeMap, BTreeSet}; + +/// Thresholds, all configurable and all reported in the run manifest. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Thresholds { + /// Lifetime signatures at or above which an address is a volume hub. + /// + /// Deliberately far below the paging cap, and the two must never be the + /// same constant. They sound like the same question — "how many signatures + /// do we care about" — but setting the hub threshold equal to the RPC page + /// limit makes "is a hub" mean "hit the page cap", which admits every DEX + /// program and bot while excluding a genuine exchange withdrawal address + /// with 800 transactions. + pub hub_signatures: u64, + /// Minimum account age for the hub rule, in seconds. A young address with + /// many transactions is a bot or an airdrop, not an origin. + pub hub_min_age_seconds: i64, + /// Distinct addresses an account must have created to be a distributor. + pub distributor_fanout: usize, + /// Members a fee-payer cluster needs before it counts as structural. + pub cluster_min_size: usize, +} + +impl Default for Thresholds { + fn default() -> Self { + Thresholds { + hub_signatures: 5_000, + hub_min_age_seconds: 30 * 24 * 3_600, + distributor_fanout: 20, + cluster_min_size: 3, + } + } +} + +/// The curated anchor set: addresses whose operator is known by name. +#[derive(Debug, Clone, Default)] +pub struct AnchorSet { + entries: BTreeMap, +} + +impl AnchorSet { + pub fn from_pairs, V: Into>( + pairs: impl IntoIterator, + ) -> Self { + AnchorSet { + entries: pairs + .into_iter() + .map(|(k, v)| (k.into(), v.into())) + .collect(), + } + } + + pub fn name_of(&self, address: &str) -> Option<&str> { + self.entries.get(address).map(|s| s.as_str()) + } + + pub fn len(&self) -> usize { + self.entries.len() + } + + pub fn is_empty(&self) -> bool { + self.entries.is_empty() + } +} + +/// Set-level structure derived once from the complete fact set. +/// +/// Built in one pass over everything collected, so membership never depends on +/// the order addresses were visited in. +#[derive(Debug, Clone, Default)] +pub struct SetStructure { + /// address -> canonical cluster id, for clusters at or above the threshold. + cluster_of: BTreeMap, +} + +impl SetStructure { + /// Groups addresses by shared fee payer and keeps groups large enough to be + /// structural. + /// + /// The cluster id is the lexicographically smallest member, so it does not + /// depend on iteration order or on which member was seen first. + pub fn build(facts: &BTreeMap, thresholds: &Thresholds) -> Self { + let mut by_payer: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new(); + for f in facts.values() { + for payer in &f.fee_payers { + by_payer + .entry(payer.as_str()) + .or_default() + .insert(f.address.as_str()); + } + } + + let mut cluster_of = BTreeMap::new(); + for members in by_payer.values() { + if members.len() < thresholds.cluster_min_size { + continue; + } + let canonical = members + .iter() + .min() + .expect("non-empty by construction") + .to_string(); + for m in members { + // A member already in a cluster keeps the smaller id, so + // overlapping payer groups resolve deterministically. + cluster_of + .entry(m.to_string()) + .and_modify(|existing: &mut String| { + if canonical < *existing { + *existing = canonical.clone(); + } + }) + .or_insert_with(|| canonical.clone()); + } + } + SetStructure { cluster_of } + } + + pub fn cluster_of(&self, address: &str) -> Option<&str> { + self.cluster_of.get(address).map(|s| s.as_str()) + } +} + +/// Applies the terminal rules to one address. +pub struct Classifier<'a> { + pub anchors: &'a AnchorSet, + pub structure: &'a SetStructure, + pub thresholds: &'a Thresholds, + /// Wall time the classification is relative to, for the age test. Passed in + /// rather than read from the clock so a replay reproduces exactly. + pub now: i64, +} + +impl Classifier<'_> { + /// Whether `facts` terminates a trace, and under which rule. + pub fn classify(&self, facts: &AddressFacts) -> Option { + // R1 — a program or PDA. Definitional and cheap, and the only thing that + // separates "funded by a protocol vault" from "funded by a person". + // Without it, one exchange hot wallet and one AMM vault land in the same + // class, and the class distribution the headline is computed over is wrong + // in a direction nothing downstream can detect. + if let Some(owner) = &facts.owner { + if owner != SYSTEM_PROGRAM || facts.executable { + return Some(Outcome::Terminal { + rule: TerminalRule::ProgramOrPda, + label: format!("program:{}", facts.address), + }); + } + } + + // R2 — a named operator. + if let Some(name) = self.anchors.name_of(&facts.address) { + return Some(Outcome::Terminal { + rule: TerminalRule::CuratedAnchor, + label: format!("entity:{name}"), + }); + } + + // R3 — a fee-payer cluster large enough to be structural. + if let Some(id) = self.structure.cluster_of(&facts.address) { + return Some(Outcome::Terminal { + rule: TerminalRule::StructuralCluster, + label: format!("cluster:{id}"), + }); + } + + // R5 — created many distinct addresses. Evaluated before R4 because it + // names a role and R4 does not. + let distinct_funded: BTreeSet<&str> = facts.funded.iter().map(|s| s.as_str()).collect(); + if distinct_funded.len() >= self.thresholds.distributor_fanout { + return Some(Outcome::Terminal { + rule: TerminalRule::Distributor, + label: format!("distributor:{}", facts.address), + }); + } + + // R4 — busy and old, but unnamed. The label says so, and it must never + // be described as an attributable origin. + let old_enough = facts + .age_seconds(self.now) + .is_some_and(|age| age >= self.thresholds.hub_min_age_seconds); + if facts.signatures.lower_bound() >= self.thresholds.hub_signatures && old_enough { + return Some(Outcome::Terminal { + rule: TerminalRule::VolumeHub, + label: format!("busy-unlabelled:{}", facts.address), + }); + } + + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::facts::SigCount; + + const NOW: i64 = 1_800_000_000; + const OLD: i64 = NOW - 400 * 24 * 3_600; + const YOUNG: i64 = NOW - 3 * 24 * 3_600; + + fn wallet(address: &str) -> AddressFacts { + let mut f = AddressFacts::new(address); + f.owner = Some(SYSTEM_PROGRAM.to_string()); + f + } + + struct Env { + anchors: AnchorSet, + structure: SetStructure, + thresholds: Thresholds, + } + + impl Env { + fn new() -> Self { + Env { + anchors: AnchorSet::from_pairs([("BinanceHot1", "binance")]), + structure: SetStructure::default(), + thresholds: Thresholds::default(), + } + } + fn classify(&self, f: &AddressFacts) -> Option { + Classifier { + anchors: &self.anchors, + structure: &self.structure, + thresholds: &self.thresholds, + now: NOW, + } + .classify(f) + } + } + + #[test] + fn r1_catches_a_program() { + let env = Env::new(); + let mut f = wallet("SomeProgram"); + f.owner = Some("BPFLoaderUpgradeab1e11111111111111111111111".into()); + f.executable = true; + let out = env.classify(&f).unwrap(); + assert!(matches!( + out, + Outcome::Terminal { + rule: TerminalRule::ProgramOrPda, + .. + } + )); + assert_eq!(out.label().unwrap(), "program:SomeProgram"); + } + + #[test] + fn r1_catches_a_pda_that_is_not_executable() { + // A PDA owned by a program is not a person's wallet even though it runs + // no code. This is what distinguishes "funded by a vault" from "funded + // by someone". + let env = Env::new(); + let mut f = wallet("SomeVault"); + f.owner = Some("Whirlpoo1111111111111111111111111111111111".into()); + f.executable = false; + assert!(matches!( + env.classify(&f).unwrap(), + Outcome::Terminal { + rule: TerminalRule::ProgramOrPda, + .. + } + )); + } + + #[test] + fn a_plain_wallet_is_not_terminal_on_r1() { + let env = Env::new(); + assert!(env.classify(&wallet("JustAWallet")).is_none()); + } + + #[test] + fn an_account_that_does_not_exist_is_not_called_a_program() { + // owner is None: the account is absent, which we do not know how to + // classify. Treating absence as "not system-owned" would label every + // closed account a program. + let env = Env::new(); + let mut f = AddressFacts::new("Gone"); + f.owner = None; + assert!(env.classify(&f).is_none()); + } + + #[test] + fn r2_names_a_curated_anchor() { + let env = Env::new(); + let out = env.classify(&wallet("BinanceHot1")).unwrap(); + assert_eq!(out.label().unwrap(), "entity:binance"); + } + + #[test] + fn r3_groups_addresses_that_share_a_fee_payer() { + let mut facts = BTreeMap::new(); + for a in ["zebra", "alpha", "mango"] { + let mut f = wallet(a); + f.fee_payers = vec!["Sweeper1".into()]; + facts.insert(a.to_string(), f); + } + let thresholds = Thresholds::default(); + let structure = SetStructure::build(&facts, &thresholds); + + // The canonical id is the smallest member, so it does not depend on the + // order addresses were collected in. + assert_eq!(structure.cluster_of("zebra"), Some("alpha")); + assert_eq!(structure.cluster_of("mango"), Some("alpha")); + + let env = Env { + anchors: AnchorSet::default(), + structure, + thresholds, + }; + let out = env.classify(&facts["zebra"]).unwrap(); + assert_eq!(out.label().unwrap(), "cluster:alpha"); + } + + #[test] + fn a_fee_payer_group_below_the_threshold_is_not_a_cluster() { + let mut facts = BTreeMap::new(); + for a in ["one", "two"] { + let mut f = wallet(a); + f.fee_payers = vec!["Payer1".into()]; + facts.insert(a.to_string(), f); + } + let structure = SetStructure::build(&facts, &Thresholds::default()); + assert!( + structure.cluster_of("one").is_none(), + "two is below the floor of three" + ); + } + + #[test] + fn r5_catches_a_distributor_and_counts_distinct_addresses_only() { + let env = Env::new(); + let mut f = wallet("Fanout1"); + // Twenty entries but only five distinct: not a distributor. + f.funded = (0..20).map(|i| format!("child{}", i % 5)).collect(); + assert!(env.classify(&f).is_none(), "repeats must not count"); + + f.funded = (0..20).map(|i| format!("child{i}")).collect(); + let out = env.classify(&f).unwrap(); + assert!(matches!( + out, + Outcome::Terminal { + rule: TerminalRule::Distributor, + .. + } + )); + } + + #[test] + fn r4_needs_both_volume_and_age() { + let env = Env::new(); + let mut f = wallet("Busy1"); + f.signatures = SigCount::AtLeast(20_000); + + f.first_seen = Some(YOUNG); + assert!( + env.classify(&f).is_none(), + "a young address with many transactions is a bot, not an origin" + ); + + f.first_seen = Some(OLD); + let out = env.classify(&f).unwrap(); + assert!(matches!( + out, + Outcome::Terminal { + rule: TerminalRule::VolumeHub, + .. + } + )); + assert_eq!(out.label().unwrap(), "busy-unlabelled:Busy1"); + } + + /// The distinction that is easiest to collapse and most costly to lose: a + /// busy address is not an attributable origin, and its label must never + /// read like one. + #[test] + fn a_volume_hub_is_labelled_as_unnamed() { + let env = Env::new(); + let mut f = wallet("Busy2"); + f.signatures = SigCount::Exact(9_000); + f.first_seen = Some(OLD); + let label = env.classify(&f).unwrap().label().unwrap().to_string(); + assert!(label.starts_with("busy-unlabelled:")); + assert!(!label.starts_with("entity:")); + } + + /// The hub threshold must be reachable well inside the paging budget, or + /// "is a hub" degenerates into "we stopped looking". + #[test] + fn the_hub_threshold_is_decoupled_from_the_page_cap() { + let t = Thresholds::default(); + assert!( + t.hub_signatures < 20_000, + "the threshold must be reachable before paging stops, not equal to it" + ); + assert!( + t.hub_signatures > 1_000, + "and above a single page, or ordinary wallets qualify" + ); + } + + #[test] + fn a_named_entity_beats_an_anonymous_hub() { + // Both rules fire. The one that names something must win, or we discard + // information we already paid an RPC call for. + let env = Env::new(); + let mut f = wallet("BinanceHot1"); + f.signatures = SigCount::AtLeast(50_000); + f.first_seen = Some(OLD); + assert_eq!(env.classify(&f).unwrap().label().unwrap(), "entity:binance"); + } + + #[test] + fn a_distributor_beats_an_anonymous_hub() { + let env = Env::new(); + let mut f = wallet("Distrib1"); + f.signatures = SigCount::AtLeast(50_000); + f.first_seen = Some(OLD); + f.funded = (0..40).map(|i| format!("child{i}")).collect(); + assert!(matches!( + env.classify(&f).unwrap(), + Outcome::Terminal { + rule: TerminalRule::Distributor, + .. + } + )); + } + + #[test] + fn rule_precedence_is_total_and_stable() { + // Every rule fires at once; R1 must win, and the result must not depend + // on anything but the rule order. + let mut facts = BTreeMap::new(); + for a in ["aaa", "bbb", "ccc"] { + let mut f = wallet(a); + f.fee_payers = vec!["Payer1".into()]; + facts.insert(a.to_string(), f); + } + let thresholds = Thresholds::default(); + let structure = SetStructure::build(&facts, &thresholds); + + let mut everything = wallet("aaa"); + everything.owner = Some("SomeProgram11111111111111111111111111111111".into()); + everything.fee_payers = vec!["Payer1".into()]; + everything.funded = (0..50).map(|i| format!("c{i}")).collect(); + everything.signatures = SigCount::AtLeast(99_999); + everything.first_seen = Some(OLD); + + let env = Env { + anchors: AnchorSet::from_pairs([("aaa", "someexchange")]), + structure, + thresholds, + }; + assert!(matches!( + env.classify(&everything).unwrap(), + Outcome::Terminal { + rule: TerminalRule::ProgramOrPda, + .. + } + )); + } + + #[test] + fn classification_is_independent_of_collection_order() { + // The same addresses inserted in two different orders must produce the + // same clusters and therefore the same labels. This is the property the + // two-pass split exists to guarantee. + let build = |order: &[&str]| { + let mut facts = BTreeMap::new(); + for a in order { + let mut f = wallet(a); + f.fee_payers = vec!["P".into()]; + facts.insert(a.to_string(), f); + } + SetStructure::build(&facts, &Thresholds::default()) + }; + let a = build(&["delta", "alpha", "charlie"]); + let b = build(&["charlie", "delta", "alpha"]); + for addr in ["alpha", "charlie", "delta"] { + assert_eq!(a.cluster_of(addr), b.cluster_of(addr)); + } + } +} diff --git a/crates/mirror-provenance/src/edge.rs b/crates/mirror-provenance/src/edge.rs new file mode 100644 index 00000000..1252d986 --- /dev/null +++ b/crates/mirror-provenance/src/edge.rs @@ -0,0 +1,249 @@ +//! Funding-edge extraction from a transaction's balance deltas. +//! +//! We diff `preBalances` against `postBalances` rather than parsing +//! instructions. Parsing `program == "system" && type == "transfer"` misses +//! every program that moves lamports by direct account mutation and emits no +//! transfer instruction at all, plus `createAccount`, +//! `createAccountWithSeed`, `transferWithSeed`, `withdrawNonceAccount`, and +//! `closeAccount` lamport returns. A tracer built on instruction parsing is +//! blind to all of it and reports the resulting gaps as "unresolved". +//! +//! Balance deltas see value movement regardless of how it was caused, which is +//! the property we actually want. +//! +//! ```text +//! Δ_i = postBalances[i] − preBalances[i] + (fee if i == 0) +//! sources = { i : Δ_i < 0 } sinks = { i : Δ_i > 0 } +//! ``` +//! +//! The fee is added back for the payer so that paying for a transaction is not +//! mistaken for sending value. + +use serde::{Deserialize, Serialize}; + +/// A value movement observed in one transaction. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct FundingEdge { + /// The account credited. + pub sink: String, + /// Accounts debited. More than one means attribution within the transaction + /// is ambiguous. + pub sources: Vec, + /// Lamports credited to the sink. + pub value: u64, + pub signature: String, + pub slot: u64, + pub block_time: Option, + /// Set when several accounts were debited, so the true source of this + /// credit is one of a set rather than known. The rate of this is reported. + pub ambiguous_attribution: bool, +} + +/// The parts of a transaction we need. Deliberately a narrow projection: the +/// committed sample stores this rather than whole transactions, which keeps the +/// artifact small enough to publish and makes what we relied on explicit. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct TransactionView { + pub signature: String, + pub slot: u64, + pub block_time: Option, + /// The **fully resolved** key list. Under `jsonParsed`, lookup-table + /// addresses are folded into `accountKeys` and `preBalances`/`postBalances` + /// align with it, so no separate `loadedAddresses` handling is needed. This + /// is verified empirically; the RPC reference text implies otherwise. + pub account_keys: Vec, + pub pre_balances: Vec, + pub post_balances: Vec, + pub fee: u64, +} + +impl TransactionView { + /// Whether the balance arrays align with the resolved key list. + /// + /// A misalignment means we would attribute a delta to the wrong account, so + /// it is checked rather than assumed — this is exactly where a v0 + /// lookup-table transaction would silently poison the graph. + pub fn is_well_formed(&self) -> bool { + !self.account_keys.is_empty() + && self.pre_balances.len() == self.account_keys.len() + && self.post_balances.len() == self.account_keys.len() + } + + /// Signed lamport change per account, with the payer's fee added back. + pub fn deltas(&self) -> Option> { + if !self.is_well_formed() { + return None; + } + Some( + self.account_keys + .iter() + .enumerate() + .map(|(i, _)| { + let d = self.post_balances[i] as i128 - self.pre_balances[i] as i128; + if i == 0 { + d + self.fee as i128 + } else { + d + } + }) + .collect(), + ) + } + + /// The edge crediting `address`, if this transaction credits it. + pub fn edge_crediting(&self, address: &str) -> Option { + let deltas = self.deltas()?; + let index = self.account_keys.iter().position(|k| k == address)?; + let credited = deltas[index]; + if credited <= 0 { + return None; + } + + let sources: Vec = deltas + .iter() + .enumerate() + .filter(|(_, d)| **d < 0) + .map(|(i, _)| self.account_keys[i].clone()) + .collect(); + if sources.is_empty() { + return None; + } + + Some(FundingEdge { + sink: address.to_string(), + ambiguous_attribution: sources.len() > 1, + sources, + value: credited as u64, + signature: self.signature.clone(), + slot: self.slot, + block_time: self.block_time, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn tx(keys: &[&str], pre: &[u64], post: &[u64], fee: u64) -> TransactionView { + TransactionView { + signature: "sig".into(), + slot: 100, + block_time: Some(1_700_000_000), + account_keys: keys.iter().map(|s| s.to_string()).collect(), + pre_balances: pre.to_vec(), + post_balances: post.to_vec(), + fee, + } + } + + #[test] + fn a_simple_transfer_yields_one_source_and_one_sink() { + // Alice pays the fee and sends 1000 to Bob. + let t = tx(&["alice", "bob"], &[10_000, 0], &[8_995, 1_000], 5); + let edge = t.edge_crediting("bob").expect("bob was credited"); + assert_eq!(edge.value, 1_000); + assert_eq!(edge.sources, vec!["alice"]); + assert!(!edge.ambiguous_attribution); + } + + /// The fee must not make the payer look like a sender when it isn't one, + /// and must not hide a genuine send. + #[test] + fn the_payers_fee_is_added_back() { + // Alice pays a fee and moves nothing. Her delta is exactly zero, so she + // is neither a source nor a sink. + let t = tx(&["alice", "bob"], &[10_000, 500], &[9_995, 500], 5); + assert_eq!(t.deltas().unwrap()[0], 0); + assert!(t.edge_crediting("bob").is_none(), "bob gained nothing"); + } + + #[test] + fn a_program_moving_lamports_directly_is_still_seen() { + // No system-transfer instruction exists here — a program mutated + // lamports. Instruction parsing would find nothing; the delta is plain. + let t = tx( + &["payer", "vault", "recipient"], + &[1_000, 50_000, 0], + &[995, 40_000, 10_000], + 5, + ); + let edge = t.edge_crediting("recipient").unwrap(); + assert_eq!(edge.value, 10_000); + assert_eq!(edge.sources, vec!["vault"]); + } + + #[test] + fn several_debited_accounts_mark_the_attribution_ambiguous() { + let t = tx( + &["payer", "second", "recipient"], + &[10_000, 10_000, 0], + &[4_995, 5_000, 10_000], + 5, + ); + let edge = t.edge_crediting("recipient").unwrap(); + assert!( + edge.ambiguous_attribution, + "two sources means the true funder is one of a set, not known" + ); + assert_eq!(edge.sources.len(), 2); + } + + #[test] + fn an_account_that_lost_value_is_not_credited() { + let t = tx(&["alice", "bob"], &[10_000, 5_000], &[10_995, 4_000], 5); + assert!(t.edge_crediting("bob").is_none()); + assert!(t.edge_crediting("alice").is_some()); + } + + #[test] + fn an_address_absent_from_the_key_list_yields_nothing() { + let t = tx(&["alice", "bob"], &[10_000, 0], &[8_995, 1_000], 5); + assert!(t.edge_crediting("carol").is_none()); + } + + /// Misaligned balance arrays are refused rather than truncated. This is the + /// shape a mishandled v0 lookup-table transaction takes, and silently + /// zipping the shorter array would attribute deltas to the wrong accounts. + #[test] + fn misaligned_balances_are_refused() { + let mut t = tx(&["a", "b", "c"], &[1, 2, 3], &[1, 2, 3], 0); + t.post_balances.pop(); + assert!(!t.is_well_formed()); + assert!(t.deltas().is_none()); + assert!(t.edge_crediting("b").is_none()); + } + + #[test] + fn a_lookup_table_transaction_is_handled_when_keys_are_fully_resolved() { + // Twenty resolved keys, eleven from the transaction and nine from a + // lookup table, with balances aligned to the full list. + let keys: Vec = (0..20).map(|i| format!("key{i}")).collect(); + let mut pre = vec![1_000u64; 20]; + let mut post = vec![1_000u64; 20]; + pre[0] = 100_000; + post[0] = 89_995; + post[17] = 11_000; + let t = TransactionView { + signature: "v0sig".into(), + slot: 1, + block_time: None, + account_keys: keys, + pre_balances: pre, + post_balances: post, + fee: 5, + }; + assert!(t.is_well_formed()); + let edge = t + .edge_crediting("key17") + .expect("a lookup-table account was credited"); + assert_eq!(edge.value, 10_000); + assert_eq!(edge.sources, vec!["key0"]); + } + + #[test] + fn zero_value_credits_are_not_edges() { + let t = tx(&["a", "b"], &[10_000, 500], &[9_995, 500], 5); + assert!(t.edge_crediting("b").is_none()); + } +} diff --git a/crates/mirror-provenance/src/facts.rs b/crates/mirror-provenance/src/facts.rs new file mode 100644 index 00000000..0615c0fb --- /dev/null +++ b/crates/mirror-provenance/src/facts.rs @@ -0,0 +1,120 @@ +//! What collection observed about an address. +//! +//! Pass one fills these in from the chain; pass two classifies over the complete +//! set. The split exists for determinism: two of the five terminal rules depend +//! on the *whole* sample — cluster membership and fan-out are properties of a +//! set, not of an address — so classifying during traversal would make the +//! result depend on visit order. Collect, then classify, and the same sample +//! always yields the same partition. + +use crate::edge::FundingEdge; +use serde::{Deserialize, Serialize}; + +/// A lifetime signature count, which is often only a lower bound. +/// +/// Paging stops at a cap. When it is hit, the true count is unknown and larger +/// than what we saw, so the distinction is kept in the type rather than +/// flattened into a number that would later be read as exact. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum SigCount { + Exact(u64), + /// Paging hit the cap. The real count is at least this. + AtLeast(u64), +} + +impl SigCount { + /// The count as a lower bound, which is all either variant guarantees. + pub fn lower_bound(&self) -> u64 { + match self { + SigCount::Exact(n) | SigCount::AtLeast(n) => *n, + } + } + + pub fn is_exact(&self) -> bool { + matches!(self, SigCount::Exact(_)) + } +} + +/// Everything pass one recorded about one address. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct AddressFacts { + pub address: String, + /// Account owner. `None` means the account does not exist on chain, which + /// is different from an RPC failure and is recorded as such. + pub owner: Option, + pub executable: bool, + pub signatures: SigCount, + /// Block time of the oldest signature seen, for the age test. + pub first_seen: Option, + /// The oldest incoming value credit: who created this account. + pub birth_edge: Option, + /// Fee payers observed across this address's transactions, for clustering. + pub fee_payers: Vec, + /// Addresses this one was the sole source of a birth edge for. Fan-out. + pub funded: Vec, + /// The birth-credit scan ran out of budget before finding a credit. + /// + /// Distinguishes "we stopped looking" from "there is nothing there". Only + /// meaningful when `birth_edge` is `None`, and when it is set the address is + /// a **budget** outcome rather than evidence about the chain. + #[serde(default)] + pub birth_scan_exhausted: bool, +} + +impl AddressFacts { + pub fn new(address: impl Into) -> Self { + AddressFacts { + address: address.into(), + owner: None, + executable: false, + signatures: SigCount::Exact(0), + first_seen: None, + birth_edge: None, + fee_payers: Vec::new(), + funded: Vec::new(), + birth_scan_exhausted: false, + } + } + + /// Age in seconds at `now`, from the oldest signature we saw. + /// + /// Clamped at zero. `saturating_sub` on a signed integer saturates at + /// `i64::MIN`, not at nothing, so a timestamp in the future — clock skew, or + /// bad data — would otherwise yield a large negative age. Zero is the + /// fail-safe reading: it means "brand new", which fails the hub age test + /// rather than passing it by accident. + pub fn age_seconds(&self, now: i64) -> Option { + self.first_seen.map(|t| (now - t).max(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn a_capped_count_is_a_lower_bound_and_says_so() { + let capped = SigCount::AtLeast(20_000); + assert_eq!(capped.lower_bound(), 20_000); + assert!(!capped.is_exact()); + + let exact = SigCount::Exact(37); + assert_eq!(exact.lower_bound(), 37); + assert!(exact.is_exact()); + } + + #[test] + fn age_is_measured_from_the_oldest_signature() { + let mut f = AddressFacts::new("addr"); + assert_eq!(f.age_seconds(1_000), None); + f.first_seen = Some(400); + assert_eq!(f.age_seconds(1_000), Some(600)); + } + + #[test] + fn a_future_timestamp_does_not_produce_a_negative_age() { + let mut f = AddressFacts::new("addr"); + f.first_seen = Some(2_000); + assert_eq!(f.age_seconds(1_000), Some(0)); + } +} diff --git a/crates/mirror-provenance/src/frame.rs b/crates/mirror-provenance/src/frame.rs new file mode 100644 index 00000000..7ae70eb1 --- /dev/null +++ b/crates/mirror-provenance/src/frame.rs @@ -0,0 +1,121 @@ +//! Building a member-weighted frame from a pool's depositors. +//! +//! The frame decides what the measurement is *of*, and getting it wrong is the +//! easiest way to produce a confident number about the wrong population. +//! +//! **Member-weighted, not transaction-weighted.** Each depositor appears once +//! however often they transact. Sampling addresses because they appear in recent +//! blocks is size-biased: an address that transacts a thousand times a day is a +//! thousand times likelier to be drawn than one that transacts daily, so the +//! frame fills with market makers and bots. Our own first run did exactly this +//! and produced nothing; `docs/MEASUREMENT_LOG.md` records it. +//! +//! **Spread across the pool's history, not its last minute.** Pages are walked +//! backwards through the whole signature history and depositors are taken from +//! every page. A published measurement in this space draws its entire sample +//! from a nine-slot window — about four seconds of chain time — and reports +//! Wilson intervals over it as though it were an independent sample of a +//! population. +//! +//! **Nothing is excluded for being hard to trace.** Busy depositors stay in. +//! Dropping them inflates the resolved fraction by construction, and whatever +//! the remaining sample then reports is a property of the exclusion rule rather +//! than a finding about the pool. + +use crate::edge::TransactionView; + +/// The address that funded a deposit, if this transaction looks like one. +/// +/// A deposit debits the payer and credits the pool. We take the fee payer, whose +/// index is zero, and require that they lost at least `min_lamports` beyond the +/// fee — so a withdrawal, in which the payer is a relayer moving nothing of +/// their own, is not mistaken for a deposit. +pub fn depositor_of(tx: &TransactionView, min_lamports: u64) -> Option { + let deltas = tx.deltas()?; + let payer_delta = *deltas.first()?; + if payer_delta >= 0 { + return None; + } + if payer_delta.unsigned_abs() < min_lamports as u128 { + return None; + } + // Something else in the transaction must have gained: a payer who only + // burned lamports has not deposited anywhere. + if !deltas.iter().skip(1).any(|d| *d > 0) { + return None; + } + tx.account_keys.first().cloned() +} + +#[cfg(test)] +mod tests { + use super::*; + + fn tx(keys: &[&str], pre: &[u64], post: &[u64], fee: u64) -> TransactionView { + TransactionView { + signature: "sig".into(), + slot: 1, + block_time: Some(1_700_000_000), + account_keys: keys.iter().map(|s| s.to_string()).collect(), + pre_balances: pre.to_vec(), + post_balances: post.to_vec(), + fee, + } + } + + const MIN: u64 = 10_000_000; + + #[test] + fn a_deposit_names_its_payer() { + // The payer sends 1 SOL into the pool vault. + let t = tx( + &["depositor", "pool_vault"], + &[2_000_000_000, 5_000_000_000], + &[999_995_000, 6_000_000_000], + 5_000, + ); + assert_eq!(depositor_of(&t, MIN).as_deref(), Some("depositor")); + } + + #[test] + fn a_withdrawal_is_not_a_deposit() { + // A relayer pays the fee; the pool pays a recipient. The relayer moved + // nothing of their own and must not enter the frame as a member. + let t = tx( + &["relayer", "pool_vault", "recipient"], + &[1_000_000_000, 5_000_000_000, 0], + &[999_995_000, 4_000_000_000, 1_000_000_000], + 5_000, + ); + assert!(depositor_of(&t, MIN).is_none()); + } + + #[test] + fn a_payer_who_only_burned_the_fee_is_not_a_depositor() { + let t = tx( + &["payer", "other"], + &[1_000_000_000, 7], + &[999_995_000, 7], + 5_000, + ); + assert!(depositor_of(&t, MIN).is_none()); + } + + #[test] + fn a_transfer_below_the_threshold_is_not_a_deposit() { + let t = tx( + &["payer", "sink"], + &[1_000_000_000, 0], + &[999_994_000, 1_000], + 5_000, + ); + assert!(depositor_of(&t, MIN).is_none()); + } + + #[test] + fn a_malformed_transaction_yields_nothing_rather_than_a_guess() { + let mut t = tx(&["a", "b"], &[1, 2], &[1, 2], 0); + t.post_balances.pop(); + assert!(depositor_of(&t, MIN).is_none()); + } +} diff --git a/crates/mirror-provenance/src/lib.rs b/crates/mirror-provenance/src/lib.rs new file mode 100644 index 00000000..0822e097 --- /dev/null +++ b/crates/mirror-provenance/src/lib.rs @@ -0,0 +1,30 @@ +//! Funding-provenance measurement over real on-chain data. +//! +//! An anonymity set on a public ledger can be partitioned by where each member's +//! capital came from, and once it is, what survives is the size of the actor's +//! class rather than the advertised `k`. This crate measures that. +//! +//! It is a measurement crate. It makes no privacy claims by itself, and every +//! number it produces names the data it came from. Method, adversary model and +//! the limits of what the numbers prove are in `docs/PROVENANCE_METHOD.md`. +#![forbid(unsafe_code)] + +pub mod bootstrap; +pub mod classify; +pub mod edge; +pub mod facts; +pub mod frame; +pub mod metrics; +pub mod outcome; +pub mod rpc; +pub mod trace; + +pub use bootstrap::{difference_interval, loss_factor_interval, Interval}; +pub use classify::{AnchorSet, Classifier, SetStructure, Thresholds}; +pub use edge::{FundingEdge, TransactionView}; +pub use facts::{AddressFacts, SigCount}; +pub use frame::depositor_of; +pub use metrics::{Anonymity, Bracket}; +pub use outcome::{Census, Outcome, TerminalRule, Unresolved}; +pub use rpc::{RpcClient, RpcError}; +pub use trace::{classify_sample, Chain, CollectionConfig, Collector, Sample, Scope}; diff --git a/crates/mirror-provenance/src/metrics.rs b/crates/mirror-provenance/src/metrics.rs new file mode 100644 index 00000000..e38b59e8 --- /dev/null +++ b/crates/mirror-provenance/src/metrics.rs @@ -0,0 +1,450 @@ +//! Anonymity metrics over a provenance partition. +//! +//! An anonymity set of `K` members is partitioned into classes by where each +//! member's capital came from. An adversary who learns a member's class is left +//! guessing only within it, so what survives is not `K` but the residual +//! anonymity `H(X|C)`. +//! +//! The whole module rests on one identity, which `the_chain_rule_holds` pins: +//! +//! ```text +//! log2 K = H(C) + H(X|C) +//! ``` +//! +//! **The folklore formula is inverted.** `2^{H(C)}` — entropy over the +//! class-size *distribution* — is widely quoted as the effective anonymity set. +//! It is the leakage: it is maximised when every member is alone, which is total +//! deanonymisation. The anonymity is `2^{H(X|C)}`. Getting this backwards +//! produces a number that improves as privacy gets worse. +//! +//! ## Attribution +//! +//! `H` is the Serjantov–Danezis entropy metric (PET 2002, Definition 2), which +//! is defined in *bits* over *users*. The exponentiated form `2^H` as a member +//! count is Andersson & Lundin (IFIP AICT 262, 2008, Definition 1), who +//! explicitly dispute the common misattribution. We do not write "Serjantov and +//! Danezis define the effective anonymity set size as `2^H`", because they did +//! not. +//! +//! For each observation `C = c` the adversary's posterior is uniform on class +//! `c`, whose Serjantov–Danezis effective size is `log2 n_c` bits. `H(X|C)` is +//! therefore the expectation of that size over the adversary's observation. + +use std::collections::BTreeMap; + +/// Every quantity we report. Never a scalar — a single number hides the tail, +/// and the tail is where the people with no anonymity are. +#[derive(Debug, Clone, PartialEq)] +pub struct Anonymity { + /// Members in the set. + pub nominal_k: u64, + /// Distinct provenance classes. + pub classes: u64, + /// `ρ = 2^{−H(C)}`, the fraction of nominal k that survives. + /// + /// The headline, because it is independent of `k` and therefore comparable + /// across pools of different sizes. Effective-k measured at small `k` + /// systematically understates the steady-state loss and cannot be + /// extrapolated upward. + pub loss_factor: f64, + /// `2^{H(X|C)}`: the membership-weighted geometric mean of class sizes. + pub eff_k_shannon: f64, + /// `H(C)` in bits. Exactly the Shannon leakage `I(X;C)`. + pub leakage_shannon_bits: f64, + /// `K/m`: Bayes vulnerability, the unweighted arithmetic mean of class sizes. + pub eff_k_min_entropy: f64, + /// `log2 m` in bits. Exactly the min-entropy leakage. + pub leakage_min_entropy_bits: f64, + /// Smallest class. Meaningless without its null distribution — see + /// [`Anonymity::worst_case_is_informative`]. + pub worst_case: u64, + /// Expected number of guesses, `G(X|C)`. Uniform baseline is `(K+1)/2`. + pub guessing_entropy: f64, + /// Good–Turing coverage `1 − f₁/K`: the fraction of class mass observed. + pub good_turing_coverage: f64, + /// Chao1 richness estimate. A saturation diagnostic, not a class count. + pub chao1: f64, + /// `P(my class ≤ t)` at `t ∈ {1,2,4,8,16,32,64,128}`. + pub class_size_ccdf: Vec<(u64, f64)>, +} + +impl Anonymity { + /// Computes every metric from the class sizes of a partition. + /// + /// Returns `None` for an empty partition or one containing an empty class — + /// both mean the caller's partitioning is wrong, and silently coping would + /// hide that. + pub fn from_class_sizes(sizes: &[u64]) -> Option { + if sizes.is_empty() || sizes.contains(&0) { + return None; + } + let k: u64 = sizes.iter().sum(); + let m = sizes.len() as u64; + let kf = k as f64; + + // H(C) = -Σ p_c log2 p_c and H(X|C) = Σ p_c log2 n_c + let mut h_c = 0.0f64; + let mut h_x_given_c = 0.0f64; + for &n in sizes { + let p = n as f64 / kf; + h_c -= p * p.log2(); + h_x_given_c += p * (n as f64).log2(); + } + + let f1 = sizes.iter().filter(|&&n| n == 1).count() as f64; + let f2 = sizes.iter().filter(|&&n| n == 2).count() as f64; + + // G(X|C) = (1/K) Σ n_c(n_c+1)/2 + let guessing_entropy = sizes + .iter() + .map(|&n| { + let nf = n as f64; + nf * (nf + 1.0) / 2.0 + }) + .sum::() + / kf; + + let mut ccdf = Vec::new(); + for t in [1u64, 2, 4, 8, 16, 32, 64, 128] { + let members_in_small_classes: u64 = sizes.iter().filter(|&&n| n <= t).sum(); + ccdf.push((t, members_in_small_classes as f64 / kf)); + } + + Some(Anonymity { + nominal_k: k, + classes: m, + loss_factor: (-h_c).exp2(), + eff_k_shannon: h_x_given_c.exp2(), + leakage_shannon_bits: h_c, + eff_k_min_entropy: kf / m as f64, + leakage_min_entropy_bits: (m as f64).log2(), + worst_case: *sizes.iter().min().expect("non-empty"), + guessing_entropy, + good_turing_coverage: 1.0 - f1 / kf, + chao1: m as f64 + f1 * (f1 - 1.0) / (2.0 * (f2 + 1.0)), + class_size_ccdf: ccdf, + }) + } + + /// Groups members by class label and measures the resulting partition. + pub fn from_labels(labels: &[L]) -> Option { + let mut counts: BTreeMap = BTreeMap::new(); + for l in labels { + *counts.entry(l.clone()).or_insert(0) += 1; + } + let sizes: Vec = counts.into_values().collect(); + Self::from_class_sizes(&sizes) + } + + /// Whether reporting `worst_case` says anything about *this* pool. + /// + /// Under any heavy-tailed provenance prior somebody is always alone: in + /// simulation `P(min_c n_c = 1) ≈ 1.00` for every `k ≤ 512`. So "worst case + /// is 1" describes the shape of provenance in general, not a property of the + /// pool being measured, and quoting it as a finding — as a published + /// measurement of a live Solana pool does — is not informative. + /// + /// It becomes informative only when the smallest class is larger than one, + /// which is a genuine and unusual claim. + pub fn worst_case_is_informative(&self) -> bool { + self.worst_case > 1 + } + + /// The ordering that must hold for any partition. + /// + /// `min_c n_c ≤ K/m ≤ 2^{H(X|C)} ≤ K` + /// + /// Worst case is at most the arithmetic mean of class sizes, which is at + /// most the membership-weighted geometric mean, which is at most nominal. + /// A violation means an arithmetic error, so it is asserted rather than + /// assumed. + pub fn ordering_holds(&self) -> bool { + const EPS: f64 = 1e-9; + let worst = self.worst_case as f64; + let nominal = self.nominal_k as f64; + worst <= self.eff_k_min_entropy + EPS + && self.eff_k_min_entropy <= self.eff_k_shannon + EPS + && self.eff_k_shannon <= nominal + EPS + } + + /// `H(C) + H(X|C) == log2 K`, the identity the module rests on. + pub fn chain_rule_residual(&self) -> f64 { + let h_x_given_c = self.eff_k_shannon.log2(); + (self.leakage_shannon_bits + h_x_given_c) - (self.nominal_k as f64).log2() + } +} + +/// The bracket that must accompany any point estimate. +/// +/// Members whose trace did not reach a class are **not** a class. Merging them +/// assumes they are all alike, which is charitable to the pool and raises the +/// figure; splitting them into singletons assumes they are all distinct, which +/// is charitable to the adversary and lowers it. Neither is known, so both are +/// reported and the truth is somewhere between. +/// +/// A point estimate without this is not publishable output, because the reader +/// cannot tell whether the number is driven by what was measured or by what was +/// not. +#[derive(Debug, Clone, PartialEq)] +pub struct Bracket { + /// Unresolved merged into one class: the most favourable reading. + pub upper: Anonymity, + /// Unresolved split into singletons: the least favourable reading. + pub lower: Anonymity, + /// Members that reached a class. + pub resolved: u64, + /// Members that did not, excluding infrastructure failures. + pub unresolved: u64, +} + +impl Bracket { + /// Builds the bracket from resolved class sizes and a count of unresolved + /// members. + /// + /// `unresolved` must exclude RPC failures: those are our own and belong to + /// neither reading. + pub fn new(resolved_sizes: &[u64], unresolved: u64) -> Option { + let resolved: u64 = resolved_sizes.iter().sum(); + + let mut merged: Vec = resolved_sizes.to_vec(); + if unresolved > 0 { + merged.push(unresolved); + } + + let mut split: Vec = resolved_sizes.to_vec(); + split.extend(std::iter::repeat_n(1, unresolved as usize)); + + Some(Bracket { + upper: Anonymity::from_class_sizes(&merged)?, + lower: Anonymity::from_class_sizes(&split)?, + resolved, + unresolved, + }) + } + + /// Whether the bracket is tight enough for the point estimate to carry the + /// argument on its own. + /// + /// When most members are unresolved the two readings diverge, and quoting + /// either as *the* result would be reporting the sampling budget rather than + /// the pool. + pub fn is_informative(&self) -> bool { + let total = self.resolved + self.unresolved; + total > 0 && self.resolved * 2 >= total + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn close(a: f64, b: f64, tol: f64) -> bool { + (a - b).abs() < tol + } + + /// Reference vector A from the methodology, computed independently at full + /// double precision. Asserted to 1e-9 so an arithmetic slip cannot hide. + #[test] + fn reference_vector_a() { + let a = Anonymity::from_class_sizes(&[50, 20, 10, 10, 5, 3, 1, 1]).unwrap(); + assert_eq!(a.nominal_k, 100); + assert_eq!(a.classes, 8); + assert!( + close(a.leakage_shannon_bits, 2.1295115772, 1e-9), + "H(C) = {}", + a.leakage_shannon_bits + ); + assert!( + close(a.eff_k_shannon, 22.8535219812, 1e-9), + "eff_k = {}", + a.eff_k_shannon + ); + assert!(close(a.eff_k_min_entropy, 12.5, 1e-9)); + assert!(close(a.leakage_min_entropy_bits, 3.0, 1e-9)); + assert_eq!(a.worst_case, 1); + assert!( + close(a.guessing_entropy, 16.18, 1e-9), + "G = {}", + a.guessing_entropy + ); + assert!(close(a.good_turing_coverage, 0.98, 1e-9)); + assert!(close(a.chao1, 9.0, 1e-9)); + } + + /// Reference vector B: the shape of the published live-pool measurement — + /// one class of 19 plus eleven singletons. + #[test] + fn reference_vector_b() { + let b = Anonymity::from_class_sizes(&[19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]).unwrap(); + assert_eq!(b.nominal_k, 30); + assert_eq!(b.classes, 12); + assert!(close(b.leakage_shannon_bits, 2.2165365038, 1e-9)); + assert!( + close(b.eff_k_shannon, 6.4547181110, 1e-9), + "eff_k = {}", + b.eff_k_shannon + ); + assert!(close(b.eff_k_min_entropy, 2.5, 1e-9)); + assert!(close(b.leakage_min_entropy_bits, 3.5849625007, 1e-9)); + assert!(close(b.guessing_entropy, 6.7, 1e-9)); + assert!(close(b.good_turing_coverage, 0.6333333333, 1e-9)); + } + + /// The identity the module rests on. If this fails, every number above is + /// meaningless. + #[test] + fn the_chain_rule_holds() { + for sizes in [ + vec![1u64], + vec![5, 5], + vec![50, 20, 10, 10, 5, 3, 1, 1], + vec![19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + vec![1000, 1], + (1..=40u64).collect::>(), + ] { + let a = Anonymity::from_class_sizes(&sizes).unwrap(); + assert!( + a.chain_rule_residual().abs() < 1e-9, + "H(C) + H(X|C) != log2 K for {sizes:?}: residual {}", + a.chain_rule_residual() + ); + } + } + + #[test] + fn the_ordering_invariant_holds_over_many_partitions() { + // A deterministic sweep rather than a random one, so a failure is + // reproducible without recording a seed. + let mut checked = 0; + for m in 1..=12u64 { + for spread in 0..12u64 { + let sizes: Vec = (0..m).map(|i| 1 + i * spread).collect(); + let a = Anonymity::from_class_sizes(&sizes).unwrap(); + assert!(a.ordering_holds(), "ordering violated for {sizes:?}: {a:?}"); + assert!(a.chain_rule_residual().abs() < 1e-9); + checked += 1; + } + } + assert!(checked > 100); + } + + /// One class means no leakage and full anonymity. + #[test] + fn a_single_class_leaks_nothing() { + let a = Anonymity::from_class_sizes(&[64]).unwrap(); + assert!(close(a.leakage_shannon_bits, 0.0, 1e-12)); + assert!(close(a.loss_factor, 1.0, 1e-12)); + assert!(close(a.eff_k_shannon, 64.0, 1e-9)); + assert_eq!(a.worst_case, 64); + assert!(a.worst_case_is_informative()); + } + + /// All singletons is total deanonymisation, and the folklore formula would + /// report this as *maximum* anonymity. + #[test] + fn all_singletons_is_total_deanonymisation() { + let a = Anonymity::from_class_sizes(&[1; 32]).unwrap(); + assert!( + close(a.eff_k_shannon, 1.0, 1e-12), + "eff_k = {}", + a.eff_k_shannon + ); + assert!(close(a.eff_k_min_entropy, 1.0, 1e-12)); + assert!(close(a.loss_factor, 1.0 / 32.0, 1e-12)); + // The inverted folklore quantity, for contrast: 2^{H(C)} = 32 here, + // which would be reported as "effective k = 32" — the nominal size, at + // the exact moment every member stands alone. + assert!(close(a.leakage_shannon_bits.exp2(), 32.0, 1e-9)); + } + + #[test] + fn the_loss_factor_is_independent_of_k_for_a_fixed_prior() { + // Doubling every class doubles nominal k and doubles effective k, so the + // ratio is unchanged. That is why it is the headline. + let small = Anonymity::from_class_sizes(&[8, 4, 2, 1, 1]).unwrap(); + let large = Anonymity::from_class_sizes(&[16, 8, 4, 2, 2]).unwrap(); + assert!( + close(small.loss_factor, large.loss_factor, 1e-12), + "{} vs {}", + small.loss_factor, + large.loss_factor + ); + assert!(large.nominal_k == 2 * small.nominal_k); + } + + #[test] + fn worst_case_alone_is_not_a_finding() { + // Both have a singleton, but they are not equally private. Reporting + // "worst case 1" for either says the same thing about two very + // different pools. + let bad = Anonymity::from_class_sizes(&[1; 20]).unwrap(); + let good = Anonymity::from_class_sizes(&[999, 1]).unwrap(); + assert_eq!(bad.worst_case, good.worst_case); + assert!(!bad.worst_case_is_informative()); + assert!(!good.worst_case_is_informative()); + assert!(good.eff_k_shannon > 900.0); + assert!(bad.eff_k_shannon < 1.001); + } + + #[test] + fn the_ccdf_reports_the_tail_the_averages_hide() { + let a = Anonymity::from_class_sizes(&[100, 1, 1, 1, 1]).unwrap(); + // Four of 104 members are alone. + let at_one = a.class_size_ccdf.iter().find(|(t, _)| *t == 1).unwrap().1; + assert!(close(at_one, 4.0 / 104.0, 1e-12)); + } + + #[test] + fn the_bracket_spans_both_readings_of_the_unresolved() { + // Six resolved in two classes of three, six unresolved. + let b = Bracket::new(&[3, 3], 6).unwrap(); + + // Merged: three classes of three, six, three. + assert_eq!(b.upper.nominal_k, 12); + // Split: two classes of three plus six singletons. + assert_eq!(b.lower.nominal_k, 12); + assert_eq!(b.lower.classes, 8); + assert_eq!(b.upper.classes, 3); + + assert!( + b.upper.eff_k_shannon > b.lower.eff_k_shannon, + "merging the unresolved must be the more favourable reading" + ); + assert!(b.upper.loss_factor > b.lower.loss_factor); + } + + #[test] + fn a_mostly_unresolved_sample_is_not_informative() { + // Two resolved, ten unresolved: the two readings are far apart and + // neither describes the pool. + let thin = Bracket::new(&[1, 1], 10).unwrap(); + assert!(!thin.is_informative()); + + let solid = Bracket::new(&[4, 4, 4], 3).unwrap(); + assert!(solid.is_informative()); + } + + #[test] + fn with_nothing_unresolved_the_bracket_collapses_to_a_point() { + let b = Bracket::new(&[5, 3, 2], 0).unwrap(); + assert_eq!(b.upper, b.lower); + assert_eq!(b.unresolved, 0); + assert!(b.is_informative()); + } + + #[test] + fn an_empty_or_degenerate_partition_is_refused() { + assert!(Anonymity::from_class_sizes(&[]).is_none()); + assert!(Anonymity::from_class_sizes(&[3, 0, 2]).is_none()); + } + + #[test] + fn labels_group_into_the_same_partition_as_sizes() { + let by_label = + Anonymity::from_labels(&["binance", "binance", "binance", "coinbase", "rootless"]) + .unwrap(); + let by_size = Anonymity::from_class_sizes(&[3, 1, 1]).unwrap(); + assert!(close(by_label.eff_k_shannon, by_size.eff_k_shannon, 1e-12)); + assert_eq!(by_label.classes, 3); + } +} diff --git a/crates/mirror-provenance/src/outcome.rs b/crates/mirror-provenance/src/outcome.rs new file mode 100644 index 00000000..281b26ba --- /dev/null +++ b/crates/mirror-provenance/src/outcome.rs @@ -0,0 +1,293 @@ +//! How a trace ends, and the census that keeps infrastructure limits from +//! reading as evidence. +//! +//! The governing principle: **an RPC failure is not a finding.** A rate-limited +//! call that returns nothing must never be recorded as "this address has no +//! funder", because that is indistinguishable in the output from a genuine +//! terminal — and it inflates exactly the bucket a privacy measurement most +//! wants to be large. +//! +//! A published tracer in this space uses `.unwrap_or(0)` for signature counts +//! and `.unwrap_or_default()` for signature lists. A throttled call there makes +//! an address look like it has zero history, so it is not detected as a hub and +//! is admitted to the sample, and a throttled trace yields no funder, so the +//! member is classified unresolved. Its large unresolved bucket is what +//! systematic rate limiting would manufacture, and its headline does not say so. + +use serde::{Deserialize, Serialize}; + +/// Which terminal rule classified an address. Recorded so every rule can be +/// ablated in the sensitivity table rather than taken on faith. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum TerminalRule { + /// R1: the account is a program or PDA — not owned by the system program, + /// or executable. Definitional, one call, and what separates "funded by a + /// Raydium vault" from "funded by a person". + ProgramOrPda, + /// R2: a hit in the curated, MIT-licensed anchor set. + CuratedAnchor, + /// R3: a member of a fee-payer or sweep cluster of at least three. + StructuralCluster, + /// R4: high lifetime activity and at least thirty days old. + /// + /// This is **not** an attributable origin and must never be described as + /// one. It means "busy address we could not name". + VolumeHub, + /// R5: has funded many distinct previously-unseen addresses. + Distributor, +} + +/// Why a trace failed to reach a class. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum Unresolved { + /// The address has no qualifying incoming value edge. Genuine evidence. + NoIncomingEdge, + /// The incoming edge was below the minimum value threshold. Evidence. + BelowThreshold, + /// Hit the depth limit. A budget limit, not evidence. + DepthExceeded, + /// Hit the signature page cap without terminating. Budget, not evidence. + PageCapHit, + /// An RPC error, 429 exhaustion, or timeout. **Not evidence.** + RpcFailure, + /// SOL-only scope, and the address holds token accounts with inflow, so the + /// funding event is structurally invisible. A scope limit, not evidence. + SplBlindSpot, + /// The oldest transactions were read up to the birth-scan cap and none of + /// them credited the address. **Budget, not evidence** — the credit is + /// plausibly the next transaction along. + /// + /// Kept separate from `NoIncomingEdge` deliberately. Collapsing the two + /// would let "we stopped looking" be reported as "there is nothing there", + /// which is the exact substitution this taxonomy exists to prevent. + BirthScanExhausted, +} + +impl Unresolved { + /// Whether this outcome tells us something about the address, as opposed to + /// something about our own budget or infrastructure. + pub fn is_evidence(&self) -> bool { + matches!( + self, + Unresolved::NoIncomingEdge | Unresolved::BelowThreshold + ) + } + + /// Whether this outcome is a failure of ours rather than a property of the + /// chain. These members leave the class distribution entirely. + pub fn is_failure(&self) -> bool { + matches!(self, Unresolved::RpcFailure) + } +} + +/// The end state of tracing one member. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum Outcome { + /// Classified. The label is what the partition groups on. + Terminal { rule: TerminalRule, label: String }, + /// Not classified, with the reason kept. + Unresolved { reason: Unresolved, depth: u32 }, +} + +impl Outcome { + pub fn label(&self) -> Option<&str> { + match self { + Outcome::Terminal { label, .. } => Some(label), + Outcome::Unresolved { .. } => None, + } + } +} + +/// A count of every terminal state in a run. There is no "other" bucket, +/// because an "other" bucket is where an unaccounted failure would hide. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct Census { + pub resolved: u64, + pub no_incoming_edge: u64, + pub below_threshold: u64, + pub depth_exceeded: u64, + pub page_cap_hit: u64, + pub rpc_failure: u64, + pub spl_blind_spot: u64, + /// Budget, not evidence: the birth-credit scan ran out before finding one. + #[serde(default)] + pub birth_scan_exhausted: u64, +} + +/// Above this rate of RPC failures a run refuses to publish a headline. +/// +/// One percent. Beyond it, the unresolved bucket is substantially our own +/// making, and any effective-k computed from it would be measuring our +/// infrastructure rather than the pool. +pub const MAX_FAILURE_RATE: f64 = 0.01; + +impl Census { + pub fn record(&mut self, outcome: &Outcome) { + match outcome { + Outcome::Terminal { .. } => self.resolved += 1, + Outcome::Unresolved { reason, .. } => match reason { + Unresolved::NoIncomingEdge => self.no_incoming_edge += 1, + Unresolved::BelowThreshold => self.below_threshold += 1, + Unresolved::DepthExceeded => self.depth_exceeded += 1, + Unresolved::PageCapHit => self.page_cap_hit += 1, + Unresolved::RpcFailure => self.rpc_failure += 1, + Unresolved::SplBlindSpot => self.spl_blind_spot += 1, + Unresolved::BirthScanExhausted => self.birth_scan_exhausted += 1, + }, + } + } + + /// Every member the run attempted, including failures. + pub fn attempted(&self) -> u64 { + self.resolved + + self.no_incoming_edge + + self.below_threshold + + self.depth_exceeded + + self.page_cap_hit + + self.rpc_failure + + self.spl_blind_spot + + self.birth_scan_exhausted + } + + /// Members whose outcome says something about the chain: everything except + /// our own RPC failures. + pub fn measurable(&self) -> u64 { + self.attempted() - self.rpc_failure + } + + pub fn failure_rate(&self) -> f64 { + let attempted = self.attempted(); + if attempted == 0 { + return 0.0; + } + self.rpc_failure as f64 / attempted as f64 + } + + /// Whether a headline may be published from this run. + /// + /// Deliberately a hard gate rather than a warning. A warning printed above a + /// number gets dropped when the number is quoted. + pub fn may_publish(&self) -> bool { + self.attempted() > 0 && self.failure_rate() <= MAX_FAILURE_RATE + } + + /// The line that must accompany any reported figure. + pub fn summary(&self) -> String { + format!( + "attempted {} | resolved {} | evidence-unresolved {} | budget-unresolved {} \ + | scope-unresolved {} | rpc failures {} ({:.2}%)", + self.attempted(), + self.resolved, + self.no_incoming_edge + self.below_threshold, + self.depth_exceeded + self.page_cap_hit + self.birth_scan_exhausted, + self.spl_blind_spot, + self.rpc_failure, + self.failure_rate() * 100.0 + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn terminal(label: &str) -> Outcome { + Outcome::Terminal { + rule: TerminalRule::CuratedAnchor, + label: label.to_string(), + } + } + + fn unresolved(reason: Unresolved) -> Outcome { + Outcome::Unresolved { reason, depth: 3 } + } + + #[test] + fn an_rpc_failure_is_never_evidence() { + assert!(!Unresolved::RpcFailure.is_evidence()); + assert!(Unresolved::RpcFailure.is_failure()); + // The two that genuinely say something about the address. + assert!(Unresolved::NoIncomingEdge.is_evidence()); + assert!(Unresolved::BelowThreshold.is_evidence()); + // Budget and scope limits are neither. + for r in [ + Unresolved::DepthExceeded, + Unresolved::PageCapHit, + Unresolved::SplBlindSpot, + ] { + assert!(!r.is_evidence(), "{r:?} must not count as evidence"); + assert!(!r.is_failure(), "{r:?} is not an infrastructure failure"); + } + } + + #[test] + fn the_census_accounts_for_every_member() { + let mut c = Census::default(); + c.record(&terminal("entity:binance")); + c.record(&terminal("entity:binance")); + c.record(&unresolved(Unresolved::NoIncomingEdge)); + c.record(&unresolved(Unresolved::RpcFailure)); + c.record(&unresolved(Unresolved::DepthExceeded)); + c.record(&unresolved(Unresolved::SplBlindSpot)); + assert_eq!(c.attempted(), 6); + assert_eq!( + c.measurable(), + 5, + "failures leave the distribution entirely" + ); + assert_eq!(c.resolved, 2); + } + + #[test] + fn a_run_with_too_many_failures_refuses_to_publish() { + let mut c = Census::default(); + for _ in 0..99 { + c.record(&terminal("entity:x")); + } + c.record(&unresolved(Unresolved::RpcFailure)); + // 1 in 100 is exactly at the limit and still publishable. + assert!((c.failure_rate() - 0.01).abs() < 1e-12); + assert!(c.may_publish()); + + c.record(&unresolved(Unresolved::RpcFailure)); + assert!( + !c.may_publish(), + "two failures in 101 is above the limit and must block the headline" + ); + } + + #[test] + fn an_empty_run_cannot_publish() { + assert!(!Census::default().may_publish()); + } + + #[test] + fn the_summary_names_every_bucket_separately() { + let mut c = Census::default(); + c.record(&terminal("a")); + c.record(&unresolved(Unresolved::RpcFailure)); + let s = c.summary(); + for expected in ["attempted", "resolved", "rpc failures"] { + assert!(s.contains(expected), "summary missing {expected}: {s}"); + } + // The failure count must be visible as its own number, not folded into + // the unresolved total. + assert!(s.contains("rpc failures 1"), "{s}"); + } + + #[test] + fn a_volume_hub_is_not_an_attributable_origin() { + // Encoded as a test because this is where a provenance tracer most + // easily launders a budget limit into a finding: if a volume hub counts + // as an origin, "reaches an attributable origin" degenerates into "the + // address hit the RPC page cap". + let hub = Outcome::Terminal { + rule: TerminalRule::VolumeHub, + label: "busy-unlabelled:SomeAddress".to_string(), + }; + assert!( + hub.label().unwrap().starts_with("busy-unlabelled:"), + "a volume hub must be labelled as unnamed, never as an entity" + ); + } +} diff --git a/crates/mirror-provenance/src/rpc.rs b/crates/mirror-provenance/src/rpc.rs new file mode 100644 index 00000000..6f81505a --- /dev/null +++ b/crates/mirror-provenance/src/rpc.rs @@ -0,0 +1,485 @@ +//! A Solana JSON-RPC client that fails loudly. +//! +//! Two properties matter here more than throughput. +//! +//! **Every error propagates.** There is no `unwrap_or(0)` and no +//! `unwrap_or_default()` anywhere in this module. A throttled call returns an +//! error that becomes `Unresolved::RpcFailure`, which the census counts on its +//! own line and excludes from the class distribution. The alternative — a +//! default value — turns a rate limit into the claim "this address has no +//! funding history", which is the single easiest way for a provenance +//! measurement to be wrong in the direction that flatters it. +//! +//! **The endpoint is checked before the run.** Third-party "public" endpoints +//! silently truncate history: one reports a first available block 2.5 days +//! behind the tip and returns `{"result": null}` — not an error — for a 2021 +//! transaction. A collector pointed at it records "not found" for every old +//! funding event and produces a truncated graph that looks exactly like a +//! finding. [`RpcClient::check_preconditions`] refuses to run against one. + +use crate::edge::TransactionView; +use serde::Deserialize; +use std::time::{Duration, Instant}; + +/// A slot old enough that only an archival endpoint can serve it. +/// +/// Slot 50,000,000 was produced on 2020-11-19. An endpoint that cannot return +/// it cannot answer questions about where anybody's money came from. +pub const ARCHIVAL_PROBE_SLOT: u64 = 50_000_000; + +#[derive(Debug, thiserror::Error)] +pub enum RpcError { + #[error("transport failure: {0}")] + Transport(String), + #[error("rpc returned an error: {0}")] + Rpc(String), + #[error("unexpected response shape: {0}")] + Shape(String), + #[error("endpoint is not archival: {0}")] + NotArchival(String), +} + +/// What the endpoint claimed about itself, recorded in the run manifest so a +/// reader can see which endpoint produced the numbers and that it passed. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EndpointCheck { + pub endpoint: String, + pub first_available_block: u64, + pub archival_probe_ok: bool, +} + +pub struct RpcClient { + endpoint: String, + agent: ureq::Agent, + /// Minimum spacing between calls. + /// + /// The public endpoint sustains a measured 0.28–0.55 requests per second, + /// far below its documented allowance; the documented figure is not + /// reproducible. Pacing is therefore set from measurement, and the measured + /// range is what gets reported rather than the advertised one. + min_interval: Duration, + last_call: Option, + calls: u64, +} + +#[derive(Deserialize)] +struct JsonRpcResponse { + result: Option, + error: Option, +} + +/// One entry from `getSignaturesForAddress`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SignatureInfo { + pub signature: String, + pub slot: u64, + pub block_time: Option, + pub err: bool, +} + +/// The fields of `getAccountInfo` the program/PDA rule needs. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AccountOwner { + pub owner: String, + pub executable: bool, +} + +/// The system program. An account owned by anything else is a program account +/// or a PDA, never a person's wallet. +pub const SYSTEM_PROGRAM: &str = "11111111111111111111111111111111"; + +impl RpcClient { + pub fn new(endpoint: impl Into, requests_per_second: f64) -> Self { + let interval = if requests_per_second > 0.0 { + Duration::from_secs_f64(1.0 / requests_per_second) + } else { + Duration::ZERO + }; + RpcClient { + endpoint: endpoint.into(), + agent: ureq::AgentBuilder::new() + . // A full signature page is a large response, and the slowest ones on a + // busy address exceeded thirty seconds — which arrived as a + // transport failure and was counted against the run rather than + // retried. + timeout(Duration::from_secs(90)) + .build(), + min_interval: interval, + last_call: None, + calls: 0, + } + } + + pub fn calls_made(&self) -> u64 { + self.calls + } + + pub fn endpoint(&self) -> &str { + &self.endpoint + } + + fn pace(&mut self) { + if let Some(last) = self.last_call { + let elapsed = last.elapsed(); + if elapsed < self.min_interval { + std::thread::sleep(self.min_interval - elapsed); + } + } + self.last_call = Some(Instant::now()); + } + + /// One call, retrying through rate limits. + /// + /// A 429 is not evidence about the chain, so abandoning a trace on the first + /// one converts throttling into an `RpcFailure` — and enough of those push + /// the run past the threshold where it refuses to publish at all. Which is + /// what happened on the first real run of this collector: the chain client + /// had backoff and this one did not, and the analysis correctly refused a + /// headline computed from our own throttling. + /// + /// Persistent throttling still surfaces as an error. The point is not to + /// hide it, only to distinguish a transient limit from a real one. + fn call( + &mut self, + method: &str, + params: serde_json::Value, + ) -> Result { + let body = serde_json::json!({ + "jsonrpc": "2.0", + "id": self.calls + 1, + "method": method, + "params": params, + }); + + // Providers meter by compute units, not request count, and a full + // signature page is expensive in those terms — so a 429 arrives even at + // well under one request per second, and the budget needs seconds to + // refill rather than milliseconds. + let mut wait = std::time::Duration::from_secs(2); + let mut response: Option = None; + for attempt in 0..8 { + self.pace(); + self.calls += 1; + match self.agent.post(&self.endpoint).send_json(body.clone()) { + Ok(r) => { + response = Some(r.into_json().map_err(|e| RpcError::Shape(e.to_string()))?); + break; + } + Err(ureq::Error::Status(429 | 502 | 503, _)) if attempt < 7 => { + std::thread::sleep(wait); + wait *= 2; + } + Err(e) => return Err(RpcError::Transport(e.to_string())), + } + } + let response = response + .ok_or_else(|| RpcError::Transport(format!("{method}: throttled past retries")))?; + + if let Some(err) = response.error { + return Err(RpcError::Rpc(err.to_string())); + } + response + .result + .ok_or_else(|| RpcError::Shape(format!("{method}: neither result nor error"))) + } + + /// Refuses to proceed against an endpoint that cannot see the whole chain. + /// + /// Both probes are hard. A truncated endpoint does not error on old data, it + /// returns nothing, so without these the run would look healthy and be + /// systematically wrong. + pub fn check_preconditions(&mut self) -> Result { + let first = self.call("getFirstAvailableBlock", serde_json::json!([]))?; + let first_available_block = first + .as_u64() + .ok_or_else(|| RpcError::Shape("getFirstAvailableBlock: not a number".into()))?; + if first_available_block != 0 { + return Err(RpcError::NotArchival(format!( + "first available block is {first_available_block}, not 0; this endpoint \ + retains only recent history and would report old funding events as absent" + ))); + } + + let block = self.call( + "getBlock", + serde_json::json!([ + ARCHIVAL_PROBE_SLOT, + { "encoding": "json", "transactionDetails": "none", "rewards": false, + "maxSupportedTransactionVersion": 0 } + ]), + ); + let archival_probe_ok = matches!(&block, Ok(v) if !v.is_null()); + if !archival_probe_ok { + return Err(RpcError::NotArchival(format!( + "slot {ARCHIVAL_PROBE_SLOT} is unavailable; the endpoint cannot serve \ + the history this measurement depends on" + ))); + } + + Ok(EndpointCheck { + endpoint: self.endpoint.clone(), + first_available_block, + archival_probe_ok, + }) + } + + /// One page of signatures, newest first. `before` pages backwards. + /// + /// There is no forward cursor and `limit` caps at 1,000, so for an address + /// with fewer than 1,000 lifetime signatures the **last element of the first + /// page is the birth transaction**. That is what the birth-edge rule reads. + pub fn signatures_for_address( + &mut self, + address: &str, + before: Option<&str>, + limit: u32, + ) -> Result, RpcError> { + let mut config = serde_json::json!({ "limit": limit }); + if let Some(b) = before { + config["before"] = serde_json::Value::String(b.to_string()); + } + let result = self.call( + "getSignaturesForAddress", + serde_json::json!([address, config]), + )?; + let array = result + .as_array() + .ok_or_else(|| RpcError::Shape("getSignaturesForAddress: not an array".into()))?; + + array + .iter() + .map(|v| { + Ok(SignatureInfo { + signature: v + .get("signature") + .and_then(|s| s.as_str()) + .ok_or_else(|| RpcError::Shape("signature missing".into()))? + .to_string(), + slot: v + .get("slot") + .and_then(|s| s.as_u64()) + .ok_or_else(|| RpcError::Shape("slot missing".into()))?, + block_time: v.get("blockTime").and_then(|s| s.as_i64()), + err: v.get("err").map(|e| !e.is_null()).unwrap_or(false), + }) + }) + .collect() + } + + /// The narrow projection of a transaction the edge extractor needs. + /// + /// A `null` result is an error here, not an empty view. Against a truncated + /// endpoint `null` is what every old transaction returns, and treating it as + /// "no such transaction" is precisely the failure this module exists to + /// prevent. + pub fn transaction(&mut self, signature: &str) -> Result { + let result = self.call( + "getTransaction", + serde_json::json!([ + signature, + { "encoding": "jsonParsed", "maxSupportedTransactionVersion": 0 } + ]), + )?; + if result.is_null() { + return Err(RpcError::Rpc(format!( + "getTransaction({signature}) returned null; on an archival endpoint this \ + means the signature does not exist, but on a truncated one it means the \ + history was pruned — which is why preconditions are checked first" + ))); + } + parse_transaction(signature, &result) + } + + /// Owner and executability, for the program/PDA terminal rule. + pub fn account_owner(&mut self, address: &str) -> Result, RpcError> { + let result = self.call( + "getAccountInfo", + serde_json::json!([address, { "encoding": "base64" }]), + )?; + let value = result.get("value").unwrap_or(&serde_json::Value::Null); + if value.is_null() { + // A genuinely absent account. Distinct from a failure, and the + // caller treats it as such. + return Ok(None); + } + Ok(Some(AccountOwner { + owner: value + .get("owner") + .and_then(|o| o.as_str()) + .ok_or_else(|| RpcError::Shape("account owner missing".into()))? + .to_string(), + executable: value + .get("executable") + .and_then(|e| e.as_bool()) + .unwrap_or(false), + })) + } +} + +/// Projects a `getTransaction` response into the fields the edge extractor uses. +/// +/// Split out so it can be tested against a committed fixture without a network. +pub fn parse_transaction( + signature: &str, + value: &serde_json::Value, +) -> Result { + let meta = value + .get("meta") + .ok_or_else(|| RpcError::Shape("meta missing".into()))?; + + // Under `transactionDetails: "accounts"` the path is + // `transaction.accountKeys`; under `"full"` it is + // `transaction.message.accountKeys`. Accept either rather than depending on + // a request parameter staying in sync with a parser. + let keys_value = value + .pointer("/transaction/message/accountKeys") + .or_else(|| value.pointer("/transaction/accountKeys")) + .ok_or_else(|| RpcError::Shape("accountKeys missing".into()))?; + let account_keys: Vec = keys_value + .as_array() + .ok_or_else(|| RpcError::Shape("accountKeys is not an array".into()))? + .iter() + .map(|k| { + // jsonParsed renders each key as an object; base64/json as a string. + k.get("pubkey") + .and_then(|p| p.as_str()) + .or_else(|| k.as_str()) + .map(|s| s.to_string()) + .ok_or_else(|| RpcError::Shape("account key is neither object nor string".into())) + }) + .collect::>()?; + + let numbers = |field: &str| -> Result, RpcError> { + meta.get(field) + .and_then(|v| v.as_array()) + .ok_or_else(|| RpcError::Shape(format!("{field} missing")))? + .iter() + .map(|v| { + v.as_u64() + .ok_or_else(|| RpcError::Shape(format!("{field} entry is not a number"))) + }) + .collect() + }; + + Ok(TransactionView { + signature: signature.to_string(), + slot: value + .get("slot") + .and_then(|s| s.as_u64()) + .ok_or_else(|| RpcError::Shape("slot missing".into()))?, + block_time: value.get("blockTime").and_then(|t| t.as_i64()), + account_keys, + pre_balances: numbers("preBalances")?, + post_balances: numbers("postBalances")?, + fee: meta + .get("fee") + .and_then(|f| f.as_u64()) + .ok_or_else(|| RpcError::Shape("fee missing".into()))?, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// A `jsonParsed` response whose keys are objects, which is the shape the + /// collector actually receives. + fn json_parsed_fixture() -> serde_json::Value { + serde_json::json!({ + "slot": 250_000_000u64, + "blockTime": 1_700_000_000i64, + "transaction": { + "message": { + "accountKeys": [ + { "pubkey": "Payer1111111111111111111111111111111111111", "signer": true, "writable": true, "source": "transaction" }, + { "pubkey": "Recip111111111111111111111111111111111111", "signer": false, "writable": true, "source": "transaction" }, + { "pubkey": "Lut11111111111111111111111111111111111111", "signer": false, "writable": true, "source": "lookupTable" } + ] + } + }, + "meta": { + "fee": 5000u64, + "preBalances": [1_000_000u64, 0u64, 7u64], + "postBalances": [ 895_000u64, 100_000u64, 7u64] + } + }) + } + + #[test] + fn a_json_parsed_transaction_projects_correctly() { + let v = json_parsed_fixture(); + let t = parse_transaction("sig123", &v).unwrap(); + assert_eq!(t.account_keys.len(), 3); + assert_eq!(t.pre_balances.len(), 3); + assert!(t.is_well_formed()); + assert_eq!(t.fee, 5000); + assert_eq!(t.slot, 250_000_000); + + let edge = t + .edge_crediting("Recip111111111111111111111111111111111111") + .expect("recipient credited"); + assert_eq!(edge.value, 100_000); + assert_eq!( + edge.sources, + vec!["Payer1111111111111111111111111111111111111"] + ); + } + + /// Lookup-table addresses arrive folded into `accountKeys`, and the balance + /// arrays align with the full resolved list. If that ever stopped being + /// true, deltas would be attributed to the wrong accounts. + #[test] + fn lookup_table_keys_are_included_and_balances_align() { + let t = parse_transaction("sig123", &json_parsed_fixture()).unwrap(); + assert!( + t.account_keys.iter().any(|k| k.starts_with("Lut1")), + "lookup-table key was dropped" + ); + assert_eq!(t.account_keys.len(), t.post_balances.len()); + } + + #[test] + fn the_flat_account_keys_shape_is_also_accepted() { + let v = serde_json::json!({ + "slot": 1u64, + "transaction": { "accountKeys": ["aaa", "bbb"] }, + "meta": { "fee": 0u64, "preBalances": [10u64, 0u64], "postBalances": [5u64, 5u64] } + }); + let t = parse_transaction("s", &v).unwrap(); + assert_eq!(t.account_keys, vec!["aaa", "bbb"]); + } + + #[test] + fn a_malformed_response_is_an_error_not_a_default() { + // Every one of these would become a silent zero under unwrap_or. + let no_meta = serde_json::json!({ "slot": 1u64, "transaction": { "accountKeys": ["a"] } }); + assert!(parse_transaction("s", &no_meta).is_err()); + + let no_balances = serde_json::json!({ + "slot": 1u64, + "transaction": { "accountKeys": ["a"] }, + "meta": { "fee": 0u64 } + }); + assert!(parse_transaction("s", &no_balances).is_err()); + + let no_slot = serde_json::json!({ + "transaction": { "accountKeys": ["a"] }, + "meta": { "fee": 0u64, "preBalances": [1u64], "postBalances": [1u64] } + }); + assert!(parse_transaction("s", &no_slot).is_err()); + } + + #[test] + fn the_system_program_constant_is_right() { + assert_eq!(SYSTEM_PROGRAM.len(), 32); + assert!(SYSTEM_PROGRAM.chars().all(|c| c == '1')); + } + + #[test] + fn pacing_is_derived_from_the_measured_rate() { + let slow = RpcClient::new("http://example.invalid", 0.4); + assert!(slow.min_interval >= Duration::from_millis(2_400)); + let fast = RpcClient::new("http://example.invalid", 10.0); + assert!(fast.min_interval <= Duration::from_millis(100)); + } +} diff --git a/crates/mirror-provenance/src/trace.rs b/crates/mirror-provenance/src/trace.rs new file mode 100644 index 00000000..aa93c46c --- /dev/null +++ b/crates/mirror-provenance/src/trace.rs @@ -0,0 +1,1029 @@ +//! Pass one: walk the birth-edge chain and record what was seen. +//! +//! The only networked step. Everything it observes is written to a sample file, +//! and pass two runs over that file with no network at all — so a published +//! number can be recomputed by anyone holding the sample, without RPC access and +//! without trusting that our endpoint behaved the same way on their machine. +//! +//! ## Why the oldest edge +//! +//! Funding is, by definition, among an address's *oldest* transactions. +//! `getSignaturesForAddress` returns newest-first with no forward cursor, so for +//! an address with fewer than one page of lifetime signatures the birth +//! transaction is the **last element of the first page**. +//! +//! Taking the first few entries of that page instead — the most **recent** +//! transactions — is the wrong end of the history for any address with more +//! than a page-fragment of activity. It also fails silently, reporting +//! "unresolved" where the truth is "we looked in the wrong place", and it does +//! so for exactly the active wallets a funding trace most wants to follow. +//! +//! ## Where pass one stops +//! +//! Only on rules that are properties of the address itself: it is a program or a +//! PDA, it has no incoming edge, the edge is too small, or the budget ran out. +//! The set-level rules wait for pass two, which sees the whole sample. Stopping +//! early on an address-local rule is safe because pass two would fire the same +//! rule at the same place; the recorded chain is always a superset of what pass +//! two needs. + +use crate::{ + classify::Thresholds, + facts::{AddressFacts, SigCount}, + outcome::Unresolved, + rpc::{EndpointCheck, RpcClient, RpcError, SYSTEM_PROGRAM}, +}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +/// Which value flows the run followed. +/// +/// Recorded in the manifest because it bounds what the result can mean: a wallet +/// funded in USDC has no SOL funding event to find, and `getSignaturesForAddress` +/// does not index the recipient's wallet for a token transfer into an existing +/// account. A SOL-only run is structurally blind to the dominant exchange +/// withdrawal path, and its unresolved bucket is partly that blindness rather +/// than a property of the pool. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum Scope { + /// Native SOL only. + Sol, + /// SOL plus SPL token flows. Two and a half to three times the call count. + SolAndSpl, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct CollectionConfig { + pub scope: Scope, + /// Hops to follow before giving up. + pub depth_max: u32, + /// Credits below this are not treated as funding. + pub min_edge_lamports: u64, + /// Signature pages to read before declaring the address high-activity. + /// + /// Small on purpose. Paging exists to find the birth edge, and for an + /// address busy enough not to reach it, what we actually need is only enough + /// history to clear the volume-hub threshold and estimate an age — a few + /// thousand signatures, not tens of thousands. Raising this buys almost + /// nothing and costs a great deal: providers meter by compute units, and a + /// deep page walk over busy funders is what makes an endpoint start + /// refusing. + pub sig_page_cap: u32, + pub page_size: u32, + /// Transactions to examine, oldest first, while looking for the birth + /// *credit*. + /// + /// The rule is "the oldest credit", and an address's oldest **transaction** + /// is frequently not one: an account can appear as a passive participant in + /// someone else's transaction — an ATA creation, a multisig setup, a program + /// interaction that merely references it — before it ever receives value. + /// Reading only that one transaction and concluding "no incoming edge" + /// reports an absence of evidence where the truth is that we looked at a + /// single transaction out of thousands. + /// + /// So the walk continues forward from the oldest until a credit appears. + /// Exhausting this budget without finding one is a **budget** outcome and is + /// recorded as such, never as evidence about the address. + /// + /// Defaulted on deserialisation so that samples committed before this field + /// existed still load. A committed artifact is the whole point of the + /// two-pass split — anyone must be able to recompute a published number from + /// it years later — and a schema change that silently makes old samples + /// unreadable would quietly retire the evidence for every earlier claim. + #[serde(default = "default_birth_scan_cap")] + pub birth_scan_cap: u32, +} + +/// What runs before this field existed effectively did: read exactly one +/// transaction and stop. Recorded honestly rather than backfilled with today's +/// value, so an old sample reports the budget it was actually collected under. +fn default_birth_scan_cap() -> u32 { + 1 +} + +impl Default for CollectionConfig { + fn default() -> Self { + CollectionConfig { + scope: Scope::Sol, + depth_max: 6, + // Below the rent-exempt minimum for an empty account, so account + // creation itself always counts as funding. + min_edge_lamports: 500_000, + sig_page_cap: 20, + page_size: 1_000, + // Enough to clear the common cases — an ATA creation, a couple of + // program interactions — before the account is funded, without + // turning one address into a hundred transaction fetches. + birth_scan_cap: 24, + } + } +} + +/// Why pass one stopped walking a chain. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum ChainStop { + /// An address-local terminal rule fired. Pass two decides which. + LocalTerminal, + NoIncomingEdge, + BelowThreshold, + DepthExceeded, + PageCapHit, + RpcFailure, + /// The oldest transactions were examined up to `birth_scan_cap` and none of + /// them credited the address. A budget outcome: the credit may well exist + /// just beyond the scan. + BirthScanExhausted, +} + +impl ChainStop { + /// The unresolved reason this stop maps to when no rule fires in pass two. + pub fn as_unresolved(&self) -> Unresolved { + match self { + // A local terminal that pass two does not confirm means the address + // stopped being classifiable, which is a budget outcome rather than + // evidence about the chain. + ChainStop::LocalTerminal | ChainStop::DepthExceeded => Unresolved::DepthExceeded, + ChainStop::NoIncomingEdge => Unresolved::NoIncomingEdge, + ChainStop::BelowThreshold => Unresolved::BelowThreshold, + ChainStop::PageCapHit => Unresolved::PageCapHit, + ChainStop::RpcFailure => Unresolved::RpcFailure, + ChainStop::BirthScanExhausted => Unresolved::BirthScanExhausted, + } + } +} + +/// What a caller learns as each seed completes. +/// +/// Collection is bounded by network latency, not by work, so a run over a few +/// hundred seeds takes tens of minutes with nothing to show for it. Reporting +/// per seed is the difference between a tool that looks hung and one that does +/// not. +/// +/// A callback rather than printing: a library that writes to stdout takes a +/// decision that belongs to whoever is calling it. +#[derive(Debug, Clone)] +pub struct Progress<'a> { + pub done: usize, + pub total: usize, + pub seed: &'a str, + pub hops: usize, + pub stop: ChainStop, + /// RPC calls made across the whole run so far. + pub rpc_calls: u64, + /// When the chain stopped on a failure, what the endpoint actually said. + /// + /// Collapsing every failure to "RpcFailure" made the census honest and the + /// run undiagnosable: a rate limit, a timeout on a large page and a + /// malformed response are three different problems with three different + /// fixes, and they looked identical. + pub error: Option, +} + +/// One member's provenance chain, seed first. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct Chain { + pub seed: String, + pub visited: Vec, + pub stop: ChainStop, +} + +/// Strips credentials from an endpoint before it is written down. +/// +/// The manifest is a committed artifact, and provider URLs carry API keys in the +/// path or the query string. Recording the host tells a reader which provider +/// served the run — which is what they need to judge it — without publishing a +/// key that would then have to be rotated. +pub fn redact_endpoint(url: &str) -> String { + let without_query = url.split(['?', '#']).next().unwrap_or(url); + // Keep scheme and host, drop the path: Alchemy and Helius put the key there. + match without_query.split_once("://") { + Some((scheme, rest)) => { + let host = rest.split('/').next().unwrap_or(rest); + format!("{scheme}://{host}") + } + None => without_query + .split('/') + .next() + .unwrap_or(without_query) + .to_string(), + } +} + +/// What the manifest records so a reader can judge the run without rerunning it. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Manifest { + /// Host only. Any credential in the path or query is stripped by + /// [`redact_endpoint`] before this is written. + pub endpoint: String, + pub first_available_block: u64, + pub archival_probe_ok: bool, + pub collected_at: i64, + pub config: CollectionConfig, + pub thresholds_hub_signatures: u64, + pub thresholds_distributor_fanout: usize, + pub thresholds_cluster_min_size: usize, + pub rpc_calls: u64, + /// Seeds dropped before tracing because they are not wallets: a program, a + /// PDA, a token account, or an address with no account at all. + /// + /// This is a **definitional** frame criterion, not an outcome-correlated + /// one. A token account is not a person and cannot be a member of an + /// anonymity set, so including it would measure something other than the + /// pool. Excluding addresses because they looked *hard to trace* would be a + /// different thing entirely: that criterion correlates with the outcome, so + /// it manufactures whichever headline the exclusion implies. The count is + /// published rather than quietly applied, so the distinction is checkable. + pub excluded_non_wallet: Vec, + /// Share of observed credits whose source was one of several debited + /// accounts, so the funder is a set rather than a single address. + pub ambiguous_attribution_rate: f64, +} + +/// Everything pass one produced. This is the artifact that gets committed, and +/// pass two needs nothing else. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Sample { + pub manifest: Manifest, + pub chains: Vec, + pub facts: BTreeMap, +} + +impl Sample { + pub fn to_json(&self) -> Result { + serde_json::to_string_pretty(self) + } + + pub fn from_json(s: &str) -> Result { + serde_json::from_str(s) + } +} + +/// Walks chains from each seed, recording facts along the way. +pub struct Collector<'a> { + client: &'a mut RpcClient, + config: CollectionConfig, + facts: BTreeMap, + /// Addresses whose observation is *complete*, meaning signatures were paged + /// and the birth edge resolved. + /// + /// Distinct from "we know the owner". Frame validation learns the owner of + /// every seed before tracing, so keying the cache on the owner alone would + /// make the trace believe every seed was already done and skip the paging + /// entirely — which yields a run where nothing resolves and nothing errors. + fully_observed: std::collections::BTreeSet, + last_error: Option, + ambiguous: u64, + edges_seen: u64, +} + +impl<'a> Collector<'a> { + pub fn new(client: &'a mut RpcClient, config: CollectionConfig) -> Self { + Collector { + client, + config, + facts: BTreeMap::new(), + fully_observed: std::collections::BTreeSet::new(), + last_error: None, + ambiguous: 0, + edges_seen: 0, + } + } + + /// Collects every seed and assembles the sample. + pub fn collect( + self, + seeds: &[String], + check: &EndpointCheck, + thresholds: &Thresholds, + now: i64, + ) -> Sample { + self.collect_with_progress(seeds, check, thresholds, now, |_| {}) + } + + /// Collects every seed, reporting each one as it completes. + pub fn collect_with_progress)>( + mut self, + seeds: &[String], + check: &EndpointCheck, + thresholds: &Thresholds, + now: i64, + mut on_progress: F, + ) -> Sample { + let mut chains = Vec::with_capacity(seeds.len()); + let mut excluded_non_wallet = Vec::new(); + for (index, seed) in seeds.iter().enumerate() { + let chain = match self.is_wallet(seed) { + Ok(true) => Some(self.trace(seed)), + Ok(false) => { + excluded_non_wallet.push(seed.clone()); + None + } + // An endpoint failure here is not evidence that the seed is not + // a wallet, so it stays in the frame and fails honestly during + // the trace. + Err(_) => Some(self.trace(seed)), + }; + if let Some(chain) = chain { + on_progress(Progress { + done: index + 1, + total: seeds.len(), + seed, + hops: chain.visited.len(), + stop: chain.stop, + rpc_calls: self.client.calls_made(), + error: self.last_error.take(), + }); + chains.push(chain); + } + } + Sample { + manifest: Manifest { + endpoint: redact_endpoint(&check.endpoint), + first_available_block: check.first_available_block, + archival_probe_ok: check.archival_probe_ok, + collected_at: now, + config: self.config.clone(), + thresholds_hub_signatures: thresholds.hub_signatures, + thresholds_distributor_fanout: thresholds.distributor_fanout, + thresholds_cluster_min_size: thresholds.cluster_min_size, + rpc_calls: self.client.calls_made(), + excluded_non_wallet, + ambiguous_attribution_rate: if self.edges_seen == 0 { + 0.0 + } else { + self.ambiguous as f64 / self.edges_seen as f64 + }, + }, + chains, + facts: self.facts, + } + } + + /// Whether a seed belongs in the frame at all. + /// + /// A member of an anonymity set is a person's wallet: an existing account + /// owned by the system program. A token account, a PDA, a program, or an + /// address whose account has been closed is none of those. + fn is_wallet(&mut self, address: &str) -> Result { + let owner = self.client.account_owner(address)?; + let verdict = match &owner { + None => false, + Some(o) => o.owner == SYSTEM_PROGRAM && !o.executable, + }; + // Keep what we learned; the trace would otherwise fetch it again. + let entry = self + .facts + .entry(address.to_string()) + .or_insert_with(|| AddressFacts::new(address)); + entry.executable = owner.as_ref().is_some_and(|o| o.executable); + entry.owner = owner.map(|o| o.owner); + Ok(verdict) + } + + fn trace(&mut self, seed: &str) -> Chain { + let mut visited = Vec::new(); + let mut current = seed.to_string(); + + for hop in 0..=self.config.depth_max { + visited.push(current.clone()); + + let stop = match self.observe(¤t) { + Err(e) => { + self.last_error = Some(e.to_string()); + Some(ChainStop::RpcFailure) + } + Ok(local_terminal) if local_terminal => Some(ChainStop::LocalTerminal), + Ok(_) => None, + }; + if let Some(stop) = stop { + return Chain { + seed: seed.to_string(), + visited, + stop, + }; + } + + if hop == self.config.depth_max { + return Chain { + seed: seed.to_string(), + visited, + stop: ChainStop::DepthExceeded, + }; + } + + let facts = &self.facts[¤t]; + let Some(edge) = facts.birth_edge.clone() else { + // Three different reasons there is no edge, and only one of them + // is a statement about the address. Ordered from ours to theirs: + // we never reached the oldest page; we reached it but stopped + // scanning forward before a credit appeared; or we read the + // whole early history and there genuinely is no credit. + let stop = if matches!(facts.signatures, SigCount::AtLeast(_)) { + ChainStop::PageCapHit + } else if facts.birth_scan_exhausted { + ChainStop::BirthScanExhausted + } else { + ChainStop::NoIncomingEdge + }; + return Chain { + seed: seed.to_string(), + visited, + stop, + }; + }; + if edge.value < self.config.min_edge_lamports { + return Chain { + seed: seed.to_string(), + visited, + stop: ChainStop::BelowThreshold, + }; + } + + // Follow the first source. With one source this is exact; with + // several the edge is already flagged ambiguous and the rate is + // reported, rather than the choice being hidden. + let next = edge.sources[0].clone(); + self.note_funding(&next, ¤t); + current = next; + } + + Chain { + seed: seed.to_string(), + visited, + stop: ChainStop::DepthExceeded, + } + } + + /// Records that `funder` created `child`, for the fan-out rule. + fn note_funding(&mut self, funder: &str, child: &str) { + let entry = self + .facts + .entry(funder.to_string()) + .or_insert_with(|| AddressFacts::new(funder)); + if !entry.funded.iter().any(|f| f == child) { + entry.funded.push(child.to_string()); + } + } + + /// Fills in one address's facts. Returns whether an address-local terminal + /// rule fired, which is the only reason pass one stops early. + fn observe(&mut self, address: &str) -> Result { + if self.fully_observed.contains(address) { + // Seen completely on another chain. Re-fetching would cost calls and + // could return a different answer as the chain advances, which would + // make the sample internally inconsistent. + let existing = &self.facts[address]; + return Ok(is_local_terminal(existing)); + } + + let mut facts = self + .facts + .remove(address) + .unwrap_or_else(|| AddressFacts::new(address)); + + // Frame validation may already have fetched this; do not pay twice. + if facts.owner.is_none() && !facts.executable { + let owner = self.client.account_owner(address)?; + facts.executable = owner.as_ref().is_some_and(|o| o.executable); + facts.owner = owner.map(|o| o.owner); + } + + if is_local_terminal(&facts) { + // A program or PDA terminates here; its funding history is not a + // person's and costs calls to walk. + self.facts.insert(address.to_string(), facts); + self.fully_observed.insert(address.to_string()); + return Ok(true); + } + + self.page_to_birth(address, &mut facts)?; + self.facts.insert(address.to_string(), facts); + self.fully_observed.insert(address.to_string()); + Ok(false) + } + + /// Pages backwards to the oldest signature and reads the birth edge from it. + fn page_to_birth(&mut self, address: &str, facts: &mut AddressFacts) -> Result<(), RpcError> { + let mut before: Option = None; + let mut seen: u64 = 0; + let mut oldest: Option = None; + let mut last_seen_time: Option = None; + // The oldest page, kept whole. The birth credit is looked for by walking + // forward from its end, so the single oldest signature is not enough. + let mut oldest_page: Vec = Vec::new(); + + for page in 0..self.config.sig_page_cap { + let batch = self.client.signatures_for_address( + address, + before.as_deref(), + self.config.page_size, + )?; + if batch.is_empty() { + break; + } + seen += batch.len() as u64; + let last = batch.last().expect("non-empty").clone(); + before = Some(last.signature.clone()); + last_seen_time = last.block_time.or(last_seen_time); + oldest = Some(last); + oldest_page = batch.clone(); + + if (batch.len() as u32) < self.config.page_size { + // A short page is the end of the history: this is exact. + facts.signatures = SigCount::Exact(seen); + break; + } + if page + 1 == self.config.sig_page_cap { + // The cap is a classification signal with a name, never a + // silent unresolved: the count is a lower bound and says so. + facts.signatures = SigCount::AtLeast(seen); + // Record the age too, from the oldest signature reached. This + // is the whole point of the volume-hub rule: an address busy + // enough to exhaust the paging budget is exactly the kind that + // should be classified rather than dropped. + // + // The value is conservative in the right direction. We stopped + // before the true oldest signature, so the real account is at + // least this old; an address that already looks thirty days old + // from a partial view is genuinely at least that. + facts.first_seen = last_seen_time; + return Ok(()); + } + } + + let Some(oldest) = oldest else { + facts.signatures = SigCount::Exact(0); + return Ok(()); + }; + if !facts.signatures.is_exact() && seen > 0 { + facts.signatures = SigCount::Exact(seen); + } + facts.first_seen = oldest.block_time; + + // Walk forward from the oldest transaction until one credits the + // address. The oldest transaction is very often not a credit — an + // account routinely appears as a passive participant in someone else's + // transaction before it is ever funded — and stopping there reports "no + // incoming edge" for an address that plainly has one. + let scanned = self.scan_for_birth_credit(address, &oldest_page, facts)?; + facts.birth_scan_exhausted = facts.birth_edge.is_none() && scanned >= self.birth_budget(); + Ok(()) + } + + fn birth_budget(&self) -> usize { + self.config.birth_scan_cap as usize + } + + /// Examines up to `birth_scan_cap` transactions, oldest first, and records + /// the first that credits `address`. + /// + /// Returns how many were examined, so the caller can tell "there is no + /// credit here" from "we stopped looking". Those must never be the same + /// outcome. + fn scan_for_birth_credit( + &mut self, + address: &str, + oldest_page: &[crate::rpc::SignatureInfo], + facts: &mut AddressFacts, + ) -> Result { + let budget = self.birth_budget(); + let mut examined = 0usize; + + // `oldest_page` is newest-first, so walking it in reverse is oldest-first. + for info in oldest_page.iter().rev() { + if examined >= budget { + break; + } + if info.err { + // A failed transaction moved no value. It costs nothing to skip + // and is not worth a fetch. + continue; + } + examined += 1; + let tx = self.client.transaction(&info.signature)?; + + // Fee-payer clustering wants the payer of the address's earliest + // transactions, so record it for every one examined rather than + // only for the one that happens to carry the credit. + if let Some(payer) = tx.account_keys.first() { + if !facts.fee_payers.iter().any(|p| p == payer) { + facts.fee_payers.push(payer.clone()); + } + } + + if let Some(edge) = tx.edge_crediting(address) { + self.edges_seen += 1; + if edge.ambiguous_attribution { + self.ambiguous += 1; + } + facts.birth_edge = Some(edge); + return Ok(examined); + } + } + Ok(examined) + } +} + +/// Address-local terminal test: a program or a PDA. +fn is_local_terminal(facts: &AddressFacts) -> bool { + facts + .owner + .as_ref() + .is_some_and(|o| o != SYSTEM_PROGRAM || facts.executable) +} + +/// Pass two: the first terminal along each chain, over the complete sample. +pub fn classify_sample( + sample: &Sample, + anchors: &crate::classify::AnchorSet, + thresholds: &Thresholds, + now: i64, +) -> ( + Vec<(String, crate::outcome::Outcome)>, + crate::outcome::Census, +) { + use crate::{ + classify::{Classifier, SetStructure}, + outcome::{Census, Outcome}, + }; + + let structure = SetStructure::build(&sample.facts, thresholds); + let classifier = Classifier { + anchors, + structure: &structure, + thresholds, + now, + }; + + let mut results = Vec::with_capacity(sample.chains.len()); + let mut census = Census::default(); + + for chain in &sample.chains { + let mut outcome = None; + for (depth, address) in chain.visited.iter().enumerate() { + // The seed itself is a member, not its own origin. + if depth == 0 { + continue; + } + if let Some(facts) = sample.facts.get(address) { + if let Some(found) = classifier.classify(facts) { + outcome = Some(found); + break; + } + } + } + let outcome = outcome.unwrap_or(Outcome::Unresolved { + reason: chain.stop.as_unresolved(), + depth: chain.visited.len().saturating_sub(1) as u32, + }); + census.record(&outcome); + results.push((chain.seed.clone(), outcome)); + } + + (results, census) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{classify::AnchorSet, edge::FundingEdge, outcome::Outcome}; + + const NOW: i64 = 1_800_000_000; + + fn wallet(address: &str) -> AddressFacts { + let mut f = AddressFacts::new(address); + f.owner = Some(SYSTEM_PROGRAM.to_string()); + f + } + + fn edge(sink: &str, source: &str, value: u64) -> FundingEdge { + FundingEdge { + sink: sink.into(), + sources: vec![source.into()], + value, + signature: "sig".into(), + slot: 1, + block_time: Some(NOW - 1_000), + ambiguous_attribution: false, + } + } + + fn sample_with(chains: Vec, facts: Vec) -> Sample { + Sample { + manifest: Manifest { + endpoint: "test".into(), + first_available_block: 0, + archival_probe_ok: true, + collected_at: NOW, + config: CollectionConfig::default(), + thresholds_hub_signatures: 5_000, + thresholds_distributor_fanout: 20, + thresholds_cluster_min_size: 3, + rpc_calls: 0, + excluded_non_wallet: Vec::new(), + ambiguous_attribution_rate: 0.0, + }, + chains, + facts: facts.into_iter().map(|f| (f.address.clone(), f)).collect(), + } + } + + #[test] + fn a_chain_resolves_at_the_first_terminal_past_the_seed() { + let mut program = wallet("Vault1"); + program.owner = Some("Whirlpoo1111111111111111111111111111111111".into()); + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into(), "hop1".into(), "Vault1".into()], + stop: ChainStop::LocalTerminal, + }], + vec![wallet("member"), wallet("hop1"), program], + ); + let (results, census) = + classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert_eq!(results.len(), 1); + assert_eq!(results[0].1.label().unwrap(), "program:Vault1"); + assert_eq!(census.resolved, 1); + } + + /// The seed is the member being measured, so it must not classify itself. + /// Without this a member who happens to be a busy address would be its own + /// provenance class, which is meaningless. + #[test] + fn a_seed_is_never_its_own_origin() { + let mut busy_seed = wallet("member"); + busy_seed.signatures = SigCount::AtLeast(50_000); + busy_seed.first_seen = Some(NOW - 400 * 24 * 3_600); + + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into()], + stop: ChainStop::NoIncomingEdge, + }], + vec![busy_seed], + ); + let (results, _) = + classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert!( + matches!( + results[0].1, + Outcome::Unresolved { + reason: Unresolved::NoIncomingEdge, + .. + } + ), + "the seed classified itself: {:?}", + results[0].1 + ); + } + + #[test] + fn every_chain_stop_maps_to_a_named_outcome() { + // No stop may fall through to a default, and an RPC failure must stay + // distinguishable from a genuine dead end. + for (stop, expected) in [ + (ChainStop::NoIncomingEdge, Unresolved::NoIncomingEdge), + (ChainStop::BelowThreshold, Unresolved::BelowThreshold), + (ChainStop::DepthExceeded, Unresolved::DepthExceeded), + (ChainStop::PageCapHit, Unresolved::PageCapHit), + (ChainStop::RpcFailure, Unresolved::RpcFailure), + ( + ChainStop::BirthScanExhausted, + Unresolved::BirthScanExhausted, + ), + ] { + assert_eq!(stop.as_unresolved(), expected, "{stop:?} mapped wrongly"); + } + } + + /// Running out of birth-scan budget is **our** limit, so it must never be + /// counted as evidence about the address, and it must never be collapsed + /// into `NoIncomingEdge`. + /// + /// The distinction is the entire point: one says "this address has no + /// funding credit", which is a claim about the chain, and the other says + /// "we stopped reading", which is a claim about us. + #[test] + fn an_exhausted_birth_scan_is_budget_and_not_evidence() { + assert!(!Unresolved::BirthScanExhausted.is_evidence()); + assert!(!Unresolved::BirthScanExhausted.is_failure()); + + let mut seed = wallet("member"); + seed.birth_scan_exhausted = true; + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into()], + stop: ChainStop::BirthScanExhausted, + }], + vec![seed], + ); + let (_, census) = + classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert_eq!(census.birth_scan_exhausted, 1); + assert_eq!( + census.no_incoming_edge, 0, + "a budget outcome leaked into the evidence bucket" + ); + assert!( + census.summary().contains("budget-unresolved 1"), + "must be reported as budget: {}", + census.summary() + ); + assert!( + census.summary().contains("evidence-unresolved 0"), + "must not be reported as evidence: {}", + census.summary() + ); + } + + #[test] + fn an_rpc_failure_stays_a_failure_and_is_excluded_from_the_distribution() { + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into(), "hop1".into()], + stop: ChainStop::RpcFailure, + }], + vec![wallet("member"), wallet("hop1")], + ); + let (_, census) = + classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert_eq!(census.rpc_failure, 1); + assert_eq!(census.measurable(), 0); + assert!( + !census.may_publish(), + "a run that is all failure must not publish" + ); + } + + /// Two members funded through the same exchange land in the same class even + /// though their chains differ in length. That is the whole mechanism. + #[test] + fn members_sharing_an_origin_share_a_class() { + let sample = sample_with( + vec![ + Chain { + seed: "alice".into(), + visited: vec!["alice".into(), "ExchangeHot".into()], + stop: ChainStop::LocalTerminal, + }, + Chain { + seed: "bob".into(), + visited: vec!["bob".into(), "hop".into(), "ExchangeHot".into()], + stop: ChainStop::LocalTerminal, + }, + ], + vec![ + wallet("alice"), + wallet("bob"), + wallet("hop"), + wallet("ExchangeHot"), + ], + ); + let anchors = AnchorSet::from_pairs([("ExchangeHot", "someexchange")]); + let (results, _) = classify_sample(&sample, &anchors, &Thresholds::default(), NOW); + assert_eq!(results[0].1.label(), results[1].1.label()); + assert_eq!(results[0].1.label().unwrap(), "entity:someexchange"); + } + + #[test] + fn a_sample_round_trips_through_json() { + let mut funded = wallet("funder"); + funded.birth_edge = Some(edge("funder", "upstream", 1_000_000)); + funded.funded = vec!["a".into(), "b".into()]; + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into(), "funder".into()], + stop: ChainStop::DepthExceeded, + }], + vec![wallet("member"), funded], + ); + let json = sample.to_json().unwrap(); + let back = Sample::from_json(&json).unwrap(); + assert_eq!( + sample, back, + "the committed artifact must survive a round trip" + ); + } + + /// The property the whole two-pass design exists for: analysis of a + /// committed sample is a pure function, so anyone can recompute the headline + /// without RPC access. + #[test] + fn classifying_the_same_sample_twice_gives_the_same_answer() { + let mut hub = wallet("Hub"); + hub.signatures = SigCount::AtLeast(50_000); + hub.first_seen = Some(NOW - 400 * 24 * 3_600); + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into(), "Hub".into()], + stop: ChainStop::LocalTerminal, + }], + vec![wallet("member"), hub], + ); + let a = classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + let b = classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert_eq!(a.0, b.0); + assert_eq!(a.1, b.1); + assert_eq!(a.0[0].1.label().unwrap(), "busy-unlabelled:Hub"); + } + + /// An address busy enough to exhaust the paging budget is exactly the kind + /// the volume-hub rule exists for, so it must arrive at pass two carrying an + /// age. An earlier version returned from paging before recording one, and + /// every page-capped funder fell through to unresolved — which on a real + /// sample was thirty chains out of thirty-seven. + #[test] + fn a_page_capped_funder_is_classified_rather_than_dropped() { + let mut hub = wallet("BusyFunder"); + hub.signatures = SigCount::AtLeast(20_000); + hub.first_seen = Some(NOW - 400 * 24 * 3_600); + + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into(), "BusyFunder".into()], + stop: ChainStop::PageCapHit, + }], + vec![wallet("member"), hub], + ); + let (results, census) = + classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert_eq!( + results[0].1.label().unwrap(), + "busy-unlabelled:BusyFunder", + "a page-capped funder with an age must classify" + ); + assert_eq!(census.resolved, 1); + assert_eq!(census.page_cap_hit, 0); + } + + /// Without an age it cannot classify, and that is the correct outcome — but + /// it must land in the budget bucket rather than look like evidence. + #[test] + fn a_page_capped_funder_without_an_age_stays_a_budget_outcome() { + let mut hub = wallet("BusyFunder"); + hub.signatures = SigCount::AtLeast(20_000); + hub.first_seen = None; + + let sample = sample_with( + vec![Chain { + seed: "member".into(), + visited: vec!["member".into(), "BusyFunder".into()], + stop: ChainStop::PageCapHit, + }], + vec![wallet("member"), hub], + ); + let (results, census) = + classify_sample(&sample, &AnchorSet::default(), &Thresholds::default(), NOW); + assert!(matches!( + results[0].1, + Outcome::Unresolved { + reason: Unresolved::PageCapHit, + .. + } + )); + assert_eq!(census.page_cap_hit, 1); + assert!(!Unresolved::PageCapHit.is_evidence()); + } + + /// The manifest is committed, so a provider key must never reach it. + #[test] + fn a_credential_never_reaches_the_manifest() { + for (url, expected) in [ + ( + "https://solana-mainnet.g.alchemy.com/v2/alch_SECRETKEY123", + "https://solana-mainnet.g.alchemy.com", + ), + ( + "https://mainnet.helius-rpc.com/?api-key=deadbeef-cafe", + "https://mainnet.helius-rpc.com", + ), + ( + "https://api.mainnet-beta.solana.com", + "https://api.mainnet-beta.solana.com", + ), + ] { + let got = redact_endpoint(url); + assert_eq!(got, expected); + assert!(!got.contains("SECRETKEY"), "key survived redaction: {got}"); + assert!(!got.contains("deadbeef"), "key survived redaction: {got}"); + } + } + + #[test] + fn the_default_edge_threshold_admits_account_creation() { + // Rent exemption for an empty account is about 890,880 lamports, so a + // threshold above it would discard the very event that creates a wallet. + let c = CollectionConfig::default(); + assert!( + c.min_edge_lamports < 890_880, + "the threshold would reject account creation itself" + ); + } +} diff --git a/data/crowd-result-43000007.json b/data/crowd-result-43000007.json new file mode 100644 index 00000000..81d0a8a1 --- /dev/null +++ b/data/crowd-result-43000007.json @@ -0,0 +1,149 @@ +{ + "pool": "Cqg4gj4zwHZGfp1P2v6j6pB4dLbWgsL1vJB7YkjsFWAK", + "vault": "6NrJ3id157J7qMi5veukujtvX6T5rJz1WZT1m6gd8eMZ", + "denomination": 43000007, + "ceiling": { + "divergent": 6, + "uniform": 7, + "divergent_bytes": 1194, + "over_bytes": 1332, + "budget_bytes": 40 + }, + "roster": [ + { + "stake": "5P9AHY2tGoQ9xedLeyvC5WsU4FXxxH8LgtC2kzRUMZtT", + "vote": "vgcDar2pryHvMgPkKaZfh8pQy4BJxv7SpwUG7zinWjG", + "relay": "7GC9vjEJTUk1d3DLfb9ufBuSo4ooU5HzAmzeGdFejtBX" + }, + { + "stake": "DrrzXbAmLdgLfmcGtN1mAjgEuRK5mPyRSVcwazUtUWaT", + "vote": "i7NyKBMJCA9bLM2nsGyAGCKHECuR2L5eh4GqFciuwNT", + "relay": "CDNhhfH3qspD6Bgwsd6i7T6EGjE3r7yWPGBwaHyi5TXM" + }, + { + "stake": "EgGXn9y2ea9bDqGoUpU6Z8ET2JNm6zNaFu1Ux2x6RNNx", + "vote": "5ZWgXcyqrrNpQHCme5SdC5hCeYb2o3fEJhF7Gok3bTVN", + "relay": "2UWeNWf8yg3UPbeycv6SMoKLjmbtD2XgAX8wiQ92RouF" + }, + { + "stake": "FgWdYn2gN9oUxN18NJ958BkgR5zoCFagWp73pQ1YHc9x", + "vote": "23AoPQc3EPkfLWb14cKiWNahh1H9rtb3UBk8gWseohjF", + "relay": "D1oCaiaGCJGyi2Co7mE7W5nMpcATdDnGtGMSGrk8Qcpw" + }, + { + "stake": "Fa8khDvR3arVezDmDZpLPHA4VVwRuSwzfJ2gcDSKQmDo", + "vote": "7AETLyAGJWjp6AWzZqZcP362yv5LQ3nLEdwnXNjdNwwF", + "relay": "DtoAEYygmCWw156gn4DB1ZCUTJ9szUbT7mLxqNs5bTos" + }, + { + "stake": "B5unNLodBUxcsggqV4g1KzoyAXz4oNHN3bEnRTJ1Fmkw", + "vote": "2u83Dx5qPV4QnujjJQv8v2SoqG1ixuAxPK5Jwhtkovd1", + "relay": "3dYe9vTAVYpsrSYtxLRrawFYQaMNQsLhqhscmFhRKobY" + } + ], + "signature": "5SqtqpuJw3pAoBMMB9DmXaqFr93rWsnqWMyacRZ3ZpP5eQpacLTAjrYugAW2ni3PMucAzDLJ4TsLZU3aQd3ZVMPZ", + "bytes": 1194, + "compute_units": 142856, + "steps": [ + { + "name": "init_pool", + "signature": "5dPVS1efe2JcqJxV26Lxk5QwnTdsy8qfxc6wbFJXKNM9ES16qx6gG7P53c9RLnuMkzswjM9yoW4JEScrwYYg4HSN", + "note": "denomination 43000007, k_floor 6" + }, + { + "name": "deposit", + "signature": "4eTFg35LP21D3HCQYn2DE7WExrhNZsmyfh39i7GMYe9bxfsyEhdJJ2STDt2c6SmaeEGAB1whQbRtqbr71kRoMfDr", + "note": "note 1" + }, + { + "name": "deposit", + "signature": "2BqmBu6anyCMhyvexeVsuH9zLB847bW1xBNndxeidCU7FYma3VyxcqTUEmRRVvJgH95MtTzsuEbwcRuxD4K25VQm", + "note": "note 2" + }, + { + "name": "deposit", + "signature": "7RwN4jc54ioVS7Y8m8p9PKGnU2vPrwPpK7jRZ4RvfmF4TWCniBxzNrxzbXpkFt3R6VWhfKnvP4d5sypGrCCXq2E", + "note": "note 3" + }, + { + "name": "deposit", + "signature": "3drHxm9YgHi4VUy45HRVbmtZQe76oaPF7dxYWh6VAXKiJhUG7uBscPuDhmZVzRdnmFHtvg72PR9qwMU4RizpKPiE", + "note": "note 4" + }, + { + "name": "deposit", + "signature": "2YB3RHGPCu3cY3tXjnRkFisd7q2JYZUnYB2z8hC11FHbX5YAsGjSiAs7BJbGTg4JHXE3FVwSVpz9t9NFevdQ5Gxh", + "note": "note 5" + }, + { + "name": "deposit", + "signature": "2UHgtUdLYJQmqBXcJWPJPK7VM6uBLKqaZdcMucXWoUUVpYV4Cnk8ox1jMUSZx9DJk6Xp6EKEQtxL9WLdWP4jT2ZL", + "note": "note 6" + }, + { + "name": "create stake account", + "signature": "28djx5Y9hNmg58XbTzd4if4N6H2kZUwfREBKtdrCsFnV6Gu6bb6ptrGtMzL6VoZnVYSFKRXQTDNcKHdLUiQoGHwq", + "note": "1100000000 lamports, staker = the pool's vault" + }, + { + "name": "submit_spend", + "signature": "5D6VC6czzJ79fzuvvXuNHX5xcV5p7Gbv6hxDwHzgt5QtHHKScu11hYSBkdPPe7kQoUhhQEBoyiDPzjWGGVnroyFT", + "note": "note 0, relay-signed, delegate to vgcDar2pryHvMgPkKaZfh8pQy4BJxv7SpwUG7zinWjG" + }, + { + "name": "create stake account", + "signature": "2Tv4CZSFD8wxpuhiihsw2xEd53bxTE7i6ka1dpZvzhcfDqXxdCL8k1jydgPCjJ7pUuL4CuPHP11BnJHPqjsawK6V", + "note": "1100000000 lamports, staker = the pool's vault" + }, + { + "name": "submit_spend", + "signature": "4gpxQ7UzGNKBwft1Y8dmDszs2jRz1S1Q2RZsFkLf4AjmyY1B3YNSyPoLPA5uqbRonWx2SkYZCYFtyS5AZN2EKsGK", + "note": "note 1, relay-signed, delegate to i7NyKBMJCA9bLM2nsGyAGCKHECuR2L5eh4GqFciuwNT" + }, + { + "name": "create stake account", + "signature": "3znGocR1LKMkffXQ1yHm9BKfhbM1o4Y6r22J3vyKjGLK76fAfArMxe7CeoP8sk4umStTt7f7EtSKbe29zaz4iges", + "note": "1100000000 lamports, staker = the pool's vault" + }, + { + "name": "submit_spend", + "signature": "2YBakbrJy1CXTaJpkxwAr54EW5PdWytG4P2ycJqFyRx48tdKKMqMuejEjS9JaMGmxGHKY9uiJ623tjb8ErDUFHS1", + "note": "note 2, relay-signed, delegate to 5ZWgXcyqrrNpQHCme5SdC5hCeYb2o3fEJhF7Gok3bTVN" + }, + { + "name": "create stake account", + "signature": "MhASpmqysCWXNrS5B36RVopqKnQKFcSRanQBd1nueD2bCck4SQBvJEqYy98ajhb9JC8UcvvncjRQcghnDyXYqzf", + "note": "1100000000 lamports, staker = the pool's vault" + }, + { + "name": "submit_spend", + "signature": "uEZXvq615hGxgeKKYmrpP4YPp5B3xygRUNAgZ4ddCH47q6NypgQqR49B8U1vMB9XVWnZQaPjqcqbV1JeQgAKFvN", + "note": "note 3, relay-signed, delegate to 23AoPQc3EPkfLWb14cKiWNahh1H9rtb3UBk8gWseohjF" + }, + { + "name": "create stake account", + "signature": "3JYyJ1ZnuGUdX888cV4zkqmhqTd42zE8QAbo3x8jJ6bfnC4MZT2RkiQkLHnqtjkNJmTQSAeQDLbEVwWRXaMmS5ES", + "note": "1100000000 lamports, staker = the pool's vault" + }, + { + "name": "submit_spend", + "signature": "5KE1wc2VZh6GTLiiVNQ8Xad92hHoKNARZ8AEWQvwJeBsfLJ93Cc6GkvVtieTdwCh5ZjPcDTwk31Jjzwshtemr7XN", + "note": "note 4, relay-signed, delegate to 7AETLyAGJWjp6AWzZqZcP362yv5LQ3nLEdwnXNjdNwwF" + }, + { + "name": "create stake account", + "signature": "2fRNA4wLYzoJceT2HmAXEPrvK1Sv1haqfRJK7vDDcyKCLQPa65ebcE9u6Lm8DZbdgfWm2LiaS5nDUzvxaCNrwecE", + "note": "1100000000 lamports, staker = the pool's vault" + }, + { + "name": "submit_spend", + "signature": "4haLJna7fmp85ahKppvXR8bVgGSFmhsftxy1XEfuztZ8mKVKxdVzdwLVwS6CedD2fmzdMwPWc5Na2DAaNvUZdgQM", + "note": "note 5, relay-signed, delegate to 2u83Dx5qPV4QnujjJQv8v2SoqG1ixuAxPK5Jwhtkovd1" + }, + { + "name": "settle_epoch", + "signature": "5SqtqpuJw3pAoBMMB9DmXaqFr93rWsnqWMyacRZ3ZpP5eQpacLTAjrYugAW2ni3PMucAzDLJ4TsLZU3aQd3ZVMPZ", + "note": "6 delegations to 6 different validators, one transaction, 1194 bytes" + } + ] +} diff --git a/data/sample-marinade-run7.json b/data/sample-marinade-run7.json new file mode 100644 index 00000000..4471957a --- /dev/null +++ b/data/sample-marinade-run7.json @@ -0,0 +1,5302 @@ +{ + "manifest": { + "endpoint": "https://mainnet.helius-rpc.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1785043027, + "config": { + "scope": "Sol", + "depth_max": 16, + "min_edge_lamports": 500000, + "sig_page_cap": 24, + "page_size": 1000, + "birth_scan_cap": 24 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 1887, + "excluded_non_wallet": [ + "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip", + "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8", + "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv", + "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK", + "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN", + "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi", + "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg", + "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd" + ], + "ambiguous_attribution_rate": 0.021897810218978103 + }, + "chains": [ + { + "seed": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "visited": [ + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "visited": [ + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V", + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "stop": "PageCapHit" + }, + { + "seed": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "visited": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "visited": [ + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "visited": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "visited": [ + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "stop": "PageCapHit" + }, + { + "seed": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "visited": [ + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "visited": [ + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh", + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6", + "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ" + ], + "stop": "LocalTerminal" + }, + { + "seed": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "visited": [ + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "stop": "PageCapHit" + }, + { + "seed": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "visited": [ + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "stop": "PageCapHit" + }, + { + "seed": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "visited": [ + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi" + ], + "stop": "LocalTerminal" + }, + { + "seed": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "visited": [ + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "visited": [ + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "visited": [ + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw" + ], + "stop": "LocalTerminal" + }, + { + "seed": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "visited": [ + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ", + "visited": [ + "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ" + ], + "stop": "PageCapHit" + }, + { + "seed": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "visited": [ + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "visited": [ + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "stop": "PageCapHit" + }, + { + "seed": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "visited": [ + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "stop": "PageCapHit" + }, + { + "seed": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "visited": [ + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "stop": "PageCapHit" + }, + { + "seed": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "visited": [ + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ", + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi", + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "visited": [ + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i", + "visited": [ + "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i" + ], + "stop": "PageCapHit" + }, + { + "seed": "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq", + "visited": [ + "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq" + ], + "stop": "PageCapHit" + }, + { + "seed": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "visited": [ + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW", + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "stop": "PageCapHit" + }, + { + "seed": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "visited": [ + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK" + ], + "stop": "PageCapHit" + }, + { + "seed": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "visited": [ + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "visited": [ + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn", + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq", + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w" + ], + "stop": "PageCapHit" + }, + { + "seed": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "visited": [ + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "visited": [ + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "visited": [ + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "visited": [ + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "stop": "PageCapHit" + }, + { + "seed": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "visited": [ + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J", + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "visited": [ + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "stop": "PageCapHit" + }, + { + "seed": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "visited": [ + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn" + ], + "stop": "PageCapHit" + }, + { + "seed": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "visited": [ + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk", + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "stop": "PageCapHit" + }, + { + "seed": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "visited": [ + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu" + ], + "stop": "LocalTerminal" + }, + { + "seed": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "visited": [ + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "visited": [ + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "stop": "PageCapHit" + }, + { + "seed": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "visited": [ + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "stop": "PageCapHit" + }, + { + "seed": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "visited": [ + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "visited": [ + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "visited": [ + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "visited": [ + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "visited": [ + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "visited": [ + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "visited": [ + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA", + "visited": [ + "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA" + ], + "stop": "PageCapHit" + }, + { + "seed": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "visited": [ + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z" + ], + "stop": "PageCapHit" + }, + { + "seed": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "visited": [ + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G", + "visited": [ + "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G" + ], + "stop": "PageCapHit" + }, + { + "seed": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "visited": [ + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "visited": [ + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "stop": "PageCapHit" + }, + { + "seed": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "visited": [ + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "stop": "PageCapHit" + }, + { + "seed": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "visited": [ + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "stop": "PageCapHit" + }, + { + "seed": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "visited": [ + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "visited": [ + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "visited": [ + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "visited": [ + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "visited": [ + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "visited": [ + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL", + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "visited": [ + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "visited": [ + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "visited": [ + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "visited": [ + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "visited": [ + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU" + ], + "stop": "PageCapHit" + }, + { + "seed": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "visited": [ + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "stop": "PageCapHit" + }, + { + "seed": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "visited": [ + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "visited": [ + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16" + ], + "stop": "PageCapHit" + }, + { + "seed": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "visited": [ + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1", + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "visited": [ + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "visited": [ + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "visited": [ + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "stop": "PageCapHit" + }, + { + "seed": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "visited": [ + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "visited": [ + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "stop": "PageCapHit" + }, + { + "seed": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "visited": [ + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN", + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu", + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk" + ], + "stop": "PageCapHit" + }, + { + "seed": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "visited": [ + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "stop": "PageCapHit" + }, + { + "seed": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "visited": [ + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb" + ], + "stop": "PageCapHit" + }, + { + "seed": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "visited": [ + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "visited": [ + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "visited": [ + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "stop": "PageCapHit" + }, + { + "seed": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "visited": [ + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "visited": [ + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "visited": [ + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "visited": [ + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "visited": [ + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "visited": [ + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "visited": [ + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ" + ], + "stop": "PageCapHit" + }, + { + "seed": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "visited": [ + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm", + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL", + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh" + ], + "stop": "PageCapHit" + }, + { + "seed": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "visited": [ + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM", + "visited": [ + "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM" + ], + "stop": "BirthScanExhausted" + }, + { + "seed": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "visited": [ + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + } + ], + "facts": { + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm": { + "address": "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784761350, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi" + ], + "birth_scan_exhausted": false + }, + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4": { + "address": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6457 + }, + "first_seen": 1756313602, + "birth_edge": { + "sink": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "sources": [ + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V" + ], + "value": 103993966, + "signature": "55s64RhPGBNPTVDLsRnnXVpDJ5yKvuc5bW51GxXPJXNE3tRBWsSYt7nNovHNkQmP3WQD1s1hHS6RCXaec1ERULEK", + "slot": 363139506, + "block_time": 1756410719, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL": { + "address": "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL", + "owner": null, + "executable": false, + "signatures": { + "Exact": 81 + }, + "first_seen": 1736184345, + "birth_edge": { + "sink": "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL", + "sources": [ + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh" + ], + "value": 3132408210, + "signature": "3GQxAV1idjVjzeuVGWgU2o4csbnbWrQK9VGHy8doD8WTcefK8y2VdnLuThnpUaMocGRhG2ErT86zPm5ZVMyqBQdT", + "slot": 312286142, + "block_time": 1736184345, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh" + ], + "funded": [ + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm" + ], + "birth_scan_exhausted": false + }, + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL": { + "address": "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783798894, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck" + ], + "birth_scan_exhausted": false + }, + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk": { + "address": "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk", + "owner": null, + "executable": false, + "signatures": { + "Exact": 6 + }, + "first_seen": 1783099753, + "birth_edge": { + "sink": "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk", + "sources": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "value": 2039280, + "signature": "Hhyx93TXt6SLEjwsgZs3xDHb1jMgZffgEhuwMLhYYFRNqnzVcmGbo5xPrz3CGRDXVXQd3HWNbLYk2Qs2bUsz7Uf", + "slot": 430565619, + "block_time": 1783099753, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [ + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh" + ], + "birth_scan_exhausted": false + }, + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh": { + "address": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 80 + }, + "first_seen": 1752673276, + "birth_edge": { + "sink": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "sources": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "value": 12063418500, + "signature": "cKPChkvMEjtfwWt9C9UT6huX3cCp543m4ywRXBuBsuYWNKrDuvTCaJqSFFUym2mvuXMG1xCqWhQqvgUDjinFVJb", + "slot": 353692459, + "block_time": 1752673276, + "ambiguous_attribution": false + }, + "fee_payers": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK": { + "address": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7954 + }, + "first_seen": 1774268614, + "birth_edge": { + "sink": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "sources": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "value": 5000000000, + "signature": "3D9VPk2WSdFidXqT2yc7QmN4so5tcRG8oq1RMMVN4Y81op9PcSrNPPhukqLvU2fmRPAncjyFp7csZxbee2uBg8qw", + "slot": 408325661, + "block_time": 1774268614, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o": { + "address": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 72 + }, + "first_seen": 1767875809, + "birth_edge": { + "sink": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "sources": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "value": 50000000, + "signature": "jAurnGX1dLaqmmcS95zSb1N2XZHj65BdUNAtchot1MWmx3z6We5f8Jew1sGu9NrQFrWGR8QdkMCSWSUAfu1yahT", + "slot": 392132125, + "block_time": 1767875809, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7": { + "address": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 33 + }, + "first_seen": 1778858822, + "birth_edge": { + "sink": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "sources": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "value": 10000000, + "signature": "41PgkwaTASYRwAhAmSQ6VMERq4xCjh5YNSsjmzdbU5VukKn6iMn1nzoyswB2wsJJVehVwKLspNmg4RpCKLptEtxL", + "slot": 419929899, + "block_time": 1778858822, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764": { + "address": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 74 + }, + "first_seen": 1768845271, + "birth_edge": { + "sink": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "sources": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb" + ], + "value": 4000000000, + "signature": "buG8ygWB6h5RLJmX5caSxTXK786wYRXgwfS9RFABnCivqy6yNePkzmn3Hsyr3XVhs28D1qWgbXbThbyZUzymN6p", + "slot": 394584868, + "block_time": 1768845271, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv": { + "address": "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 351 + }, + "first_seen": 1715877601, + "birth_edge": { + "sink": "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 400000000, + "signature": "3vMHgLqfkYX6fLwgJKkv34rnViBSYsD2mwRJx5b2gBnMHjHemR7aMm4e12V7pwYUfDNDTNSctZ132e3GAixT72F8", + "slot": 266156059, + "block_time": 1715877601, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ" + ], + "birth_scan_exhausted": false + }, + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S": { + "address": "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1655911154, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH" + ], + "birth_scan_exhausted": false + }, + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS": { + "address": "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783794615, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "birth_scan_exhausted": false + }, + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2": { + "address": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 34 + }, + "first_seen": 1760264183, + "birth_edge": { + "sink": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 21538335, + "signature": "4uNtV2g1sTqRYn7Skm6uidpEgFEL9UUnJhUGECL3rjyahb6vVPFPKQi3ZzV69NuPPPWwwmg7MNQnWQ59XBtqgP7S", + "slot": 372861338, + "block_time": 1760265242, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4": { + "address": "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1710631332, + "birth_edge": { + "sink": "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "sources": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ], + "value": 394037978, + "signature": "3tJT334qtxVLAYkbJ8nGePCKiT4k9nP2DtwPgjwLiQuMbCMcMv6awuiXC19xq9zR9DUM3TAenySiEdiyp2uMygwB", + "slot": 254612541, + "block_time": 1710631332, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ], + "funded": [ + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg" + ], + "birth_scan_exhausted": false + }, + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j": { + "address": "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "owner": null, + "executable": false, + "signatures": { + "Exact": 499 + }, + "first_seen": 1683797389, + "birth_edge": { + "sink": "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 240000000, + "signature": "2THWQfqsFFiAxK6YpuFSVPJLzqz7mU7jXzvZ79f3aFWPfGCNR2HAhoFGKbhobBrKd4XJhRGd1guerxbyMx3wAn9V", + "slot": 193309880, + "block_time": 1683797389, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN" + ], + "birth_scan_exhausted": false + }, + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM": { + "address": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 270 + }, + "first_seen": 1649945488, + "birth_edge": { + "sink": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 11854550000, + "signature": "5LojLQtWF5mFYcGE1MiSjmeixsnYuPneTWNigfaeMGJ1Yysw88ct5X7eaJdhRTy482fAXSM97EpWV6YhYBeBHQ7n", + "slot": 129710493, + "block_time": 1649945488, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi": { + "address": "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr": { + "address": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1785 + }, + "first_seen": 1739523472, + "birth_edge": { + "sink": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "sources": [ + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "value": 1987201900, + "signature": "bzNe8Zg7oE1fXGipW89PL11Q3LbWTdjkKzFGFfSHFnM1LZr93MSbyf5JhPNZ7khZ6twbx9RF41WCFySKZEj14NX", + "slot": 320565860, + "block_time": 1739523472, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ": { + "address": "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 457 + }, + "first_seen": 1638890356, + "birth_edge": { + "sink": "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ", + "sources": [ + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi" + ], + "value": 10000000, + "signature": "3FcspUwHdAXBUQUSD7W2h6rTetqRqEnwBGaviwuYHjBRfb6nP7dpJiGLn1s5CDCQ98neMBr4D8tRAQwCxaQRxtad", + "slot": 110473576, + "block_time": 1638890406, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2J2YzRzZ7YLNva22NVNJBQC4bbRVFoJgJsbxxArUNy88", + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi" + ], + "funded": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "birth_scan_exhausted": false + }, + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw": { + "address": "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1779167369, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr" + ], + "birth_scan_exhausted": false + }, + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J": { + "address": "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1714594823, + "birth_edge": { + "sink": "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J", + "sources": [ + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX" + ], + "value": 500000000, + "signature": "5fTqyzGH9a9g4B626zks91Ln4aRi5iKy5NRGEK9LPy4c1E4XZXnNJK5raAxDDMoADYZDzyEinoYnbnbbS9NNu6w5", + "slot": 263327744, + "block_time": 1714594823, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX" + ], + "funded": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r" + ], + "birth_scan_exhausted": false + }, + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS": { + "address": "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784049508, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW" + ], + "birth_scan_exhausted": false + }, + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9": { + "address": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 254 + }, + "first_seen": 1723048172, + "birth_edge": { + "sink": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 490000000, + "signature": "4G2fwKebyh9QsNPjGHfPsCiBnjg5DYU99FUojtp5ZEcTnh5wwMxnYK7F11jQmdAsFSKSpxg1MPg67muc2FZroZrg", + "slot": 282148476, + "block_time": 1723048651, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF": { + "address": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2386 + }, + "first_seen": 1770200497, + "birth_edge": { + "sink": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "sources": [ + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU" + ], + "value": 190000000, + "signature": "51n18JMEXfFtcFurC9Eyqe7ZVgmj4qcwLmrfsF6qDdodqteHt7D6vqyidRDdWZ1syv24c84Ri7jGCs6C8nHKokJR", + "slot": 397988088, + "block_time": 1770202555, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR": { + "address": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 25 + }, + "first_seen": 1782895333, + "birth_edge": { + "sink": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "sources": [ + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "value": 734553600, + "signature": "36vjnxndxfYcSHBf37rrdBPqcwc2BBpECPGQzSr6RNhbizneiaCKc4xXpiMNNGtk6eqnexRme4xfy3GDLfkPNyRk", + "slot": 430058672, + "block_time": 1782895333, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH": { + "address": "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11742 + }, + "first_seen": 1624516734, + "birth_edge": { + "sink": "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 100000000, + "signature": "fbtWCRyRCWNtSWCCZV2HJXPt9trL74715bnz1R13hWcBnNzSeJDm9Amufv5VFLQUUUXtVLM5nPCuWkteuBx83eW", + "slot": 84190784, + "block_time": 1624516734, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf" + ], + "birth_scan_exhausted": false + }, + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL": { + "address": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18 + }, + "first_seen": 1758306486, + "birth_edge": { + "sink": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "sources": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "value": 2100000000, + "signature": "57LKR9sEPC21YHt2pbje7Ur5ACGLqqMUSF5wHYdquAVozDKs3K516nGr5sa47qJdKZiVvQnxTms11orYiYb7uvCP", + "slot": 367913728, + "block_time": 1758306486, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL": { + "address": "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 753 + }, + "first_seen": 1629221283, + "birth_edge": { + "sink": "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 5355472000, + "signature": "2W3H6wz4dVoB44Lnjkh5gnCUF4ZbgxqcmTruSYMG6vgfrP6Su4TeAcdfHTicxnRLqfasnbgZLjitokZRveP23Sp2", + "slot": 92116993, + "block_time": 1629221283, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K" + ], + "birth_scan_exhausted": false + }, + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G": { + "address": "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5722 + }, + "first_seen": 1703416057, + "birth_edge": { + "sink": "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 970000000, + "signature": "3EzUczntHsFF95zi2Kt4Sq9Hh8tB932DRH2TfP3RoLXniCmJ9yBBhwdXqQHXv1w9bDHDWoxQQ6qSfeLaxhXqpf5j", + "slot": 237735212, + "block_time": 1703416057, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3" + ], + "birth_scan_exhausted": false + }, + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw": { + "address": "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784776619, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4" + ], + "birth_scan_exhausted": false + }, + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7": { + "address": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5237 + }, + "first_seen": 1757495135, + "birth_edge": { + "sink": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "sources": [ + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm" + ], + "value": 2000000000, + "signature": "2j3tdTF7b9SQxw7tCmbtXBy8tWcoq9oMXAFBbRKVHkvHhu2VF3c9wDgAY3zVNcfHAojEvvkhQLr6oosvPosD8EjV", + "slot": 366585560, + "block_time": 1757781857, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3": { + "address": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 119 + }, + "first_seen": 1756133000, + "birth_edge": { + "sink": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "sources": [ + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G" + ], + "value": 59854218, + "signature": "39DqyYqU7RqGLLLSr8kU3mKL4xQnMVMbFjH5KN4XMoJvUDxBdYKGiwWPBGZWkASf2cYweXxb3wQ6utie6EMAANpu", + "slot": 364966880, + "block_time": 1757134451, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh": { + "address": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20761 + }, + "first_seen": 1663879176, + "birth_edge": { + "sink": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 490000000, + "signature": "5kDrBVEWkieCWXHps4mJ9h437RmD7D9Nmyo2uo2UwQsDNUWm6KiAB8T3DNQ8svrsbx11hqdXKcUBNQAY1gACJNwT", + "slot": 151875320, + "block_time": 1663879176, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh": { + "address": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20 + }, + "first_seen": 1783099754, + "birth_edge": { + "sink": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "sources": [ + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk" + ], + "value": 2238177460, + "signature": "5a7NoCBgFaHpUJqMxVp6A8vBTLQnJ3uWB59UCDYZsTm3SyXmhYfrPkXSrPDJ9jca9LCtWM5eDLK4jUMoybZ4ApV4", + "slot": 430565641, + "block_time": 1783099762, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V": { + "address": "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1756410716, + "birth_edge": { + "sink": "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V", + "sources": [ + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "value": 2039280, + "signature": "qTMcW7d2WNayJ6STKme6zWHcpCvnZm5EKYRc5mQZJqqBMKB8T3pTKBnqrKQczdNSQfz6LZH1ETAJP7Yf9eiR8W7", + "slot": 363139499, + "block_time": 1756410716, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "funded": [ + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4" + ], + "birth_scan_exhausted": false + }, + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7": { + "address": "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 15 + }, + "first_seen": 1734187345, + "birth_edge": { + "sink": "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 139459250, + "signature": "3PEFFsvAZgWyxKcjNoWzSXQJ4XtMGZbsm4BDiXGtRVT2huaSmPbopJf6Psmsg5HJRxeLCo2ewLcvhQC6JkDNTDYj", + "slot": 307446440, + "block_time": 1734188936, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6" + ], + "birth_scan_exhausted": false + }, + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV": { + "address": "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV", + "owner": null, + "executable": false, + "signatures": { + "Exact": 55 + }, + "first_seen": 1773235824, + "birth_edge": { + "sink": "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 532871511, + "signature": "nxEPT4eY8McAoUhK86oAYzDiTBXmjJgjmbGSdFaKbNZSNiSi9KoJAAP8hAKvQRZGEDExv1r77BapRvx1joJRXHf", + "slot": 405705084, + "block_time": 1773236286, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [ + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ" + ], + "birth_scan_exhausted": false + }, + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB": { + "address": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 52 + }, + "first_seen": 1770266528, + "birth_edge": { + "sink": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1204809220, + "signature": "373hVK6YWozQ1rjpFwQ9EYjzYKW7AJ3YEpfyAPGiDtdeMmRphi1bKSpnPn2vu8t8t7J7fKAug14jQu6LdRNUR4Jo", + "slot": 398150397, + "block_time": 1770266528, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ": { + "address": "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1778800198, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1": { + "address": "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784580609, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb" + ], + "birth_scan_exhausted": false + }, + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC": { + "address": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 824 + }, + "first_seen": 1757568229, + "birth_edge": { + "sink": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "sources": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "value": 800249721, + "signature": "hq8JsmuHcip8MBCGgPSwd7occB8hVnKNphP8Xm4Yk7Uuj9Vtkz5DCQEYMnh5W9bn74jGumD3LC6essjQdzqyWzp", + "slot": 366050029, + "block_time": 1757569412, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD": { + "address": "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1742045493, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr" + ], + "birth_scan_exhausted": false + }, + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt": { + "address": "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "owner": null, + "executable": false, + "signatures": { + "Exact": 124 + }, + "first_seen": 1773144352, + "birth_edge": { + "sink": "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 99000000, + "signature": "NbnA7s6aJWNM2nfCACoXNDeVGZwALbRcFCkM33u7mQyMKJ3QpSHhA1pVPVX3EugPo74gm1ycaL1CBJ4UqcN3dXi", + "slot": 405469329, + "block_time": 1773144352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3" + ], + "birth_scan_exhausted": false + }, + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z": { + "address": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 96 + }, + "first_seen": 1628597237, + "birth_edge": { + "sink": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 4990000000, + "signature": "2kUPLWWUJut6M2AfRAZAiGLkuWLJN5D4JXMZ1VKr7cj7uWWmmcY43cGMHS7UMF8Uw32rrFUdCMNh6AMyJKR7woy9", + "slot": 91034738, + "block_time": 1628597237, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ": { + "address": "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1782843699, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR" + ], + "birth_scan_exhausted": false + }, + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9": { + "address": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784935407, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4" + ], + "birth_scan_exhausted": false + }, + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF": { + "address": "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784909391, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879" + ], + "birth_scan_exhausted": false + }, + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu": { + "address": "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3947 + }, + "first_seen": 1631763613, + "birth_edge": { + "sink": "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu", + "sources": [ + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk" + ], + "value": 100000000, + "signature": "3CmYn4pR8Eaoa5ocbeLxZ9VHFTtQziQMVNpM2Pjh2V1HiJg3VCnkVskGWtaMVgf4oDRCiEW3RC8r9NbTgjY2aXQ5", + "slot": 96711846, + "block_time": 1631763613, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk" + ], + "funded": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "birth_scan_exhausted": false + }, + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39": { + "address": "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1710624873, + "birth_edge": { + "sink": "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 394042978, + "signature": "5reS92mjj8Avu1Hm8NibK41HwVLTaetYhYEb1eGpT3AYkssVwhBEq479YqaVAw7G4tPhrnwvjUai3ruhQLpUW72T", + "slot": 254597447, + "block_time": 1710624873, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "birth_scan_exhausted": false + }, + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS": { + "address": "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 194 + }, + "first_seen": 1739874778, + "birth_edge": { + "sink": "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 1000000000, + "signature": "rB8uvcS1mATGDoAm47msudGAkdiXhSJBKGnk51uiWVkyzj45DKjiJUguciDjwujSbLGaxfhYYgC6bBs1bFMwbry", + "slot": 321451943, + "block_time": 1739874778, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "birth_scan_exhausted": false + }, + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL": { + "address": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 66 + }, + "first_seen": 1730986163, + "birth_edge": { + "sink": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "sources": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "value": 240234545, + "signature": "4JGR17CZKiUrUKXVpnbhu4LzPvRc1vMRChQVcqLpjuWaPswEvUS3b8Cjf5tyNyuptuA5GGBrTt2cCgdv1QsYuwiQ", + "slot": 300009349, + "block_time": 1730986163, + "ambiguous_attribution": false + }, + "fee_payers": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk": { + "address": "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1667892868, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu" + ], + "birth_scan_exhausted": false + }, + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv": { + "address": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7163 + }, + "first_seen": 1776453682, + "birth_edge": { + "sink": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "sources": [ + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1" + ], + "value": 11193190, + "signature": "2EFWC7p4UmzuhS8ewbcBi4bJGXe3Nd8tMbRpnLY4oCDG3MTJ1nxhsVLAhzcCHhEvacNdeoyepNE54ow4jY3WnZS5", + "slot": 413882415, + "block_time": 1776453892, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "CRUSHtWNSqWK4nu8zZvXpSKxKveas1LSuG7MycL4T976", + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9": { + "address": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1771265328, + "birth_edge": { + "sink": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1465532000, + "signature": "48jcsENEjMVCHrSfUqXLDZDt8nqQfHqDR1Fhx4VH3wGT5Epbks18Mfcs5WJ3yhzdnuWVupAUKPu6jgFTArDxM7iT", + "slot": 400700540, + "block_time": 1771265328, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV": { + "address": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 22 + }, + "first_seen": 1781373138, + "birth_edge": { + "sink": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "sources": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "value": 19650094, + "signature": "5JwERz8A9ssUFHSgXzszdjoKkSs8WVRrjdmKqSRXeD7GcBCyDXqzgMjHQdtqUF9MgCA9R7cK4V7Vm9thS5ib7Fkg", + "slot": 426247804, + "block_time": 1781373138, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG": { + "address": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1780571139, + "birth_edge": { + "sink": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "sources": [ + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW" + ], + "value": 146749060, + "signature": "GhK4Hst1KZyFkxo6viVKoxPJKD3LvVUz66T2joYoM5wacEkn1gbvDtFdNiLB1qXiCMsWiTdGay3xAV3sMHb4o9e", + "slot": 424231157, + "block_time": 1780571140, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU": { + "address": "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "owner": null, + "executable": false, + "signatures": { + "Exact": 369 + }, + "first_seen": 1709827691, + "birth_edge": { + "sink": "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "sources": [ + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN" + ], + "value": 50000000, + "signature": "51rFfVkiSmUzeh1QRNcm99Ea8MUGTMAff1SaRs2dGBigE9VBBo2kkNMsY1o85nxMF4jWHeSVQk2ctJZddtPcZQmj", + "slot": 252697500, + "block_time": 1709827691, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN" + ], + "funded": [ + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY" + ], + "birth_scan_exhausted": false + }, + "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip": { + "address": "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm": { + "address": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1784211013, + "birth_edge": { + "sink": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "sources": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "value": 3895835199, + "signature": "4pntPEhmoeiCTqii4XrvYMiAG2VVja2htxSyFFuda7S8MZfTLjQCkV9XmNyCSqekAzURhwHxAxSEMMApwkM6Zayj", + "slot": 433287475, + "block_time": 1784211013, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T": { + "address": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 26 + }, + "first_seen": 1783100066, + "birth_edge": { + "sink": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "sources": [ + "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu" + ], + "value": 2247350044, + "signature": "2BdukFLQsAoYPAD8iQpWVwybrX2rZrhp46T5t1yco6c93fAAsY3wyyZdiRHmrBmDMKP1yaVjp4hmjqwa8A6bAoPr", + "slot": 430566389, + "block_time": 1783100066, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ": { + "address": "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2483 + }, + "first_seen": 1642454259, + "birth_edge": { + "sink": "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "sources": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "value": 100000000, + "signature": "4XUZRtA4Q1gAaiSWnDA7XY9RboU57S4bSkhfFscKU8Ywa8NioAKWpCu6Z9ZXRQ18qp2pQAFytHgibJ1So1dsiJ3f", + "slot": 121052633, + "block_time": 1644990871, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "funded": [ + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK" + ], + "birth_scan_exhausted": false + }, + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No": { + "address": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4949 + }, + "first_seen": 1756672617, + "birth_edge": { + "sink": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "sources": [ + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh" + ], + "value": 100000000, + "signature": "JTTb13ZHYiJd6AALvqyCnXhSZUFAXLFdKuQmPrXzPkVkYvzL16iDe8zYfBHmTtiLJkCay3pN8DjMdasCr2TqbWf", + "slot": 363900815, + "block_time": 1756711448, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "Hc2vsrdknaVuSypGNyMDuzR3FN3yWVcSuFALT6j2Cq71", + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW": { + "address": "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1769937907, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o" + ], + "birth_scan_exhausted": false + }, + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg": { + "address": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18410 + }, + "first_seen": 1710632250, + "birth_edge": { + "sink": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "sources": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "value": 394012978, + "signature": "3bvxtDsw7CBv3imPLoMrdyhA8cjSRRP3XCwzuJfyzx5AWZ9B8MjPdU3Gju47KgKxqGcd3gLP1ZhLVnHdhaZwQqYE", + "slot": 254614672, + "block_time": 1710632250, + "ambiguous_attribution": false + }, + "fee_payers": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd": { + "address": "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt": { + "address": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1777777000, + "birth_edge": { + "sink": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 9000000, + "signature": "48JSB2pqTRMXWg2S6ajewFiuyXADPk9q8QJYD1NLxSYwoBZzSFWKcPEKzQwN2K4dHJ6QYS8ppfo8Acra1LDZkffb", + "slot": 417226530, + "block_time": 1777777000, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg": { + "address": "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4": { + "address": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 650 + }, + "first_seen": 1764161875, + "birth_edge": { + "sink": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 100000000, + "signature": "5Djf6M25i7Pqn3PvuibF3UkHSDJAmj3VEiHCuV7wDCth91DGunedSr5EaJ6KwDYQHyqLE6mGTbHM1K7hCg4ejans", + "slot": 382647096, + "block_time": 1764162226, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq": { + "address": "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 92 + }, + "first_seen": 1628599869, + "birth_edge": { + "sink": "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq", + "sources": [ + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w" + ], + "value": 9880000000, + "signature": "3AVBmBvJmrKM8wMGddX2wk8Z2Jebsk4Tg17Gk1bM1YzMwaVqhqBeLLiU4uhEUeeXGa43AbPVKFCZeYDK3vDWPV5h", + "slot": 91039469, + "block_time": 1628599869, + "ambiguous_attribution": false + }, + "fee_payers": [ + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w" + ], + "funded": [ + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn" + ], + "birth_scan_exhausted": false + }, + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65": { + "address": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1243 + }, + "first_seen": 1760985667, + "birth_edge": { + "sink": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "sources": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6" + ], + "value": 110000000, + "signature": "3eeFfzc6icmbz7XsoNRMKf1ZtnXKBMUWoXSjY5oarm3GXGzBMJ3QuxuFfMNVHuPtzp8EDsUMh7psK9B85v4QsZ1h", + "slot": 374677619, + "block_time": 1760987283, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "Gem2VAypSg7Ai7vjDKPTtqFahpoQWkfgVkyzx3rPoTka" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z": { + "address": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 510 + }, + "first_seen": 1736141750, + "birth_edge": { + "sink": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 10450531000, + "signature": "5NTDt6Rswtrvt42AT1trjiRspELnF9t98z5H2TyQ4D1L7zB84w3GQjF6borcJLChNK89mRwQUTsqpowEU6MMp4yQ", + "slot": 312181544, + "block_time": 1736141750, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn": { + "address": "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 928 + }, + "first_seen": 1633089324, + "birth_edge": { + "sink": "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn", + "sources": [ + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq" + ], + "value": 1000000000, + "signature": "qjyV7pemydByaUSd3gd8tGw1uo1JZjM1eg2uKzR8jEs5U6zL1pJRN88EnT6cKsECcGegdcAV5pPbfxkhPJb2B1w", + "slot": 99242855, + "block_time": 1633089324, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq" + ], + "funded": [ + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i" + ], + "birth_scan_exhausted": false + }, + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS": { + "address": "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1773493800, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs" + ], + "birth_scan_exhausted": false + }, + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K": { + "address": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4311 + }, + "first_seen": 1729158047, + "birth_edge": { + "sink": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "sources": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "value": 200000000, + "signature": "29ZCJmU48wWT7mGpV6u7YsVzcc15Fy6CDPRWRLgjqNYfcgMUU75z79L3ruGa5wXW68AfU9m4EQzr2WtsZ1gmHRgs", + "slot": 299468871, + "block_time": 1730727939, + "ambiguous_attribution": false + }, + "fee_payers": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck": { + "address": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 37 + }, + "first_seen": 1781689177, + "birth_edge": { + "sink": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "sources": [ + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "value": 2000000000, + "signature": "2kW6Rf9kPJAZnCSgHodJwFNifHr5L1UN3Cj8afcoWHsxHKWFiDEfzFv7v8DsvNL5HFQeihiYy4GWieL826rQnH9Y", + "slot": 427044455, + "block_time": 1781689177, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr": { + "address": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1782983366, + "birth_edge": { + "sink": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "sources": [ + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "value": 65793663482, + "signature": "4uU5EhqsUfPVzpZ1jHMrg9T2TgfcMWE6s81PwMypZnVXQzjKNiB4ibWb9E2MPHa5WFC5mkZhf2DN4PRtX5zaCnB3", + "slot": 430277120, + "block_time": 1782983366, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh": { + "address": "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1028 + }, + "first_seen": 1736684311, + "birth_edge": { + "sink": "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh", + "sources": [ + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6" + ], + "value": 30000000, + "signature": "3tBtrKN5a4FNtR2Tti1gYDwxnWoZ9KhNXu1kP4ArQG4q5wDFvU2C2Z3vxS8hgZu2eLkmcT8XR8MfzLHtNfjimhfc", + "slot": 313511470, + "block_time": 1736684311, + "ambiguous_attribution": false + }, + "fee_payers": [ + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6" + ], + "funded": [ + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No" + ], + "birth_scan_exhausted": false + }, + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E": { + "address": "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 346 + }, + "first_seen": 1619103636, + "birth_edge": { + "sink": "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "sources": [ + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX" + ], + "value": 3999946680, + "signature": "5Xn9C17aBL4Qnk7ZwPJrJeT25CNbP7u7FVGh3qEz3eXKCuqeyM5UNz5KBiW42J3vboohK1ucyZAfeukZybth93Rp", + "slot": 74825696, + "block_time": 1619103636, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX" + ], + "funded": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "birth_scan_exhausted": false + }, + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb": { + "address": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1761613462, + "birth_edge": { + "sink": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 5504330, + "signature": "4X7t1Ls8Zpb3bqFZchjukeaG9Tf1MdMwUS62Ua2Nx4ALiEYLR4aSCr2Az9hTVF17HBnJsPUa4Q2amcmFnXWECY9m", + "slot": 376252987, + "block_time": 1761613462, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879": { + "address": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 59 + }, + "first_seen": 1760849092, + "birth_edge": { + "sink": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "sources": [ + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "value": 93302400, + "signature": "8d5pfjnoehDwiQkD8Uzm2oPh1t4kFwufYmpALykZYwM5KuTQ4dnfNcNHsWS55QDSLYD8mB3YK18epo2sfgEtnY7", + "slot": 376261031, + "block_time": 1761616657, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV": { + "address": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1764737043, + "birth_edge": { + "sink": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 14000853800, + "signature": "4HrqBiVtSmNYMccmWJTEBTXqQe3eztKrd3bpj9AibBehzd7QGCqiY69pbSafREg2UaAHGcv5zt1TU57vbjDFVJdx", + "slot": 416969897, + "block_time": 1777675621, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "7dq4McdQAd6ZUMajZKHNiacNuWcyJsBj1eMeZPPckyz1", + "75Cxo2H9iFZ71LVWADz1qwRV2MJkjzmUdo2b6UjXp1KN", + "6cRBcJy8YatfNYLHD5kyNtCX9ypENwXerB36MKUNUK4e" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR": { + "address": "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784454505, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh" + ], + "birth_scan_exhausted": false + }, + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2": { + "address": "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783242961, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z" + ], + "birth_scan_exhausted": false + }, + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE": { + "address": "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 27 + }, + "first_seen": 1726629672, + "birth_edge": { + "sink": "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "sources": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "value": 1000000000, + "signature": "4DvouS9aXw7ir6N3ohxgKFw3UugY7jqK3aextkEtbox1i1wue5Xh4W6NHbZE9bWvZLMb1P28LoMDY4QhBnRXcehr", + "slot": 290465228, + "block_time": 1726629672, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "funded": [ + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm" + ], + "birth_scan_exhausted": false + }, + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP": { + "address": "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 8186 + }, + "first_seen": 1711915637, + "birth_edge": { + "sink": "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "sources": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V" + ], + "value": 200000000, + "signature": "2sbPicuC4gBQYMAM312LbgX1eDfY9nWY1Aeomg7RBbYVq4ZBuxkFJ1Cpc1icLyVxYUvzPmUyBdn5tCjBbBgRco49", + "slot": 257602531, + "block_time": 1711915637, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V" + ], + "funded": [ + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n" + ], + "birth_scan_exhausted": false + }, + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri": { + "address": "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 10 + }, + "first_seen": 1742326938, + "birth_edge": { + "sink": "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 1003215950, + "signature": "3tm1fffHfNDLhNDnTLeRVe5scKp75BZtrAEcbiDoujfP9be6qpAEwP1heKegTaC1jYcGo8641hi94FUuaj6sZrJF", + "slot": 327633737, + "block_time": 1742326938, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "birth_scan_exhausted": false + }, + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU": { + "address": "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1769207730, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF" + ], + "birth_scan_exhausted": false + }, + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa": { + "address": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 81 + }, + "first_seen": 1712036070, + "birth_edge": { + "sink": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 270768410, + "signature": "4MjcwLDx2bPhGuHdRFGKiE3khiQoSd5DWZEw7RNbuHTubuJ6MvHtZyG4TA7TTAHc9CeK6yHS68ErF5gZdeKnDC2R", + "slot": 257873921, + "block_time": 1712036070, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX": { + "address": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3735 + }, + "first_seen": 1760474300, + "birth_edge": { + "sink": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "sources": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ], + "value": 100000000, + "signature": "aq7ps7k6RZcBWVMaHcqHLVemRNLYzFQukxseeeApwgmVCZ39LNCa2kh8WLCkkdM21AUUjVv9sYtYmi9Gz9BwkUB", + "slot": 373387624, + "block_time": 1760474300, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4": { + "address": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 37 + }, + "first_seen": 1775710580, + "birth_edge": { + "sink": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "sources": [ + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "value": 4639648909, + "signature": "3yQYxKyRPrcH6pk87zfhx67eL6Wzza7hDrE91MA3xHKBRcWv6fHLYeW2JfwTtG2sHw5u67qig7NJ2usnX26aqb6t", + "slot": 412000930, + "block_time": 1775710580, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8": { + "address": "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 179 + }, + "first_seen": 1739919851, + "birth_edge": { + "sink": "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "sources": [ + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY" + ], + "value": 625744930, + "signature": "3RQ4iKJW9dUmd47Tr4JANamMYoeg33wQPZvLCPB2Xy5SGpB7BjfcwYoV98YCvvbZyjJ8hgrEB3ybUJpTQrBke1oX", + "slot": 321565671, + "block_time": 1739919851, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY" + ], + "funded": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "birth_scan_exhausted": false + }, + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf": { + "address": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 450 + }, + "first_seen": 1713195781, + "birth_edge": { + "sink": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "sources": [ + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "value": 10000000, + "signature": "4CEipGPf7m8m8EfHLDWVTy1TsiKyD1LsD6ZAaaNNgvwWJdvqGxRoo9cPcFbASE47phKqZFzaG9dWKaTCFx99bTSb", + "slot": 260290481, + "block_time": 1713195781, + "ambiguous_attribution": false + }, + "fee_payers": [ + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS": { + "address": "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784772742, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL" + ], + "birth_scan_exhausted": false + }, + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh": { + "address": "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1633341120, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL" + ], + "birth_scan_exhausted": false + }, + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc": { + "address": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 64 + }, + "first_seen": 1778266848, + "birth_edge": { + "sink": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 99000000, + "signature": "3UDS6u6ncvTgLndGKD9eaT6q5NWG6JvBniKFJmXeXWPcn9uPsEb5vLWyerKgsPfDvS76r5og2onyCsvXhDw86Kiz", + "slot": 418457793, + "block_time": 1778267806, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i": { + "address": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 290 + }, + "first_seen": 1757844826, + "birth_edge": { + "sink": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "sources": [ + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn" + ], + "value": 120000000, + "signature": "5aVXbSHPmaWfGTctRcFzMuXnqujTKZAEYTX9G6cByRFswAMPGesDy2vVKWp1e9sykcHkF2QbnhiBQQgbZMhPs7EL", + "slot": 366747475, + "block_time": 1757845725, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn": { + "address": "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784572951, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa" + ], + "birth_scan_exhausted": false + }, + "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM": { + "address": "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 490 + }, + "first_seen": 1757104043, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "2nh9AXgxVtbDucnR6Psv53JZaWvjphDLMb6HohuKmr5e", + "pay3JiXTbGTdjfoYo1caZ1oGdQgWVLQ3ws8LoqbxU8i" + ], + "funded": [], + "birth_scan_exhausted": true + }, + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ": { + "address": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 440 + }, + "first_seen": 1773406077, + "birth_edge": { + "sink": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "sources": [ + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "value": 3164021672, + "signature": "cTRx38ZKrtf7ffFXLkr2E2zVgVeJBugExzbDBrxPH7AnZdU631jwEpEQwgsspZEV8QLGr39u9N9nU3vdSrK7RMi", + "slot": 406138581, + "block_time": 1773406090, + "ambiguous_attribution": false + }, + "fee_payers": [ + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij": { + "address": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2605 + }, + "first_seen": 1753207964, + "birth_edge": { + "sink": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "sources": [ + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "value": 140590159, + "signature": "2oaGcywpLPt8xEY7w84WSw4Z94DJiZgz1sTYzpCBbfT8sc5UYD99TiHCZoJqasjmLGzqUbffbHXg7LimmCk5pzu4", + "slot": 355044244, + "block_time": 1753207964, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe": { + "address": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 320 + }, + "first_seen": 1720840348, + "birth_edge": { + "sink": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 11000000000, + "signature": "1rHtsQspU78fmcbJZDfTh4hrN8xcRLjz2Ji2N7VV5KPBW29nATa6FSmt6WsnrFkmnNbz7QmuQiCDEgeRJYieX9E", + "slot": 277240691, + "block_time": 1720840348, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU": { + "address": "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784918904, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8" + ], + "birth_scan_exhausted": false + }, + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6": { + "address": "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784392728, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "birth_scan_exhausted": false + }, + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb": { + "address": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1742345740, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg": { + "address": "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2175 + }, + "first_seen": 1656406760, + "birth_edge": { + "sink": "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "sources": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "value": 9995000, + "signature": "uuctf7AvHunnmw7gS6Vn6WdB14iBXvbSCkNj7hacJUYDiFs41nFhzzoP2NqGHfV1HH1pFBEmiMsdRW8tXAmv8Qr", + "slot": 140737056, + "block_time": 1657295936, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "funded": [ + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL" + ], + "birth_scan_exhausted": false + }, + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb": { + "address": "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "owner": null, + "executable": false, + "signatures": { + "Exact": 8 + }, + "first_seen": 1768750363, + "birth_edge": { + "sink": "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 30193550020, + "signature": "4sv5REU2obsMfmgbTmSqWgiGiCnQJibid6PgNptnSpqaDLjAWGBdfotB1yiG3tnDuJv7mqRN5NyXQAstjw1QfMdr", + "slot": 394345708, + "block_time": 1768750363, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [ + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764" + ], + "birth_scan_exhausted": false + }, + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm": { + "address": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 143 + }, + "first_seen": 1767909246, + "birth_edge": { + "sink": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "sources": [ + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "value": 1310000000, + "signature": "3kDnzFaFpXEegPizm9MKtpGGJ8BnETNFdYFJpd2rxKux7Z8EF58v5sMGsnqHfGAxoPTkiZCcSUUb9VpqWL7LD4og", + "slot": 392216036, + "block_time": 1767909246, + "ambiguous_attribution": false + }, + "fee_payers": [ + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ": { + "address": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1763677438, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD": { + "address": "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1058 + }, + "first_seen": 1734856327, + "birth_edge": { + "sink": "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "sources": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "value": 491810375, + "signature": "2dMS6hZn46wpPzfXrzPMP6u4qrA8E21Pn5vhdeZGvEtMVxozhJUucnm8XfFiWA7VyrcvZCe8zVQYPdFnGx833BxP", + "slot": 310396534, + "block_time": 1735409017, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HgsxLyn8175xEwRffPRN3DeARE2EVcEeXENr12HpadL6", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "birth_scan_exhausted": false + }, + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG": { + "address": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 36 + }, + "first_seen": 1778449810, + "birth_edge": { + "sink": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "sources": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "value": 200000000, + "signature": "4XRjYBMjWrSKs8PTEPYrTgkfwVw8Er4AjCYaiHtVn9L5tRWTGu7HnxBTSKUc6gGYGoLri2jr3U9dJ3HnvDvnz1HE", + "slot": 418909903, + "block_time": 1778449810, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG": { + "address": "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1781067356, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "birth_scan_exhausted": false + }, + "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK": { + "address": "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt": { + "address": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1783210007, + "birth_edge": { + "sink": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 2290497690, + "signature": "3dZV999nzMy8zrpKZkKbhczT6DLA7J9YhLZZZKpFD6U6UoGg9oEUrySMR4VJNGeV6UTJ8rKbq6qLpL3AQ91UWu5S", + "slot": 430838822, + "block_time": 1783210007, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj": { + "address": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 126 + }, + "first_seen": 1775679727, + "birth_edge": { + "sink": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "sources": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "value": 346000000000, + "signature": "2qWrYX2VaSpYFeYPpkqG22UArD9XFzXGYmLbcvSD9zNTGSyjB87ZKsAVfq16XzCazqppJMkRB9XG9rMUJBEf6Z29", + "slot": 411923073, + "block_time": 1775679846, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c": { + "address": "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 35 + }, + "first_seen": 1775705585, + "birth_edge": { + "sink": "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "sources": [ + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ", + "8ncU5YW1CQwvr4gs7buH57bW58e86TDau4STrCJBuz8z", + "FUYyfnVhhRc3PoAyQhWYVGL5oN7BF69R6oSKFjz7jtEh" + ], + "value": 58972050, + "signature": "4Vj6GXww18MxSkppTLZFUPxyjKQQMXgohde7sNGCwZGwgQAiyAr31p73V59467WC1g9iFxPeopMWHAdz3yPdqGsW", + "slot": 411994454, + "block_time": 1775708022, + "ambiguous_attribution": true + }, + "fee_payers": [ + "4PqrAP81NRSgbeBNG3scWVev8RAiy1B5SgRDDo3Ub6Eu", + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ" + ], + "funded": [ + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28" + ], + "birth_scan_exhausted": false + }, + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN": { + "address": "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1565 + }, + "first_seen": 1700506935, + "birth_edge": { + "sink": "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "sources": [ + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j" + ], + "value": 1000000000, + "signature": "3ahr5wC3H6gNPGRX2fZbnSgnSwWo5A7rKcBcpr2MTvpk7LJbALNkrdYuFLunGG3myzFZYMC8ZzPJEtAgzXWbeqrm", + "slot": 231217678, + "block_time": 1700506935, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j" + ], + "funded": [ + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU" + ], + "birth_scan_exhausted": false + }, + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3": { + "address": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1775659926, + "birth_edge": { + "sink": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "sources": [ + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt" + ], + "value": 57015551, + "signature": "4U4QtmZTpQ15CfqzPENGoU8QKmkR4M3MzAChG1ff7qZQVRFcizNEfrp1JqoaZaAYJSYnvZB9z1fh5hs3rD2Qxa22", + "slot": 411872556, + "block_time": 1775659926, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD": { + "address": "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 159 + }, + "first_seen": 1759568115, + "birth_edge": { + "sink": "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "sources": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "value": 8793000, + "signature": "21n3KFdeWHq3Xb5KkQL5N9gb29bMcU9zgkBmHFK2EnKqpMCpNfhTmMC14oLPRoFMzrcrrUUp34sb1a7ehfKFByE1", + "slot": 371102052, + "block_time": 1759568115, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "funded": [ + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX" + ], + "birth_scan_exhausted": false + }, + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf": { + "address": "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784791291, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh" + ], + "birth_scan_exhausted": false + }, + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA": { + "address": "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784869182, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk" + ], + "birth_scan_exhausted": false + }, + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep": { + "address": "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 394 + }, + "first_seen": 1746944587, + "birth_edge": { + "sink": "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "sources": [ + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "value": 518078106, + "signature": "4jjjqQ8p9W4WSG7QFKS8FiQszm6XA3gr7ChHQzeeN9nBxWX5DMSErsAunEVF3t1y2Znu2CP95CtjKB8GA4qf8Jz2", + "slot": 339255278, + "block_time": 1746946824, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "funded": [ + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL" + ], + "birth_scan_exhausted": false + }, + "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv": { + "address": "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8": { + "address": "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN": { + "address": "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8": { + "address": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 53 + }, + "first_seen": 1781684439, + "birth_edge": { + "sink": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "sources": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "value": 38618000, + "signature": "5U5bvAmXWokcz4KHXizva51UQDG5PaZyLxQd7fECRdQ8VdX54ZjeW4bf6xBXAvqfLQWJ3394RDzjBbp3UTQX1JiK", + "slot": 427034554, + "block_time": 1781685267, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY": { + "address": "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 527 + }, + "first_seen": 1713772073, + "birth_edge": { + "sink": "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "sources": [ + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU" + ], + "value": 10000000, + "signature": "3HHA4jtCTpR6BeP3G4CfXDsDgX57eVVUQrQZyeosgzrbkhLsjtai66LSgF75UmzWp86gyVWbzLe9PnkJhzzDNCew", + "slot": 261568924, + "block_time": 1713772073, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU" + ], + "funded": [ + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8" + ], + "birth_scan_exhausted": false + }, + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z": { + "address": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1760108855, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP": { + "address": "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5145 + }, + "first_seen": 1655204850, + "birth_edge": { + "sink": "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "sources": [ + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E" + ], + "value": 100000000, + "signature": "5qCwaVyRDsEr4C3ZndJF99BkYmkRzrGycZXnShE9GujHLnD3CuCc3ETcUXSAop85SrPHBwdjmUdc51yV3GkCYfC3", + "slot": 137511084, + "block_time": 1655204887, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E" + ], + "funded": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "birth_scan_exhausted": false + }, + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX": { + "address": "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 30 + }, + "first_seen": 1714060177, + "birth_edge": { + "sink": "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 987749310, + "signature": "4T9BG6pUpJCYHdubvDe8piyaNYdHW1i8L3Aa3rGokj11eZmiipZBSLJS8updgukiSsjwakJuXsznzjRfcW7hfrhe", + "slot": 262187645, + "block_time": 1714060177, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J" + ], + "birth_scan_exhausted": false + }, + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK": { + "address": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1190 + }, + "first_seen": 1747220417, + "birth_edge": { + "sink": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "sources": [ + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "value": 3141592653, + "signature": "3mXJiiZA35B1Y6UUyqkynZBkYe8sM4WsjzRBgSfjrvqYRhSRfWSx25Xdr5ct4mFR2UpbTJQg1goGscDGfRa3NdE3", + "slot": 339946664, + "block_time": 1747220417, + "ambiguous_attribution": false + }, + "fee_payers": [ + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi": { + "address": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 200 + }, + "first_seen": 1653138893, + "birth_edge": { + "sink": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "sources": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "value": 606489437, + "signature": "62pVXVgr23rpDrywbMT9my8PUPDsRf53biB4QSm9oa67zvw14JmuaqbuC5obnSjSYS1acXMQQRgUXVYpX2s1RHaF", + "slot": 134659485, + "block_time": 1653138893, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa": { + "address": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1783201670, + "birth_edge": { + "sink": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "sources": [ + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn" + ], + "value": 185933290, + "signature": "NX3DrMfLgUE4yHC8dgbQj2vHFKiCzTrPhfTDShToZdn8skzKWLJyzEEh6dbWxeMTBEkRhqWkXVRNzmZDvGKs3Yc", + "slot": 430818102, + "block_time": 1783201670, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3ddCq8LgnyYiJFfupiNAR8rQ9BshepSMzSwWbNLageTx" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq": { + "address": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1784199361, + "birth_edge": { + "sink": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "sources": [ + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw" + ], + "value": 23682958, + "signature": "2ChU8gFx2ffsnkR6HwHJsD2Pd44iTWQ37rdfWgHwbVjMYb45X88VvqNSCaZu6vh2fgC62bXvkt6C8v9YzUrjNz26", + "slot": 433259174, + "block_time": 1784199361, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9": { + "address": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20 + }, + "first_seen": 1782002060, + "birth_edge": { + "sink": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 50000000, + "signature": "RtgJqd5sHDiondx4Z2yiq5essG1zXj5XwroXbZrtjkhy9NDPjutCezrPBr122sZqphKBa9YWJF3VPxiBUerRjBq", + "slot": 427833377, + "block_time": 1782002060, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U": { + "address": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 10 + }, + "first_seen": 1781081436, + "birth_edge": { + "sink": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 92849110, + "signature": "2d8HpMfLa5r1S3vdLKNiT69B7gPFjj4U3YHRc3skWQFqF3T2LUjTQzjPtWiHzQytw3VupQMQFiajPmjNYzN5rZfe", + "slot": 425512751, + "block_time": 1781081436, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH": { + "address": "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1703354625, + "birth_edge": { + "sink": "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "sources": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "value": 1320200000, + "signature": "3cqmB1Yi2Z7ZVQjjA37NQ4d84ViimuKf1h83J23digAMRGoJMY8VmUbNkSxyqxRqsE3qBoBFKwCMXfxhVMEGNacP", + "slot": 237597989, + "block_time": 1703354625, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "funded": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "birth_scan_exhausted": false + }, + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm": { + "address": "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 57 + }, + "first_seen": 1756226352, + "birth_edge": { + "sink": "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm", + "sources": [ + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL" + ], + "value": 19129985905, + "signature": "hwFDdbQ5JJzyNKNESkkX193G8qp1cXkGT1GJfmz6Aca26Kh6Qo54vbWPejmst4DCTFtUW7ifDYZ1XG2UFgru68q", + "slot": 362671528, + "block_time": 1756226352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL" + ], + "funded": [ + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7" + ], + "birth_scan_exhausted": false + }, + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW": { + "address": "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1780571139, + "birth_edge": { + "sink": "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW", + "sources": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS", + "ATRsNGv2nDw7hSMfkUTBoVUDsFDwN7po7KbecyiGWNB4" + ], + "value": 148788340, + "signature": "5qzt8zfBQNcj1k4sSPUrPrxcBYLMNDTg44S69HPqnkuwYNFXqhc6uJYS8ftreQQPkpNkFjk3nH8bFV5d5M7bWLXh", + "slot": 424231154, + "block_time": 1780571139, + "ambiguous_attribution": true + }, + "fee_payers": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "funded": [ + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG" + ], + "birth_scan_exhausted": false + }, + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi": { + "address": "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 924 + }, + "first_seen": 1624797610, + "birth_edge": { + "sink": "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi", + "sources": [ + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV" + ], + "value": 30170000000, + "signature": "VRM4EXex3RUYf4mnPB4E6jv9D7XmkmHdwbzeXTCTjmCqWpSfq7mKhgRibqwyzFXvu4FjpvYK5NeQrsQ6vbQ6e8A", + "slot": 84652957, + "block_time": 1624797610, + "ambiguous_attribution": false + }, + "fee_payers": [ + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV" + ], + "funded": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "birth_scan_exhausted": false + }, + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu": { + "address": "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1774369160, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V" + ], + "birth_scan_exhausted": false + }, + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r": { + "address": "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6850 + }, + "first_seen": 1714596610, + "birth_edge": { + "sink": "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "sources": [ + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J" + ], + "value": 499994950, + "signature": "32pf2BhJSmb5gunpiH6aruXu1ErmFsqfsuSuXZCrWYfk1cQGrKa1SUC8A2QEeASEkHt14zDoAJs3vJwq1CFrMoNe", + "slot": 263331626, + "block_time": 1714596610, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J" + ], + "funded": [ + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo" + ], + "birth_scan_exhausted": false + }, + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe": { + "address": "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785035720, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2" + ], + "birth_scan_exhausted": false + }, + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo": { + "address": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13145 + }, + "first_seen": 1719672752, + "birth_edge": { + "sink": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "sources": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r" + ], + "value": 150000000, + "signature": "5eDgfMWctbmhkp9ZUddUGf5pcyvMr1ReaEK9nXEYipstcuD58uVbr7UVEzkEv2XoVf464y62Wj9f8mfbfkrg3duL", + "slot": 274705160, + "block_time": 1719673479, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "3qaRfWYQitbWQe7CHVvUR4QwQpG7xcaGmtpfeA3LKrXR" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G": { + "address": "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784842995, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6": { + "address": "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1439 + }, + "first_seen": 1739722292, + "birth_edge": { + "sink": "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "sources": [ + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7" + ], + "value": 4251664084, + "signature": "2PSni2jfVeX9YUufMwGVXWanasSbzHYk7imdYtwDjjSAqERG6T7s4Hx6DWStky2bqrYgpqoqR7xy6KjTbdQ5tC9M", + "slot": 321067692, + "block_time": 1739722292, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7" + ], + "funded": [ + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65" + ], + "birth_scan_exhausted": false + }, + "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq": { + "address": "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1775881597, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf": { + "address": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11491 + }, + "first_seen": 1770490600, + "birth_edge": { + "sink": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "sources": [ + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8" + ], + "value": 11251120, + "signature": "5QwjQCxGUJfMWx2A5LAZoMeXvTKoT2yUU4GgXmo38bpidM3MWsqEouL2qi5Hbnh6ahYraSuUt3dNTAEW6dY9s47C", + "slot": 398740672, + "block_time": 1770498005, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8" + ], + "funded": [ + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1" + ], + "birth_scan_exhausted": false + }, + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA": { + "address": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 120 + }, + "first_seen": 1769087495, + "birth_edge": { + "sink": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "sources": [ + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "value": 430752000, + "signature": "2AFuX4tvKhsFguYnNfiW4QCHsYFeoARyYNbm9hMxqKHpgaX2f6d8qHfioWQsnyDCy5wFHzeUAXoSURUyGDGgmxzj", + "slot": 395193315, + "block_time": 1769087495, + "ambiguous_attribution": false + }, + "fee_payers": [ + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD": { + "address": "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1211 + }, + "first_seen": 1731582585, + "birth_edge": { + "sink": "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 146500000, + "signature": "3rHVM8ZmNB7DinaukQx8mKva26Y4YUNNXmxtPwwjZEW5Gpy72tqpWjfRBCW6jZR64WDC5QxLEFiMkAPKNK65MKTY", + "slot": 301468444, + "block_time": 1731640101, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij" + ], + "birth_scan_exhausted": false + }, + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p": { + "address": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 282 + }, + "first_seen": 1707956423, + "birth_edge": { + "sink": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 92000000, + "signature": "2Zo3SqZ1zdcF99BygckTotHufbXupGv4FLFyEdVxbSwKedaeJRsp2gb8Uwjgjf8PkwQgsibXyJvpBZwFErrJ6FDc", + "slot": 248216739, + "block_time": 1707956423, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ": { + "address": "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1770144885, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "birth_scan_exhausted": false + }, + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu": { + "address": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1783033845, + "birth_edge": { + "sink": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 1171377350, + "signature": "5T6rTfTX8JKsNiXf9PCnAEL4w7HLzJfsVBeQwsTRcsuK9TyxUV9ym5MPTpVBepapLkDMQeTPdAEigW14azAfdiT8", + "slot": 430402156, + "block_time": 1783033845, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2": { + "address": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2014 + }, + "first_seen": 1728020846, + "birth_edge": { + "sink": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 203950000, + "signature": "5U8Sgir6egiAF84ZZW13rDa1ek69yJpBcTmv227D88J6Gbm69bF6Dq7WKoLSdYEeaeXGPSCmN76jDFXzZEkeQh2Z", + "slot": 293595031, + "block_time": 1728020846, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE": { + "address": "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784934452, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA" + ], + "birth_scan_exhausted": false + }, + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1": { + "address": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7196 + }, + "first_seen": 1728755528, + "birth_edge": { + "sink": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 839200000, + "signature": "2DdKCofnd53ZCijpwVNM4xRHmTXYT8YqeRh99etQB4J3YmX48b1sNn6vq2RGrqtmsgbKq4jH1jHc9DnoSctSurUw", + "slot": 295234119, + "block_time": 1728755528, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG": { + "address": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4316 + }, + "first_seen": 1743001899, + "birth_edge": { + "sink": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "sources": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "value": 200000000, + "signature": "3Rg9fS58hDfbMcnKWU6jeJXUva4g1jetwoNwvp7YiiH1GXDadsF7ZqxutWpxq6VXuHdRWpq61TFtQMs6KRhrkmqr", + "slot": 329323260, + "block_time": 1743001899, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "funded": [ + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7" + ], + "birth_scan_exhausted": false + }, + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9": { + "address": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1773 + }, + "first_seen": 1699496374, + "birth_edge": { + "sink": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 3442545653, + "signature": "Pvpzz5cpDfRekWPtKKux8YPWQuzJhsEonx1YpQLx9HkBiWkknk4Cwj6dyvof1ha8fnmrEkZqGAefpquu6G6HUDD", + "slot": 228889688, + "block_time": 1699496374, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2": { + "address": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 163 + }, + "first_seen": 1770880341, + "birth_edge": { + "sink": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1178878050, + "signature": "3Yn2VJBxAgpBmQ8XD5EXEPEdPfyYuvrRfiJEFCMn4JS3CwYURPu7QTwjsz9Masn96rwjNriemwBLyzFe8ZVzLwbq", + "slot": 399714845, + "block_time": 1770880341, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE": { + "address": "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784782106, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "birth_scan_exhausted": false + }, + "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA": { + "address": "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783307590, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq": { + "address": "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1705 + }, + "first_seen": 1777229947, + "birth_edge": { + "sink": "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "sources": [ + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16" + ], + "value": 3615443530, + "signature": "ev9FqbVk8jCJiy27MypNycKFYYeRJJJCpH6WiNPM5buomXGKnTHqz9YL5heguK76dncGDd8KnEMvKruGMzQFDRc", + "slot": 415842709, + "block_time": 1777229947, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9WL2A89YBr6X47ABKYNzPentWiBA3H8tpaiuf5CaYHx6" + ], + "funded": [ + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV" + ], + "birth_scan_exhausted": false + }, + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs": { + "address": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 302 + }, + "first_seen": 1774289101, + "birth_edge": { + "sink": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "sources": [ + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "value": 1406603230, + "signature": "58WsdGGRCSKky5UXVe4QCaZpALbxjqfksCdHYZUj6HtNo5GmE3SwBi7tfun9dovyXN7CHVXt56c7wc28deCM4NKb", + "slot": 408377546, + "block_time": 1774289101, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL": { + "address": "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 363 + }, + "first_seen": 1763311616, + "birth_edge": { + "sink": "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL", + "sources": [ + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS" + ], + "value": 128226803, + "signature": "5eRiYettfDeQJtbPPvuTnLYDt5fpqjhqxut1xMhVUk3za3oCNTFqNvBAtDwNCWxsWrPrKRQXj5xeECz2VjpFq6zd", + "slot": 380496679, + "block_time": 1763311783, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AF6B9C43LrVEZLSNdoVXuWeXZBM3voyQgykCxRRoUxqG", + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS" + ], + "funded": [ + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj" + ], + "birth_scan_exhausted": false + }, + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq": { + "address": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1758453103, + "birth_edge": { + "sink": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "sources": [ + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi" + ], + "value": 1111260006, + "signature": "2wqEciaCd8SdPS1BaEWBxZfVTrHk3sMS7PZB8LobFDQA7e49g7awaW44rGj2gRiWbCoU4rW4SWbn7qCpQtPXaetx", + "slot": 368284051, + "block_time": 1758453103, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i": { + "address": "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1753315217, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb": { + "address": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 253 + }, + "first_seen": 1776516090, + "birth_edge": { + "sink": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "sources": [ + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "value": 268000000, + "signature": "3KB7X9tCYoBd3HrsMzGTYQ1avb3ceSiXpHuQv6qQ9LPLKVnxVoUaXdBeKF5qLp71mMTNmHXsNcKe3Hbd4JYs29C8", + "slot": 414039567, + "block_time": 1776516090, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z": { + "address": "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1230 + }, + "first_seen": 1769712791, + "birth_edge": { + "sink": "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "sources": [ + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "value": 159000000, + "signature": "37ERW5HvvBbZ7xPSZK8kHSjpshWttD8PGTqwnw4hrmou8DyqToYBSU1oV1YqHfEdVbqBkkLULdg7VUmuZBsNkVZG", + "slot": 396754483, + "block_time": 1769712791, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "funded": [ + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG" + ], + "birth_scan_exhausted": false + }, + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf": { + "address": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 180 + }, + "first_seen": 1745992468, + "birth_edge": { + "sink": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "sources": [ + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH" + ], + "value": 2000000000, + "signature": "5ZbHXjZUDRS32uKijFGaJzvbiKBMYLHWcuES7gteaUuErcDjefnt9jsanTDhirv5Rs6JdCv9JbvLrNPPY29kLvEv", + "slot": 336839074, + "block_time": 1745993216, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX": { + "address": "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 166 + }, + "first_seen": 1604753907, + "birth_edge": { + "sink": "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 4990000000, + "signature": "5fNviBm3ujhH54CxhFVkMHGhBh3ycHu52naQLLfeipzWZXT5HXfNUswH9ovncyDCLMGWuFTkc8ZfSGwZRZKuFm67", + "slot": 47336493, + "block_time": 1604753907, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E" + ], + "birth_scan_exhausted": false + }, + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv": { + "address": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 49 + }, + "first_seen": 1778543921, + "birth_edge": { + "sink": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1999000000, + "signature": "2577uZmHHHp14Cdos1o2FWPAe3yv8JQWbbDZ2MXz7UPeYsivzQKF7BxbnhK3x4ACnD4J4HUSi9URYrAfqLY5Et7T", + "slot": 422526013, + "block_time": 1779894352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx": { + "address": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 639 + }, + "first_seen": 1681873953, + "birth_edge": { + "sink": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "sources": [ + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK", + "2AdZQmGikAMWahuJRb27PGABQyF6iyQ8aUUYyDDwRRG6" + ], + "value": 1390880, + "signature": "4UjTtnFx1zxwZ3HfMqZJipdoHQ5Gcjujq9gJgoYaraMkeuRfhb3DhbJnFA7aRpYipMV3rWuBNdJG51K4m1gXs5Qj", + "slot": 189363909, + "block_time": 1681936762, + "ambiguous_attribution": true + }, + "fee_payers": [ + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw": { + "address": "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq" + ], + "birth_scan_exhausted": false + }, + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R": { + "address": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9 + }, + "first_seen": 1784990514, + "birth_edge": { + "sink": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 10091911, + "signature": "8noYJ5aCs9N6rbVBKCGMwVfVeCg1GQHGXhaNHP2rVcBZSMgbgiUpoNtpQ8XkASe78iZs3JqGk3c178jbeFgdrzc", + "slot": 435145890, + "block_time": 1784990514, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS": { + "address": "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784779900, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "birth_scan_exhausted": false + }, + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi": { + "address": "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq" + ], + "birth_scan_exhausted": false + }, + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K": { + "address": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 483 + }, + "first_seen": 1756671400, + "birth_edge": { + "sink": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "sources": [ + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL" + ], + "value": 100000000, + "signature": "5K8mBvSCxvxNt81ymbqjhH5Umde57URqC9pVdVzczT8JpRrPrKoEo5t8xEqBLWW2N74Fi5vNNKiCVKbBZZvLu8Gq", + "slot": 372063796, + "block_time": 1759948805, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "Hc2vsrdknaVuSypGNyMDuzR3FN3yWVcSuFALT6j2Cq71", + "BeVVXuvvGNmFBeK1bazfc2CYdvvJ5AFi4aNv75Ah7vo8", + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu": { + "address": "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T" + ], + "birth_scan_exhausted": false + }, + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1": { + "address": "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 653 + }, + "first_seen": 1773754017, + "birth_edge": { + "sink": "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1", + "sources": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "value": 128164040, + "signature": "2PwhcVHygfgnrC6dUDdkyZG6XQq8QzBS5PY4ar7MKwUmnCWtXhhVYACkh8goKM7MozqdANUYs4MhnSVagFBJt7kn", + "slot": 407022368, + "block_time": 1773754017, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "funded": [ + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv" + ], + "birth_scan_exhausted": false + }, + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw": { + "address": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1783107306, + "birth_edge": { + "sink": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 9000000, + "signature": "4B1byRx7pvEAt5NfXDUwEqo2TyMbm1qFV1Qakd6tnjmjfUHQ6ThQJFpcN129xXoS29GPPtvScVyHGBkCV6kd9s2m", + "slot": 430584264, + "block_time": 1783107306, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh": { + "address": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 322 + }, + "first_seen": 1761374606, + "birth_edge": { + "sink": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "sources": [ + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "value": 25732740, + "signature": "3AhoNZZLvSQ5gNfWsTeRkjLi8W9t1P63EPXD3YKxErjnAP37U44njwCmpBaygX1xi5fgUNHHSZaeMiEJq9F2jrHi", + "slot": 375651141, + "block_time": 1761374606, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16": { + "address": "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1781755484, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "birth_scan_exhausted": false + }, + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V": { + "address": "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1582 + }, + "first_seen": 1700759478, + "birth_edge": { + "sink": "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 951634000, + "signature": "5vBY9n8k1qYPBcapzouiPJ9whnVFx18Y9Y574PJfDDwMNKt59QoCsGbRgke24y6T3zTyjNNRqEzCnJUAwfWGNeE7", + "slot": 231795042, + "block_time": 1700759478, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "birth_scan_exhausted": false + }, + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n": { + "address": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 135 + }, + "first_seen": 1780765625, + "birth_edge": { + "sink": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "sources": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "value": 271700000000, + "signature": "5R2ekhoYBR8fWYnM27srHHH24YNpF79Bu2uws2dh3otMMSt7Kku9tgV5NUx2yFN53YjfhZ8iDv6zNzFJpuoZgyg2", + "slot": 424718918, + "block_time": 1780765625, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6": { + "address": "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 337 + }, + "first_seen": 1719988520, + "birth_edge": { + "sink": "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6", + "sources": [ + "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ" + ], + "value": 669445618, + "signature": "2xwdfPkgWLvHhKL2f1su7F6qyRR7LgaNsYiakS8wpTpeoMc89PLbARf8HR29phRhtdRyRbkj6iWbfbB6KVa68pZX", + "slot": 275394508, + "block_time": 1719988520, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7FfB2zQRYUQwpPzkRxAeg2mCBGeCRKp4PCEeULJA9xTo" + ], + "funded": [ + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh" + ], + "birth_scan_exhausted": false + }, + "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ": { + "address": "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6" + ], + "birth_scan_exhausted": false + }, + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN": { + "address": "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 104 + }, + "first_seen": 1757553631, + "birth_edge": { + "sink": "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN", + "sources": [ + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu" + ], + "value": 823856392, + "signature": "43aFuJ62SGgRmkXfrQfgydDDuYgrbTzLoNbZ4LD3afHdZyjd9SnUv9o64bxryezdAGxHpBVUt3Eyj8eSeYKtiCiS", + "slot": 366017478, + "block_time": 1757556380, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu" + ], + "funded": [ + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC" + ], + "birth_scan_exhausted": false + }, + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu": { + "address": "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784721217, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt" + ], + "birth_scan_exhausted": false + }, + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV": { + "address": "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784714858, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "birth_scan_exhausted": false + }, + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4": { + "address": "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1777643790, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm" + ], + "birth_scan_exhausted": false + }, + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK": { + "address": "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1723294092, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx" + ], + "birth_scan_exhausted": false + }, + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ": { + "address": "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 21 + }, + "first_seen": 1709918366, + "birth_edge": { + "sink": "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 1696237745, + "signature": "qdFZbtFQnSrYx5CCo78yqoFY1ZYvhKgUL5gPeKiiG1LJ2TG2jC4yKtUdwidZiH5tZZ2bt4HEqU4pfjBbMeDYJNc", + "slot": 252918864, + "block_time": 1709918366, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf" + ], + "birth_scan_exhausted": false + }, + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28": { + "address": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 98 + }, + "first_seen": 1780986875, + "birth_edge": { + "sink": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "sources": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "value": 30000000, + "signature": "5RkppwfwvNhhTswurZaM4gwPQiDaie82UhBdHt8mHJSES3ci8cmDuHHRLYXoFuWD7KdurykQXq7dUBfaBw8HAiqW", + "slot": 425274321, + "block_time": 1780986875, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm": { + "address": "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1751863543, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK" + ], + "birth_scan_exhausted": false + }, + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV": { + "address": "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1619359279, + "birth_edge": { + "sink": "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 31483630200, + "signature": "f6cQSbVaFKTPqNogr3WADjYPSr8ZgwcvYK5uaJiAP9A63W7WZgCjcDoGHxZWK8fdAVBqJzsjF43XYsuCG42fsNX", + "slot": 75325833, + "block_time": 1619359279, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi" + ], + "birth_scan_exhausted": false + }, + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w": { + "address": "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784364506, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq" + ], + "birth_scan_exhausted": false + }, + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ": { + "address": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 34 + }, + "first_seen": 1784808222, + "birth_edge": { + "sink": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "sources": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv" + ], + "value": 100000000, + "signature": "3XFtWHvCubsszFNB4U9XX592rAbYqdKaUjy7KPTjxKmcAUziERiSHsPLvbSozHGgAgiZjZmdStGTB99ASeYB8GPU", + "slot": 434711620, + "block_time": 1784808222, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv" + ], + "funded": [], + "birth_scan_exhausted": false + } + } +} \ No newline at end of file diff --git a/data/sample-marinade-run8.json b/data/sample-marinade-run8.json new file mode 100644 index 00000000..efd39ee9 --- /dev/null +++ b/data/sample-marinade-run8.json @@ -0,0 +1,5612 @@ +{ + "manifest": { + "endpoint": "https://mainnet.helius-rpc.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1785045254, + "config": { + "scope": "Sol", + "depth_max": 16, + "min_edge_lamports": 500000, + "sig_page_cap": 48, + "page_size": 1000, + "birth_scan_cap": 24 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 3133, + "excluded_non_wallet": [ + "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip", + "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8", + "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv", + "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK", + "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN", + "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi", + "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg", + "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd" + ], + "ambiguous_attribution_rate": 0.020134228187919462 + }, + "chains": [ + { + "seed": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "visited": [ + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "visited": [ + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V", + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "stop": "PageCapHit" + }, + { + "seed": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "visited": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "visited": [ + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "visited": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "visited": [ + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "stop": "PageCapHit" + }, + { + "seed": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "visited": [ + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "visited": [ + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh", + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6", + "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ" + ], + "stop": "LocalTerminal" + }, + { + "seed": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "visited": [ + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "stop": "PageCapHit" + }, + { + "seed": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "visited": [ + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "stop": "PageCapHit" + }, + { + "seed": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "visited": [ + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi" + ], + "stop": "LocalTerminal" + }, + { + "seed": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "visited": [ + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "visited": [ + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "visited": [ + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw" + ], + "stop": "LocalTerminal" + }, + { + "seed": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "visited": [ + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ", + "visited": [ + "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ" + ], + "stop": "PageCapHit" + }, + { + "seed": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "visited": [ + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "visited": [ + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "stop": "PageCapHit" + }, + { + "seed": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "visited": [ + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "stop": "PageCapHit" + }, + { + "seed": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "visited": [ + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "stop": "PageCapHit" + }, + { + "seed": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "visited": [ + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ", + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi", + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "visited": [ + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i", + "visited": [ + "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i" + ], + "stop": "PageCapHit" + }, + { + "seed": "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq", + "visited": [ + "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq" + ], + "stop": "PageCapHit" + }, + { + "seed": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "visited": [ + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW", + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "stop": "PageCapHit" + }, + { + "seed": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "visited": [ + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK" + ], + "stop": "PageCapHit" + }, + { + "seed": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "visited": [ + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "visited": [ + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn", + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq", + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w" + ], + "stop": "PageCapHit" + }, + { + "seed": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "visited": [ + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "visited": [ + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "visited": [ + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "visited": [ + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "stop": "PageCapHit" + }, + { + "seed": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "visited": [ + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J", + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "visited": [ + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "stop": "PageCapHit" + }, + { + "seed": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "visited": [ + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn" + ], + "stop": "PageCapHit" + }, + { + "seed": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "visited": [ + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk", + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "stop": "PageCapHit" + }, + { + "seed": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "visited": [ + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu" + ], + "stop": "LocalTerminal" + }, + { + "seed": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "visited": [ + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "visited": [ + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "stop": "PageCapHit" + }, + { + "seed": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "visited": [ + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "stop": "PageCapHit" + }, + { + "seed": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "visited": [ + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "visited": [ + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "visited": [ + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "visited": [ + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "visited": [ + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "visited": [ + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "visited": [ + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA", + "visited": [ + "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA" + ], + "stop": "PageCapHit" + }, + { + "seed": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "visited": [ + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "visited": [ + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G", + "visited": [ + "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G" + ], + "stop": "PageCapHit" + }, + { + "seed": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "visited": [ + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "visited": [ + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "stop": "PageCapHit" + }, + { + "seed": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "visited": [ + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "stop": "PageCapHit" + }, + { + "seed": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "visited": [ + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "stop": "PageCapHit" + }, + { + "seed": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "visited": [ + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "visited": [ + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "visited": [ + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "visited": [ + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "visited": [ + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "visited": [ + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL", + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "visited": [ + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "visited": [ + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "visited": [ + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "visited": [ + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "visited": [ + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU" + ], + "stop": "PageCapHit" + }, + { + "seed": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "visited": [ + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "stop": "PageCapHit" + }, + { + "seed": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "visited": [ + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "visited": [ + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16" + ], + "stop": "PageCapHit" + }, + { + "seed": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "visited": [ + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1", + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "visited": [ + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "visited": [ + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "visited": [ + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW", + "4AcmsW4k1JKCRv9irityUMkJ8eMm1JSqG9rR5FcNdZvy" + ], + "stop": "PageCapHit" + }, + { + "seed": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "visited": [ + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "visited": [ + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "stop": "PageCapHit" + }, + { + "seed": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "visited": [ + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN", + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu", + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk" + ], + "stop": "PageCapHit" + }, + { + "seed": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "visited": [ + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "stop": "PageCapHit" + }, + { + "seed": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "visited": [ + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "HFWv1riXSRJ3nVnnLZ9xi1K4r3zppRvcfVuiAGqAA8Y6" + ], + "stop": "PageCapHit" + }, + { + "seed": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "visited": [ + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "visited": [ + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "visited": [ + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "stop": "PageCapHit" + }, + { + "seed": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "visited": [ + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "visited": [ + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "visited": [ + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "visited": [ + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "visited": [ + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "visited": [ + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "visited": [ + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "visited": [ + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm", + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL", + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh", + "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc", + "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy", + "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88", + "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW", + "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr", + "GbG7Kekbzjypekv9vEEdyERXp3XvpvAqhtFfvEUwrAb7" + ], + "stop": "BelowThreshold" + }, + { + "seed": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "visited": [ + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM", + "visited": [ + "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM" + ], + "stop": "BirthScanExhausted" + }, + { + "seed": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "visited": [ + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + } + ], + "facts": { + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm": { + "address": "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784474223, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi" + ], + "birth_scan_exhausted": false + }, + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4": { + "address": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6457 + }, + "first_seen": 1756313602, + "birth_edge": { + "sink": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "sources": [ + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V" + ], + "value": 103993966, + "signature": "55s64RhPGBNPTVDLsRnnXVpDJ5yKvuc5bW51GxXPJXNE3tRBWsSYt7nNovHNkQmP3WQD1s1hHS6RCXaec1ERULEK", + "slot": 363139506, + "block_time": 1756410719, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL": { + "address": "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL", + "owner": null, + "executable": false, + "signatures": { + "Exact": 81 + }, + "first_seen": 1736184345, + "birth_edge": { + "sink": "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL", + "sources": [ + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh" + ], + "value": 3132408210, + "signature": "3GQxAV1idjVjzeuVGWgU2o4csbnbWrQK9VGHy8doD8WTcefK8y2VdnLuThnpUaMocGRhG2ErT86zPm5ZVMyqBQdT", + "slot": 312286142, + "block_time": 1736184345, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh" + ], + "funded": [ + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm" + ], + "birth_scan_exhausted": false + }, + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL": { + "address": "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1782776045, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck" + ], + "birth_scan_exhausted": false + }, + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk": { + "address": "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk", + "owner": null, + "executable": false, + "signatures": { + "Exact": 6 + }, + "first_seen": 1783099753, + "birth_edge": { + "sink": "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk", + "sources": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "value": 2039280, + "signature": "Hhyx93TXt6SLEjwsgZs3xDHb1jMgZffgEhuwMLhYYFRNqnzVcmGbo5xPrz3CGRDXVXQd3HWNbLYk2Qs2bUsz7Uf", + "slot": 430565619, + "block_time": 1783099753, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [ + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh" + ], + "birth_scan_exhausted": false + }, + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh": { + "address": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 80 + }, + "first_seen": 1752673276, + "birth_edge": { + "sink": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "sources": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "value": 12063418500, + "signature": "cKPChkvMEjtfwWt9C9UT6huX3cCp543m4ywRXBuBsuYWNKrDuvTCaJqSFFUym2mvuXMG1xCqWhQqvgUDjinFVJb", + "slot": 353692459, + "block_time": 1752673276, + "ambiguous_attribution": false + }, + "fee_payers": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK": { + "address": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7962 + }, + "first_seen": 1774268614, + "birth_edge": { + "sink": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "sources": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "value": 5000000000, + "signature": "3D9VPk2WSdFidXqT2yc7QmN4so5tcRG8oq1RMMVN4Y81op9PcSrNPPhukqLvU2fmRPAncjyFp7csZxbee2uBg8qw", + "slot": 408325661, + "block_time": 1774268614, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o": { + "address": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 72 + }, + "first_seen": 1767875809, + "birth_edge": { + "sink": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "sources": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "value": 50000000, + "signature": "jAurnGX1dLaqmmcS95zSb1N2XZHj65BdUNAtchot1MWmx3z6We5f8Jew1sGu9NrQFrWGR8QdkMCSWSUAfu1yahT", + "slot": 392132125, + "block_time": 1767875809, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7": { + "address": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 33 + }, + "first_seen": 1778858822, + "birth_edge": { + "sink": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "sources": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "value": 10000000, + "signature": "41PgkwaTASYRwAhAmSQ6VMERq4xCjh5YNSsjmzdbU5VukKn6iMn1nzoyswB2wsJJVehVwKLspNmg4RpCKLptEtxL", + "slot": 419929899, + "block_time": 1778858822, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764": { + "address": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 74 + }, + "first_seen": 1768845271, + "birth_edge": { + "sink": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "sources": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb" + ], + "value": 4000000000, + "signature": "buG8ygWB6h5RLJmX5caSxTXK786wYRXgwfS9RFABnCivqy6yNePkzmn3Hsyr3XVhs28D1qWgbXbThbyZUzymN6p", + "slot": 394584868, + "block_time": 1768845271, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv": { + "address": "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 351 + }, + "first_seen": 1715877601, + "birth_edge": { + "sink": "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 400000000, + "signature": "3vMHgLqfkYX6fLwgJKkv34rnViBSYsD2mwRJx5b2gBnMHjHemR7aMm4e12V7pwYUfDNDTNSctZ132e3GAixT72F8", + "slot": 266156059, + "block_time": 1715877601, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ" + ], + "birth_scan_exhausted": false + }, + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S": { + "address": "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1655749768, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH" + ], + "birth_scan_exhausted": false + }, + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS": { + "address": "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1782918463, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "birth_scan_exhausted": false + }, + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2": { + "address": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 34 + }, + "first_seen": 1760264183, + "birth_edge": { + "sink": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 21538335, + "signature": "4uNtV2g1sTqRYn7Skm6uidpEgFEL9UUnJhUGECL3rjyahb6vVPFPKQi3ZzV69NuPPPWwwmg7MNQnWQ59XBtqgP7S", + "slot": 372861338, + "block_time": 1760265242, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4": { + "address": "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1710631332, + "birth_edge": { + "sink": "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "sources": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ], + "value": 394037978, + "signature": "3tJT334qtxVLAYkbJ8nGePCKiT4k9nP2DtwPgjwLiQuMbCMcMv6awuiXC19xq9zR9DUM3TAenySiEdiyp2uMygwB", + "slot": 254612541, + "block_time": 1710631332, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ], + "funded": [ + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg" + ], + "birth_scan_exhausted": false + }, + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j": { + "address": "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "owner": null, + "executable": false, + "signatures": { + "Exact": 499 + }, + "first_seen": 1683797389, + "birth_edge": { + "sink": "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 240000000, + "signature": "2THWQfqsFFiAxK6YpuFSVPJLzqz7mU7jXzvZ79f3aFWPfGCNR2HAhoFGKbhobBrKd4XJhRGd1guerxbyMx3wAn9V", + "slot": 193309880, + "block_time": 1683797389, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN" + ], + "birth_scan_exhausted": false + }, + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM": { + "address": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 270 + }, + "first_seen": 1649945488, + "birth_edge": { + "sink": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 11854550000, + "signature": "5LojLQtWF5mFYcGE1MiSjmeixsnYuPneTWNigfaeMGJ1Yysw88ct5X7eaJdhRTy482fAXSM97EpWV6YhYBeBHQ7n", + "slot": 129710493, + "block_time": 1649945488, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi": { + "address": "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr": { + "address": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1785 + }, + "first_seen": 1739523472, + "birth_edge": { + "sink": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "sources": [ + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "value": 1987201900, + "signature": "bzNe8Zg7oE1fXGipW89PL11Q3LbWTdjkKzFGFfSHFnM1LZr93MSbyf5JhPNZ7khZ6twbx9RF41WCFySKZEj14NX", + "slot": 320565860, + "block_time": 1739523472, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ": { + "address": "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 457 + }, + "first_seen": 1638890356, + "birth_edge": { + "sink": "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ", + "sources": [ + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi" + ], + "value": 10000000, + "signature": "3FcspUwHdAXBUQUSD7W2h6rTetqRqEnwBGaviwuYHjBRfb6nP7dpJiGLn1s5CDCQ98neMBr4D8tRAQwCxaQRxtad", + "slot": 110473576, + "block_time": 1638890406, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2J2YzRzZ7YLNva22NVNJBQC4bbRVFoJgJsbxxArUNy88", + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi" + ], + "funded": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "birth_scan_exhausted": false + }, + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw": { + "address": "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1773549082, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr" + ], + "birth_scan_exhausted": false + }, + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J": { + "address": "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1714594823, + "birth_edge": { + "sink": "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J", + "sources": [ + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX" + ], + "value": 500000000, + "signature": "5fTqyzGH9a9g4B626zks91Ln4aRi5iKy5NRGEK9LPy4c1E4XZXnNJK5raAxDDMoADYZDzyEinoYnbnbbS9NNu6w5", + "slot": 263327744, + "block_time": 1714594823, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX" + ], + "funded": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r" + ], + "birth_scan_exhausted": false + }, + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS": { + "address": "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1783195595, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW" + ], + "birth_scan_exhausted": false + }, + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9": { + "address": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 254 + }, + "first_seen": 1723048172, + "birth_edge": { + "sink": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 490000000, + "signature": "4G2fwKebyh9QsNPjGHfPsCiBnjg5DYU99FUojtp5ZEcTnh5wwMxnYK7F11jQmdAsFSKSpxg1MPg67muc2FZroZrg", + "slot": 282148476, + "block_time": 1723048651, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF": { + "address": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2386 + }, + "first_seen": 1770200497, + "birth_edge": { + "sink": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "sources": [ + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU" + ], + "value": 190000000, + "signature": "51n18JMEXfFtcFurC9Eyqe7ZVgmj4qcwLmrfsF6qDdodqteHt7D6vqyidRDdWZ1syv24c84Ri7jGCs6C8nHKokJR", + "slot": 397988088, + "block_time": 1770202555, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR": { + "address": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 25 + }, + "first_seen": 1782895333, + "birth_edge": { + "sink": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "sources": [ + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "value": 734553600, + "signature": "36vjnxndxfYcSHBf37rrdBPqcwc2BBpECPGQzSr6RNhbizneiaCKc4xXpiMNNGtk6eqnexRme4xfy3GDLfkPNyRk", + "slot": 430058672, + "block_time": 1782895333, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH": { + "address": "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11742 + }, + "first_seen": 1624516734, + "birth_edge": { + "sink": "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 100000000, + "signature": "fbtWCRyRCWNtSWCCZV2HJXPt9trL74715bnz1R13hWcBnNzSeJDm9Amufv5VFLQUUUXtVLM5nPCuWkteuBx83eW", + "slot": 84190784, + "block_time": 1624516734, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf" + ], + "birth_scan_exhausted": false + }, + "4AcmsW4k1JKCRv9irityUMkJ8eMm1JSqG9rR5FcNdZvy": { + "address": "4AcmsW4k1JKCRv9irityUMkJ8eMm1JSqG9rR5FcNdZvy", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1771562805, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "birth_scan_exhausted": false + }, + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL": { + "address": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18 + }, + "first_seen": 1758306486, + "birth_edge": { + "sink": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "sources": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "value": 2100000000, + "signature": "57LKR9sEPC21YHt2pbje7Ur5ACGLqqMUSF5wHYdquAVozDKs3K516nGr5sa47qJdKZiVvQnxTms11orYiYb7uvCP", + "slot": 367913728, + "block_time": 1758306486, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL": { + "address": "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 753 + }, + "first_seen": 1629221283, + "birth_edge": { + "sink": "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 5355472000, + "signature": "2W3H6wz4dVoB44Lnjkh5gnCUF4ZbgxqcmTruSYMG6vgfrP6Su4TeAcdfHTicxnRLqfasnbgZLjitokZRveP23Sp2", + "slot": 92116993, + "block_time": 1629221283, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K" + ], + "birth_scan_exhausted": false + }, + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G": { + "address": "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5722 + }, + "first_seen": 1703416057, + "birth_edge": { + "sink": "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 970000000, + "signature": "3EzUczntHsFF95zi2Kt4Sq9Hh8tB932DRH2TfP3RoLXniCmJ9yBBhwdXqQHXv1w9bDHDWoxQQ6qSfeLaxhXqpf5j", + "slot": 237735212, + "block_time": 1703416057, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3" + ], + "birth_scan_exhausted": false + }, + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw": { + "address": "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784500317, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4" + ], + "birth_scan_exhausted": false + }, + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7": { + "address": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5237 + }, + "first_seen": 1757495135, + "birth_edge": { + "sink": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "sources": [ + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm" + ], + "value": 2000000000, + "signature": "2j3tdTF7b9SQxw7tCmbtXBy8tWcoq9oMXAFBbRKVHkvHhu2VF3c9wDgAY3zVNcfHAojEvvkhQLr6oosvPosD8EjV", + "slot": 366585560, + "block_time": 1757781857, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3": { + "address": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 119 + }, + "first_seen": 1756133000, + "birth_edge": { + "sink": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "sources": [ + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G" + ], + "value": 59854218, + "signature": "39DqyYqU7RqGLLLSr8kU3mKL4xQnMVMbFjH5KN4XMoJvUDxBdYKGiwWPBGZWkASf2cYweXxb3wQ6utie6EMAANpu", + "slot": 364966880, + "block_time": 1757134451, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh": { + "address": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20761 + }, + "first_seen": 1663879176, + "birth_edge": { + "sink": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 490000000, + "signature": "5kDrBVEWkieCWXHps4mJ9h437RmD7D9Nmyo2uo2UwQsDNUWm6KiAB8T3DNQ8svrsbx11hqdXKcUBNQAY1gACJNwT", + "slot": 151875320, + "block_time": 1663879176, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh": { + "address": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20 + }, + "first_seen": 1783099754, + "birth_edge": { + "sink": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "sources": [ + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk" + ], + "value": 2238177460, + "signature": "5a7NoCBgFaHpUJqMxVp6A8vBTLQnJ3uWB59UCDYZsTm3SyXmhYfrPkXSrPDJ9jca9LCtWM5eDLK4jUMoybZ4ApV4", + "slot": 430565641, + "block_time": 1783099762, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V": { + "address": "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1756410716, + "birth_edge": { + "sink": "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V", + "sources": [ + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "value": 2039280, + "signature": "qTMcW7d2WNayJ6STKme6zWHcpCvnZm5EKYRc5mQZJqqBMKB8T3pTKBnqrKQczdNSQfz6LZH1ETAJP7Yf9eiR8W7", + "slot": 363139499, + "block_time": 1756410716, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu" + ], + "funded": [ + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4" + ], + "birth_scan_exhausted": false + }, + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7": { + "address": "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 15 + }, + "first_seen": 1734187345, + "birth_edge": { + "sink": "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 139459250, + "signature": "3PEFFsvAZgWyxKcjNoWzSXQJ4XtMGZbsm4BDiXGtRVT2huaSmPbopJf6Psmsg5HJRxeLCo2ewLcvhQC6JkDNTDYj", + "slot": 307446440, + "block_time": 1734188936, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6" + ], + "birth_scan_exhausted": false + }, + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV": { + "address": "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV", + "owner": null, + "executable": false, + "signatures": { + "Exact": 55 + }, + "first_seen": 1773235824, + "birth_edge": { + "sink": "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 532871511, + "signature": "nxEPT4eY8McAoUhK86oAYzDiTBXmjJgjmbGSdFaKbNZSNiSi9KoJAAP8hAKvQRZGEDExv1r77BapRvx1joJRXHf", + "slot": 405705084, + "block_time": 1773236286, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [ + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ" + ], + "birth_scan_exhausted": false + }, + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB": { + "address": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 52 + }, + "first_seen": 1770266528, + "birth_edge": { + "sink": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1204809220, + "signature": "373hVK6YWozQ1rjpFwQ9EYjzYKW7AJ3YEpfyAPGiDtdeMmRphi1bKSpnPn2vu8t8t7J7fKAug14jQu6LdRNUR4Jo", + "slot": 398150397, + "block_time": 1770266528, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ": { + "address": "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1774679440, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1": { + "address": "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784129811, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb" + ], + "birth_scan_exhausted": false + }, + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC": { + "address": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 824 + }, + "first_seen": 1757568229, + "birth_edge": { + "sink": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "sources": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "value": 800249721, + "signature": "hq8JsmuHcip8MBCGgPSwd7occB8hVnKNphP8Xm4Yk7Uuj9Vtkz5DCQEYMnh5W9bn74jGumD3LC6essjQdzqyWzp", + "slot": 366050029, + "block_time": 1757569412, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD": { + "address": "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1741847245, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr" + ], + "birth_scan_exhausted": false + }, + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt": { + "address": "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "owner": null, + "executable": false, + "signatures": { + "Exact": 124 + }, + "first_seen": 1773144352, + "birth_edge": { + "sink": "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 99000000, + "signature": "NbnA7s6aJWNM2nfCACoXNDeVGZwALbRcFCkM33u7mQyMKJ3QpSHhA1pVPVX3EugPo74gm1ycaL1CBJ4UqcN3dXi", + "slot": 405469329, + "block_time": 1773144352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3" + ], + "birth_scan_exhausted": false + }, + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z": { + "address": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 96 + }, + "first_seen": 1628597237, + "birth_edge": { + "sink": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 4990000000, + "signature": "2kUPLWWUJut6M2AfRAZAiGLkuWLJN5D4JXMZ1VKr7cj7uWWmmcY43cGMHS7UMF8Uw32rrFUdCMNh6AMyJKR7woy9", + "slot": 91034738, + "block_time": 1628597237, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ": { + "address": "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1777762335, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR" + ], + "birth_scan_exhausted": false + }, + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9": { + "address": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784840303, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "4HUVDexUL67zLvj2Q7AddoNoDvmruYKHuHguQx1Jed7G", + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4" + ], + "birth_scan_exhausted": false + }, + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF": { + "address": "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784797145, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879" + ], + "birth_scan_exhausted": false + }, + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu": { + "address": "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3947 + }, + "first_seen": 1631763613, + "birth_edge": { + "sink": "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu", + "sources": [ + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk" + ], + "value": 100000000, + "signature": "3CmYn4pR8Eaoa5ocbeLxZ9VHFTtQziQMVNpM2Pjh2V1HiJg3VCnkVskGWtaMVgf4oDRCiEW3RC8r9NbTgjY2aXQ5", + "slot": 96711846, + "block_time": 1631763613, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk" + ], + "funded": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "birth_scan_exhausted": false + }, + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39": { + "address": "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1710624873, + "birth_edge": { + "sink": "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 394042978, + "signature": "5reS92mjj8Avu1Hm8NibK41HwVLTaetYhYEb1eGpT3AYkssVwhBEq479YqaVAw7G4tPhrnwvjUai3ruhQLpUW72T", + "slot": 254597447, + "block_time": 1710624873, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "birth_scan_exhausted": false + }, + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS": { + "address": "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 194 + }, + "first_seen": 1739874778, + "birth_edge": { + "sink": "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 1000000000, + "signature": "rB8uvcS1mATGDoAm47msudGAkdiXhSJBKGnk51uiWVkyzj45DKjiJUguciDjwujSbLGaxfhYYgC6bBs1bFMwbry", + "slot": 321451943, + "block_time": 1739874778, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "birth_scan_exhausted": false + }, + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL": { + "address": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 66 + }, + "first_seen": 1730986163, + "birth_edge": { + "sink": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "sources": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "value": 240234545, + "signature": "4JGR17CZKiUrUKXVpnbhu4LzPvRc1vMRChQVcqLpjuWaPswEvUS3b8Cjf5tyNyuptuA5GGBrTt2cCgdv1QsYuwiQ", + "slot": 300009349, + "block_time": 1730986163, + "ambiguous_attribution": false + }, + "fee_payers": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk": { + "address": "6ZRCB7AAqGre6c72PRz3MHLC73VMYvJ8bi9KHf1HFpNk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1667834292, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu" + ], + "birth_scan_exhausted": false + }, + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv": { + "address": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7163 + }, + "first_seen": 1776453682, + "birth_edge": { + "sink": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "sources": [ + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1" + ], + "value": 11193190, + "signature": "2EFWC7p4UmzuhS8ewbcBi4bJGXe3Nd8tMbRpnLY4oCDG3MTJ1nxhsVLAhzcCHhEvacNdeoyepNE54ow4jY3WnZS5", + "slot": 413882415, + "block_time": 1776453892, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "CRUSHtWNSqWK4nu8zZvXpSKxKveas1LSuG7MycL4T976", + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9": { + "address": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1771265328, + "birth_edge": { + "sink": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1465532000, + "signature": "48jcsENEjMVCHrSfUqXLDZDt8nqQfHqDR1Fhx4VH3wGT5Epbks18Mfcs5WJ3yhzdnuWVupAUKPu6jgFTArDxM7iT", + "slot": 400700540, + "block_time": 1771265328, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV": { + "address": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 22 + }, + "first_seen": 1781373138, + "birth_edge": { + "sink": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "sources": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "value": 19650094, + "signature": "5JwERz8A9ssUFHSgXzszdjoKkSs8WVRrjdmKqSRXeD7GcBCyDXqzgMjHQdtqUF9MgCA9R7cK4V7Vm9thS5ib7Fkg", + "slot": 426247804, + "block_time": 1781373138, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG": { + "address": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1780571139, + "birth_edge": { + "sink": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "sources": [ + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW" + ], + "value": 146749060, + "signature": "GhK4Hst1KZyFkxo6viVKoxPJKD3LvVUz66T2joYoM5wacEkn1gbvDtFdNiLB1qXiCMsWiTdGay3xAV3sMHb4o9e", + "slot": 424231157, + "block_time": 1780571140, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU": { + "address": "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "owner": null, + "executable": false, + "signatures": { + "Exact": 369 + }, + "first_seen": 1709827691, + "birth_edge": { + "sink": "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU", + "sources": [ + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN" + ], + "value": 50000000, + "signature": "51rFfVkiSmUzeh1QRNcm99Ea8MUGTMAff1SaRs2dGBigE9VBBo2kkNMsY1o85nxMF4jWHeSVQk2ctJZddtPcZQmj", + "slot": 252697500, + "block_time": 1709827691, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN" + ], + "funded": [ + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY" + ], + "birth_scan_exhausted": false + }, + "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip": { + "address": "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm": { + "address": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1784211013, + "birth_edge": { + "sink": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "sources": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "value": 3895835199, + "signature": "4pntPEhmoeiCTqii4XrvYMiAG2VVja2htxSyFFuda7S8MZfTLjQCkV9XmNyCSqekAzURhwHxAxSEMMApwkM6Zayj", + "slot": 433287475, + "block_time": 1784211013, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T": { + "address": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 26 + }, + "first_seen": 1783100066, + "birth_edge": { + "sink": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "sources": [ + "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu" + ], + "value": 2247350044, + "signature": "2BdukFLQsAoYPAD8iQpWVwybrX2rZrhp46T5t1yco6c93fAAsY3wyyZdiRHmrBmDMKP1yaVjp4hmjqwa8A6bAoPr", + "slot": 430566389, + "block_time": 1783100066, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ": { + "address": "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2483 + }, + "first_seen": 1642454259, + "birth_edge": { + "sink": "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "sources": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "value": 100000000, + "signature": "4XUZRtA4Q1gAaiSWnDA7XY9RboU57S4bSkhfFscKU8Ywa8NioAKWpCu6Z9ZXRQ18qp2pQAFytHgibJ1So1dsiJ3f", + "slot": 121052633, + "block_time": 1644990871, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "funded": [ + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK" + ], + "birth_scan_exhausted": false + }, + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No": { + "address": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4949 + }, + "first_seen": 1756672617, + "birth_edge": { + "sink": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "sources": [ + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh" + ], + "value": 100000000, + "signature": "JTTb13ZHYiJd6AALvqyCnXhSZUFAXLFdKuQmPrXzPkVkYvzL16iDe8zYfBHmTtiLJkCay3pN8DjMdasCr2TqbWf", + "slot": 363900815, + "block_time": 1756711448, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "Hc2vsrdknaVuSypGNyMDuzR3FN3yWVcSuFALT6j2Cq71", + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW": { + "address": "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41819 + }, + "first_seen": 1764758526, + "birth_edge": { + "sink": "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW", + "sources": [ + "4AcmsW4k1JKCRv9irityUMkJ8eMm1JSqG9rR5FcNdZvy" + ], + "value": 9985000, + "signature": "3fu8JhzdiMdctHfTAjDCULnVrMPbCjEcZkmLvtNUeMUPxmxsq7Nw9UQoFWxPApgKrBJUJtBy5hSrMzCvUsEX5GnR", + "slot": 384183027, + "block_time": 1764758526, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4AcmsW4k1JKCRv9irityUMkJ8eMm1JSqG9rR5FcNdZvy" + ], + "funded": [ + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o" + ], + "birth_scan_exhausted": false + }, + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg": { + "address": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18410 + }, + "first_seen": 1710632250, + "birth_edge": { + "sink": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "sources": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "value": 394012978, + "signature": "3bvxtDsw7CBv3imPLoMrdyhA8cjSRRP3XCwzuJfyzx5AWZ9B8MjPdU3Gju47KgKxqGcd3gLP1ZhLVnHdhaZwQqYE", + "slot": 254614672, + "block_time": 1710632250, + "ambiguous_attribution": false + }, + "fee_payers": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW": { + "address": "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW", + "owner": null, + "executable": false, + "signatures": { + "Exact": 18 + }, + "first_seen": 1628591660, + "birth_edge": { + "sink": "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW", + "sources": [ + "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr" + ], + "value": 10000000, + "signature": "3BKCN6eibAWudB7osE6dbMTVB82nVSBi9QymACMrs1e1EY7a6pTSJ1unJCYf9R7eKqkztukJpvCVTRZ9wyvz6cH7", + "slot": 91024783, + "block_time": 1628591660, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr" + ], + "funded": [ + "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88" + ], + "birth_scan_exhausted": false + }, + "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd": { + "address": "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt": { + "address": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1777777000, + "birth_edge": { + "sink": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 9000000, + "signature": "48JSB2pqTRMXWg2S6ajewFiuyXADPk9q8QJYD1NLxSYwoBZzSFWKcPEKzQwN2K4dHJ6QYS8ppfo8Acra1LDZkffb", + "slot": 417226530, + "block_time": 1777777000, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88": { + "address": "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1628608093, + "birth_edge": { + "sink": "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88", + "sources": [ + "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW" + ], + "value": 24320650, + "signature": "WYyc2zqFMthAQW6w1z79FphC3swbwe5U9WERwpC2xanQhsFomPDqLeoJMU3aemNdDHZYVqEEpywT5sSSaYLm3sz", + "slot": 91055360, + "block_time": 1628608745, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW" + ], + "funded": [ + "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy" + ], + "birth_scan_exhausted": false + }, + "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg": { + "address": "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4": { + "address": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 650 + }, + "first_seen": 1764161875, + "birth_edge": { + "sink": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 100000000, + "signature": "5Djf6M25i7Pqn3PvuibF3UkHSDJAmj3VEiHCuV7wDCth91DGunedSr5EaJ6KwDYQHyqLE6mGTbHM1K7hCg4ejans", + "slot": 382647096, + "block_time": 1764162226, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq": { + "address": "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 92 + }, + "first_seen": 1628599869, + "birth_edge": { + "sink": "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq", + "sources": [ + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w" + ], + "value": 9880000000, + "signature": "3AVBmBvJmrKM8wMGddX2wk8Z2Jebsk4Tg17Gk1bM1YzMwaVqhqBeLLiU4uhEUeeXGa43AbPVKFCZeYDK3vDWPV5h", + "slot": 91039469, + "block_time": 1628599869, + "ambiguous_attribution": false + }, + "fee_payers": [ + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w" + ], + "funded": [ + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn" + ], + "birth_scan_exhausted": false + }, + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65": { + "address": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1243 + }, + "first_seen": 1760985667, + "birth_edge": { + "sink": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "sources": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6" + ], + "value": 110000000, + "signature": "3eeFfzc6icmbz7XsoNRMKf1ZtnXKBMUWoXSjY5oarm3GXGzBMJ3QuxuFfMNVHuPtzp8EDsUMh7psK9B85v4QsZ1h", + "slot": 374677619, + "block_time": 1760987283, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "Gem2VAypSg7Ai7vjDKPTtqFahpoQWkfgVkyzx3rPoTka" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z": { + "address": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 510 + }, + "first_seen": 1736141750, + "birth_edge": { + "sink": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 10450531000, + "signature": "5NTDt6Rswtrvt42AT1trjiRspELnF9t98z5H2TyQ4D1L7zB84w3GQjF6borcJLChNK89mRwQUTsqpowEU6MMp4yQ", + "slot": 312181544, + "block_time": 1736141750, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn": { + "address": "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 928 + }, + "first_seen": 1633089324, + "birth_edge": { + "sink": "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn", + "sources": [ + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq" + ], + "value": 1000000000, + "signature": "qjyV7pemydByaUSd3gd8tGw1uo1JZjM1eg2uKzR8jEs5U6zL1pJRN88EnT6cKsECcGegdcAV5pPbfxkhPJb2B1w", + "slot": 99242855, + "block_time": 1633089324, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq" + ], + "funded": [ + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i" + ], + "birth_scan_exhausted": false + }, + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS": { + "address": "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1768118748, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs" + ], + "birth_scan_exhausted": false + }, + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K": { + "address": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4311 + }, + "first_seen": 1729158047, + "birth_edge": { + "sink": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "sources": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "value": 200000000, + "signature": "29ZCJmU48wWT7mGpV6u7YsVzcc15Fy6CDPRWRLgjqNYfcgMUU75z79L3ruGa5wXW68AfU9m4EQzr2WtsZ1gmHRgs", + "slot": 299468871, + "block_time": 1730727939, + "ambiguous_attribution": false + }, + "fee_payers": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck": { + "address": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 37 + }, + "first_seen": 1781689177, + "birth_edge": { + "sink": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "sources": [ + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "value": 2000000000, + "signature": "2kW6Rf9kPJAZnCSgHodJwFNifHr5L1UN3Cj8afcoWHsxHKWFiDEfzFv7v8DsvNL5HFQeihiYy4GWieL826rQnH9Y", + "slot": 427044455, + "block_time": 1781689177, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr": { + "address": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1782983366, + "birth_edge": { + "sink": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "sources": [ + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "value": 65793663482, + "signature": "4uU5EhqsUfPVzpZ1jHMrg9T2TgfcMWE6s81PwMypZnVXQzjKNiB4ibWb9E2MPHa5WFC5mkZhf2DN4PRtX5zaCnB3", + "slot": 430277120, + "block_time": 1782983366, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh": { + "address": "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1028 + }, + "first_seen": 1736684311, + "birth_edge": { + "sink": "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh", + "sources": [ + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6" + ], + "value": 30000000, + "signature": "3tBtrKN5a4FNtR2Tti1gYDwxnWoZ9KhNXu1kP4ArQG4q5wDFvU2C2Z3vxS8hgZu2eLkmcT8XR8MfzLHtNfjimhfc", + "slot": 313511470, + "block_time": 1736684311, + "ambiguous_attribution": false + }, + "fee_payers": [ + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6" + ], + "funded": [ + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No" + ], + "birth_scan_exhausted": false + }, + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E": { + "address": "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 346 + }, + "first_seen": 1619103636, + "birth_edge": { + "sink": "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E", + "sources": [ + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX" + ], + "value": 3999946680, + "signature": "5Xn9C17aBL4Qnk7ZwPJrJeT25CNbP7u7FVGh3qEz3eXKCuqeyM5UNz5KBiW42J3vboohK1ucyZAfeukZybth93Rp", + "slot": 74825696, + "block_time": 1619103636, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX" + ], + "funded": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "birth_scan_exhausted": false + }, + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb": { + "address": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1761613462, + "birth_edge": { + "sink": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 5504330, + "signature": "4X7t1Ls8Zpb3bqFZchjukeaG9Tf1MdMwUS62Ua2Nx4ALiEYLR4aSCr2Az9hTVF17HBnJsPUa4Q2amcmFnXWECY9m", + "slot": 376252987, + "block_time": 1761613462, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879": { + "address": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 59 + }, + "first_seen": 1760849092, + "birth_edge": { + "sink": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "sources": [ + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "value": 93302400, + "signature": "8d5pfjnoehDwiQkD8Uzm2oPh1t4kFwufYmpALykZYwM5KuTQ4dnfNcNHsWS55QDSLYD8mB3YK18epo2sfgEtnY7", + "slot": 376261031, + "block_time": 1761616657, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV": { + "address": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1764737043, + "birth_edge": { + "sink": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 14000853800, + "signature": "4HrqBiVtSmNYMccmWJTEBTXqQe3eztKrd3bpj9AibBehzd7QGCqiY69pbSafREg2UaAHGcv5zt1TU57vbjDFVJdx", + "slot": 416969897, + "block_time": 1777675621, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "7dq4McdQAd6ZUMajZKHNiacNuWcyJsBj1eMeZPPckyz1", + "75Cxo2H9iFZ71LVWADz1qwRV2MJkjzmUdo2b6UjXp1KN", + "6cRBcJy8YatfNYLHD5kyNtCX9ypENwXerB36MKUNUK4e" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR": { + "address": "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1783931673, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh" + ], + "birth_scan_exhausted": false + }, + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2": { + "address": "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1781807941, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7", + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z" + ], + "birth_scan_exhausted": false + }, + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE": { + "address": "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 27 + }, + "first_seen": 1726629672, + "birth_edge": { + "sink": "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "sources": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "value": 1000000000, + "signature": "4DvouS9aXw7ir6N3ohxgKFw3UugY7jqK3aextkEtbox1i1wue5Xh4W6NHbZE9bWvZLMb1P28LoMDY4QhBnRXcehr", + "slot": 290465228, + "block_time": 1726629672, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "funded": [ + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm" + ], + "birth_scan_exhausted": false + }, + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP": { + "address": "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 8186 + }, + "first_seen": 1711915637, + "birth_edge": { + "sink": "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "sources": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V" + ], + "value": 200000000, + "signature": "2sbPicuC4gBQYMAM312LbgX1eDfY9nWY1Aeomg7RBbYVq4ZBuxkFJ1Cpc1icLyVxYUvzPmUyBdn5tCjBbBgRco49", + "slot": 257602531, + "block_time": 1711915637, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V" + ], + "funded": [ + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n" + ], + "birth_scan_exhausted": false + }, + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri": { + "address": "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 10 + }, + "first_seen": 1742326938, + "birth_edge": { + "sink": "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 1003215950, + "signature": "3tm1fffHfNDLhNDnTLeRVe5scKp75BZtrAEcbiDoujfP9be6qpAEwP1heKegTaC1jYcGo8641hi94FUuaj6sZrJF", + "slot": 327633737, + "block_time": 1742326938, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "birth_scan_exhausted": false + }, + "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU": { + "address": "AMrWYhuEETZDBEwbajGuxHXH3nZHDNk99nYwpb3hDzrU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1754719629, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF" + ], + "birth_scan_exhausted": false + }, + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ": { + "address": "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784372764, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z" + ], + "birth_scan_exhausted": false + }, + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa": { + "address": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 81 + }, + "first_seen": 1712036070, + "birth_edge": { + "sink": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 270768410, + "signature": "4MjcwLDx2bPhGuHdRFGKiE3khiQoSd5DWZEw7RNbuHTubuJ6MvHtZyG4TA7TTAHc9CeK6yHS68ErF5gZdeKnDC2R", + "slot": 257873921, + "block_time": 1712036070, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX": { + "address": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3735 + }, + "first_seen": 1760474300, + "birth_edge": { + "sink": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "sources": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ], + "value": 100000000, + "signature": "aq7ps7k6RZcBWVMaHcqHLVemRNLYzFQukxseeeApwgmVCZ39LNCa2kh8WLCkkdM21AUUjVv9sYtYmi9Gz9BwkUB", + "slot": 373387624, + "block_time": 1760474300, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4": { + "address": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 37 + }, + "first_seen": 1775710580, + "birth_edge": { + "sink": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "sources": [ + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "value": 4639648909, + "signature": "3yQYxKyRPrcH6pk87zfhx67eL6Wzza7hDrE91MA3xHKBRcWv6fHLYeW2JfwTtG2sHw5u67qig7NJ2usnX26aqb6t", + "slot": 412000930, + "block_time": 1775710580, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8": { + "address": "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 179 + }, + "first_seen": 1739919851, + "birth_edge": { + "sink": "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8", + "sources": [ + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY" + ], + "value": 625744930, + "signature": "3RQ4iKJW9dUmd47Tr4JANamMYoeg33wQPZvLCPB2Xy5SGpB7BjfcwYoV98YCvvbZyjJ8hgrEB3ybUJpTQrBke1oX", + "slot": 321565671, + "block_time": 1739919851, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY" + ], + "funded": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "birth_scan_exhausted": false + }, + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf": { + "address": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 450 + }, + "first_seen": 1713195781, + "birth_edge": { + "sink": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "sources": [ + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "value": 10000000, + "signature": "4CEipGPf7m8m8EfHLDWVTy1TsiKyD1LsD6ZAaaNNgvwWJdvqGxRoo9cPcFbASE47phKqZFzaG9dWKaTCFx99bTSb", + "slot": 260290481, + "block_time": 1713195781, + "ambiguous_attribution": false + }, + "fee_payers": [ + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS": { + "address": "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784479518, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j", + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu", + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL" + ], + "birth_scan_exhausted": false + }, + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh": { + "address": "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 24077 + }, + "first_seen": 1631688013, + "birth_edge": { + "sink": "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh", + "sources": [ + "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc" + ], + "value": 25000000, + "signature": "3vmCJ69AbCNgG1VseFN5Gp3j59XFEYZAXbXE7KjgJP5qa336ZyXUUMvZ8ehs9t3tLgyvKTLM2S56H2uQ6UDuuD24", + "slot": 96579112, + "block_time": 1631688094, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc" + ], + "funded": [ + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL" + ], + "birth_scan_exhausted": false + }, + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc": { + "address": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 64 + }, + "first_seen": 1778266848, + "birth_edge": { + "sink": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 99000000, + "signature": "3UDS6u6ncvTgLndGKD9eaT6q5NWG6JvBniKFJmXeXWPcn9uPsEb5vLWyerKgsPfDvS76r5og2onyCsvXhDw86Kiz", + "slot": 418457793, + "block_time": 1778267806, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i": { + "address": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 290 + }, + "first_seen": 1757844826, + "birth_edge": { + "sink": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "sources": [ + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn" + ], + "value": 120000000, + "signature": "5aVXbSHPmaWfGTctRcFzMuXnqujTKZAEYTX9G6cByRFswAMPGesDy2vVKWp1e9sykcHkF2QbnhiBQQgbZMhPs7EL", + "slot": 366747475, + "block_time": 1757845725, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "8fzTAsHMTPh8AdfqhiAmzMydVGkYYh1r1bbCntD9XbMn" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn": { + "address": "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784104058, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa" + ], + "birth_scan_exhausted": false + }, + "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM": { + "address": "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 491 + }, + "first_seen": 1757104043, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "2nh9AXgxVtbDucnR6Psv53JZaWvjphDLMb6HohuKmr5e", + "pay3JiXTbGTdjfoYo1caZ1oGdQgWVLQ3ws8LoqbxU8i" + ], + "funded": [], + "birth_scan_exhausted": true + }, + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ": { + "address": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 440 + }, + "first_seen": 1773406077, + "birth_edge": { + "sink": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "sources": [ + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "value": 3164021672, + "signature": "cTRx38ZKrtf7ffFXLkr2E2zVgVeJBugExzbDBrxPH7AnZdU631jwEpEQwgsspZEV8QLGr39u9N9nU3vdSrK7RMi", + "slot": 406138581, + "block_time": 1773406090, + "ambiguous_attribution": false + }, + "fee_payers": [ + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij": { + "address": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2605 + }, + "first_seen": 1753207964, + "birth_edge": { + "sink": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "sources": [ + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "value": 140590159, + "signature": "2oaGcywpLPt8xEY7w84WSw4Z94DJiZgz1sTYzpCBbfT8sc5UYD99TiHCZoJqasjmLGzqUbffbHXg7LimmCk5pzu4", + "slot": 355044244, + "block_time": 1753207964, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe": { + "address": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 320 + }, + "first_seen": 1720840348, + "birth_edge": { + "sink": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 11000000000, + "signature": "1rHtsQspU78fmcbJZDfTh4hrN8xcRLjz2Ji2N7VV5KPBW29nATa6FSmt6WsnrFkmnNbz7QmuQiCDEgeRJYieX9E", + "slot": 277240691, + "block_time": 1720840348, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr": { + "address": "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 78 + }, + "first_seen": 1627941588, + "birth_edge": { + "sink": "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr", + "sources": [ + "GbG7Kekbzjypekv9vEEdyERXp3XvpvAqhtFfvEUwrAb7" + ], + "value": 1924720, + "signature": "3iPiaULqy4K1QhBFMTjHRr5Tk4mkqD5AZQhUUBf26YBmmAfptupMLE9w4FXdx6YcNH5oU6LR2TPu7DDYmcekAx6s", + "slot": 89819719, + "block_time": 1627941726, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GbG7Kekbzjypekv9vEEdyERXp3XvpvAqhtFfvEUwrAb7" + ], + "funded": [ + "7g35rQ6bsxgXrMuDqLoYXJFFwjKp6uJkZZujrnLRnTuW" + ], + "birth_scan_exhausted": false + }, + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU": { + "address": "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784816847, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8" + ], + "birth_scan_exhausted": false + }, + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6": { + "address": "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1783883458, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "birth_scan_exhausted": false + }, + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb": { + "address": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 47155 + }, + "first_seen": 1717142675, + "birth_edge": { + "sink": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "sources": [ + "HFWv1riXSRJ3nVnnLZ9xi1K4r3zppRvcfVuiAGqAA8Y6" + ], + "value": 1495286656, + "signature": "47dN3fYBZ93es4jepSiFL2Ez7j1bR2KCsyWjsEPqifDoZ2K1U2m62tUkp2e1F1BgG6YaUCqAkto4uyUU5Ax95QY4", + "slot": 268999910, + "block_time": 1717142675, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HFWv1riXSRJ3nVnnLZ9xi1K4r3zppRvcfVuiAGqAA8Y6" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg": { + "address": "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2175 + }, + "first_seen": 1656406760, + "birth_edge": { + "sink": "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "sources": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "value": 9995000, + "signature": "uuctf7AvHunnmw7gS6Vn6WdB14iBXvbSCkNj7hacJUYDiFs41nFhzzoP2NqGHfV1HH1pFBEmiMsdRW8tXAmv8Qr", + "slot": 140737056, + "block_time": 1657295936, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "funded": [ + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL" + ], + "birth_scan_exhausted": false + }, + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb": { + "address": "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "owner": null, + "executable": false, + "signatures": { + "Exact": 8 + }, + "first_seen": 1768750363, + "birth_edge": { + "sink": "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 30193550020, + "signature": "4sv5REU2obsMfmgbTmSqWgiGiCnQJibid6PgNptnSpqaDLjAWGBdfotB1yiG3tnDuJv7mqRN5NyXQAstjw1QfMdr", + "slot": 394345708, + "block_time": 1768750363, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [ + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764" + ], + "birth_scan_exhausted": false + }, + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm": { + "address": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 143 + }, + "first_seen": 1767909246, + "birth_edge": { + "sink": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "sources": [ + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "value": 1310000000, + "signature": "3kDnzFaFpXEegPizm9MKtpGGJ8BnETNFdYFJpd2rxKux7Z8EF58v5sMGsnqHfGAxoPTkiZCcSUUb9VpqWL7LD4og", + "slot": 392216036, + "block_time": 1767909246, + "ambiguous_attribution": false + }, + "fee_payers": [ + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ": { + "address": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 31687 + }, + "first_seen": 1756413585, + "birth_edge": { + "sink": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "sources": [ + "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu" + ], + "value": 1000000000, + "signature": "3vd3hUkFUjy3i73ogetQDJmWEQfnL8rtfm9W4SKgbcLmyfpnB2i2CCXBBraQ5MhBzp6JLe73XbQ7JLQGM94t3D5H", + "slot": 363150428, + "block_time": 1756415016, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD": { + "address": "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1058 + }, + "first_seen": 1734856327, + "birth_edge": { + "sink": "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "sources": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "value": 491810375, + "signature": "2dMS6hZn46wpPzfXrzPMP6u4qrA8E21Pn5vhdeZGvEtMVxozhJUucnm8XfFiWA7VyrcvZCe8zVQYPdFnGx833BxP", + "slot": 310396534, + "block_time": 1735409017, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HgsxLyn8175xEwRffPRN3DeARE2EVcEeXENr12HpadL6", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "birth_scan_exhausted": false + }, + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG": { + "address": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 36 + }, + "first_seen": 1778449810, + "birth_edge": { + "sink": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "sources": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "value": 200000000, + "signature": "4XRjYBMjWrSKs8PTEPYrTgkfwVw8Er4AjCYaiHtVn9L5tRWTGu7HnxBTSKUc6gGYGoLri2jr3U9dJ3HnvDvnz1HE", + "slot": 418909903, + "block_time": 1778449810, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG": { + "address": "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1774751413, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "birth_scan_exhausted": false + }, + "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK": { + "address": "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt": { + "address": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1783210007, + "birth_edge": { + "sink": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 2290497690, + "signature": "3dZV999nzMy8zrpKZkKbhczT6DLA7J9YhLZZZKpFD6U6UoGg9oEUrySMR4VJNGeV6UTJ8rKbq6qLpL3AQ91UWu5S", + "slot": 430838822, + "block_time": 1783210007, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj": { + "address": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 126 + }, + "first_seen": 1775679727, + "birth_edge": { + "sink": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "sources": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "value": 346000000000, + "signature": "2qWrYX2VaSpYFeYPpkqG22UArD9XFzXGYmLbcvSD9zNTGSyjB87ZKsAVfq16XzCazqppJMkRB9XG9rMUJBEf6Z29", + "slot": 411923073, + "block_time": 1775679846, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c": { + "address": "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 35 + }, + "first_seen": 1775705585, + "birth_edge": { + "sink": "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "sources": [ + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ", + "8ncU5YW1CQwvr4gs7buH57bW58e86TDau4STrCJBuz8z", + "FUYyfnVhhRc3PoAyQhWYVGL5oN7BF69R6oSKFjz7jtEh" + ], + "value": 58972050, + "signature": "4Vj6GXww18MxSkppTLZFUPxyjKQQMXgohde7sNGCwZGwgQAiyAr31p73V59467WC1g9iFxPeopMWHAdz3yPdqGsW", + "slot": 411994454, + "block_time": 1775708022, + "ambiguous_attribution": true + }, + "fee_payers": [ + "4PqrAP81NRSgbeBNG3scWVev8RAiy1B5SgRDDo3Ub6Eu", + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ" + ], + "funded": [ + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28" + ], + "birth_scan_exhausted": false + }, + "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN": { + "address": "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1565 + }, + "first_seen": 1700506935, + "birth_edge": { + "sink": "CubEiTN5Hi9qwx9Sg4R5BD4aY8sTK2yoxNy3Z7Ve3kzN", + "sources": [ + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j" + ], + "value": 1000000000, + "signature": "3ahr5wC3H6gNPGRX2fZbnSgnSwWo5A7rKcBcpr2MTvpk7LJbALNkrdYuFLunGG3myzFZYMC8ZzPJEtAgzXWbeqrm", + "slot": 231217678, + "block_time": 1700506935, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3Az8dMJrZw64QGKVSq5qmQGQHiLA9eP7hG4e6NwHdN1j" + ], + "funded": [ + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU" + ], + "birth_scan_exhausted": false + }, + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3": { + "address": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 92 + }, + "first_seen": 1775659926, + "birth_edge": { + "sink": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "sources": [ + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt" + ], + "value": 57015551, + "signature": "4U4QtmZTpQ15CfqzPENGoU8QKmkR4M3MzAChG1ff7qZQVRFcizNEfrp1JqoaZaAYJSYnvZB9z1fh5hs3rD2Qxa22", + "slot": 411872556, + "block_time": 1775659926, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD": { + "address": "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 159 + }, + "first_seen": 1759568115, + "birth_edge": { + "sink": "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "sources": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "value": 8793000, + "signature": "21n3KFdeWHq3Xb5KkQL5N9gb29bMcU9zgkBmHFK2EnKqpMCpNfhTmMC14oLPRoFMzrcrrUUp34sb1a7ehfKFByE1", + "slot": 371102052, + "block_time": 1759568115, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "funded": [ + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX" + ], + "birth_scan_exhausted": false + }, + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf": { + "address": "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784517084, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh" + ], + "birth_scan_exhausted": false + }, + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA": { + "address": "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784730422, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2WJdW5qeFhvCZawVtd2EZQqacAUAA2NUDfwGE7m269dk" + ], + "birth_scan_exhausted": false + }, + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep": { + "address": "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 394 + }, + "first_seen": 1746944587, + "birth_edge": { + "sink": "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "sources": [ + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "value": 518078106, + "signature": "4jjjqQ8p9W4WSG7QFKS8FiQszm6XA3gr7ChHQzeeN9nBxWX5DMSErsAunEVF3t1y2Znu2CP95CtjKB8GA4qf8Jz2", + "slot": 339255278, + "block_time": 1746946824, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "funded": [ + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL" + ], + "birth_scan_exhausted": false + }, + "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv": { + "address": "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8": { + "address": "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN": { + "address": "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8": { + "address": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 53 + }, + "first_seen": 1781684439, + "birth_edge": { + "sink": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "sources": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "value": 38618000, + "signature": "5U5bvAmXWokcz4KHXizva51UQDG5PaZyLxQd7fECRdQ8VdX54ZjeW4bf6xBXAvqfLQWJ3394RDzjBbp3UTQX1JiK", + "slot": 427034554, + "block_time": 1781685267, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY": { + "address": "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 527 + }, + "first_seen": 1713772073, + "birth_edge": { + "sink": "DPSzVGbgvC3hK6YJvWzMenwL7vjtoWta97kG5xQMGXCY", + "sources": [ + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU" + ], + "value": 10000000, + "signature": "3HHA4jtCTpR6BeP3G4CfXDsDgX57eVVUQrQZyeosgzrbkhLsjtai66LSgF75UmzWp86gyVWbzLe9PnkJhzzDNCew", + "slot": 261568924, + "block_time": 1713772073, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6rgUKmt7Kvd6GnRQTJRJuGhQr3FydoZKJDXyPBTAXTXU" + ], + "funded": [ + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8" + ], + "birth_scan_exhausted": false + }, + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z": { + "address": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 24677 + }, + "first_seen": 1756146669, + "birth_edge": { + "sink": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "sources": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "value": 588787000, + "signature": "4yWtHAoxf24J9RJDTqre7SLD3WPGvtXKBWYhGfyxaqRdmKkfHHpWnAzCcMK1Q6PjXATUdxQ6gthBDghnjcuSSGK", + "slot": 370862324, + "block_time": 1759473301, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP": { + "address": "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5145 + }, + "first_seen": 1655204850, + "birth_edge": { + "sink": "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP", + "sources": [ + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E" + ], + "value": 100000000, + "signature": "5qCwaVyRDsEr4C3ZndJF99BkYmkRzrGycZXnShE9GujHLnD3CuCc3ETcUXSAop85SrPHBwdjmUdc51yV3GkCYfC3", + "slot": 137511084, + "block_time": 1655204887, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E" + ], + "funded": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "birth_scan_exhausted": false + }, + "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX": { + "address": "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 30 + }, + "first_seen": 1714060177, + "birth_edge": { + "sink": "DYz1UqNf2pRoEZygfhN9nUafhjUpcrZQXBqBGccvyPJX", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 987749310, + "signature": "4T9BG6pUpJCYHdubvDe8piyaNYdHW1i8L3Aa3rGokj11eZmiipZBSLJS8updgukiSsjwakJuXsznzjRfcW7hfrhe", + "slot": 262187645, + "block_time": 1714060177, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J" + ], + "birth_scan_exhausted": false + }, + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK": { + "address": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1190 + }, + "first_seen": 1747220417, + "birth_edge": { + "sink": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "sources": [ + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "value": 3141592653, + "signature": "3mXJiiZA35B1Y6UUyqkynZBkYe8sM4WsjzRBgSfjrvqYRhSRfWSx25Xdr5ct4mFR2UpbTJQg1goGscDGfRa3NdE3", + "slot": 339946664, + "block_time": 1747220417, + "ambiguous_attribution": false + }, + "fee_payers": [ + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi": { + "address": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 200 + }, + "first_seen": 1653138893, + "birth_edge": { + "sink": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "sources": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "value": 606489437, + "signature": "62pVXVgr23rpDrywbMT9my8PUPDsRf53biB4QSm9oa67zvw14JmuaqbuC5obnSjSYS1acXMQQRgUXVYpX2s1RHaF", + "slot": 134659485, + "block_time": 1653138893, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa": { + "address": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1783201670, + "birth_edge": { + "sink": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "sources": [ + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn" + ], + "value": 185933290, + "signature": "NX3DrMfLgUE4yHC8dgbQj2vHFKiCzTrPhfTDShToZdn8skzKWLJyzEEh6dbWxeMTBEkRhqWkXVRNzmZDvGKs3Yc", + "slot": 430818102, + "block_time": 1783201670, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3ddCq8LgnyYiJFfupiNAR8rQ9BshepSMzSwWbNLageTx" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq": { + "address": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1784199361, + "birth_edge": { + "sink": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "sources": [ + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw" + ], + "value": 23682958, + "signature": "2ChU8gFx2ffsnkR6HwHJsD2Pd44iTWQ37rdfWgHwbVjMYb45X88VvqNSCaZu6vh2fgC62bXvkt6C8v9YzUrjNz26", + "slot": 433259174, + "block_time": 1784199361, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9": { + "address": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20 + }, + "first_seen": 1782002060, + "birth_edge": { + "sink": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 50000000, + "signature": "RtgJqd5sHDiondx4Z2yiq5essG1zXj5XwroXbZrtjkhy9NDPjutCezrPBr122sZqphKBa9YWJF3VPxiBUerRjBq", + "slot": 427833377, + "block_time": 1782002060, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U": { + "address": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 10 + }, + "first_seen": 1781081436, + "birth_edge": { + "sink": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 92849110, + "signature": "2d8HpMfLa5r1S3vdLKNiT69B7gPFjj4U3YHRc3skWQFqF3T2LUjTQzjPtWiHzQytw3VupQMQFiajPmjNYzN5rZfe", + "slot": 425512751, + "block_time": 1781081436, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH": { + "address": "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1703354625, + "birth_edge": { + "sink": "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "sources": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "value": 1320200000, + "signature": "3cqmB1Yi2Z7ZVQjjA37NQ4d84ViimuKf1h83J23digAMRGoJMY8VmUbNkSxyqxRqsE3qBoBFKwCMXfxhVMEGNacP", + "slot": 237597989, + "block_time": 1703354625, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "funded": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "birth_scan_exhausted": false + }, + "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm": { + "address": "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 57 + }, + "first_seen": 1756226352, + "birth_edge": { + "sink": "EH2iggdS9PkEop953PN4bzz7CHDZqtDC7mv7iptfHGFm", + "sources": [ + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL" + ], + "value": 19129985905, + "signature": "hwFDdbQ5JJzyNKNESkkX193G8qp1cXkGT1GJfmz6Aca26Kh6Qo54vbWPejmst4DCTFtUW7ifDYZ1XG2UFgru68q", + "slot": 362671528, + "block_time": 1756226352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2TXA7bkgZ4NA2sj79KVcxCVjGjA7fXMiYM5dBiymeacL" + ], + "funded": [ + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7" + ], + "birth_scan_exhausted": false + }, + "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu": { + "address": "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1060 + }, + "first_seen": 1702411020, + "birth_edge": { + "sink": "EZA5v8GGTDkPohspz9sVP6gBaP2D7ji3MVLvEsowRcnu", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 3389000000, + "signature": "47LG2tdxdb2EobJxigyBr9ex7Pq9wUViz9B6jmpciWrdYTTnPM9QV7Wb6K3usRuGkdohVZDd63gu3HmVQFrXFXhL", + "slot": 235528960, + "block_time": 1702411020, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ" + ], + "birth_scan_exhausted": false + }, + "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW": { + "address": "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1780571139, + "birth_edge": { + "sink": "EgTLawBEJpUzBR8hVPZNVgr1RLQmR3EfYMTJiWqERgLW", + "sources": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS", + "ATRsNGv2nDw7hSMfkUTBoVUDsFDwN7po7KbecyiGWNB4" + ], + "value": 148788340, + "signature": "5qzt8zfBQNcj1k4sSPUrPrxcBYLMNDTg44S69HPqnkuwYNFXqhc6uJYS8ftreQQPkpNkFjk3nH8bFV5d5M7bWLXh", + "slot": 424231154, + "block_time": 1780571139, + "ambiguous_attribution": true + }, + "fee_payers": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "funded": [ + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG" + ], + "birth_scan_exhausted": false + }, + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi": { + "address": "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 924 + }, + "first_seen": 1624797610, + "birth_edge": { + "sink": "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi", + "sources": [ + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV" + ], + "value": 30170000000, + "signature": "VRM4EXex3RUYf4mnPB4E6jv9D7XmkmHdwbzeXTCTjmCqWpSfq7mKhgRibqwyzFXvu4FjpvYK5NeQrsQ6vbQ6e8A", + "slot": 84652957, + "block_time": 1624797610, + "ambiguous_attribution": false + }, + "fee_payers": [ + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV" + ], + "funded": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "birth_scan_exhausted": false + }, + "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu": { + "address": "EnxFkSMoJkEzYUkWHubEXYKw2y9HQVUEHGmXrMyQniKu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1774008783, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4rSid2157LwgYUZPKP8wzDiinhj9xzwrwD4U43bTJg5V" + ], + "birth_scan_exhausted": false + }, + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r": { + "address": "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6850 + }, + "first_seen": 1714596610, + "birth_edge": { + "sink": "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "sources": [ + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J" + ], + "value": 499994950, + "signature": "32pf2BhJSmb5gunpiH6aruXu1ErmFsqfsuSuXZCrWYfk1cQGrKa1SUC8A2QEeASEkHt14zDoAJs3vJwq1CFrMoNe", + "slot": 263331626, + "block_time": 1714596610, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3mWripBCZNSHXzFYMuJ1FCuFMjERzvNDRTi3MGUrSf1J" + ], + "funded": [ + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo" + ], + "birth_scan_exhausted": false + }, + "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc": { + "address": "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc", + "owner": null, + "executable": false, + "signatures": { + "Exact": 64 + }, + "first_seen": 1630955531, + "birth_edge": { + "sink": "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc", + "sources": [ + "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy" + ], + "value": 26665052, + "signature": "3oB8DhsZ527MLy5RizmCUof2vPHxYDUHM765JutCu76qmC7pTvsAsu7H5Jz9XNMGFoJUkTp6FZbakrqCeU7Ty32e", + "slot": 95279723, + "block_time": 1630955731, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy", + "BVeiZCPoE3CEPBJsej63LsukQwGz2LtNdzuvqXbpoT1m" + ], + "funded": [ + "AposS2QBW5NZ2i3WNbsHVxTJa5CJGfKHJSVfiX3FYQfh" + ], + "birth_scan_exhausted": false + }, + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe": { + "address": "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1785030928, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2" + ], + "birth_scan_exhausted": false + }, + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo": { + "address": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13145 + }, + "first_seen": 1719672752, + "birth_edge": { + "sink": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "sources": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r" + ], + "value": 150000000, + "signature": "5eDgfMWctbmhkp9ZUddUGf5pcyvMr1ReaEK9nXEYipstcuD58uVbr7UVEzkEv2XoVf464y62Wj9f8mfbfkrg3duL", + "slot": 274705160, + "block_time": 1719673479, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r", + "3qaRfWYQitbWQe7CHVvUR4QwQpG7xcaGmtpfeA3LKrXR" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G": { + "address": "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784659957, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6": { + "address": "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1439 + }, + "first_seen": 1739722292, + "birth_edge": { + "sink": "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6", + "sources": [ + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7" + ], + "value": 4251664084, + "signature": "2PSni2jfVeX9YUufMwGVXWanasSbzHYk7imdYtwDjjSAqERG6T7s4Hx6DWStky2bqrYgpqoqR7xy6KjTbdQ5tC9M", + "slot": 321067692, + "block_time": 1739722292, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4rhzLD41xPiwkcMVddw6jsQxXG6YmyE6cw9MLvPeu8u7" + ], + "funded": [ + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65" + ], + "birth_scan_exhausted": false + }, + "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq": { + "address": "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1774722184, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf": { + "address": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11491 + }, + "first_seen": 1770490600, + "birth_edge": { + "sink": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "sources": [ + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8" + ], + "value": 11251120, + "signature": "5QwjQCxGUJfMWx2A5LAZoMeXvTKoT2yUU4GgXmo38bpidM3MWsqEouL2qi5Hbnh6ahYraSuUt3dNTAEW6dY9s47C", + "slot": 398740672, + "block_time": 1770498005, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "Ak9XCgo8ks8K1KftUxREdKnD7DHRcqE8ABxY3mB8y4D8" + ], + "funded": [ + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1" + ], + "birth_scan_exhausted": false + }, + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA": { + "address": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 120 + }, + "first_seen": 1769087495, + "birth_edge": { + "sink": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "sources": [ + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "value": 430752000, + "signature": "2AFuX4tvKhsFguYnNfiW4QCHsYFeoARyYNbm9hMxqKHpgaX2f6d8qHfioWQsnyDCy5wFHzeUAXoSURUyGDGgmxzj", + "slot": 395193315, + "block_time": 1769087495, + "ambiguous_attribution": false + }, + "fee_payers": [ + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD": { + "address": "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1211 + }, + "first_seen": 1731582585, + "birth_edge": { + "sink": "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 146500000, + "signature": "3rHVM8ZmNB7DinaukQx8mKva26Y4YUNNXmxtPwwjZEW5Gpy72tqpWjfRBCW6jZR64WDC5QxLEFiMkAPKNK65MKTY", + "slot": 301468444, + "block_time": 1731640101, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij" + ], + "birth_scan_exhausted": false + }, + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p": { + "address": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 282 + }, + "first_seen": 1707956423, + "birth_edge": { + "sink": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 92000000, + "signature": "2Zo3SqZ1zdcF99BygckTotHufbXupGv4FLFyEdVxbSwKedaeJRsp2gb8Uwjgjf8PkwQgsibXyJvpBZwFErrJ6FDc", + "slot": 248216739, + "block_time": 1707956423, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ": { + "address": "Fuz4rVwvFGZFvzU2cTLkXB9tSh4MVBGW59HxY4fdkHNZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1760949235, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "birth_scan_exhausted": false + }, + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu": { + "address": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1783033845, + "birth_edge": { + "sink": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 1171377350, + "signature": "5T6rTfTX8JKsNiXf9PCnAEL4w7HLzJfsVBeQwsTRcsuK9TyxUV9ym5MPTpVBepapLkDMQeTPdAEigW14azAfdiT8", + "slot": 430402156, + "block_time": 1783033845, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2": { + "address": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2014 + }, + "first_seen": 1728020846, + "birth_edge": { + "sink": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 203950000, + "signature": "5U8Sgir6egiAF84ZZW13rDa1ek69yJpBcTmv227D88J6Gbm69bF6Dq7WKoLSdYEeaeXGPSCmN76jDFXzZEkeQh2Z", + "slot": 293595031, + "block_time": 1728020846, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE": { + "address": "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784818542, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA" + ], + "birth_scan_exhausted": false + }, + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1": { + "address": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7196 + }, + "first_seen": 1728755528, + "birth_edge": { + "sink": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 839200000, + "signature": "2DdKCofnd53ZCijpwVNM4xRHmTXYT8YqeRh99etQB4J3YmX48b1sNn6vq2RGrqtmsgbKq4jH1jHc9DnoSctSurUw", + "slot": 295234119, + "block_time": 1728755528, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG": { + "address": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4316 + }, + "first_seen": 1743001899, + "birth_edge": { + "sink": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "sources": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "value": 200000000, + "signature": "3Rg9fS58hDfbMcnKWU6jeJXUva4g1jetwoNwvp7YiiH1GXDadsF7ZqxutWpxq6VXuHdRWpq61TFtQMs6KRhrkmqr", + "slot": 329323260, + "block_time": 1743001899, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "funded": [ + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7" + ], + "birth_scan_exhausted": false + }, + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9": { + "address": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1773 + }, + "first_seen": 1699496374, + "birth_edge": { + "sink": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 3442545653, + "signature": "Pvpzz5cpDfRekWPtKKux8YPWQuzJhsEonx1YpQLx9HkBiWkknk4Cwj6dyvof1ha8fnmrEkZqGAefpquu6G6HUDD", + "slot": 228889688, + "block_time": 1699496374, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2": { + "address": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 163 + }, + "first_seen": 1770880341, + "birth_edge": { + "sink": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1178878050, + "signature": "3Yn2VJBxAgpBmQ8XD5EXEPEdPfyYuvrRfiJEFCMn4JS3CwYURPu7QTwjsz9Masn96rwjNriemwBLyzFe8ZVzLwbq", + "slot": 399714845, + "block_time": 1770880341, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE": { + "address": "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784508412, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "birth_scan_exhausted": false + }, + "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA": { + "address": "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1778466268, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq": { + "address": "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1705 + }, + "first_seen": 1777229947, + "birth_edge": { + "sink": "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "sources": [ + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16" + ], + "value": 3615443530, + "signature": "ev9FqbVk8jCJiy27MypNycKFYYeRJJJCpH6WiNPM5buomXGKnTHqz9YL5heguK76dncGDd8KnEMvKruGMzQFDRc", + "slot": 415842709, + "block_time": 1777229947, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9WL2A89YBr6X47ABKYNzPentWiBA3H8tpaiuf5CaYHx6" + ], + "funded": [ + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV" + ], + "birth_scan_exhausted": false + }, + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs": { + "address": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 302 + }, + "first_seen": 1774289101, + "birth_edge": { + "sink": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "sources": [ + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "value": 1406603230, + "signature": "58WsdGGRCSKky5UXVe4QCaZpALbxjqfksCdHYZUj6HtNo5GmE3SwBi7tfun9dovyXN7CHVXt56c7wc28deCM4NKb", + "slot": 408377546, + "block_time": 1774289101, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL": { + "address": "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 363 + }, + "first_seen": 1763311616, + "birth_edge": { + "sink": "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL", + "sources": [ + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS" + ], + "value": 128226803, + "signature": "5eRiYettfDeQJtbPPvuTnLYDt5fpqjhqxut1xMhVUk3za3oCNTFqNvBAtDwNCWxsWrPrKRQXj5xeECz2VjpFq6zd", + "slot": 380496679, + "block_time": 1763311783, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AF6B9C43LrVEZLSNdoVXuWeXZBM3voyQgykCxRRoUxqG", + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS" + ], + "funded": [ + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj" + ], + "birth_scan_exhausted": false + }, + "GbG7Kekbzjypekv9vEEdyERXp3XvpvAqhtFfvEUwrAb7": { + "address": "GbG7Kekbzjypekv9vEEdyERXp3XvpvAqhtFfvEUwrAb7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1626721614, + "birth_edge": { + "sink": "GbG7Kekbzjypekv9vEEdyERXp3XvpvAqhtFfvEUwrAb7", + "sources": [ + "Bv4V3C1A2XmzpPdFbqdSmP9q5Rqy9bAHDeBPBXwbG7iz" + ], + "value": 97561, + "signature": "DowUfWFauC8sgYihAc3sk2chPEUyaCiDBRWZnbgex8xTiqbmoyMeJmD5v1umefRT2UQZ2mDRPPXEKUybbjaHPCU", + "slot": 87738989, + "block_time": 1626721614, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Bv4V3C1A2XmzpPdFbqdSmP9q5Rqy9bAHDeBPBXwbG7iz" + ], + "funded": [ + "BfqUSbXDfxKz99QdzfiiYeuUh5BzqvCVtTppV7DHy4cr" + ], + "birth_scan_exhausted": false + }, + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq": { + "address": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1758453103, + "birth_edge": { + "sink": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "sources": [ + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi" + ], + "value": 1111260006, + "signature": "2wqEciaCd8SdPS1BaEWBxZfVTrHk3sMS7PZB8LobFDQA7e49g7awaW44rGj2gRiWbCoU4rW4SWbn7qCpQtPXaetx", + "slot": 368284051, + "block_time": 1758453103, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i": { + "address": "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1745978694, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb": { + "address": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 253 + }, + "first_seen": 1776516090, + "birth_edge": { + "sink": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "sources": [ + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "value": 268000000, + "signature": "3KB7X9tCYoBd3HrsMzGTYQ1avb3ceSiXpHuQv6qQ9LPLKVnxVoUaXdBeKF5qLp71mMTNmHXsNcKe3Hbd4JYs29C8", + "slot": 414039567, + "block_time": 1776516090, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z": { + "address": "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1230 + }, + "first_seen": 1769712791, + "birth_edge": { + "sink": "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "sources": [ + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "value": 159000000, + "signature": "37ERW5HvvBbZ7xPSZK8kHSjpshWttD8PGTqwnw4hrmou8DyqToYBSU1oV1YqHfEdVbqBkkLULdg7VUmuZBsNkVZG", + "slot": 396754483, + "block_time": 1769712791, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "funded": [ + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG" + ], + "birth_scan_exhausted": false + }, + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf": { + "address": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 180 + }, + "first_seen": 1745992468, + "birth_edge": { + "sink": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "sources": [ + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH" + ], + "value": 2000000000, + "signature": "5ZbHXjZUDRS32uKijFGaJzvbiKBMYLHWcuES7gteaUuErcDjefnt9jsanTDhirv5Rs6JdCv9JbvLrNPPY29kLvEv", + "slot": 336839074, + "block_time": 1745993216, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "493qjjgknUqwZevRrgc6FygdfiQ47dg49uAJR41aUvgH" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX": { + "address": "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 166 + }, + "first_seen": 1604753907, + "birth_edge": { + "sink": "Gsun7cGFrSUm3N8TEBq7Uu9xz4c9cE4pKdbtETQiSgZX", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 4990000000, + "signature": "5fNviBm3ujhH54CxhFVkMHGhBh3ycHu52naQLLfeipzWZXT5HXfNUswH9ovncyDCLMGWuFTkc8ZfSGwZRZKuFm67", + "slot": 47336493, + "block_time": 1604753907, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "9U3iaCz3Zk9YRdKux1GL78tdc4vEAo4MmFWWs6ZciA1E" + ], + "birth_scan_exhausted": false + }, + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv": { + "address": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 49 + }, + "first_seen": 1778543921, + "birth_edge": { + "sink": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1999000000, + "signature": "2577uZmHHHp14Cdos1o2FWPAe3yv8JQWbbDZ2MXz7UPeYsivzQKF7BxbnhK3x4ACnD4J4HUSi9URYrAfqLY5Et7T", + "slot": 422526013, + "block_time": 1779894352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx": { + "address": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 639 + }, + "first_seen": 1681873953, + "birth_edge": { + "sink": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "sources": [ + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK", + "2AdZQmGikAMWahuJRb27PGABQyF6iyQ8aUUYyDDwRRG6" + ], + "value": 1390880, + "signature": "4UjTtnFx1zxwZ3HfMqZJipdoHQ5Gcjujq9gJgoYaraMkeuRfhb3DhbJnFA7aRpYipMV3rWuBNdJG51K4m1gXs5Qj", + "slot": 189363909, + "block_time": 1681936762, + "ambiguous_attribution": true + }, + "fee_payers": [ + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw": { + "address": "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq" + ], + "birth_scan_exhausted": false + }, + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R": { + "address": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9 + }, + "first_seen": 1784990514, + "birth_edge": { + "sink": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 10091911, + "signature": "8noYJ5aCs9N6rbVBKCGMwVfVeCg1GQHGXhaNHP2rVcBZSMgbgiUpoNtpQ8XkASe78iZs3JqGk3c178jbeFgdrzc", + "slot": 435145890, + "block_time": 1784990514, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS": { + "address": "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784496736, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "6XuEpNrmbv4SsLVgXcQtkvr8NFKg5kS4nrhjX5eM5vYS", + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "birth_scan_exhausted": false + }, + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi": { + "address": "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq" + ], + "birth_scan_exhausted": false + }, + "HFWv1riXSRJ3nVnnLZ9xi1K4r3zppRvcfVuiAGqAA8Y6": { + "address": "HFWv1riXSRJ3nVnnLZ9xi1K4r3zppRvcfVuiAGqAA8Y6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1771006540, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb" + ], + "birth_scan_exhausted": false + }, + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K": { + "address": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 483 + }, + "first_seen": 1756671400, + "birth_edge": { + "sink": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "sources": [ + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL" + ], + "value": 100000000, + "signature": "5K8mBvSCxvxNt81ymbqjhH5Umde57URqC9pVdVzczT8JpRrPrKoEo5t8xEqBLWW2N74Fi5vNNKiCVKbBZZvLu8Gq", + "slot": 372063796, + "block_time": 1759948805, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4", + "Hc2vsrdknaVuSypGNyMDuzR3FN3yWVcSuFALT6j2Cq71", + "BeVVXuvvGNmFBeK1bazfc2CYdvvJ5AFi4aNv75Ah7vo8", + "4Cq8mMU23qSW47xk9n7jfzooXJFvEUgdaFBnPBfFbVZL" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu": { + "address": "HK2mrz7pr8x9e4J7Bh1rsd6YidBWNk72fR3LUGpdy3hu", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T" + ], + "birth_scan_exhausted": false + }, + "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1": { + "address": "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 653 + }, + "first_seen": 1773754017, + "birth_edge": { + "sink": "HLSTtn8qsn9MkJZhPzCnxTtgE6HN6HcjiSeCQwydTSu1", + "sources": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "value": 128164040, + "signature": "2PwhcVHygfgnrC6dUDdkyZG6XQq8QzBS5PY4ar7MKwUmnCWtXhhVYACkh8goKM7MozqdANUYs4MhnSVagFBJt7kn", + "slot": 407022368, + "block_time": 1773754017, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "funded": [ + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv" + ], + "birth_scan_exhausted": false + }, + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw": { + "address": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1783107306, + "birth_edge": { + "sink": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 9000000, + "signature": "4B1byRx7pvEAt5NfXDUwEqo2TyMbm1qFV1Qakd6tnjmjfUHQ6ThQJFpcN129xXoS29GPPtvScVyHGBkCV6kd9s2m", + "slot": 430584264, + "block_time": 1783107306, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh": { + "address": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 322 + }, + "first_seen": 1761374606, + "birth_edge": { + "sink": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "sources": [ + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "value": 25732740, + "signature": "3AhoNZZLvSQ5gNfWsTeRkjLi8W9t1P63EPXD3YKxErjnAP37U44njwCmpBaygX1xi5fgUNHHSZaeMiEJq9F2jrHi", + "slot": 375651141, + "block_time": 1761374606, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy": { + "address": "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy", + "owner": null, + "executable": false, + "signatures": { + "Exact": 45 + }, + "first_seen": 1628144077, + "birth_edge": { + "sink": "HUGi35NLzi1Kch86pkdDJLpkX6dccj5vDjAKwP5SCTy", + "sources": [ + "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88" + ], + "value": 24315650, + "signature": "3erwrev4k27SHrAaug5ixMEMbB4bt1dRMmET5Z8YRa8eN8qpsiKdZjJ358UJxD2L56tmsvrCoHNaWUYYzKjtnn6N", + "slot": 92971861, + "block_time": 1629719306, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BVeiZCPoE3CEPBJsej63LsukQwGz2LtNdzuvqXbpoT1m", + "7tyVqmZ42VWKz9NcktM4drZQrypcnk73F33Brjnmtc88" + ], + "funded": [ + "F3Jh7vot1xC4gmr4AjcJBKouHEej13KMyySUFk2CFmUc" + ], + "birth_scan_exhausted": false + }, + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16": { + "address": "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1781299438, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "birth_scan_exhausted": false + }, + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V": { + "address": "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1582 + }, + "first_seen": 1700759478, + "birth_edge": { + "sink": "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 951634000, + "signature": "5vBY9n8k1qYPBcapzouiPJ9whnVFx18Y9Y574PJfDDwMNKt59QoCsGbRgke24y6T3zTyjNNRqEzCnJUAwfWGNeE7", + "slot": 231795042, + "block_time": 1700759478, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "birth_scan_exhausted": false + }, + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n": { + "address": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 135 + }, + "first_seen": 1780765625, + "birth_edge": { + "sink": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "sources": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "value": 271700000000, + "signature": "5R2ekhoYBR8fWYnM27srHHH24YNpF79Bu2uws2dh3otMMSt7Kku9tgV5NUx2yFN53YjfhZ8iDv6zNzFJpuoZgyg2", + "slot": 424718918, + "block_time": 1780765625, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6": { + "address": "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 337 + }, + "first_seen": 1719988520, + "birth_edge": { + "sink": "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6", + "sources": [ + "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ" + ], + "value": 669445618, + "signature": "2xwdfPkgWLvHhKL2f1su7F6qyRR7LgaNsYiakS8wpTpeoMc89PLbARf8HR29phRhtdRyRbkj6iWbfbB6KVa68pZX", + "slot": 275394508, + "block_time": 1719988520, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7FfB2zQRYUQwpPzkRxAeg2mCBGeCRKp4PCEeULJA9xTo" + ], + "funded": [ + "9FcCfYD4nriwojppNTPRjYyvw647bMH2tbYwjuGN1Zdh" + ], + "birth_scan_exhausted": false + }, + "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ": { + "address": "RBNV3esFPQ4jAkzW9hzxtZj34vJ9Snzrm6arXLs1mYZ", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "PK6ZHjXu2r4FwcPBtCFJCKs6gbea1U2JNvBpNXpVLq6" + ], + "birth_scan_exhausted": false + }, + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN": { + "address": "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 104 + }, + "first_seen": 1757553631, + "birth_edge": { + "sink": "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN", + "sources": [ + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu" + ], + "value": 823856392, + "signature": "43aFuJ62SGgRmkXfrQfgydDDuYgrbTzLoNbZ4LD3afHdZyjd9SnUv9o64bxryezdAGxHpBVUt3Eyj8eSeYKtiCiS", + "slot": 366017478, + "block_time": 1757556380, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6PZZAFrg1tnfGg5VhFdqqE6qDtbP7ChyYAsQ2iMax1Cu" + ], + "funded": [ + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC" + ], + "birth_scan_exhausted": false + }, + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu": { + "address": "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784395426, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt" + ], + "birth_scan_exhausted": false + }, + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV": { + "address": "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1784374285, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "birth_scan_exhausted": false + }, + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4": { + "address": "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1772684886, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm" + ], + "birth_scan_exhausted": false + }, + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK": { + "address": "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1712393128, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx" + ], + "birth_scan_exhausted": false + }, + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ": { + "address": "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 21 + }, + "first_seen": 1709918366, + "birth_edge": { + "sink": "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 1696237745, + "signature": "qdFZbtFQnSrYx5CCo78yqoFY1ZYvhKgUL5gPeKiiG1LJ2TG2jC4yKtUdwidZiH5tZZ2bt4HEqU4pfjBbMeDYJNc", + "slot": 252918864, + "block_time": 1709918366, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf" + ], + "birth_scan_exhausted": false + }, + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28": { + "address": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 98 + }, + "first_seen": 1780986875, + "birth_edge": { + "sink": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "sources": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "value": 30000000, + "signature": "5RkppwfwvNhhTswurZaM4gwPQiDaie82UhBdHt8mHJSES3ci8cmDuHHRLYXoFuWD7KdurykQXq7dUBfaBw8HAiqW", + "slot": 425274321, + "block_time": 1780986875, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm": { + "address": "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1740542110, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK" + ], + "birth_scan_exhausted": false + }, + "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV": { + "address": "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1619359279, + "birth_edge": { + "sink": "sCi7J7vm9ZVZjP6hpALTjwfu8q8r8WAyDRH1tigdSqV", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 31483630200, + "signature": "f6cQSbVaFKTPqNogr3WADjYPSr8ZgwcvYK5uaJiAP9A63W7WZgCjcDoGHxZWK8fdAVBqJzsjF43XYsuCG42fsNX", + "slot": 75325833, + "block_time": 1619359279, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "Eh4xhABcg3985rP8Pyv6yTv6vogugh4Hv2cQJRbaDiMi" + ], + "birth_scan_exhausted": false + }, + "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w": { + "address": "u6PJ8DtQuPFnfmwHbGFULQ4u4EgjDiyYKjVEsynXq2w", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 48000 + }, + "first_seen": 1783682136, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8DtiG89DwrvkwctcC2U3vGwjhEkngfi1jHh2pHNUGxMq" + ], + "birth_scan_exhausted": false + }, + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ": { + "address": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 34 + }, + "first_seen": 1784808222, + "birth_edge": { + "sink": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "sources": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv" + ], + "value": 100000000, + "signature": "3XFtWHvCubsszFNB4U9XX592rAbYqdKaUjy7KPTjxKmcAUziERiSHsPLvbSozHGgAgiZjZmdStGTB99ASeYB8GPU", + "slot": 434711620, + "block_time": 1784808222, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv" + ], + "funded": [], + "birth_scan_exhausted": false + } + } +} \ No newline at end of file diff --git a/data/sample-marinade.json b/data/sample-marinade.json new file mode 100644 index 00000000..23d62651 --- /dev/null +++ b/data/sample-marinade.json @@ -0,0 +1,3539 @@ +{ + "manifest": { + "endpoint": "https://mainnet.helius-rpc.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1785041387, + "config": { + "scope": "Sol", + "depth_max": 16, + "min_edge_lamports": 500000, + "sig_page_cap": 24, + "page_size": 1000 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 1357, + "excluded_non_wallet": [ + "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip", + "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8", + "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv", + "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK", + "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN", + "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi", + "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg", + "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd" + ], + "ambiguous_attribution_rate": 0.0 + }, + "chains": [ + { + "seed": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "visited": [ + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "visited": [ + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "visited": [ + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "visited": [ + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "visited": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "visited": [ + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "stop": "PageCapHit" + }, + { + "seed": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "visited": [ + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "visited": [ + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "visited": [ + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "stop": "PageCapHit" + }, + { + "seed": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "visited": [ + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "stop": "PageCapHit" + }, + { + "seed": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "visited": [ + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi" + ], + "stop": "LocalTerminal" + }, + { + "seed": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "visited": [ + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "visited": [ + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "visited": [ + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw" + ], + "stop": "LocalTerminal" + }, + { + "seed": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "visited": [ + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ", + "visited": [ + "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ" + ], + "stop": "PageCapHit" + }, + { + "seed": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "visited": [ + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "visited": [ + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "stop": "PageCapHit" + }, + { + "seed": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "visited": [ + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "stop": "PageCapHit" + }, + { + "seed": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "visited": [ + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "stop": "PageCapHit" + }, + { + "seed": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "visited": [ + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "visited": [ + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i", + "visited": [ + "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i" + ], + "stop": "PageCapHit" + }, + { + "seed": "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq", + "visited": [ + "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq" + ], + "stop": "PageCapHit" + }, + { + "seed": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "visited": [ + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "visited": [ + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "visited": [ + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "visited": [ + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "visited": [ + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "visited": [ + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "visited": [ + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "visited": [ + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "stop": "PageCapHit" + }, + { + "seed": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "visited": [ + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "visited": [ + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "stop": "PageCapHit" + }, + { + "seed": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "visited": [ + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn" + ], + "stop": "PageCapHit" + }, + { + "seed": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "visited": [ + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "visited": [ + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "visited": [ + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "visited": [ + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "stop": "PageCapHit" + }, + { + "seed": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "visited": [ + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "stop": "PageCapHit" + }, + { + "seed": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "visited": [ + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "stop": "PageCapHit" + }, + { + "seed": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "visited": [ + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "visited": [ + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "visited": [ + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "visited": [ + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "visited": [ + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "visited": [ + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA", + "visited": [ + "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA" + ], + "stop": "PageCapHit" + }, + { + "seed": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "visited": [ + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z" + ], + "stop": "PageCapHit" + }, + { + "seed": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "visited": [ + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G", + "visited": [ + "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G" + ], + "stop": "PageCapHit" + }, + { + "seed": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "visited": [ + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "visited": [ + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "stop": "PageCapHit" + }, + { + "seed": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "visited": [ + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "stop": "PageCapHit" + }, + { + "seed": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "visited": [ + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "stop": "PageCapHit" + }, + { + "seed": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "visited": [ + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "visited": [ + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "visited": [ + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "visited": [ + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "visited": [ + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "visited": [ + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "visited": [ + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "visited": [ + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "visited": [ + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "visited": [ + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "visited": [ + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "visited": [ + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "visited": [ + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "visited": [ + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16" + ], + "stop": "PageCapHit" + }, + { + "seed": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "visited": [ + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "visited": [ + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "visited": [ + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "visited": [ + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "stop": "PageCapHit" + }, + { + "seed": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "visited": [ + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "visited": [ + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "visited": [ + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "visited": [ + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "stop": "PageCapHit" + }, + { + "seed": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "visited": [ + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb" + ], + "stop": "PageCapHit" + }, + { + "seed": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "visited": [ + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "stop": "PageCapHit" + }, + { + "seed": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "visited": [ + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "visited": [ + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "stop": "PageCapHit" + }, + { + "seed": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "visited": [ + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "stop": "PageCapHit" + }, + { + "seed": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "visited": [ + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "visited": [ + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "visited": [ + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "visited": [ + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "visited": [ + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "visited": [ + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ" + ], + "stop": "PageCapHit" + }, + { + "seed": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "visited": [ + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "visited": [ + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM", + "visited": [ + "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "visited": [ + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K" + ], + "stop": "NoIncomingEdge" + } + ], + "facts": { + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm": { + "address": "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784759973, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi" + ] + }, + "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4": { + "address": "2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6457 + }, + "first_seen": 1756313602, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL": { + "address": "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783798536, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck" + ] + }, + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh": { + "address": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 80 + }, + "first_seen": 1752673276, + "birth_edge": { + "sink": "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh", + "sources": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "value": 12063418500, + "signature": "cKPChkvMEjtfwWt9C9UT6huX3cCp543m4ywRXBuBsuYWNKrDuvTCaJqSFFUym2mvuXMG1xCqWhQqvgUDjinFVJb", + "slot": 353692459, + "block_time": 1752673276, + "ambiguous_attribution": false + }, + "fee_payers": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "funded": [] + }, + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK": { + "address": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7945 + }, + "first_seen": 1774268614, + "birth_edge": { + "sink": "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK", + "sources": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "value": 5000000000, + "signature": "3D9VPk2WSdFidXqT2yc7QmN4so5tcRG8oq1RMMVN4Y81op9PcSrNPPhukqLvU2fmRPAncjyFp7csZxbee2uBg8qw", + "slot": 408325661, + "block_time": 1774268614, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ" + ], + "funded": [] + }, + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o": { + "address": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 72 + }, + "first_seen": 1767875809, + "birth_edge": { + "sink": "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o", + "sources": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "value": 50000000, + "signature": "jAurnGX1dLaqmmcS95zSb1N2XZHj65BdUNAtchot1MWmx3z6We5f8Jew1sGu9NrQFrWGR8QdkMCSWSUAfu1yahT", + "slot": 392132125, + "block_time": 1767875809, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW" + ], + "funded": [] + }, + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7": { + "address": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 33 + }, + "first_seen": 1778858822, + "birth_edge": { + "sink": "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7", + "sources": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "value": 10000000, + "signature": "41PgkwaTASYRwAhAmSQ6VMERq4xCjh5YNSsjmzdbU5VukKn6iMn1nzoyswB2wsJJVehVwKLspNmg4RpCKLptEtxL", + "slot": 419929899, + "block_time": 1778858822, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ], + "funded": [] + }, + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764": { + "address": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 74 + }, + "first_seen": 1768845271, + "birth_edge": { + "sink": "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764", + "sources": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb" + ], + "value": 4000000000, + "signature": "buG8ygWB6h5RLJmX5caSxTXK786wYRXgwfS9RFABnCivqy6yNePkzmn3Hsyr3XVhs28D1qWgbXbThbyZUzymN6p", + "slot": 394584868, + "block_time": 1768845271, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb" + ], + "funded": [] + }, + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv": { + "address": "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 351 + }, + "first_seen": 1715877601, + "birth_edge": { + "sink": "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 400000000, + "signature": "3vMHgLqfkYX6fLwgJKkv34rnViBSYsD2mwRJx5b2gBnMHjHemR7aMm4e12V7pwYUfDNDTNSctZ132e3GAixT72F8", + "slot": 266156059, + "block_time": 1715877601, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ" + ] + }, + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S": { + "address": "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1655911154, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z" + ] + }, + "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2": { + "address": "2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 34 + }, + "first_seen": 1760264183, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4": { + "address": "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1710631332, + "birth_edge": { + "sink": "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4", + "sources": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ], + "value": 394037978, + "signature": "3tJT334qtxVLAYkbJ8nGePCKiT4k9nP2DtwPgjwLiQuMbCMcMv6awuiXC19xq9zR9DUM3TAenySiEdiyp2uMygwB", + "slot": 254612541, + "block_time": 1710631332, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ], + "funded": [ + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg" + ] + }, + "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM": { + "address": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 270 + }, + "first_seen": 1649945488, + "birth_edge": { + "sink": "3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 11854550000, + "signature": "5LojLQtWF5mFYcGE1MiSjmeixsnYuPneTWNigfaeMGJ1Yysw88ct5X7eaJdhRTy482fAXSM97EpWV6YhYBeBHQ7n", + "slot": 129710493, + "block_time": 1649945488, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [] + }, + "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi": { + "address": "3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr": { + "address": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1785 + }, + "first_seen": 1739523472, + "birth_edge": { + "sink": "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr", + "sources": [ + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "value": 1987201900, + "signature": "bzNe8Zg7oE1fXGipW89PL11Q3LbWTdjkKzFGFfSHFnM1LZr93MSbyf5JhPNZ7khZ6twbx9RF41WCFySKZEj14NX", + "slot": 320565860, + "block_time": 1739523472, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD" + ], + "funded": [] + }, + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw": { + "address": "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1779165822, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr" + ] + }, + "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9": { + "address": "3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 254 + }, + "first_seen": 1723048172, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF": { + "address": "3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2386 + }, + "first_seen": 1770200497, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR": { + "address": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 25 + }, + "first_seen": 1782895333, + "birth_edge": { + "sink": "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR", + "sources": [ + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "value": 734553600, + "signature": "36vjnxndxfYcSHBf37rrdBPqcwc2BBpECPGQzSr6RNhbizneiaCKc4xXpiMNNGtk6eqnexRme4xfy3GDLfkPNyRk", + "slot": 430058672, + "block_time": 1782895333, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ" + ], + "funded": [] + }, + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL": { + "address": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18 + }, + "first_seen": 1758306486, + "birth_edge": { + "sink": "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL", + "sources": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "value": 2100000000, + "signature": "57LKR9sEPC21YHt2pbje7Ur5ACGLqqMUSF5wHYdquAVozDKs3K516nGr5sa47qJdKZiVvQnxTms11orYiYb7uvCP", + "slot": 367913728, + "block_time": 1758306486, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep" + ], + "funded": [] + }, + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw": { + "address": "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784775886, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4" + ] + }, + "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7": { + "address": "4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5237 + }, + "first_seen": 1757495135, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3": { + "address": "4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 119 + }, + "first_seen": 1756133000, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh": { + "address": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20761 + }, + "first_seen": 1663879176, + "birth_edge": { + "sink": "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 490000000, + "signature": "5kDrBVEWkieCWXHps4mJ9h437RmD7D9Nmyo2uo2UwQsDNUWm6KiAB8T3DNQ8svrsbx11hqdXKcUBNQAY1gACJNwT", + "slot": 151875320, + "block_time": 1663879176, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh": { + "address": "4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20 + }, + "first_seen": 1783099754, + "birth_edge": null, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [] + }, + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB": { + "address": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 52 + }, + "first_seen": 1770266528, + "birth_edge": { + "sink": "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1204809220, + "signature": "373hVK6YWozQ1rjpFwQ9EYjzYKW7AJ3YEpfyAPGiDtdeMmRphi1bKSpnPn2vu8t8t7J7fKAug14jQu6LdRNUR4Jo", + "slot": 398150397, + "block_time": 1770266528, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ": { + "address": "5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1778800198, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1": { + "address": "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784580231, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb" + ] + }, + "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC": { + "address": "5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 824 + }, + "first_seen": 1757568229, + "birth_edge": null, + "fee_payers": [ + "ffHGfMu2CpRtowXyZU6uGsj21gr8PZBpLpQBP6JF3yN" + ], + "funded": [] + }, + "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD": { + "address": "5VCwKtCXgCJ6kit5FybXjvriW3xELsFDhYrPSqtJNmcD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1742045493, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr" + ] + }, + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt": { + "address": "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "owner": null, + "executable": false, + "signatures": { + "Exact": 124 + }, + "first_seen": 1773144352, + "birth_edge": { + "sink": "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 99000000, + "signature": "NbnA7s6aJWNM2nfCACoXNDeVGZwALbRcFCkM33u7mQyMKJ3QpSHhA1pVPVX3EugPo74gm1ycaL1CBJ4UqcN3dXi", + "slot": 405469329, + "block_time": 1773144352, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3" + ] + }, + "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z": { + "address": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 96 + }, + "first_seen": 1628597237, + "birth_edge": { + "sink": "5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 4990000000, + "signature": "2kUPLWWUJut6M2AfRAZAiGLkuWLJN5D4JXMZ1VKr7cj7uWWmmcY43cGMHS7UMF8Uw32rrFUdCMNh6AMyJKR7woy9", + "slot": 91034738, + "block_time": 1628597237, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [] + }, + "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ": { + "address": "5njZuDSS2WTFkvWWsgv8Q4TfQBuCASKJAztc5yF2qLWZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1782843699, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR" + ] + }, + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9": { + "address": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784934009, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv", + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh", + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB", + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt", + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2" + ] + }, + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39": { + "address": "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1710624873, + "birth_edge": { + "sink": "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 394042978, + "signature": "5reS92mjj8Avu1Hm8NibK41HwVLTaetYhYEb1eGpT3AYkssVwhBEq479YqaVAw7G4tPhrnwvjUai3ruhQLpUW72T", + "slot": 254597447, + "block_time": 1710624873, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ] + }, + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL": { + "address": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 66 + }, + "first_seen": 1730986163, + "birth_edge": { + "sink": "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL", + "sources": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "value": 240234545, + "signature": "4JGR17CZKiUrUKXVpnbhu4LzPvRc1vMRChQVcqLpjuWaPswEvUS3b8Cjf5tyNyuptuA5GGBrTt2cCgdv1QsYuwiQ", + "slot": 300009349, + "block_time": 1730986163, + "ambiguous_attribution": false + }, + "fee_payers": [ + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg" + ], + "funded": [] + }, + "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv": { + "address": "6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7163 + }, + "first_seen": 1776453682, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9": { + "address": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1771265328, + "birth_edge": { + "sink": "6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1465532000, + "signature": "48jcsENEjMVCHrSfUqXLDZDt8nqQfHqDR1Fhx4VH3wGT5Epbks18Mfcs5WJ3yhzdnuWVupAUKPu6jgFTArDxM7iT", + "slot": 400700540, + "block_time": 1771265328, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV": { + "address": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 22 + }, + "first_seen": 1781373138, + "birth_edge": { + "sink": "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV", + "sources": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "value": 19650094, + "signature": "5JwERz8A9ssUFHSgXzszdjoKkSs8WVRrjdmKqSRXeD7GcBCyDXqzgMjHQdtqUF9MgCA9R7cK4V7Vm9thS5ib7Fkg", + "slot": 426247804, + "block_time": 1781373138, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ], + "funded": [] + }, + "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG": { + "address": "6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1780571139, + "birth_edge": null, + "fee_payers": [ + "3oUEaNt7uL7pjZ6gdiAiEVRp9ZCcGRec7B5aSvXcjbWS" + ], + "funded": [] + }, + "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip": { + "address": "71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm": { + "address": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1784211013, + "birth_edge": { + "sink": "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm", + "sources": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "value": 3895835199, + "signature": "4pntPEhmoeiCTqii4XrvYMiAG2VVja2htxSyFFuda7S8MZfTLjQCkV9XmNyCSqekAzURhwHxAxSEMMApwkM6Zayj", + "slot": 433287475, + "block_time": 1784211013, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ], + "funded": [] + }, + "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T": { + "address": "759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 26 + }, + "first_seen": 1783100066, + "birth_edge": null, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [] + }, + "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ": { + "address": "79eU8KVV53emiMcvMhrBEDSLQkrzk2fjgvFGALjaU1AJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2483 + }, + "first_seen": 1642454259, + "birth_edge": null, + "fee_payers": [ + "3ZZXVgV8vVtkmFD2x31EfwEG3kBBFnFDzeza4RHoR5kZ" + ], + "funded": [ + "2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK" + ] + }, + "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No": { + "address": "7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4949 + }, + "first_seen": 1756672617, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW": { + "address": "7LXCcQvWfNstriHZzUcJKxSTmUtQWH2KJjbP84ofNBeW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1769937907, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o" + ] + }, + "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg": { + "address": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18410 + }, + "first_seen": 1710632250, + "birth_edge": { + "sink": "7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg", + "sources": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "value": 394012978, + "signature": "3bvxtDsw7CBv3imPLoMrdyhA8cjSRRP3XCwzuJfyzx5AWZ9B8MjPdU3Gju47KgKxqGcd3gLP1ZhLVnHdhaZwQqYE", + "slot": 254614672, + "block_time": 1710632250, + "ambiguous_attribution": false + }, + "fee_payers": [ + "33mh56kAULKie24w43B7pd1jDaXsbebFr296SBhniaq4" + ], + "funded": [] + }, + "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd": { + "address": "7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt": { + "address": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1777777000, + "birth_edge": { + "sink": "7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 9000000, + "signature": "48JSB2pqTRMXWg2S6ajewFiuyXADPk9q8QJYD1NLxSYwoBZzSFWKcPEKzQwN2K4dHJ6QYS8ppfo8Acra1LDZkffb", + "slot": 417226530, + "block_time": 1777777000, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg": { + "address": "83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4": { + "address": "86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 650 + }, + "first_seen": 1764161875, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65": { + "address": "8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1243 + }, + "first_seen": 1760985667, + "birth_edge": null, + "fee_payers": [ + "FKfUBiFJRFquLrwqR4x7dsZdiTVsGoJMvG7v93ajALz6" + ], + "funded": [] + }, + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z": { + "address": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 510 + }, + "first_seen": 1736141750, + "birth_edge": { + "sink": "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 10450531000, + "signature": "5NTDt6Rswtrvt42AT1trjiRspELnF9t98z5H2TyQ4D1L7zB84w3GQjF6borcJLChNK89mRwQUTsqpowEU6MMp4yQ", + "slot": 312181544, + "block_time": 1736141750, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [] + }, + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS": { + "address": "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1773493201, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs" + ] + }, + "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K": { + "address": "93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4311 + }, + "first_seen": 1729158047, + "birth_edge": null, + "fee_payers": [ + "98tv7iW1D1prUGNX6VsCfR878jfMoHs1cF1vdMc6TYoq" + ], + "funded": [] + }, + "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck": { + "address": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 37 + }, + "first_seen": 1781689177, + "birth_edge": { + "sink": "9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck", + "sources": [ + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "value": 2000000000, + "signature": "2kW6Rf9kPJAZnCSgHodJwFNifHr5L1UN3Cj8afcoWHsxHKWFiDEfzFv7v8DsvNL5HFQeihiYy4GWieL826rQnH9Y", + "slot": 427044455, + "block_time": 1781689177, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2UL8hbNaoErAYNePqgQYPP9yDCDRZGWbzKW4krLqkhNL" + ], + "funded": [] + }, + "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr": { + "address": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1782983366, + "birth_edge": { + "sink": "9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr", + "sources": [ + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "value": 65793663482, + "signature": "4uU5EhqsUfPVzpZ1jHMrg9T2TgfcMWE6s81PwMypZnVXQzjKNiB4ibWb9E2MPHa5WFC5mkZhf2DN4PRtX5zaCnB3", + "slot": 430277120, + "block_time": 1782983366, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3i2HU1oBjZrff9QM6SACYW8C1QjExveDNso9saFSJdYw" + ], + "funded": [] + }, + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb": { + "address": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1761613462, + "birth_edge": { + "sink": "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 5504330, + "signature": "4X7t1Ls8Zpb3bqFZchjukeaG9Tf1MdMwUS62Ua2Nx4ALiEYLR4aSCr2Az9hTVF17HBnJsPUa4Q2amcmFnXWECY9m", + "slot": 376252987, + "block_time": 1761613462, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [] + }, + "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879": { + "address": "9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 59 + }, + "first_seen": 1760849092, + "birth_edge": null, + "fee_payers": [ + "6LY1JzAFVZsP2a2xKrtU6znQMQ5h4i7tocWdgrkZzkzF" + ], + "funded": [] + }, + "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV": { + "address": "9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1764737043, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR": { + "address": "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784452952, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh" + ] + }, + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2": { + "address": "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783242816, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z" + ] + }, + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE": { + "address": "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 27 + }, + "first_seen": 1726629672, + "birth_edge": { + "sink": "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE", + "sources": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "value": 1000000000, + "signature": "4DvouS9aXw7ir6N3ohxgKFw3UugY7jqK3aextkEtbox1i1wue5Xh4W6NHbZE9bWvZLMb1P28LoMDY4QhBnRXcehr", + "slot": 290465228, + "block_time": 1726629672, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ], + "funded": [ + "71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm" + ] + }, + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP": { + "address": "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 8186 + }, + "first_seen": 1711915637, + "birth_edge": { + "sink": "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP", + "sources": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V" + ], + "value": 200000000, + "signature": "2sbPicuC4gBQYMAM312LbgX1eDfY9nWY1Aeomg7RBbYVq4ZBuxkFJ1Cpc1icLyVxYUvzPmUyBdn5tCjBbBgRco49", + "slot": 257602531, + "block_time": 1711915637, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V" + ], + "funded": [ + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n" + ] + }, + "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa": { + "address": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 81 + }, + "first_seen": 1712036070, + "birth_edge": { + "sink": "AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 270768410, + "signature": "4MjcwLDx2bPhGuHdRFGKiE3khiQoSd5DWZEw7RNbuHTubuJ6MvHtZyG4TA7TTAHc9CeK6yHS68ErF5gZdeKnDC2R", + "slot": 257873921, + "block_time": 1712036070, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX": { + "address": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3735 + }, + "first_seen": 1760474300, + "birth_edge": { + "sink": "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX", + "sources": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ], + "value": 100000000, + "signature": "aq7ps7k6RZcBWVMaHcqHLVemRNLYzFQukxseeeApwgmVCZ39LNCa2kh8WLCkkdM21AUUjVv9sYtYmi9Gz9BwkUB", + "slot": 373387624, + "block_time": 1760474300, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ], + "funded": [] + }, + "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4": { + "address": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 37 + }, + "first_seen": 1775710580, + "birth_edge": { + "sink": "AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4", + "sources": [ + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "value": 4639648909, + "signature": "3yQYxKyRPrcH6pk87zfhx67eL6Wzza7hDrE91MA3xHKBRcWv6fHLYeW2JfwTtG2sHw5u67qig7NJ2usnX26aqb6t", + "slot": 412000930, + "block_time": 1775710580, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4NyK1AdJBNbgaJ9EsKz3J4rfeHsuYdjkTPg3JaNdLeFw" + ], + "funded": [] + }, + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf": { + "address": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 450 + }, + "first_seen": 1713195781, + "birth_edge": { + "sink": "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf", + "sources": [ + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "value": 10000000, + "signature": "4CEipGPf7m8m8EfHLDWVTy1TsiKyD1LsD6ZAaaNNgvwWJdvqGxRoo9cPcFbASE47phKqZFzaG9dWKaTCFx99bTSb", + "slot": 260290481, + "block_time": 1713195781, + "ambiguous_attribution": false + }, + "fee_payers": [ + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ], + "funded": [] + }, + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS": { + "address": "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784771253, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p" + ] + }, + "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc": { + "address": "B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 64 + }, + "first_seen": 1778266848, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i": { + "address": "B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 290 + }, + "first_seen": 1757844826, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn": { + "address": "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784572075, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa" + ] + }, + "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM": { + "address": "B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 490 + }, + "first_seen": 1757104043, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ": { + "address": "BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 440 + }, + "first_seen": 1773406077, + "birth_edge": null, + "fee_payers": [ + "55H6tESQVFVERF6LzGeUev4p1pCDzeVGML2Tk9UeJRmV" + ], + "funded": [] + }, + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij": { + "address": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2605 + }, + "first_seen": 1753207964, + "birth_edge": { + "sink": "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij", + "sources": [ + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "value": 140590159, + "signature": "2oaGcywpLPt8xEY7w84WSw4Z94DJiZgz1sTYzpCBbfT8sc5UYD99TiHCZoJqasjmLGzqUbffbHXg7LimmCk5pzu4", + "slot": 355044244, + "block_time": 1753207964, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD" + ], + "funded": [] + }, + "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe": { + "address": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 320 + }, + "first_seen": 1720840348, + "birth_edge": { + "sink": "BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 11000000000, + "signature": "1rHtsQspU78fmcbJZDfTh4hrN8xcRLjz2Ji2N7VV5KPBW29nATa6FSmt6WsnrFkmnNbz7QmuQiCDEgeRJYieX9E", + "slot": 277240691, + "block_time": 1720840348, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU": { + "address": "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784918504, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD" + ] + }, + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6": { + "address": "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784392003, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH" + ] + }, + "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb": { + "address": "C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1742345740, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg": { + "address": "C3XueH9USYvEioWKvn3TkApiAf2TjYd7Gpqi83h6cNXg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2175 + }, + "first_seen": 1656406760, + "birth_edge": null, + "fee_payers": [ + "DVXCjVUkz7yAvwufKgSBSieHjLtkDDc1jWanAZtSt3FP" + ], + "funded": [ + "6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL" + ] + }, + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb": { + "address": "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "owner": null, + "executable": false, + "signatures": { + "Exact": 8 + }, + "first_seen": 1768750363, + "birth_edge": { + "sink": "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 30193550020, + "signature": "4sv5REU2obsMfmgbTmSqWgiGiCnQJibid6PgNptnSpqaDLjAWGBdfotB1yiG3tnDuJv7mqRN5NyXQAstjw1QfMdr", + "slot": 394345708, + "block_time": 1768750363, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [ + "2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764" + ] + }, + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm": { + "address": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 143 + }, + "first_seen": 1767909246, + "birth_edge": { + "sink": "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm", + "sources": [ + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "value": 1310000000, + "signature": "3kDnzFaFpXEegPizm9MKtpGGJ8BnETNFdYFJpd2rxKux7Z8EF58v5sMGsnqHfGAxoPTkiZCcSUUb9VpqWL7LD4og", + "slot": 392216036, + "block_time": 1767909246, + "ambiguous_attribution": false + }, + "fee_payers": [ + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4" + ], + "funded": [] + }, + "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ": { + "address": "CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1763677438, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD": { + "address": "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1058 + }, + "first_seen": 1734856327, + "birth_edge": null, + "fee_payers": [ + "HgsxLyn8175xEwRffPRN3DeARE2EVcEeXENr12HpadL6" + ], + "funded": [ + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG" + ] + }, + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG": { + "address": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 36 + }, + "first_seen": 1778449810, + "birth_edge": { + "sink": "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG", + "sources": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "value": 200000000, + "signature": "4XRjYBMjWrSKs8PTEPYrTgkfwVw8Er4AjCYaiHtVn9L5tRWTGu7HnxBTSKUc6gGYGoLri2jr3U9dJ3HnvDvnz1HE", + "slot": 418909903, + "block_time": 1778449810, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ], + "funded": [] + }, + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG": { + "address": "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1781062219, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z" + ] + }, + "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK": { + "address": "Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt": { + "address": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1783210007, + "birth_edge": { + "sink": "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 2290497690, + "signature": "3dZV999nzMy8zrpKZkKbhczT6DLA7J9YhLZZZKpFD6U6UoGg9oEUrySMR4VJNGeV6UTJ8rKbq6qLpL3AQ91UWu5S", + "slot": 430838822, + "block_time": 1783210007, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj": { + "address": "ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 126 + }, + "first_seen": 1775679727, + "birth_edge": null, + "fee_payers": [ + "GWgEFWoUBmE9UocKc3DsvDsVyhYXzd1Wc4cmVy5kbkgL" + ], + "funded": [] + }, + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c": { + "address": "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 35 + }, + "first_seen": 1775705585, + "birth_edge": null, + "fee_payers": [ + "4PqrAP81NRSgbeBNG3scWVev8RAiy1B5SgRDDo3Ub6Eu" + ], + "funded": [ + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28" + ] + }, + "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3": { + "address": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1775659926, + "birth_edge": { + "sink": "D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3", + "sources": [ + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt" + ], + "value": 57015551, + "signature": "4U4QtmZTpQ15CfqzPENGoU8QKmkR4M3MzAChG1ff7qZQVRFcizNEfrp1JqoaZaAYJSYnvZB9z1fh5hs3rD2Qxa22", + "slot": 411872556, + "block_time": 1775659926, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5deQzA8qG2x6qYUERSzSnosHY5n1xLiDPcxSA3npueLt" + ], + "funded": [] + }, + "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD": { + "address": "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 159 + }, + "first_seen": 1759568115, + "birth_edge": { + "sink": "D5SuN8o8FF9fBT3a7vRNMsbhwbzFNERWpFrE99DN5FAD", + "sources": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "value": 8793000, + "signature": "21n3KFdeWHq3Xb5KkQL5N9gb29bMcU9zgkBmHFK2EnKqpMCpNfhTmMC14oLPRoFMzrcrrUUp34sb1a7ehfKFByE1", + "slot": 371102052, + "block_time": 1759568115, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "funded": [ + "Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX" + ] + }, + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf": { + "address": "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784789318, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh" + ] + }, + "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep": { + "address": "DBCVCfKZDX6UwNnfnVraKDeYjfrLER4dmBtSbj3Lueep", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 394 + }, + "first_seen": 1746944587, + "birth_edge": null, + "fee_payers": [ + "AKW1MakJXmUa8Ux5pCRai8zKVAexhhG8d8mZCoQKX4Ri" + ], + "funded": [ + "4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL" + ] + }, + "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv": { + "address": "DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8": { + "address": "DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN": { + "address": "DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8": { + "address": "DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 53 + }, + "first_seen": 1781684439, + "birth_edge": null, + "fee_payers": [ + "Biw4eeaiYYYq6xSqEd7GzdwsrrndxA8mqdxfAtG3PTUU" + ], + "funded": [] + }, + "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z": { + "address": "DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1760102727, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK": { + "address": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1190 + }, + "first_seen": 1747220417, + "birth_edge": { + "sink": "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK", + "sources": [ + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "value": 3141592653, + "signature": "3mXJiiZA35B1Y6UUyqkynZBkYe8sM4WsjzRBgSfjrvqYRhSRfWSx25Xdr5ct4mFR2UpbTJQg1goGscDGfRa3NdE3", + "slot": 339946664, + "block_time": 1747220417, + "ambiguous_attribution": false + }, + "fee_payers": [ + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm" + ], + "funded": [] + }, + "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi": { + "address": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 200 + }, + "first_seen": 1653138893, + "birth_edge": { + "sink": "Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi", + "sources": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "value": 606489437, + "signature": "62pVXVgr23rpDrywbMT9my8PUPDsRf53biB4QSm9oa67zvw14JmuaqbuC5obnSjSYS1acXMQQRgUXVYpX2s1RHaF", + "slot": 134659485, + "block_time": 1653138893, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "funded": [] + }, + "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa": { + "address": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1783201670, + "birth_edge": { + "sink": "DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa", + "sources": [ + "B48kNVXs4YK4amkBCH2XokQiv1SeiVQGHDR17xDeKAAn" + ], + "value": 185933290, + "signature": "NX3DrMfLgUE4yHC8dgbQj2vHFKiCzTrPhfTDShToZdn8skzKWLJyzEEh6dbWxeMTBEkRhqWkXVRNzmZDvGKs3Yc", + "slot": 430818102, + "block_time": 1783201670, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3ddCq8LgnyYiJFfupiNAR8rQ9BshepSMzSwWbNLageTx" + ], + "funded": [] + }, + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq": { + "address": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1784199361, + "birth_edge": { + "sink": "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq", + "sources": [ + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw" + ], + "value": 23682958, + "signature": "2ChU8gFx2ffsnkR6HwHJsD2Pd44iTWQ37rdfWgHwbVjMYb45X88VvqNSCaZu6vh2fgC62bXvkt6C8v9YzUrjNz26", + "slot": 433259174, + "block_time": 1784199361, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9": { + "address": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20 + }, + "first_seen": 1782002060, + "birth_edge": { + "sink": "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 50000000, + "signature": "RtgJqd5sHDiondx4Z2yiq5essG1zXj5XwroXbZrtjkhy9NDPjutCezrPBr122sZqphKBa9YWJF3VPxiBUerRjBq", + "slot": 427833377, + "block_time": 1782002060, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [] + }, + "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U": { + "address": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 10 + }, + "first_seen": 1781081436, + "birth_edge": { + "sink": "EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 92849110, + "signature": "2d8HpMfLa5r1S3vdLKNiT69B7gPFjj4U3YHRc3skWQFqF3T2LUjTQzjPtWiHzQytw3VupQMQFiajPmjNYzN5rZfe", + "slot": 425512751, + "block_time": 1781081436, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH": { + "address": "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1703354625, + "birth_edge": { + "sink": "ED8vhGPWyBfUi7toDZ6vzuB4TmShsBqaT6Eyr6kC7iLH", + "sources": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "value": 1320200000, + "signature": "3cqmB1Yi2Z7ZVQjjA37NQ4d84ViimuKf1h83J23digAMRGoJMY8VmUbNkSxyqxRqsE3qBoBFKwCMXfxhVMEGNacP", + "slot": 237597989, + "block_time": 1703354625, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "funded": [ + "ACfTomwEEeikA7FTtBZZ4yh9QoDho7WAj8nfDxQxjHoE" + ] + }, + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe": { + "address": "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785033307, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R" + ] + }, + "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo": { + "address": "FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13145 + }, + "first_seen": 1719672752, + "birth_edge": null, + "fee_payers": [ + "EobHT3dMnAxoPa5Wox3ZbE9pQ88dHxqU7FypMnWfWu5r" + ], + "funded": [] + }, + "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G": { + "address": "FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784837372, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq": { + "address": "FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1775881597, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf": { + "address": "FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11491 + }, + "first_seen": 1770490600, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA": { + "address": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 120 + }, + "first_seen": 1769087495, + "birth_edge": { + "sink": "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA", + "sources": [ + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "value": 430752000, + "signature": "2AFuX4tvKhsFguYnNfiW4QCHsYFeoARyYNbm9hMxqKHpgaX2f6d8qHfioWQsnyDCy5wFHzeUAXoSURUyGDGgmxzj", + "slot": 395193315, + "block_time": 1769087495, + "ambiguous_attribution": false + }, + "fee_payers": [ + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE" + ], + "funded": [] + }, + "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD": { + "address": "FqQQ91XsCxJNN2LGMpvJRV3vzDV7wzA4viCz7LSqdiTD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1211 + }, + "first_seen": 1731582585, + "birth_edge": null, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [ + "BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij" + ] + }, + "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p": { + "address": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 282 + }, + "first_seen": 1707956423, + "birth_edge": { + "sink": "FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 92000000, + "signature": "2Zo3SqZ1zdcF99BygckTotHufbXupGv4FLFyEdVxbSwKedaeJRsp2gb8Uwjgjf8PkwQgsibXyJvpBZwFErrJ6FDc", + "slot": 248216739, + "block_time": 1707956423, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [] + }, + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu": { + "address": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1783033845, + "birth_edge": { + "sink": "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu", + "sources": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "value": 1171377350, + "signature": "5T6rTfTX8JKsNiXf9PCnAEL4w7HLzJfsVBeQwsTRcsuK9TyxUV9ym5MPTpVBepapLkDMQeTPdAEigW14azAfdiT8", + "slot": 430402156, + "block_time": 1783033845, + "ambiguous_attribution": false + }, + "fee_payers": [ + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV" + ], + "funded": [] + }, + "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2": { + "address": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2014 + }, + "first_seen": 1728020846, + "birth_edge": { + "sink": "G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 203950000, + "signature": "5U8Sgir6egiAF84ZZW13rDa1ek69yJpBcTmv227D88J6Gbm69bF6Dq7WKoLSdYEeaeXGPSCmN76jDFXzZEkeQh2Z", + "slot": 293595031, + "block_time": 1728020846, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE": { + "address": "G9X7F4JzLzbSGMCndiBdWNi5YzZZakmtkdwq7xS3Q3FE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784933634, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA" + ] + }, + "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1": { + "address": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7196 + }, + "first_seen": 1728755528, + "birth_edge": { + "sink": "G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1", + "sources": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "value": 839200000, + "signature": "2DdKCofnd53ZCijpwVNM4xRHmTXYT8YqeRh99etQB4J3YmX48b1sNn6vq2RGrqtmsgbKq4jH1jHc9DnoSctSurUw", + "slot": 295234119, + "block_time": 1728755528, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AobVSwdW9BbpMdJvTqeCN4hPAmh4rHm7vwLnQ5ATSyrS" + ], + "funded": [] + }, + "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG": { + "address": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4316 + }, + "first_seen": 1743001899, + "birth_edge": { + "sink": "GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG", + "sources": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "value": 200000000, + "signature": "3Rg9fS58hDfbMcnKWU6jeJXUva4g1jetwoNwvp7YiiH1GXDadsF7ZqxutWpxq6VXuHdRWpq61TFtQMs6KRhrkmqr", + "slot": 329323260, + "block_time": 1743001899, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CYar4VLpjCQ14VZAiXeNntta2oVw5CRQz8U1ajhEPYaD" + ], + "funded": [ + "2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7" + ] + }, + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9": { + "address": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1773 + }, + "first_seen": 1699496374, + "birth_edge": { + "sink": "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 3442545653, + "signature": "Pvpzz5cpDfRekWPtKKux8YPWQuzJhsEonx1YpQLx9HkBiWkknk4Cwj6dyvof1ha8fnmrEkZqGAefpquu6G6HUDD", + "slot": 228889688, + "block_time": 1699496374, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [] + }, + "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2": { + "address": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 163 + }, + "first_seen": 1770880341, + "birth_edge": { + "sink": "GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 1178878050, + "signature": "3Yn2VJBxAgpBmQ8XD5EXEPEdPfyYuvrRfiJEFCMn4JS3CwYURPu7QTwjsz9Masn96rwjNriemwBLyzFe8ZVzLwbq", + "slot": 399714845, + "block_time": 1770880341, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE": { + "address": "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784780643, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "6VkpbHZ4Q5jS42ZeNaGCUUqeQyP4CXrbP5fuDgyVuh39" + ] + }, + "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA": { + "address": "GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783307215, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq": { + "address": "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1705 + }, + "first_seen": 1777229947, + "birth_edge": { + "sink": "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq", + "sources": [ + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16" + ], + "value": 3615443530, + "signature": "ev9FqbVk8jCJiy27MypNycKFYYeRJJJCpH6WiNPM5buomXGKnTHqz9YL5heguK76dncGDd8KnEMvKruGMzQFDRc", + "slot": 415842709, + "block_time": 1777229947, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9WL2A89YBr6X47ABKYNzPentWiBA3H8tpaiuf5CaYHx6" + ], + "funded": [ + "6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV" + ] + }, + "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs": { + "address": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 302 + }, + "first_seen": 1774289101, + "birth_edge": { + "sink": "GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs", + "sources": [ + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "value": 1406603230, + "signature": "58WsdGGRCSKky5UXVe4QCaZpALbxjqfksCdHYZUj6HtNo5GmE3SwBi7tfun9dovyXN7CHVXt56c7wc28deCM4NKb", + "slot": 408377546, + "block_time": 1774289101, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8xYmtDVzZN9fGT4kKFQZzbGSJQR5Lu2FPebJ3b1ZKgfS" + ], + "funded": [] + }, + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq": { + "address": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1758453103, + "birth_edge": { + "sink": "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq", + "sources": [ + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi" + ], + "value": 1111260006, + "signature": "2wqEciaCd8SdPS1BaEWBxZfVTrHk3sMS7PZB8LobFDQA7e49g7awaW44rGj2gRiWbCoU4rW4SWbn7qCpQtPXaetx", + "slot": 368284051, + "block_time": 1758453103, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i": { + "address": "GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1753315217, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb": { + "address": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 253 + }, + "first_seen": 1776516090, + "birth_edge": { + "sink": "GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb", + "sources": [ + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "value": 268000000, + "signature": "3KB7X9tCYoBd3HrsMzGTYQ1avb3ceSiXpHuQv6qQ9LPLKVnxVoUaXdBeKF5qLp71mMTNmHXsNcKe3Hbd4JYs29C8", + "slot": 414039567, + "block_time": 1776516090, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5F1seMKUqSNhv45f6FhB2cFmgJbk8U1avJw7M6TexUq1" + ], + "funded": [] + }, + "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z": { + "address": "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1230 + }, + "first_seen": 1769712791, + "birth_edge": { + "sink": "Gh2FkrqEtKgHmBQKKJ4SMWui9BhjBF6GiinpYCZ2t59z", + "sources": [ + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "value": 159000000, + "signature": "37ERW5HvvBbZ7xPSZK8kHSjpshWttD8PGTqwnw4hrmou8DyqToYBSU1oV1YqHfEdVbqBkkLULdg7VUmuZBsNkVZG", + "slot": 396754483, + "block_time": 1769712791, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CdcVvn23Bzxj14ibBe7xRcK3g8QbrcXKYYQpqkTrW1KG" + ], + "funded": [ + "CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG" + ] + }, + "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf": { + "address": "GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 180 + }, + "first_seen": 1745992468, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv": { + "address": "GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 49 + }, + "first_seen": 1778543921, + "birth_edge": null, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx": { + "address": "H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 639 + }, + "first_seen": 1681873953, + "birth_edge": null, + "fee_payers": [ + "mgrArTL62g582wWV6iM4fwU1LKnbUikDN6akKJ76pzK" + ], + "funded": [] + }, + "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw": { + "address": "H292B1VbSvD6GuUmSvUvfQstg1Acfzog796uQ7d1ccCw", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq" + ] + }, + "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R": { + "address": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9 + }, + "first_seen": 1784990514, + "birth_edge": { + "sink": "H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 10091911, + "signature": "8noYJ5aCs9N6rbVBKCGMwVfVeCg1GQHGXhaNHP2rVcBZSMgbgiUpoNtpQ8XkASe78iZs3JqGk3c178jbeFgdrzc", + "slot": 435145890, + "block_time": 1784990514, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS": { + "address": "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784778578, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9", + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ" + ] + }, + "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi": { + "address": "HBYGbsQxBy3DPMTWT8UYsqTbGQEc2Sq7NnVUnHnS1XAi", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq" + ] + }, + "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K": { + "address": "HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 483 + }, + "first_seen": 1756671400, + "birth_edge": null, + "fee_payers": [ + "GT2zuHVaZQYZSyQMgJPLzvkmyztfyXg2NJunqFp4p3A4" + ], + "funded": [] + }, + "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw": { + "address": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1783107306, + "birth_edge": { + "sink": "HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 9000000, + "signature": "4B1byRx7pvEAt5NfXDUwEqo2TyMbm1qFV1Qakd6tnjmjfUHQ6ThQJFpcN129xXoS29GPPtvScVyHGBkCV6kd9s2m", + "slot": 430584264, + "block_time": 1783107306, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh": { + "address": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 322 + }, + "first_seen": 1761374606, + "birth_edge": { + "sink": "HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh", + "sources": [ + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "value": 25732740, + "signature": "3AhoNZZLvSQ5gNfWsTeRkjLi8W9t1P63EPXD3YKxErjnAP37U44njwCmpBaygX1xi5fgUNHHSZaeMiEJq9F2jrHi", + "slot": 375651141, + "block_time": 1761374606, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D89hHJT5Aqyx1trP6EnGY9jJUB3whgnq3aUvvCqedvzf" + ], + "funded": [] + }, + "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16": { + "address": "HWjmoUNYckccg9Qrwi43JTzBcGcM1nbdAtATf9GXmz16", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1781755484, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GPa8qRLhtXojtAR5SG9AcZ2WH32N8V4KDXWip9Waq3Hq" + ] + }, + "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V": { + "address": "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1582 + }, + "first_seen": 1700759478, + "birth_edge": { + "sink": "Hkhy3fzLpxhtSZ1UWmkRtSCzmtYYsDdz8dZBPS9iWC7V", + "sources": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "value": 951634000, + "signature": "5vBY9n8k1qYPBcapzouiPJ9whnVFx18Y9Y574PJfDDwMNKt59QoCsGbRgke24y6T3zTyjNNRqEzCnJUAwfWGNeE7", + "slot": 231795042, + "block_time": 1700759478, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AC5RDfQFmDS1deWZos921JfqscXdByf8BKHs5ACWjtW2" + ], + "funded": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ] + }, + "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n": { + "address": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 135 + }, + "first_seen": 1780765625, + "birth_edge": { + "sink": "JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n", + "sources": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "value": 271700000000, + "signature": "5R2ekhoYBR8fWYnM27srHHH24YNpF79Bu2uws2dh3otMMSt7Kku9tgV5NUx2yFN53YjfhZ8iDv6zNzFJpuoZgyg2", + "slot": 424718918, + "block_time": 1780765625, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AEGLU3WiZcuc6yDx1saV4ay1CVFSPTXiExRVRr5iDngP" + ], + "funded": [] + }, + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu": { + "address": "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784720381, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CCPurEuY4xLWaWf6GynxdnuNDCD7wQCGTYTFwvNUkvcb", + "CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt" + ] + }, + "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV": { + "address": "is6MTRHEgyFLNTfYcuV4QBWLjrZBfmhVNYR6ccgr8KV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784708330, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb", + "EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9", + "G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu" + ] + }, + "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4": { + "address": "jmLtKSEWyQhCbHgTa52XZwcfLQ2ze9J8VN3nfSTEjt4", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1777641452, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm" + ] + }, + "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ": { + "address": "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 21 + }, + "first_seen": 1709918366, + "birth_edge": { + "sink": "og4JD8pHjchseQfyMK56upFjAzNirKZM8unbpPQ1YEJ", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 1696237745, + "signature": "qdFZbtFQnSrYx5CCo78yqoFY1ZYvhKgUL5gPeKiiG1LJ2TG2jC4yKtUdwidZiH5tZZ2bt4HEqU4pfjBbMeDYJNc", + "slot": 252918864, + "block_time": 1709918366, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf" + ] + }, + "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28": { + "address": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 98 + }, + "first_seen": 1780986875, + "birth_edge": { + "sink": "okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28", + "sources": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "value": 30000000, + "signature": "5RkppwfwvNhhTswurZaM4gwPQiDaie82UhBdHt8mHJSES3ci8cmDuHHRLYXoFuWD7KdurykQXq7dUBfaBw8HAiqW", + "slot": 425274321, + "block_time": 1780986875, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CrnsXJJGBEM4d6eYwKtZ7xccdnWRTv7qUAfu3eo7Aj8c" + ], + "funded": [] + }, + "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm": { + "address": "opLSF7LdfyWNBby5o6FT8UFsr2A4UGKteECgtLSYrSm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1751863543, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK" + ] + }, + "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ": { + "address": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 34 + }, + "first_seen": 1784808222, + "birth_edge": { + "sink": "umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ", + "sources": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv" + ], + "value": 100000000, + "signature": "3XFtWHvCubsszFNB4U9XX592rAbYqdKaUjy7KPTjxKmcAUziERiSHsPLvbSozHGgAgiZjZmdStGTB99ASeYB8GPU", + "slot": 434711620, + "block_time": 1784808222, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2mrhMbUXyffTymehpWDr59YzXVi6h7v6otbJjLGfzhCv" + ], + "funded": [] + } + } +} \ No newline at end of file diff --git a/data/sample-privacycash-run4.json b/data/sample-privacycash-run4.json new file mode 100644 index 00000000..1897d488 --- /dev/null +++ b/data/sample-privacycash-run4.json @@ -0,0 +1,5285 @@ +{ + "manifest": { + "endpoint": "https://mainnet.helius-rpc.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1785030724, + "config": { + "scope": "Sol", + "depth_max": 16, + "min_edge_lamports": 500000, + "sig_page_cap": 24, + "page_size": 1000 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 1613, + "excluded_non_wallet": [ + "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp", + "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7", + "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB", + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr", + "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY", + "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv", + "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis", + "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX", + "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo", + "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG", + "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS", + "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA", + "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha", + "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp", + "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH" + ], + "ambiguous_attribution_rate": 0.2013888888888889 + }, + "chains": [ + { + "seed": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "visited": [ + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "visited": [ + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "visited": [ + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E", + "visited": [ + "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E" + ], + "stop": "PageCapHit" + }, + { + "seed": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "visited": [ + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE", + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g", + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99", + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT", + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD" + ], + "stop": "PageCapHit" + }, + { + "seed": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "visited": [ + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "visited": [ + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "stop": "PageCapHit" + }, + { + "seed": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "visited": [ + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff", + "visited": [ + "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff" + ], + "stop": "PageCapHit" + }, + { + "seed": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "visited": [ + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "visited": [ + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "visited": [ + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "visited": [ + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "visited": [ + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "stop": "PageCapHit" + }, + { + "seed": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "visited": [ + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf", + "visited": [ + "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf" + ], + "stop": "PageCapHit" + }, + { + "seed": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "visited": [ + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "stop": "PageCapHit" + }, + { + "seed": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "visited": [ + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "visited": [ + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR", + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9", + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j", + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "visited": [ + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165", + "visited": [ + "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165" + ], + "stop": "PageCapHit" + }, + { + "seed": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "visited": [ + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "visited": [ + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "stop": "PageCapHit" + }, + { + "seed": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "visited": [ + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X", + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF" + ], + "stop": "PageCapHit" + }, + { + "seed": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "visited": [ + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB" + ], + "stop": "LocalTerminal" + }, + { + "seed": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "visited": [ + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "visited": [ + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "visited": [ + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "visited": [ + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "visited": [ + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "visited": [ + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "visited": [ + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV" + ], + "stop": "LocalTerminal" + }, + { + "seed": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "visited": [ + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "visited": [ + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe", + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "visited": [ + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "visited": [ + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "visited": [ + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "stop": "PageCapHit" + }, + { + "seed": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "visited": [ + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "visited": [ + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "visited": [ + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "visited": [ + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U", + "visited": [ + "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U" + ], + "stop": "PageCapHit" + }, + { + "seed": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "visited": [ + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ" + ], + "stop": "LocalTerminal" + }, + { + "seed": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "visited": [ + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "visited": [ + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "visited": [ + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "stop": "PageCapHit" + }, + { + "seed": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "visited": [ + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT", + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "visited": [ + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "visited": [ + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "visited": [ + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "stop": "PageCapHit" + }, + { + "seed": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "visited": [ + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf", + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs", + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K", + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "visited": [ + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "visited": [ + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "visited": [ + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "stop": "PageCapHit" + }, + { + "seed": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "visited": [ + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "stop": "PageCapHit" + }, + { + "seed": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "visited": [ + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "visited": [ + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme", + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "stop": "PageCapHit" + }, + { + "seed": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "visited": [ + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "visited": [ + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "visited": [ + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "visited": [ + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "visited": [ + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "stop": "PageCapHit" + }, + { + "seed": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "visited": [ + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o" + ], + "stop": "LocalTerminal" + }, + { + "seed": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "visited": [ + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "visited": [ + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "visited": [ + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "visited": [ + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "visited": [ + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "stop": "PageCapHit" + }, + { + "seed": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "visited": [ + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "visited": [ + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "visited": [ + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ", + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x", + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha", + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t", + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe", + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH", + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz", + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ" + ], + "stop": "DepthExceeded" + }, + { + "seed": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "visited": [ + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "visited": [ + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "visited": [ + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR", + "visited": [ + "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR" + ], + "stop": "PageCapHit" + }, + { + "seed": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "visited": [ + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn" + ], + "stop": "PageCapHit" + }, + { + "seed": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "visited": [ + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "visited": [ + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "visited": [ + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "visited": [ + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "visited": [ + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "visited": [ + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "stop": "PageCapHit" + }, + { + "seed": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "visited": [ + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "stop": "PageCapHit" + }, + { + "seed": "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM", + "visited": [ + "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM" + ], + "stop": "PageCapHit" + } + ], + "facts": { + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E": { + "address": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1784615427, + "birth_edge": { + "sink": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 110900000, + "signature": "5e6e31Ja1kF2DbV7qrcSW9RZYywU7TpJfxr667CtkwBe4toXGeyZnYtdT8NJeQzM1fTpQULLkDXkraeVcYxArg8W", + "slot": 434252353, + "block_time": 1784615427, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma": { + "address": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 607 + }, + "first_seen": 1783375005, + "birth_edge": { + "sink": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 22913500000, + "signature": "2AkoeVHhVQwaNuxQEya9FmdWcho8YDPBUExnQwQ51LZCGAN81Xa6gmUiq5KufZD7VNapVbL566cGNQ54cHcQGDAZ", + "slot": 431247217, + "block_time": 1783375005, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z": { + "address": "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4277 + }, + "first_seen": 1647049347, + "birth_edge": { + "sink": "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "sources": [ + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "value": 7244953950, + "signature": "419TeAWehDaugVDXtfT9GochWU2uzZfYE8Mj9KcRLxDtwZpVies6nT8ujSsqz5xcah5gEALomEeyeL5igrt1ZFeG", + "slot": 124535935, + "block_time": 1647049347, + "ambiguous_attribution": false + }, + "fee_payers": [ + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "funded": [ + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H" + ] + }, + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm": { + "address": "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784753164, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ] + }, + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ": { + "address": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 35 + }, + "first_seen": 1783722353, + "birth_edge": { + "sink": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 12948500000, + "signature": "5rMkvoDiSrN16YHjCLekrebvkmsHxvssazWRbP2Fq5rZNhyyMcUTULMb136XBMrKVZzwRyhbj7qb3cx3sgGiWAoX", + "slot": 432098751, + "block_time": 1783722353, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha": { + "address": "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9": { + "address": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784475307, + "birth_edge": { + "sink": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "sources": [ + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn", + "6tckHFBpiJ8YgYN8FUskvtvTpXQZ55g5LHeo1kvELoDQ" + ], + "value": 5010000000, + "signature": "4bs1AqpjFmhSM6Hgg7nGwN7FbytYnLRcGmiTMP6TCCRP2rhhT4hf8Bb62Jm7uTqxc4vs9scPgT3vbEb98uQfdNF3", + "slot": 433922248, + "block_time": 1784475307, + "ambiguous_attribution": true + }, + "fee_payers": [ + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn" + ], + "funded": [] + }, + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X": { + "address": "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1743262736, + "birth_edge": { + "sink": "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X", + "sources": [ + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF" + ], + "value": 779470319, + "signature": "2YjKzdqoKhck9hGc8VmXR5gxdnX1SPDG6WByy1Mm3tHz5rzESsiEf3TLLof8but3XH3XqMVX9ZHbvAR9fhVPanWM", + "slot": 329976683, + "block_time": 1743262736, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF" + ], + "funded": [ + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu" + ] + }, + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V": { + "address": "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "owner": null, + "executable": false, + "signatures": { + "Exact": 249 + }, + "first_seen": 1776070891, + "birth_edge": { + "sink": "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "sources": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "value": 600000000, + "signature": "2ifPXJE5e8zqjQTqTP7duLXvDyDjTsJrqcf5iEdywn3Z29p3Zsr3RcgYFXPkkxZMhMNg3HQyeVHSqQHhCrDAYnPM", + "slot": 412912638, + "block_time": 1776070891, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "funded": [ + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU" + ] + }, + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH": { + "address": "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894159, + "birth_edge": { + "sink": "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH", + "sources": [ + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz" + ], + "value": 849144919, + "signature": "4YP76aBoEjaNaxf1e6Va5x4ZZLNVfo6vNpY8kzqQcquQZWaGeiiJgrKaPTrP1udmGV8Kj82jNeBCsH8PzcwBPk9b", + "slot": 394707612, + "block_time": 1768894159, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz" + ], + "funded": [ + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe" + ] + }, + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy": { + "address": "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1593 + }, + "first_seen": 1784752160, + "birth_edge": { + "sink": "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "sources": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "value": 43881516584, + "signature": "3NEwDfuC73NVthq8zeasPw9Ud6qcWZiy65wFFZSWcbxP86UjAsc9ZPApAdjk7EYo88ptZcUZbSLdmQwZkgqSCcRc", + "slot": 434577818, + "block_time": 1784752160, + "ambiguous_attribution": false + }, + "fee_payers": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "funded": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ] + }, + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg": { + "address": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1781285770, + "birth_edge": { + "sink": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "sources": [ + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "value": 1677937000, + "signature": "2TJSuukc2SNr9YL2qRHeNHmu37kfsE2cBnQkz7TJTxuRkVw48fefVYqxsGCV2ULsb1PnVvzmcQGJt5J7uouabgYZ", + "slot": 426027687, + "block_time": 1781285770, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "funded": [] + }, + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem": { + "address": "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "owner": null, + "executable": false, + "signatures": { + "Exact": 263 + }, + "first_seen": 1713736580, + "birth_edge": { + "sink": "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "sources": [ + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "value": 12006763000, + "signature": "62g49CyyWTmom7Qxdnr64iSy7W8PDuxrZojz5q6ztpgYkM7WwwXkfcyeNVditM45iomtRpgqXUbLW8kXpScStkuL", + "slot": 261492401, + "block_time": 1713736580, + "ambiguous_attribution": false + }, + "fee_payers": [ + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "funded": [ + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq" + ] + }, + "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf": { + "address": "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1768518508, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz": { + "address": "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1771845560, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38" + ] + }, + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS": { + "address": "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783787452, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ] + }, + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1": { + "address": "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 100 + }, + "first_seen": 1784818359, + "birth_edge": { + "sink": "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "sources": [ + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7" + ], + "value": 6000000000, + "signature": "2StbhyBVwhP2wRhTYMM31x5qU3B2WBr1jFXx6KD6CGeXp9xpWQqN7RKoxa98X86h8v6SGprqMdi9CVGh9PLSjAQH", + "slot": 434735789, + "block_time": 1784818359, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7" + ], + "funded": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ] + }, + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr": { + "address": "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784752151, + "birth_edge": { + "sink": "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "sources": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "value": 45278992944, + "signature": "LnCoQVyRCZyi9ktCp3JyZPKhGrTu19FzpmhP7SjvQ8TKYS7uu9dPE23AuzRQz32YWqaTQG9rabCkoAihw2swguS", + "slot": 434577797, + "block_time": 1784752151, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "funded": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ] + }, + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT": { + "address": "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1332 + }, + "first_seen": 1632786500, + "birth_edge": { + "sink": "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT", + "sources": [ + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m" + ], + "value": 100000000, + "signature": "2BLRDfM37WhxjZUNXSnPPqSZP3Yq2xTG2BsyUiQWCFaLcqPigMGHgSrX2uijsXVbB9AKL4sYZenPjui5ArFMGjcP", + "slot": 98678981, + "block_time": 1632786500, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m" + ], + "funded": [ + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t" + ] + }, + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt": { + "address": "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784444104, + "birth_edge": { + "sink": "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "sources": [ + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "value": 5986856990, + "signature": "3k3C9SKrmZZ9aKwV75WzsqDnXRj1jnrfVoq6W5E4wxyjcAH7ZGiMbrDKVqStRdtpFm4Y2vzYA8WvEyUdSs67b1UN", + "slot": 433847718, + "block_time": 1784444104, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "funded": [ + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH" + ] + }, + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL": { + "address": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784544632, + "birth_edge": { + "sink": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "sources": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "value": 928815670, + "signature": "85PNojTrpgdkLHWP1CQRGD6G6CttqKUCr5zYDjLXkFsB4teH5D9kcZqZjTAWX3ydRqfVhwLAKLzC6zYsU3K1A8L", + "slot": 434085334, + "block_time": 1784544632, + "ambiguous_attribution": false + }, + "fee_payers": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "funded": [] + }, + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe": { + "address": "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894162, + "birth_edge": { + "sink": "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe", + "sources": [ + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH" + ], + "value": 849139919, + "signature": "2R1Goqyiuu2pZC2cXWBUawgSdAFH38yF9ciQW9p9igR6YUwHoKq9iigoHZeQgBq4ZrcmdMkp39jThvqv2bZcevMF", + "slot": 394707621, + "block_time": 1768894162, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH" + ], + "funded": [ + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t" + ] + }, + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H": { + "address": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 528 + }, + "first_seen": 1734052375, + "birth_edge": { + "sink": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "sources": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "value": 1020000000, + "signature": "4Mm83Hp6ciDRNzM3tSFJt6AyoXPc7kD4moyqFobEtqzXDAnC2k5hNt83wNGSsn61KQjaNdyYYqWHcJjaUA9qubwX", + "slot": 307120184, + "block_time": 1734052375, + "ambiguous_attribution": false + }, + "fee_payers": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "funded": [] + }, + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH": { + "address": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 277 + }, + "first_seen": 1784444332, + "birth_edge": { + "sink": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "sources": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "value": 2985933011, + "signature": "4e1bYdz4z6QTzWFbSbjFRJpDdhuc2m2zaopi6x8N1w81fa6352rDi2VCzqyxKdRuvPKthVeikZXGj91o6bvCfeK4", + "slot": 433848260, + "block_time": 1784444332, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "funded": [] + }, + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr": { + "address": "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1780914830, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh" + ] + }, + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7": { + "address": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784462394, + "birth_edge": { + "sink": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 90000000, + "signature": "4jhAt2GJwyGRfe5sJkFB2HVjnUzLi86PVfucCvUM6u3JFRwegv57f4ZkhmRH6huyS8pNEZa8nbPs9Kb6PtXYUAqz", + "slot": 433891372, + "block_time": 1784462394, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99": { + "address": "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99", + "owner": null, + "executable": false, + "signatures": { + "Exact": 662 + }, + "first_seen": 1783864275, + "birth_edge": { + "sink": "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99", + "sources": [ + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT" + ], + "value": 16330335554, + "signature": "32dUmLfqYokcYLdCcE19JzJ8Y423ssL8GJ6qLEDaZtmWHsQtpTF4e9KVxmSuidihQAcV5cuPpsMZjhWWd8F149TB", + "slot": 432444959, + "block_time": 1783864275, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT" + ], + "funded": [ + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g" + ] + }, + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu": { + "address": "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1764 + }, + "first_seen": 1781821319, + "birth_edge": { + "sink": "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "sources": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "value": 400000000, + "signature": "t439hwXMQP6B4Yk83sUHquHMZR9q8bqQK4na6cWaxbvVCnQKw5hzceNSBXCJKRmcEzmJBFLd19bfcWsSDKGxhU6", + "slot": 427377732, + "block_time": 1781821319, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "funded": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ] + }, + "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv": { + "address": "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze": { + "address": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 697 + }, + "first_seen": 1784674265, + "birth_edge": { + "sink": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 6040700317, + "signature": "3tGju22hVCi5Tn5mQv65Uokr3ahGwzYsU5urYkse9Bq4SgSRPmwiU8FzhX51HBdMCKyTor6i8G1uc2LnhHge4uRb", + "slot": 434392522, + "block_time": 1784674265, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9": { + "address": "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9", + "owner": null, + "executable": false, + "signatures": { + "Exact": 42 + }, + "first_seen": 1682118364, + "birth_edge": { + "sink": "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9", + "sources": [ + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j" + ], + "value": 11742708040, + "signature": "4fDKVyLL5y4Kzuedc8MGwhkkXd1oWbkMqBZTsHtc1H7NFTWijug7Lciv42HG6VkxfjZSemzGn6fCysTTxQPG2Zsb", + "slot": 189742975, + "block_time": 1682118364, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j" + ], + "funded": [ + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR" + ] + }, + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ": { + "address": "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894142, + "birth_edge": { + "sink": "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ", + "sources": [ + "3LKFtdjyaX773fYgnXShWhicr3ZcNaSWWz2ggQVBgtsC" + ], + "value": 849154919, + "signature": "3fTk4eCJFMtoe3jFJ4XhXYEHqurQ5DHnehPcQoWMQLXmPmQTdns183yrWX7C8YWCvrtV7GPaU1GJ7WZfpdB9KSo1", + "slot": 394707570, + "block_time": 1768894142, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3LKFtdjyaX773fYgnXShWhicr3ZcNaSWWz2ggQVBgtsC" + ], + "funded": [ + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz" + ] + }, + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz": { + "address": "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894156, + "birth_edge": { + "sink": "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz", + "sources": [ + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ" + ], + "value": 849149919, + "signature": "ebF99xjMkDDNHUYqxCU6fukrRihQpvEHCgpii9dnf6AeBFGPYvk94S2cq7QnfBfhRooK1361Xddiaksk6hnVxQX", + "slot": 394707604, + "block_time": 1768894156, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ" + ], + "funded": [ + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH" + ] + }, + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr": { + "address": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9790 + }, + "first_seen": 1781265894, + "birth_edge": { + "sink": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 209692102518, + "signature": "2WnT866FtZdcXqRvfQoypXGhWSQRtqa4cCg453yjkGSuZA9fs8LJviugPbbGP9GYu3TDJhohtJeDwq1AuoeqJBFi", + "slot": 425977688, + "block_time": 1781265894, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16": { + "address": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9762 + }, + "first_seen": 1772531584, + "birth_edge": { + "sink": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "sources": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "value": 302066170, + "signature": "5A3SzsgcHRLJQUVBqDNdCW7M8XnW6jS7TBjiuERozS7a5YAXc4EieN5d58j5Ts7mqNssUsZZj3TKUTNAett3gqgK", + "slot": 403914286, + "block_time": 1772531584, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "funded": [] + }, + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT": { + "address": "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT", + "owner": null, + "executable": false, + "signatures": { + "Exact": 273 + }, + "first_seen": 1782950807, + "birth_edge": { + "sink": "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT", + "sources": [ + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD" + ], + "value": 100000000, + "signature": "5xcQPdqkxyx3pQsyF85wNxj7b4TuW3nB3wqryzTVHLtMeDfKsGzjY64jXDCnnfvru4BqEunbdYQzBAHBBJKG3d6V", + "slot": 430196288, + "block_time": 1782950807, + "ambiguous_attribution": false + }, + "fee_payers": [ + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD" + ], + "funded": [ + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99" + ] + }, + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w": { + "address": "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1783188037, + "birth_edge": { + "sink": "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 100528380, + "signature": "5CdkjWty9v98DDGJPREJK7UpeGUaaBdQxo87kDxyqajMtFtbnzVuL2h9UCu4Ue4iVqu4vWgiBLbs8XCjnAswLrDR", + "slot": 430784309, + "block_time": 1783188037, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [ + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k" + ] + }, + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk": { + "address": "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1013 + }, + "first_seen": 1781819169, + "birth_edge": { + "sink": "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 25895028000, + "signature": "5e4gkh2xn451jv5rnKUJN81VDUN9bJTY3VESq2eQ7ACZJ51DuXZMFBaat5X5tVe5VBLzSnGbKri4KnpFezdqG3mu", + "slot": 427372317, + "block_time": 1781819169, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ] + }, + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd": { + "address": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 133 + }, + "first_seen": 1784917747, + "birth_edge": { + "sink": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3063734792, + "signature": "5iF2hZ9Pg77skU74ve2HwpkKpHnSjw2W13DmC67uSo2FAFaUC4FSLEZvv2BSwjwtF1NTfCVuBRKbghGoqpmtUmd7", + "slot": 434972545, + "block_time": 1784917747, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs": { + "address": "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1663976471, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ] + }, + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ": { + "address": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1784823865, + "birth_edge": { + "sink": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "sources": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "value": 26325656111, + "signature": "4Fvr5kGDCyhHU3xmpCJvMRy4YAGLs93UAu2mbCG3V39pu9ASyDAqEeMqve3CmwgDUieLGp4q6uoGvFHWBmqt2hvK", + "slot": 434748892, + "block_time": 1784823865, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "funded": [] + }, + "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr": { + "address": "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr": { + "address": "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894220, + "birth_edge": { + "sink": "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "sources": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "value": 849094919, + "signature": "4MJQDBRmFT2jFhKZx7rY84rz4GThjUhU2twqk6URjTrCx1k6SQwZd4toBBR6bKnqS7GvPowPP17GnwJw8DGFqviH", + "slot": 394707768, + "block_time": 1768894220, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "funded": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ] + }, + "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS": { + "address": "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t": { + "address": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9235 + }, + "first_seen": 1638557855, + "birth_edge": { + "sink": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "sources": [ + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT" + ], + "value": 1500000000, + "signature": "54yv3HKUtdYAymSqK7g6Hv3Q3CX9ugxzGJ2SZSF2Mv5oq28tBAwGVdKC6d9NXfbfcxSdkxjaUWson8cdW2Hw2ruH", + "slot": 109908841, + "block_time": 1638557855, + "ambiguous_attribution": false + }, + "fee_payers": [ + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT" + ], + "funded": [] + }, + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV": { + "address": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5586 + }, + "first_seen": 1774645255, + "birth_edge": { + "sink": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 500000000, + "signature": "3wVtJf5fiq7g5cSb8ynKPJswdRx5RQ7GV1oPF1BMiFYKpAkf6T4ZdEbrnfEMQR3DLusyex4JCeZ8aSr9xxYkiuuq", + "slot": 409285335, + "block_time": 1774645255, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [] + }, + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za": { + "address": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 739 + }, + "first_seen": 1784934334, + "birth_edge": { + "sink": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "sources": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "value": 52977372793, + "signature": "4JY37vAAtVC9a5sQn4z8CY5mRJ5t8njqiBziNK9Ps8QtpG9m1qPsfCLFFo8HuGFjdPNTUtDaLQ9v2TF1auyUDWg7", + "slot": 435012131, + "block_time": 1784934334, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "funded": [] + }, + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p": { + "address": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1783475831, + "birth_edge": { + "sink": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "sources": [ + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ" + ], + "value": 388393719000, + "signature": "5imCWUcQWCKj7vDdLUbDXDeE567zN2Eg4Le8AWi6v7f1ZnsbtijSC6i65rA6BpVCsK9kc9fRrBwF4jGBARwWPf1m", + "slot": 431495612, + "block_time": 1783475831, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BrGihgGjCmpu2p96rou6GQj3sQpwgeud937jf4RvZP9G" + ], + "funded": [] + }, + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3": { + "address": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1784433292, + "birth_edge": { + "sink": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 669228400, + "signature": "66Tc5f3Uko3nDvDySXyoV4rhTBSka9cPczYiReZ8upWdrXKNhRGUHTTsZizm9mdNDEYdTkUmfuynxX3QEPjthemd", + "slot": 433821901, + "block_time": 1784433292, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs": { + "address": "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783951130, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk" + ] + }, + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV": { + "address": "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u" + ] + }, + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9": { + "address": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784926254, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ] + }, + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA": { + "address": "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 15633 + }, + "first_seen": 1739951269, + "birth_edge": { + "sink": "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "sources": [ + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR" + ], + "value": 3000000000, + "signature": "2GUhQXYjQ56ULyk5kFQ5pfduXNtqXhiikEMcLeZBaVDu2zrQfTDkt9bpVV6ETHzmmXaJn7oyGxu73eK9FqtRTF3g", + "slot": 321645004, + "block_time": 1739951269, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR" + ], + "funded": [ + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF" + ] + }, + "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7": { + "address": "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk": { + "address": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 142 + }, + "first_seen": 1784420501, + "birth_edge": { + "sink": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1488750000, + "signature": "5reLwzaWen3xeyYobmDJv4AWkboVwkmQea8aqnBXo6AW86tVotCN8aD4HVUseVngB1i8Nz7bWPVayfkXMjq2NZWd", + "slot": 433791379, + "block_time": 1784420501, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S": { + "address": "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894225, + "birth_edge": { + "sink": "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "sources": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "value": 849089919, + "signature": "5mpXMBqiqCUXVfjKe2fqnfr1yXBFt2MnSb5sU4PhDCru1KLnWw7Aji9tVP8ywUoP2X2yAAsgDnLsybmSY33VB9LJ", + "slot": 394707780, + "block_time": 1768894225, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "funded": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ] + }, + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq": { + "address": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 54 + }, + "first_seen": 1784676427, + "birth_edge": { + "sink": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 49804000, + "signature": "2ksPaRqePKa3tLNgb6dfJ4xGxBvHsRJuNXeikfUEuupy8NvcTgf3AL8cq7AZRYALiWDeKz2BWxhNZdDHxdVEoDQg", + "slot": 434397667, + "block_time": 1784676427, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx": { + "address": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1784813668, + "birth_edge": null, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [] + }, + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY": { + "address": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19394 + }, + "first_seen": 1774644767, + "birth_edge": { + "sink": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "sources": [ + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv" + ], + "value": 5972990500, + "signature": "2FGgEReXPwdXR3S6e4R5wxsotsqmfJU3EEC2QmGDtQF5WxGAspSae7s8GWY2FGx4o9u1oyWSsWMrPznZdTD7KNkn", + "slot": 409284086, + "block_time": 1774644767, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv" + ], + "funded": [] + }, + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB": { + "address": "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT" + ] + }, + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S": { + "address": "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1310 + }, + "first_seen": 1781821301, + "birth_edge": { + "sink": "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "sources": [ + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk" + ], + "value": 600000000, + "signature": "3B7AsVriGEHPW4TRFBkaFhV6YD4RDZ1w7g4UwNtT7psQb95ZMifH6v4QDUwL1k42tLpqhGqiExaje5LTEMkMBwQ8", + "slot": 427377690, + "block_time": 1781821301, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk" + ], + "funded": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ] + }, + "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB": { + "address": "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz": { + "address": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 963 + }, + "first_seen": 1774473115, + "birth_edge": { + "sink": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 34895500000, + "signature": "3omGYaNeXk9VjMv3rTp9aoaJrkED6b9jTiHoPx4UbRupiWmUn7op8udTBwguzph7YGJWQpNEhnv1FFDskSRsZANh", + "slot": 408844844, + "block_time": 1774473115, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g": { + "address": "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g", + "owner": null, + "executable": false, + "signatures": { + "Exact": 387 + }, + "first_seen": 1783864288, + "birth_edge": { + "sink": "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g", + "sources": [ + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99" + ], + "value": 15184373714, + "signature": "H1qHMYUqhmFjKH3uLfmAM4qZqHch53iJgKFsf93aSE4nfPZujKefZuX633Rn2aSk1PkWTbw341zXYNTC1ZNBTqT", + "slot": 432444990, + "block_time": 1783864288, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99" + ], + "funded": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ] + }, + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE": { + "address": "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1750857325, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ] + }, + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw": { + "address": "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 277 + }, + "first_seen": 1780094619, + "birth_edge": { + "sink": "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 2991500000, + "signature": "84Spr3goYUhDoyS5JCevCc1nDRjo6vWCWeKajzmd3qHWAmsNkBoEjw8322ajWKS5GJyVShK56h1ZUh2VdxtBeCz", + "slot": 423031442, + "block_time": 1780094619, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ" + ] + }, + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme": { + "address": "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1712133901, + "birth_edge": { + "sink": "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme", + "sources": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "value": 981006000, + "signature": "2718Lqzzrche69Pqhrt41GqkDBghW5SrqpxVVjrYV5fDNZ2tdipmhyYVKaXEj7Fex4h5mF5NMJ5QU8ohazEukjZG", + "slot": 258093459, + "block_time": 1712133901, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "funded": [ + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW" + ] + }, + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF": { + "address": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1758995033, + "birth_edge": { + "sink": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "sources": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "value": 10000000, + "signature": "5eJNQ4bhKNQYiTVSpUhrHjGpFSs7Ft4GKLrJWqAK5BTnkuzd1xqVV8P1FcpXKG6Zb77U9qdDkyVN6gz1UYzoeB1T", + "slot": 369652410, + "block_time": 1758995033, + "ambiguous_attribution": false + }, + "fee_payers": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "funded": [] + }, + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x": { + "address": "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894183, + "birth_edge": { + "sink": "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x", + "sources": [ + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha" + ], + "value": 849124919, + "signature": "4b7V78kfU1AxK6fRrczLLEdLEkMQfF6AurV4jSBMBVLEKstbLTQ65VSPjVyWmyRmz1VuMQNDC7vV1gQDAiLtLdrV", + "slot": 394707672, + "block_time": 1768894183, + "ambiguous_attribution": false + }, + "fee_payers": [ + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha" + ], + "funded": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ] + }, + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW": { + "address": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11302 + }, + "first_seen": 1728079811, + "birth_edge": { + "sink": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "sources": [ + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme" + ], + "value": 200000000, + "signature": "4rvwJT124GYcZAHHJJBqaZ9YRgnxYLF4nQ58wLbJSr1Z9BgH2NXyKvMRRCbN7CUWooZ9BMNPYAACSwPAqq7NgLvt", + "slot": 293725783, + "block_time": 1728079811, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme" + ], + "funded": [] + }, + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG": { + "address": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 27 + }, + "first_seen": 1784565160, + "birth_edge": { + "sink": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "sources": [ + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "value": 232000000000, + "signature": "28bt62zYkiihXsM3o7rp2D6YS63G8CpZwUzpqqp2b8jNzGoUih1PWx9FGMdwfQFAEdRGTgz15pPQ8j9uZgDeyvw8", + "slot": 434133197, + "block_time": 1784565160, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "funded": [] + }, + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j": { + "address": "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 72 + }, + "first_seen": 1682118021, + "birth_edge": { + "sink": "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j", + "sources": [ + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ" + ], + "value": 11744752320, + "signature": "pALYeH3rq18atGAUHgbqmMBXckY34TfyqKywTwxPzmeg23rXbtbqW9mf3NMct3WsizeZszfuwskkXvbGefvGRRA", + "slot": 189742217, + "block_time": 1682118021, + "ambiguous_attribution": false + }, + "fee_payers": [ + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ" + ], + "funded": [ + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9" + ] + }, + "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG": { + "address": "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP": { + "address": "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "owner": null, + "executable": false, + "signatures": { + "Exact": 999 + }, + "first_seen": 1784462436, + "birth_edge": { + "sink": "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "sources": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "value": 49648773129, + "signature": "3xd1Te2qtTYHjh2ohyorXsFLgxgWxaveB9tfyGzszJf9MmM1XHhFzQoi5C5ftnUWhXMPRvJpBuHpFidFgZVh2i3g", + "slot": 433891472, + "block_time": 1784462436, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "funded": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ] + }, + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ": { + "address": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 32 + }, + "first_seen": 1784389227, + "birth_edge": { + "sink": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "sources": [ + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb" + ], + "value": 807208726, + "signature": "3vny3LuBCtnjHmNBUw4YGWxGiJdB6MDgCTTwB85ixPF8urpfbhjUiR3DJvptVkoB82k8MLKxgudAvq8m5CPLHCG", + "slot": 433716525, + "block_time": 1784389227, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb" + ], + "funded": [] + }, + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH": { + "address": "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1705 + }, + "first_seen": 1715894645, + "birth_edge": { + "sink": "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "sources": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "value": 106710780, + "signature": "xDgEvEFQw8Qer5vQHtG755NyT2FHXPnFV9CPvhuvZn4NfZ3b5tWrUL5wDcGVyBDVSSA13r7Y6Tgtdp2mjrmHZrH", + "slot": 266193828, + "block_time": 1715894645, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "funded": [ + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo" + ] + }, + "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH": { + "address": "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ": { + "address": "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1697388134, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j" + ] + }, + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u": { + "address": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784630445, + "birth_edge": { + "sink": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "sources": [ + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV" + ], + "value": 6831797746, + "signature": "4V6TatwrgYYdAXsbYZ58LgACqMKm51JVfQ6cgiJvjtXwvz8NPjZbhsrz9j2QvwKXXv18bkkgtJScAaw5wZy5sKZk", + "slot": 434288158, + "block_time": 1784630445, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [] + }, + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5": { + "address": "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784362513, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ] + }, + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7": { + "address": "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 176 + }, + "first_seen": 1731698151, + "birth_edge": null, + "fee_payers": [ + "4ritJBeodrzcSDDeAJbKafJniczjYhAfsoZRXTQq9h82" + ], + "funded": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ] + }, + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT": { + "address": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784049521, + "birth_edge": { + "sink": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "sources": [ + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB" + ], + "value": 2110033428, + "signature": "1tK2a5Q2E19ZBWkhkhMDf36cuv8NZD8pcRFbVhxkR4kedkEjLsxS7dD1QsKHuZ1T77XRbGiWQx9fnQWcDtgLQmD", + "slot": 432895720, + "block_time": 1784049521, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH": { + "address": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784564457, + "birth_edge": { + "sink": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 156610510360, + "signature": "3HmDQGGFDNXPquCgrBn4oFueH8EcudAUohYxWiRVekmuX53cZhFotqNnLLPzUEeBnnhHikzZWtUwuP2M6K8EZq1L", + "slot": 434131562, + "block_time": 1784564457, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U": { + "address": "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1782852024, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ": { + "address": "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p" + ] + }, + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx": { + "address": "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784205554, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC" + ] + }, + "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E": { + "address": "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1673079363, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1": { + "address": "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2157 + }, + "first_seen": 1684141322, + "birth_edge": { + "sink": "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "sources": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "value": 90000000, + "signature": "52ZPH7cfAzwauMYh529GgHWhTzRwReNdJyWYr5ZugsAB5gvSmP6CYuCV1U79B9SLxLjk6qy5nsDUmao8Xa5y5EBB", + "slot": 194024003, + "block_time": 1684141322, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "funded": [ + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6" + ] + }, + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1": { + "address": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5535 + }, + "first_seen": 1747156899, + "birth_edge": { + "sink": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "sources": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "value": 1000000000, + "signature": "2cATjnRUeA8sBSjhU4udUTHwqFk5cLQfx2mMZ7isJfKvdfGEJNn4q3Ex72Ww3fRNX7JUQTGpy25R6FVdfFwRP5dV", + "slot": 339786892, + "block_time": 1747156899, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "funded": [] + }, + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb": { + "address": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1391 + }, + "first_seen": 1778270115, + "birth_edge": { + "sink": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 31543190000, + "signature": "23eCmHrxuyS6rMmjNNDsJtUZk4vesD5maoraeVjWmqKuLe1yeuELQgEDaqfBDUWSTrkM3iuQFUWAsPpkjAiD6meJ", + "slot": 418463518, + "block_time": 1778270115, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr": { + "address": "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1774935711, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ] + }, + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha": { + "address": "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894180, + "birth_edge": { + "sink": "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha", + "sources": [ + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t" + ], + "value": 849129919, + "signature": "z18ostGmqULsMip19y3QrR6sRFfittsoYwNTF1SjPA5iLq1dJfQw8yJvyWKryxBGjhXnhfnVPiuUjpFyggjQj8v", + "slot": 394707664, + "block_time": 1768894180, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t" + ], + "funded": [ + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x" + ] + }, + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu": { + "address": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20517 + }, + "first_seen": 1743263000, + "birth_edge": { + "sink": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "sources": [ + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X" + ], + "value": 770000000, + "signature": "rWZNiWUUErqSurTeKbooG5bPJgChg9SvYyYCsgNUy6AXuiHTsyVDYCyzCmYssFrs94PhG2ok9FwYAkVEDrK6efw", + "slot": 329977339, + "block_time": 1743263000, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X" + ], + "funded": [] + }, + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu": { + "address": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 430 + }, + "first_seen": 1783530592, + "birth_edge": { + "sink": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "sources": [ + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o" + ], + "value": 3608900737, + "signature": "39zbFyzcd2pWwLEQBD1gB1qWrjTekKNiicL8TpyjTAoyLABpT518QVo9WVz8yxdzCJF1WiRcvuHzJRR85WFBXjfv", + "slot": 431630423, + "block_time": 1783530592, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn": { + "address": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784565684, + "birth_edge": { + "sink": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 841356800, + "signature": "4Y2A99s86tDM9Ef8DQ62ED34YhLejSy9dfkYDHR2rAi6kcnSNvg5pW1F83RyJuHK4DPoxkN5mAkvqvyA1EHJj4Wd", + "slot": 434134426, + "block_time": 1784565684, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh": { + "address": "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894217, + "birth_edge": { + "sink": "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "sources": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "value": 849099919, + "signature": "4UhWatoFQvHLdrg56s4qh3NjJaa9jpsS55YeGbi2FwyNHuoqfnZBLZx3npfoyjhFbvMaNm5vxYmYSAkjPdK2Gioi", + "slot": 394707760, + "block_time": 1768894217, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "funded": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ] + }, + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp": { + "address": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 205 + }, + "first_seen": 1775579392, + "birth_edge": { + "sink": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 9131905000, + "signature": "3zWVxUN5PpQhBBHTb7q2iVdGYZWzYX96QFS1nC467YtQBSKuqjZzLFQEPh816DEVyZmtn6xdFvssDpQqdopjccPh", + "slot": 411667852, + "block_time": 1775579392, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi": { + "address": "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1780957321, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ] + }, + "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY": { + "address": "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR": { + "address": "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784446630, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL" + ] + }, + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf": { + "address": "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1778787271, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ] + }, + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW": { + "address": "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1782168865, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM" + ] + }, + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx": { + "address": "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894233, + "birth_edge": { + "sink": "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "sources": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "value": 849084919, + "signature": "4MQSbWiBDWsVRVVKMjprc9fMfevDFzvAJJDcTd7PPwkGKXTfqJtB5frc9naHWzJv1S5yi3XLnmKZPMEbQx95M7aU", + "slot": 394707800, + "block_time": 1768894233, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "funded": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ] + }, + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ": { + "address": "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784653077, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16" + ] + }, + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW": { + "address": "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "owner": null, + "executable": false, + "signatures": { + "Exact": 711 + }, + "first_seen": 1663704019, + "birth_edge": { + "sink": "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 3079735480, + "signature": "24tTRqCdoMDLxwi41jhddFdaqydjZowSRXZHW2xuBqNttskX1ej72PhQUDqGoiF9jY5u9i8kbdyMcx5MMUrRWXsD", + "slot": 151573078, + "block_time": 1663704019, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq" + ] + }, + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t": { + "address": "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894166, + "birth_edge": { + "sink": "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t", + "sources": [ + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe" + ], + "value": 849134919, + "signature": "2HfqS2otjA4GU4BjEiL2ei8YhTcqcwpSZYh7L5E7UfwfaigJ78sP6qi22gs9zZjcZFk8S3FkSK1tf7Zx5CSAKmYE", + "slot": 394707631, + "block_time": 1768894166, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe" + ], + "funded": [ + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha" + ] + }, + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ": { + "address": "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2412 + }, + "first_seen": 1781821309, + "birth_edge": { + "sink": "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "sources": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "value": 500000000, + "signature": "4wVPQe58DmcHwkdVmHuvqWFGnQZhQ4ndiumpcrvNSYx6bL2bBCk6CCNeWpKDPzvc8Y68RpfFKuCrfScRuL2VaE58", + "slot": 427377712, + "block_time": 1781821309, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "funded": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ] + }, + "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo": { + "address": "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk": { + "address": "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784996107, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD" + ] + }, + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX": { + "address": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 16379 + }, + "first_seen": 1774739788, + "birth_edge": { + "sink": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3440555488, + "signature": "3YjE4YpSZT1wXeSk57dn8UrLTMQEWkLqF2r7LpApgEvjMt2h6k5GrkEQfeu4JtsHkPZJvVKqGZkhzKeDxFvroTJj", + "slot": 409527481, + "block_time": 1774739788, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ": { + "address": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 107 + }, + "first_seen": 1783458420, + "birth_edge": null, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ": { + "address": "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 618 + }, + "first_seen": 1774728729, + "birth_edge": { + "sink": "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "sources": [ + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "value": 11650417543, + "signature": "5TnbPcr9zLALAWF82aL7PVBNbX7PkaUTzdXgAWEnvZAeE8n5cYzXhyEKh438w9uj6LrF316rj73McA84g5DHueHM", + "slot": 409499170, + "block_time": 1774728729, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "funded": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ] + }, + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG": { + "address": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6 + }, + "first_seen": 1784519630, + "birth_edge": { + "sink": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "sources": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "value": 104889883544, + "signature": "5162f689Bxmi9PA5Fj9QVxBuxjHrWqbJnoHVVjnmUg4HB9j8XnMvUmLaugVAcyEnAbpiPQNQiukSiE2D2H2AUKaQ", + "slot": 434026767, + "block_time": 1784519630, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "funded": [] + }, + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC": { + "address": "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1748177913, + "birth_edge": { + "sink": "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "sources": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "value": 1029000000, + "signature": "CfG62TFDb4cuNH7FNWz4Cr2Ga14r88NoTXbSDkWmGSDhFTqxdKxinZcyAeSJ33eE1VPiqfwfgcBcmyMRijYEDNb", + "slot": 342369414, + "block_time": 1748177913, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "funded": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ] + }, + "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM": { + "address": "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783098061, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm": { + "address": "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784580094, + "birth_edge": { + "sink": "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "sources": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "value": 50607243678, + "signature": "2h4gvshcwfRhkDXQhiLMAWYTWM4xMUnW8iGdJpEnhQRUYZy5DuMQma319GnL8wCprP7MTXGgb8ymBWvQ1jwTwoht", + "slot": 434168171, + "block_time": 1784580094, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "funded": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ] + }, + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m": { + "address": "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3738 + }, + "first_seen": 1632342722, + "birth_edge": { + "sink": "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 2099995000, + "signature": "56mSUdyemWLDwZbWDjZCUhJDHGqgJaGiMGVKSDovzLsM54Lc26JshmZPgz4R3N6Se2B12z8CkeAQGsQz8ELb4XjJ", + "slot": 97853541, + "block_time": 1632342722, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT" + ] + }, + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K": { + "address": "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 581 + }, + "first_seen": 1775667915, + "birth_edge": { + "sink": "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "sources": [ + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "value": 12399485120, + "signature": "1hqU1oga3ZT4F3uT5iAm3W4zB3eiH9vd2Rop2Rtyva35zubCfiYZCFgAaSaBCD48a3iTz1aL9zpTnZ4JRq6yZE5", + "slot": 411892813, + "block_time": 1775667915, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "funded": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ] + }, + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE": { + "address": "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE", + "owner": null, + "executable": false, + "signatures": { + "Exact": 930 + }, + "first_seen": 1784212794, + "birth_edge": { + "sink": "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE", + "sources": [ + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g" + ], + "value": 23308100465, + "signature": "48hdxxJEtMvxPq47QrfdcsDqMDNP8FzBPgM3RN4YfsmFxFrnsRSuNHEdiXcnjYTxujSyVAooQqfo271w8BCoKFVk", + "slot": 433291812, + "block_time": 1784212794, + "ambiguous_attribution": false + }, + "fee_payers": [ + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g" + ], + "funded": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ] + }, + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38": { + "address": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 567 + }, + "first_seen": 1759849779, + "birth_edge": { + "sink": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "sources": [ + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "value": 1000000000, + "signature": "55aNfhpFmWyptpJ52kvWWSpaHePRjZLDNbf9kzwSKgUtvvcp4XFhGpKXbU5tVD4wYFh3DrtjJpfnKfLoyGKkadYN", + "slot": 371813843, + "block_time": 1759849779, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "funded": [] + }, + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6": { + "address": "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784387653, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme" + ] + }, + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo": { + "address": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3597 + }, + "first_seen": 1736334578, + "birth_edge": { + "sink": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "sources": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "value": 170000000000, + "signature": "2MLS8L4uUc8L3nNZpej5csKZ3d5JuNqKGkUjpX1E1ebmqEBzcxBP3ZccC4FvbAgAFWchKPoey8mhH98JCnCxCQ9x", + "slot": 312653033, + "block_time": 1736334578, + "ambiguous_attribution": false + }, + "fee_payers": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "funded": [] + }, + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw": { + "address": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 155 + }, + "first_seen": 1780608496, + "birth_edge": { + "sink": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3965000, + "signature": "2jPiYFrpAtgu9YXus8V7NPkAWW6xWy5zBdh42P7S5sticdDDVgPGo91ne8yDeLjXhZHyH6zxZnWg69yPXRApwheC", + "slot": 424324895, + "block_time": 1780608496, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ": { + "address": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2999 + }, + "first_seen": 1780098381, + "birth_edge": { + "sink": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "sources": [ + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw" + ], + "value": 800000000, + "signature": "3owWqGQL5cNVZcCTN235bbaS2gyez3LxGz663Gej6dtmqBhUyrbhJNfoP1VaVryXN47bdKWoxji34CAu6oUPsxdP", + "slot": 423040927, + "block_time": 1780098381, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw" + ], + "funded": [] + }, + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P": { + "address": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 96 + }, + "first_seen": 1784854429, + "birth_edge": { + "sink": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "sources": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "value": 6000000000, + "signature": "5KA9mkbPhkRXKEhf1FeiRuxHphiMMkRgq3FsNjkKk2Ra7gRMMqmB7V5gEvocEESMeK24LVsUC24gWjBx7EyiX3Kp", + "slot": 434821643, + "block_time": 1784854429, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "funded": [] + }, + "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis": { + "address": "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD": { + "address": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 627 + }, + "first_seen": 1753997946, + "birth_edge": { + "sink": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "sources": [ + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "value": 123066991, + "signature": "5Rtx3JoWd3XaAGxkckRh6w7aeW4W9M2ZbG8NQt7SDLdunYiy5eHXiF3Kc9Dp8QBMJABzH2T2ctoAzCEZF57ckAAB", + "slot": 357026958, + "block_time": 1753997946, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "funded": [] + }, + "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA": { + "address": "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr": { + "address": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1784599658, + "birth_edge": { + "sink": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "sources": [ + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW" + ], + "value": 440000000, + "signature": "4QJkfNCAWjNh2mfYrx9WN6EBe6cCpPUABueLgf4WfqJ5smBUdqbHDcsQXAHT6d8a6q4hFNMvf7jAozFE4jw1rXwj", + "slot": 434214781, + "block_time": 1784599658, + "ambiguous_attribution": false + }, + "fee_payers": [ + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW" + ], + "funded": [] + }, + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob": { + "address": "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 134 + }, + "first_seen": 1784218241, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG" + ] + }, + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh": { + "address": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784649420, + "birth_edge": { + "sink": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "sources": [ + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "value": 1850143000, + "signature": "3YgFygisXK1X8kyUXV6LzPEcJ36tKUDkuyo7UvX3KdwULNGDe2wLYiB7KSCVcyM9NejVf2Q4Gr2KV2p11SSvGbCy", + "slot": 434333385, + "block_time": 1784649420, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "funded": [] + }, + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb": { + "address": "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784389224, + "birth_edge": { + "sink": "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 807213726, + "signature": "2MwPJoYeQHsFvpTXyue8m776mx5fBtFDYgY7hcZpTuz641UR5R8xz7yoe7NXT8e1mRojMFpwKs6Pkdk1fFgSe6zr", + "slot": 433716518, + "block_time": 1784389224, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ" + ] + }, + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT": { + "address": "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1784838909, + "birth_edge": { + "sink": "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "sources": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "value": 6000000000, + "signature": "3wsTxnCcjxate2zoeFse3mstAwC5KUkvVH4AWjgi9FTKZmwvm7vjJb7N5EPGR5rpcDePeFVXxopoMKiWRsG67bTu", + "slot": 434784661, + "block_time": 1784838909, + "ambiguous_attribution": false + }, + "fee_payers": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "funded": [ + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P" + ] + }, + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB": { + "address": "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 44 + }, + "first_seen": 1768894237, + "birth_edge": { + "sink": "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "sources": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "value": 849079919, + "signature": "ZPtjQoLcno8LwEZaoxwJrAZfMfcHmszyxAA1V2FW6ohJxa3tbczaP1T4s4d5HgxHTxDS7tTjRK5GnV3x55nWPCQ", + "slot": 394707808, + "block_time": 1768894237, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "funded": [ + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG" + ] + }, + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN": { + "address": "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784377763, + "birth_edge": { + "sink": "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1299793806, + "signature": "wbcYZ4GZzni8ThU986zLwqQUmhcY4gZfGFBbC1ffpv6TwUkWtxPLvUt6FB3fT9DvuaEKu21bsm6RwpSBVgrkiEh", + "slot": 433689096, + "block_time": 1784377763, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9" + ] + }, + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU": { + "address": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784657908, + "birth_edge": { + "sink": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1996965000, + "signature": "5bJGTURSxfgDoe8QBCjFXtRwNcrBHqLyN8oJ3HjztNDMnbgtzNG11DtZ51MgkqAkcii2BWghA9KB3MitvWTQxF5d", + "slot": 434353532, + "block_time": 1784657908, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94": { + "address": "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894203, + "birth_edge": { + "sink": "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "sources": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "value": 849109919, + "signature": "2XXhJExg7yyA6WH34H5Q99ZtCVavER65hC3V7tf6oNm5onx4KDVoDEpSgAaoupvn721NrE7KdSiMQ4cjKZY1UfJy", + "slot": 394707725, + "block_time": 1768894203, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "funded": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ] + }, + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR": { + "address": "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12753 + }, + "first_seen": 1710763330, + "birth_edge": { + "sink": "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR", + "sources": [ + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9" + ], + "value": 1200000000, + "signature": "3BsEYvaLSedjLWzUCzbGUVGT33rwY35m6mzWnXSLit5zTTJ7vctb7oDjhv1mCdUZLWtRHcLMYSxYz5Dp4hhhc5Nw", + "slot": 254924622, + "block_time": 1710763330, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9" + ], + "funded": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ] + }, + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz": { + "address": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12525 + }, + "first_seen": 1781801872, + "birth_edge": { + "sink": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "sources": [ + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe" + ], + "value": 100000000, + "signature": "2B1U3i2nZKDXancwuyt9UxUa7AJcqgiVyuXzZhECVSZwiy5CKYE7xe5KcEgGymmMS2FcifLQRD7PNgDhhE3zGEkJ", + "slot": 427328708, + "block_time": 1781801872, + "ambiguous_attribution": false + }, + "fee_payers": [ + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe" + ], + "funded": [] + }, + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU": { + "address": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2660 + }, + "first_seen": 1777272559, + "birth_edge": { + "sink": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "sources": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "value": 2500000000, + "signature": "ETzNdupbU3xXhkPGEw9Hn8tPN6NDugSpsVob4iHjzcfzccdcUAisMiYbqkwSbCm6AxsfqxZvhjfCCUC3P1kEHRc", + "slot": 415950310, + "block_time": 1777272559, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "funded": [] + }, + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U": { + "address": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 272 + }, + "first_seen": 1757688961, + "birth_edge": { + "sink": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 93700000, + "signature": "3PeWiircHtHEH9T78i4FKAoUNP3568WEdnJr8PgTPdhPPi958X6NrtthHtGn2r21ovMKKWwCo8TkMtc6rmzw6odX", + "slot": 366350032, + "block_time": 1757688961, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR": { + "address": "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1776160820, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi": { + "address": "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18105 + }, + "first_seen": 1738500891, + "birth_edge": { + "sink": "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "sources": [ + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf" + ], + "value": 29400000000, + "signature": "4ChkDoLctkN81tVBKsZMZVqvdAZViy4zrsKb9K8FiiuD4zvuJnzXq2qjMZAnVNqReUqo7Tb12d3knN7qTDW96mZw", + "slot": 317992649, + "block_time": 1738500891, + "ambiguous_attribution": false + }, + "fee_payers": [ + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf" + ], + "funded": [ + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1" + ] + }, + "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX": { + "address": "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff": { + "address": "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784043064, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x": { + "address": "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784934326, + "birth_edge": { + "sink": "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "sources": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "value": 54374849153, + "signature": "4Y7SpKFVWPXmK1GJQMsZfuQnxiYyoi7NcJbchUzRemXMGt3DWRUWJBT7L8seY3MymYCvHhSv7XravPdS34KHgmpL", + "slot": 435012112, + "block_time": 1784934326, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "funded": [ + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za" + ] + }, + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn": { + "address": "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784432144, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9" + ] + }, + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K": { + "address": "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K", + "owner": null, + "executable": false, + "signatures": { + "Exact": 55 + }, + "first_seen": 1730861242, + "birth_edge": { + "sink": "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K", + "sources": [ + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF" + ], + "value": 50000000, + "signature": "BoLFuKgcg38xZSUt14Y5926pkU6LLbaXAKPHPqTzfCKUCYyRNa5T3msnqj7QtwrjP8FUFHxsTKELrjYKA1gUvtX", + "slot": 299749544, + "block_time": 1730861242, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF" + ], + "funded": [ + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs" + ] + }, + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq": { + "address": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 294 + }, + "first_seen": 1764868637, + "birth_edge": { + "sink": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "sources": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "value": 1390000000, + "signature": "42jLxFrfSKoLo8ZPnaMZfGU56WVo4mrSi1RUEweRK84j2R4vSSRetdHu9HErxgK6eR87R6vt2c7T2C4KUTaDjf4F", + "slot": 384466286, + "block_time": 1764868637, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "funded": [] + }, + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do": { + "address": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1776858197, + "birth_edge": { + "sink": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "sources": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "value": 1007615782, + "signature": "2KPM9xqT2mfMAqEZDX51t6o3RgYoLnJZgU6NPzZ57YV14DZy8VsnyYxntqnKbhtYAZwE4puvnjUP9PmE5y4aUBa1", + "slot": 414903289, + "block_time": 1776858197, + "ambiguous_attribution": false + }, + "fee_payers": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "funded": [] + }, + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW": { + "address": "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 545 + }, + "first_seen": 1778972678, + "birth_edge": { + "sink": "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 6632702930, + "signature": "vJcCHLLH6FaWPDarJWTvMdpKckbK9yPGhy9qgUgypRyheTmVdPiEMf5vCioqKT82iF8G7VZ95vXGuYWoECTAh2B", + "slot": 420215149, + "block_time": 1778972678, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr" + ] + }, + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH": { + "address": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 369 + }, + "first_seen": 1745361264, + "birth_edge": { + "sink": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "sources": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "value": 1000000000, + "signature": "5Ugmig4PTLRcf3GTuiY6G47gQn5bxj3UDp4YpKDsvY1JaPwwn1DMU1bQPnTXgrP8wQtrEZfmpLthv8gjADrp7mpu", + "slot": 335243820, + "block_time": 1745361264, + "ambiguous_attribution": false + }, + "fee_payers": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "funded": [] + }, + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o": { + "address": "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu" + ] + }, + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn": { + "address": "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5289 + }, + "first_seen": 1702336727, + "birth_edge": { + "sink": "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 4372981634, + "signature": "5KeWCHfUdwtMws4e48ZDAqSa2K6bFWeiX4irurLzrFw1geWqtgjHvY1F8T8Cma4n6XuaJ3TbQBaKFZjeLGEK6Wau", + "slot": 235369057, + "block_time": 1702336727, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH" + ] + }, + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM": { + "address": "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 157 + }, + "first_seen": 1780522066, + "birth_edge": null, + "fee_payers": [ + "7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q" + ], + "funded": [ + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW" + ] + }, + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx": { + "address": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1150 + }, + "first_seen": 1737448881, + "birth_edge": { + "sink": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "sources": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "value": 672745485, + "signature": "64C1Msn6wiLA7U5x5ZjYhPx2cj813py9Pft9Bc41VYtbtWHinBJefXt3rj5KaWTuvXC7aoYwr3Y8tsfj1zed1ZSw", + "slot": 315391758, + "block_time": 1737448881, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "funded": [] + }, + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ": { + "address": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 58 + }, + "first_seen": 1783645887, + "birth_edge": { + "sink": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 14433952357, + "signature": "4RbXiaGAmS7WfUmruWn3zBUTwaF2WzVDno2bSTiZFH7cbYSeVeUGgS184pvQaV3ySoRBNGkx6r68M8r5AA5ZbJTo", + "slot": 431912014, + "block_time": 1783645887, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp": { + "address": "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe": { + "address": "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785023492, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ" + ] + }, + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL": { + "address": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 89 + }, + "first_seen": 1784429559, + "birth_edge": { + "sink": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1987000000, + "signature": "22tiKy2Uhr5HbzaoUTkf5gTS2VHov1xMY998kBCQbYybACx6Y3fJtxRBaj8ppaMyahAGEgnC5SggnKt6HbxcwNRb", + "slot": 433813000, + "block_time": 1784429559, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B": { + "address": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 145 + }, + "first_seen": 1769758558, + "birth_edge": { + "sink": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 193300000, + "signature": "52ygQjkxX6CiTWcaT8KoncyGrbR97uAqzrJ91LySCtkZDCNDa3WTHpnvNSJkRXacynWy4D5j16sFCh1PWGdesPET", + "slot": 396868730, + "block_time": 1769758558, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt": { + "address": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11 + }, + "first_seen": 1784509948, + "birth_edge": { + "sink": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "sources": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "value": 14000000000, + "signature": "55y1RvP9p644eWZy6JypDF39fB4u7XCBXYmQhjDRX5AgytWCpsC2J4SiffzCo9gLPHpPoqs6AXrCXyb7mgUooZXD", + "slot": 434004156, + "block_time": 1784509948, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "funded": [] + }, + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm": { + "address": "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894210, + "birth_edge": { + "sink": "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "sources": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "value": 849104919, + "signature": "2ga76DPJVD9CWDYmtpb17BURi9EcLNFxeNFi172x5aRN9es1qAh5HRHf9ZNCzGtADfp9LzzcF2t26MdDn5jEDT5C", + "slot": 394707744, + "block_time": 1768894210, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "funded": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ] + }, + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor": { + "address": "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 856 + }, + "first_seen": 1783108022, + "birth_edge": { + "sink": "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "sources": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "value": 200000000, + "signature": "3XBCwvm2pUrPEp3PCUKm4NiNy7pGhpxqpy2u2eWnMBs5sJgoYk55DPp77RSEn4m2vL9C61sWiefBAiArFGEaUgFw", + "slot": 430586035, + "block_time": 1783108022, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "funded": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ] + }, + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd": { + "address": "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 48 + }, + "first_seen": 1765645486, + "birth_edge": { + "sink": "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "sources": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "value": 88200000, + "signature": "sH5bnyJn2BNFN3TgD2isA2G5ygXEsGzWr9kpgN2PW5Ubxk3nAHyLRprFmS5M2FzdbTTZD2RjxfgH7xfbARZtdHc", + "slot": 386459128, + "block_time": 1765645486, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "funded": [ + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ" + ] + }, + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM": { + "address": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1784461923, + "birth_edge": { + "sink": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 990500000, + "signature": "9duBpzRRMAZ2cQv2n79HKMzurHUBWmDWdDwNR8y6U48bnG6HKY2HZnrQxXNFVFpg8RtSy3KPNEY4ByMKHEBJCEb", + "slot": 433890247, + "block_time": 1784461923, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ": { + "address": "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1670 + }, + "first_seen": 1784580105, + "birth_edge": { + "sink": "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "sources": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "value": 49209767318, + "signature": "2BVoGzFZrFnuRLqpW1EAHxkFXmnp7xWp1wog4n3EBnCbTgQLvSgFVZHB8z4Z1FgdzjYGBh9tTUFZ1aLF2XtYCuKU", + "slot": 434168198, + "block_time": 1784580105, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "funded": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ] + }, + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN": { + "address": "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18203 + }, + "first_seen": 1712861701, + "birth_edge": null, + "fee_payers": [ + "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J" + ], + "funded": [ + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe" + ] + }, + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7": { + "address": "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 48 + }, + "first_seen": 1784809669, + "birth_edge": { + "sink": "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 5973000000, + "signature": "3MSs2ea12TniywAz7iM9anGzcgJr8oB1kCVxVQm8YgQxqoCwwPpzBhg6EACKhpDuWoT6J723YZfrnDq8qqfLSTRJ", + "slot": 434715093, + "block_time": 1784809669, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ] + }, + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k": { + "address": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 955 + }, + "first_seen": 1781405876, + "birth_edge": null, + "fee_payers": [ + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK" + ], + "funded": [] + }, + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B": { + "address": "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "owner": null, + "executable": false, + "signatures": { + "Exact": 15 + }, + "first_seen": 1737447329, + "birth_edge": { + "sink": "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "sources": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "value": 672750485, + "signature": "4gBVShePEtPdc8c9vLekxqxtKnHN1CaY2ECsfrU3Ysoo7AeQGVwwpqLDW9aAWYF3KSsekeoaA1aqHrTqAEHwSGuN", + "slot": 315387958, + "block_time": 1737447329, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [ + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx" + ] + }, + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv": { + "address": "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1774644756, + "birth_edge": { + "sink": "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 5973000000, + "signature": "5fTttEt3Pb3F4Sj5dKKrkqFCZEJqR37qyLLYVSA7GwBqbyn4MCv2LDEZBKuh9pGRhdxTJa7xNMKH6c53gXrno7RZ", + "slot": 409284059, + "block_time": 1774644756, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY" + ] + }, + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF": { + "address": "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF", + "owner": null, + "executable": false, + "signatures": { + "Exact": 253 + }, + "first_seen": 1730807547, + "birth_edge": null, + "fee_payers": [ + "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP" + ], + "funded": [ + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K" + ] + }, + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw": { + "address": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 14493 + }, + "first_seen": 1777091838, + "birth_edge": { + "sink": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 18571768434, + "signature": "44VV33bxUiT3rDmG3dtN2uxnDx4uBs6keq7PWCmx3rdqWhvPmPXJhrA7Sq7atABrqAkpaBZH5wdRRWMkFQ7j8kNA", + "slot": 415493545, + "block_time": 1777091838, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs": { + "address": "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7899 + }, + "first_seen": 1731918662, + "birth_edge": { + "sink": "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs", + "sources": [ + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K" + ], + "value": 11000000000, + "signature": "4NrJoknq1Jx9gtAQ8bxTuhWoNxMWggLDQS4XBN1zsNRVXGfCvC21JBkKGsxLH9hppZBa6KxaMLve5iiowk75DVLb", + "slot": 302103526, + "block_time": 1731918662, + "ambiguous_attribution": false + }, + "fee_payers": [ + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K" + ], + "funded": [ + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf" + ] + }, + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G": { + "address": "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1781110081, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg" + ] + }, + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE": { + "address": "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784771569, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV" + ] + }, + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT": { + "address": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784758056, + "birth_edge": { + "sink": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "sources": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "value": 90000000000, + "signature": "2yFwMANAjHWBoCUWXwsF2NS8Vm24oSkE5oJ6RfsDe2jPVeo782fE98nePAJqpuxWL1VkA5iQXoXdDoU8SqopCTR2", + "slot": 434591833, + "block_time": 1784758056, + "ambiguous_attribution": false + }, + "fee_payers": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "funded": [] + }, + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq": { + "address": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 65 + }, + "first_seen": 1784659136, + "birth_edge": { + "sink": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 32880718309, + "signature": "4wZbNhexVa96s82hAQbdZ9Pq1fqencGxxmKYCwghVjT6iwxMLyyKBssfwvWVJFXFMXxNwSfrDo8TqZ4AiJbEPC6U", + "slot": 434356458, + "block_time": 1784659136, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC": { + "address": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 294 + }, + "first_seen": 1783054209, + "birth_edge": { + "sink": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "sources": [ + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "value": 180834295, + "signature": "55tLEDwJyuDGaSo8c6yYz4bj5utz7zJiVtQnsQuwqKg7abdYWVoK1vFkLQd7pyJhjh4r8ku6i9oCyXRa8a6kX18z", + "slot": 430452695, + "block_time": 1783054209, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "funded": [] + }, + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf": { + "address": "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894200, + "birth_edge": { + "sink": "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "sources": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "value": 849114919, + "signature": "5Gb3um1roTYvbjCFckDeFVPkU7QxKeShYSL3KWDxSEX8qhCrwgDEJgbSiuL3L4tCXzk1GaguKXBbmAU2yjAVmkdG", + "slot": 394707716, + "block_time": 1768894200, + "ambiguous_attribution": false + }, + "fee_payers": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "funded": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ] + }, + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk": { + "address": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1152 + }, + "first_seen": 1777988933, + "birth_edge": { + "sink": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "sources": [ + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "value": 2362855000, + "signature": "Vdct3Y5hjgKy2gHHjimC9YE8faisFo7jz3EiFYjmb3yAYuHpY2tE5ZqJcXhMNtbrrXTRr5CxYpCz5djyYzwgJyb", + "slot": 417761237, + "block_time": 1777988933, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "funded": [] + }, + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho": { + "address": "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "owner": null, + "executable": false, + "signatures": { + "Exact": 600 + }, + "first_seen": 1784462427, + "birth_edge": { + "sink": "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "sources": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "value": 51022180729, + "signature": "4udxkWqxkyLqBAZpUJHNMkZDcFMVTq1BpaC2A5YqNGbm6He6WAYpQGQXMY5J91YcUxxZATqVkJooVP9y3EXqpABd", + "slot": 433891452, + "block_time": 1784462427, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "funded": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ] + }, + "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp": { + "address": "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF": { + "address": "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1744045119, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X" + ] + }, + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva": { + "address": "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1629 + }, + "first_seen": 1784212802, + "birth_edge": { + "sink": "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "sources": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "value": 22180583705, + "signature": "59BrgexB78Kj9fCJkHmKs2UZYsp5Ntc5ia4RpE3T1WS8xtwyJEhn49w5VcofBvhkHWa9AxfEQsR1L6qjNFKdZnhj", + "slot": 433291830, + "block_time": 1784212802, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "funded": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ] + }, + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS": { + "address": "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784769521, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ] + }, + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ": { + "address": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19785 + }, + "first_seen": 1780029667, + "birth_edge": { + "sink": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 2442413156, + "signature": "2UXxvAd3GMF7t1ZMWhrXJcFP3q6iYYcZBEMeynG6PWWz8vrttyjdwXo1KSxrYhGU8zchaaM6979gnU1mz4d3dHKr", + "slot": 422867536, + "block_time": 1780029667, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe": { + "address": "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 737 + }, + "first_seen": 1784227892, + "birth_edge": { + "sink": "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "sources": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "value": 130000000, + "signature": "kTyjASGv9R4C1zjLJriyX96k2ZWgbAwPw3Qd2z3pCzb5cRPuZs3vt8uqzKH2bjr5AdqMDwf8SnxCqbwyt2cWwdm", + "slot": 433328336, + "block_time": 1784227892, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "funded": [ + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt" + ] + }, + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq": { + "address": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 14 + }, + "first_seen": 1784552253, + "birth_edge": { + "sink": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "sources": [ + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "value": 23698818508, + "signature": "3uywYCF5VuSzVQkMX6Pghx7SXTsJuW55Jv37zcHt1foh71Nuq6vGrb4keCz7JNFjLMRWkK5Aq2jNmWhqkWbXuH8y", + "slot": 434103135, + "block_time": 1784552253, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "funded": [] + }, + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC": { + "address": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4402 + }, + "first_seen": 1776709519, + "birth_edge": { + "sink": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 4909585890, + "signature": "5VEpmW6pcMbLtJQHaJbctF8BUkixM7cH6gwV5yMHLtJtq5DaCpFaKRydWVjQ85d3uA9ErzyjYTkqyfHriUeN1D8E", + "slot": 414528392, + "block_time": 1776709519, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165": { + "address": "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1776477179, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9": { + "address": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1784377766, + "birth_edge": { + "sink": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "sources": [ + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN" + ], + "value": 1299788806, + "signature": "DonAnKr8whXoDnWemm9bqSjoUQdEohd9sus4nhstSat4cF5HxAmnrHQqMEbbNW3s9KhRDYLvL28ifTpBj16tWha", + "slot": 433689104, + "block_time": 1784377766, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN" + ], + "funded": [] + }, + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k": { + "address": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 112 + }, + "first_seen": 1783337142, + "birth_edge": { + "sink": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "sources": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w" + ], + "value": 2000000000, + "signature": "3TYxeVhY5FHcpE3BqdMtf6RUScLkjcsXBpZnPjc8YfGiTXw25vLWWvd3vZWPE9V6kBcLpzMrph82uRoprzHPNvKU", + "slot": 431153926, + "block_time": 1783337142, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w" + ], + "funded": [] + }, + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v": { + "address": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 8839 + }, + "first_seen": 1769181912, + "birth_edge": null, + "fee_payers": [ + "BidtDwH9WbEvm9T6tqqsEgAscTzLJeX6H2rGbw22jR39" + ], + "funded": [] + }, + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ": { + "address": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 45 + }, + "first_seen": 1783637441, + "birth_edge": { + "sink": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 22952461058, + "signature": "63UUpBFp2VbRkpjKsc3FaXXucqtzjTyPZCsqEtoXBxNiW263FxXHdr6Coo7FksLHC3amGnSZoV9rD9uR4G4yKMfo", + "slot": 431891370, + "block_time": 1783637441, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE": { + "address": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3053 + }, + "first_seen": 1761711549, + "birth_edge": { + "sink": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "sources": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "value": 10000000, + "signature": "42BSukNNZwdKRuESCNwP7Dr8xn7HmRc21PNP6PdSa36WrF1mbw2n3CatJwkBzviQiutmRPDn9oCR7bJo4jXDVtzM", + "slot": 376499867, + "block_time": 1761711549, + "ambiguous_attribution": false + }, + "fee_payers": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "funded": [] + }, + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ": { + "address": "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894187, + "birth_edge": { + "sink": "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ", + "sources": [ + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x" + ], + "value": 849119919, + "signature": "5hopWZ3eVdGLYmfhGBcqbvTV2SGzmQc8X3KyyfBQ36QzCcyGtMkxBKhTLuYwftq866p9ZdaZFVMbrsRNNGjzE3Cm", + "slot": 394707684, + "block_time": 1768894187, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x" + ], + "funded": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ] + }, + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu": { + "address": "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784715142, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn" + ] + }, + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW": { + "address": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 108 + }, + "first_seen": 1784490766, + "birth_edge": { + "sink": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "sources": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "value": 150000000, + "signature": "2uKVQ2Do2Vandv4rqHhJQZEFKrKQGFQdt15BtdaknzdY8Rxas2Bx3smqkhK6D3Hz8urRCANByPKEJxDcCAKTaq3G", + "slot": 433959006, + "block_time": 1784490766, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "funded": [] + }, + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD": { + "address": "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785020655, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT" + ] + }, + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU": { + "address": "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 583 + }, + "first_seen": 1769032382, + "birth_edge": { + "sink": "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "sources": [ + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "value": 20000000, + "signature": "AG1dX11PZCL7yBeTVs4PuNNECWsZ7tuvE94MP16zRMdtgyqchb5gyD512vVb7bd5pk3rYHpfg1RFFCwSLaahc4w", + "slot": 395055111, + "block_time": 1769032382, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "funded": [ + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT" + ] + }, + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q": { + "address": "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q", + "owner": null, + "executable": false, + "signatures": { + "Exact": 9987 + }, + "first_seen": 1753767232, + "birth_edge": null, + "fee_payers": [ + "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r" + ], + "funded": [ + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE" + ] + }, + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf": { + "address": "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2651 + }, + "first_seen": 1737914051, + "birth_edge": { + "sink": "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf", + "sources": [ + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs" + ], + "value": 50000000000, + "signature": "2rpBPJocSrWKt2G59e29e8Tj7MJDUAQLEKx2GaoAApyUBLbynToft6iDKYZKTWr2BL9UhfiwV7qr6E1exQn6mnAP", + "slot": 316536578, + "block_time": 1737914051, + "ambiguous_attribution": false + }, + "fee_payers": [ + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs" + ], + "funded": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ] + }, + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe": { + "address": "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1994 + }, + "first_seen": 1762263640, + "birth_edge": { + "sink": "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe", + "sources": [ + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN" + ], + "value": 10000000, + "signature": "2abx2yUwotMytWNz2EAiW6RTrAsz9otzWMXKPyVN8FjtaEa3hp4MTJYi2C3R8XrnUND8MyuMJ5T2yKEb4prkrBVJ", + "slot": 377877154, + "block_time": 1762263640, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN" + ], + "funded": [ + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz" + ] + }, + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6": { + "address": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 531 + }, + "first_seen": 1783364451, + "birth_edge": { + "sink": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "sources": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ], + "value": 1100000000, + "signature": "4kLBV2LbExCtK85mRP4FnNGDaHVTBNNvvtyQjbFVqiqeLgvs3fcSUVbsxtmuZ6WzVUBYV9h9GJzyUuWpYf6nAxTD", + "slot": 431221166, + "block_time": 1783364451, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ], + "funded": [] + }, + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx": { + "address": "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 74 + }, + "first_seen": 1776857831, + "birth_edge": { + "sink": "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "sources": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "value": 1000000000, + "signature": "4mEmeFnTKjqyT3XM3UZbp7fGA5gWeMB8ny87kZJbBbGGW89NJv5i5GBSvAJqx4JQN4eKDKNUomka7gE4AvgLRm8v", + "slot": 414902368, + "block_time": 1776857831, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "funded": [ + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do" + ] + } + } +} \ No newline at end of file diff --git a/data/sample-privacycash-run6.json b/data/sample-privacycash-run6.json new file mode 100644 index 00000000..102fb96c --- /dev/null +++ b/data/sample-privacycash-run6.json @@ -0,0 +1,5980 @@ +{ + "manifest": { + "endpoint": "https://mainnet.helius-rpc.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1785042653, + "config": { + "scope": "Sol", + "depth_max": 16, + "min_edge_lamports": 500000, + "sig_page_cap": 24, + "page_size": 1000, + "birth_scan_cap": 24 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 1776, + "excluded_non_wallet": [ + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp", + "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7", + "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB", + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr", + "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY", + "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv", + "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis", + "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX", + "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo", + "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG", + "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS", + "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA", + "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha", + "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp", + "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH" + ], + "ambiguous_attribution_rate": 0.18902439024390244 + }, + "chains": [ + { + "seed": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "visited": [ + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "visited": [ + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "visited": [ + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E", + "visited": [ + "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E" + ], + "stop": "PageCapHit" + }, + { + "seed": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "visited": [ + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE", + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g", + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99", + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT", + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD" + ], + "stop": "PageCapHit" + }, + { + "seed": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "visited": [ + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "visited": [ + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "stop": "PageCapHit" + }, + { + "seed": "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff", + "visited": [ + "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff" + ], + "stop": "PageCapHit" + }, + { + "seed": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "visited": [ + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "visited": [ + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "visited": [ + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai", + "C8nKoCYa6vbtv51Gszak8W8UoMzCu32ks56rDYdMpwwr", + "FzZ77TM8Ekcb6gyWPmcT9upWkAZKZc5xrYfuFu7pifPn" + ], + "stop": "PageCapHit" + }, + { + "seed": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "visited": [ + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7", + "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "visited": [ + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "stop": "PageCapHit" + }, + { + "seed": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "visited": [ + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf", + "visited": [ + "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf" + ], + "stop": "PageCapHit" + }, + { + "seed": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "visited": [ + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "stop": "PageCapHit" + }, + { + "seed": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "visited": [ + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "visited": [ + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR", + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9", + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j", + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "visited": [ + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165", + "visited": [ + "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165" + ], + "stop": "PageCapHit" + }, + { + "seed": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "visited": [ + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "visited": [ + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "stop": "PageCapHit" + }, + { + "seed": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "visited": [ + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X", + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF" + ], + "stop": "PageCapHit" + }, + { + "seed": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "visited": [ + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB" + ], + "stop": "LocalTerminal" + }, + { + "seed": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "visited": [ + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "visited": [ + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "visited": [ + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "visited": [ + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "visited": [ + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "visited": [ + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "DkzL477CEJQSynqqqStK378vfCjzxRMvotCz8xdoVzv9", + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "stop": "PageCapHit" + }, + { + "seed": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "visited": [ + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV" + ], + "stop": "LocalTerminal" + }, + { + "seed": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "visited": [ + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "visited": [ + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe", + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN", + "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "stop": "PageCapHit" + }, + { + "seed": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "visited": [ + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "visited": [ + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "visited": [ + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "stop": "PageCapHit" + }, + { + "seed": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "visited": [ + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "visited": [ + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "visited": [ + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "visited": [ + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U", + "visited": [ + "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U" + ], + "stop": "PageCapHit" + }, + { + "seed": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "visited": [ + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ" + ], + "stop": "LocalTerminal" + }, + { + "seed": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "visited": [ + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "visited": [ + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q", + "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r", + "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf", + "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "visited": [ + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "stop": "PageCapHit" + }, + { + "seed": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "visited": [ + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT", + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "visited": [ + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM", + "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9", + "6ZPorXXoNedd3u2unPzZRg18LDrE4CQZcUarumuhZdbD" + ], + "stop": "LocalTerminal" + }, + { + "seed": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "visited": [ + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "visited": [ + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "stop": "PageCapHit" + }, + { + "seed": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "visited": [ + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf", + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs", + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K", + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF", + "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP", + "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja", + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "stop": "PageCapHit" + }, + { + "seed": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "visited": [ + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "visited": [ + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "visited": [ + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "stop": "PageCapHit" + }, + { + "seed": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "visited": [ + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "stop": "PageCapHit" + }, + { + "seed": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "visited": [ + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "visited": [ + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme", + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "stop": "PageCapHit" + }, + { + "seed": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "visited": [ + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "visited": [ + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "visited": [ + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "visited": [ + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "visited": [ + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "stop": "PageCapHit" + }, + { + "seed": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "visited": [ + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o" + ], + "stop": "LocalTerminal" + }, + { + "seed": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "visited": [ + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "visited": [ + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "stop": "BirthScanExhausted" + }, + { + "seed": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "visited": [ + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "visited": [ + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "visited": [ + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "stop": "PageCapHit" + }, + { + "seed": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "visited": [ + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "visited": [ + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "visited": [ + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ", + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x", + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha", + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t", + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe", + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH", + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz", + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ" + ], + "stop": "DepthExceeded" + }, + { + "seed": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "visited": [ + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "visited": [ + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "visited": [ + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR", + "visited": [ + "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR" + ], + "stop": "PageCapHit" + }, + { + "seed": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "visited": [ + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn" + ], + "stop": "PageCapHit" + }, + { + "seed": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "visited": [ + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "visited": [ + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "visited": [ + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "visited": [ + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "visited": [ + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "visited": [ + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "stop": "PageCapHit" + }, + { + "seed": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "visited": [ + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "stop": "PageCapHit" + }, + { + "seed": "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM", + "visited": [ + "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM" + ], + "stop": "PageCapHit" + } + ], + "facts": { + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E": { + "address": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1784615427, + "birth_edge": { + "sink": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 110900000, + "signature": "5e6e31Ja1kF2DbV7qrcSW9RZYywU7TpJfxr667CtkwBe4toXGeyZnYtdT8NJeQzM1fTpQULLkDXkraeVcYxArg8W", + "slot": 434252353, + "block_time": 1784615427, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma": { + "address": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 607 + }, + "first_seen": 1783375005, + "birth_edge": { + "sink": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 22913500000, + "signature": "2AkoeVHhVQwaNuxQEya9FmdWcho8YDPBUExnQwQ51LZCGAN81Xa6gmUiq5KufZD7VNapVbL566cGNQ54cHcQGDAZ", + "slot": 431247217, + "block_time": 1783375005, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z": { + "address": "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4277 + }, + "first_seen": 1647049347, + "birth_edge": { + "sink": "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "sources": [ + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "value": 7244953950, + "signature": "419TeAWehDaugVDXtfT9GochWU2uzZfYE8Mj9KcRLxDtwZpVies6nT8ujSsqz5xcah5gEALomEeyeL5igrt1ZFeG", + "slot": 124535935, + "block_time": 1647049347, + "ambiguous_attribution": false + }, + "fee_payers": [ + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "funded": [ + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H" + ], + "birth_scan_exhausted": false + }, + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm": { + "address": "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784761134, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "birth_scan_exhausted": false + }, + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ": { + "address": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 38 + }, + "first_seen": 1783722353, + "birth_edge": { + "sink": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 12948500000, + "signature": "5rMkvoDiSrN16YHjCLekrebvkmsHxvssazWRbP2Fq5rZNhyyMcUTULMb136XBMrKVZzwRyhbj7qb3cx3sgGiWAoX", + "slot": 432098751, + "block_time": 1783722353, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha": { + "address": "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9": { + "address": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784475307, + "birth_edge": { + "sink": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "sources": [ + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn", + "6tckHFBpiJ8YgYN8FUskvtvTpXQZ55g5LHeo1kvELoDQ" + ], + "value": 5010000000, + "signature": "4bs1AqpjFmhSM6Hgg7nGwN7FbytYnLRcGmiTMP6TCCRP2rhhT4hf8Bb62Jm7uTqxc4vs9scPgT3vbEb98uQfdNF3", + "slot": 433922248, + "block_time": 1784475307, + "ambiguous_attribution": true + }, + "fee_payers": [ + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X": { + "address": "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1743262736, + "birth_edge": { + "sink": "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X", + "sources": [ + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF" + ], + "value": 779470319, + "signature": "2YjKzdqoKhck9hGc8VmXR5gxdnX1SPDG6WByy1Mm3tHz5rzESsiEf3TLLof8but3XH3XqMVX9ZHbvAR9fhVPanWM", + "slot": 329976683, + "block_time": 1743262736, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF" + ], + "funded": [ + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu" + ], + "birth_scan_exhausted": false + }, + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V": { + "address": "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "owner": null, + "executable": false, + "signatures": { + "Exact": 249 + }, + "first_seen": 1776070891, + "birth_edge": { + "sink": "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "sources": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "value": 600000000, + "signature": "2ifPXJE5e8zqjQTqTP7duLXvDyDjTsJrqcf5iEdywn3Z29p3Zsr3RcgYFXPkkxZMhMNg3HQyeVHSqQHhCrDAYnPM", + "slot": 412912638, + "block_time": 1776070891, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "funded": [ + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU" + ], + "birth_scan_exhausted": false + }, + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH": { + "address": "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894159, + "birth_edge": { + "sink": "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH", + "sources": [ + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz" + ], + "value": 849144919, + "signature": "4YP76aBoEjaNaxf1e6Va5x4ZZLNVfo6vNpY8kzqQcquQZWaGeiiJgrKaPTrP1udmGV8Kj82jNeBCsH8PzcwBPk9b", + "slot": 394707612, + "block_time": 1768894159, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz" + ], + "funded": [ + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe" + ], + "birth_scan_exhausted": false + }, + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy": { + "address": "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1600 + }, + "first_seen": 1784752160, + "birth_edge": { + "sink": "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "sources": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "value": 43881516584, + "signature": "3NEwDfuC73NVthq8zeasPw9Ud6qcWZiy65wFFZSWcbxP86UjAsc9ZPApAdjk7EYo88ptZcUZbSLdmQwZkgqSCcRc", + "slot": 434577818, + "block_time": 1784752160, + "ambiguous_attribution": false + }, + "fee_payers": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "funded": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "birth_scan_exhausted": false + }, + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg": { + "address": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1781285770, + "birth_edge": { + "sink": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "sources": [ + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "value": 1677937000, + "signature": "2TJSuukc2SNr9YL2qRHeNHmu37kfsE2cBnQkz7TJTxuRkVw48fefVYqxsGCV2ULsb1PnVvzmcQGJt5J7uouabgYZ", + "slot": 426027687, + "block_time": 1781285770, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem": { + "address": "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "owner": null, + "executable": false, + "signatures": { + "Exact": 263 + }, + "first_seen": 1713736580, + "birth_edge": { + "sink": "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "sources": [ + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "value": 12006763000, + "signature": "62g49CyyWTmom7Qxdnr64iSy7W8PDuxrZojz5q6ztpgYkM7WwwXkfcyeNVditM45iomtRpgqXUbLW8kXpScStkuL", + "slot": 261492401, + "block_time": 1713736580, + "ambiguous_attribution": false + }, + "fee_payers": [ + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "funded": [ + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq" + ], + "birth_scan_exhausted": false + }, + "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf": { + "address": "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1768518508, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz": { + "address": "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1771863926, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38" + ], + "birth_scan_exhausted": false + }, + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S": { + "address": "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1655911154, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J" + ], + "birth_scan_exhausted": false + }, + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS": { + "address": "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783794615, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "birth_scan_exhausted": false + }, + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1": { + "address": "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 100 + }, + "first_seen": 1784818359, + "birth_edge": { + "sink": "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "sources": [ + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7" + ], + "value": 6000000000, + "signature": "2StbhyBVwhP2wRhTYMM31x5qU3B2WBr1jFXx6KD6CGeXp9xpWQqN7RKoxa98X86h8v6SGprqMdi9CVGh9PLSjAQH", + "slot": 434735789, + "block_time": 1784818359, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7" + ], + "funded": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "birth_scan_exhausted": false + }, + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr": { + "address": "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784752151, + "birth_edge": { + "sink": "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "sources": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "value": 45278992944, + "signature": "LnCoQVyRCZyi9ktCp3JyZPKhGrTu19FzpmhP7SjvQ8TKYS7uu9dPE23AuzRQz32YWqaTQG9rabCkoAihw2swguS", + "slot": 434577797, + "block_time": 1784752151, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "funded": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "birth_scan_exhausted": false + }, + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT": { + "address": "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1332 + }, + "first_seen": 1632786500, + "birth_edge": { + "sink": "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT", + "sources": [ + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m" + ], + "value": 100000000, + "signature": "2BLRDfM37WhxjZUNXSnPPqSZP3Yq2xTG2BsyUiQWCFaLcqPigMGHgSrX2uijsXVbB9AKL4sYZenPjui5ArFMGjcP", + "slot": 98678981, + "block_time": 1632786500, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m" + ], + "funded": [ + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t" + ], + "birth_scan_exhausted": false + }, + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt": { + "address": "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784444104, + "birth_edge": { + "sink": "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "sources": [ + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "value": 5986856990, + "signature": "3k3C9SKrmZZ9aKwV75WzsqDnXRj1jnrfVoq6W5E4wxyjcAH7ZGiMbrDKVqStRdtpFm4Y2vzYA8WvEyUdSs67b1UN", + "slot": 433847718, + "block_time": 1784444104, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "funded": [ + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH" + ], + "birth_scan_exhausted": false + }, + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL": { + "address": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784544632, + "birth_edge": { + "sink": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "sources": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "value": 928815670, + "signature": "85PNojTrpgdkLHWP1CQRGD6G6CttqKUCr5zYDjLXkFsB4teH5D9kcZqZjTAWX3ydRqfVhwLAKLzC6zYsU3K1A8L", + "slot": 434085334, + "block_time": 1784544632, + "ambiguous_attribution": false + }, + "fee_payers": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe": { + "address": "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894162, + "birth_edge": { + "sink": "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe", + "sources": [ + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH" + ], + "value": 849139919, + "signature": "2R1Goqyiuu2pZC2cXWBUawgSdAFH38yF9ciQW9p9igR6YUwHoKq9iigoHZeQgBq4ZrcmdMkp39jThvqv2bZcevMF", + "slot": 394707621, + "block_time": 1768894162, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH" + ], + "funded": [ + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t" + ], + "birth_scan_exhausted": false + }, + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H": { + "address": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 528 + }, + "first_seen": 1734052375, + "birth_edge": { + "sink": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "sources": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "value": 1020000000, + "signature": "4Mm83Hp6ciDRNzM3tSFJt6AyoXPc7kD4moyqFobEtqzXDAnC2k5hNt83wNGSsn61KQjaNdyYYqWHcJjaUA9qubwX", + "slot": 307120184, + "block_time": 1734052375, + "ambiguous_attribution": false + }, + "fee_payers": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH": { + "address": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 277 + }, + "first_seen": 1784444332, + "birth_edge": { + "sink": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "sources": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "value": 2985933011, + "signature": "4e1bYdz4z6QTzWFbSbjFRJpDdhuc2m2zaopi6x8N1w81fa6352rDi2VCzqyxKdRuvPKthVeikZXGj91o6bvCfeK4", + "slot": 433848260, + "block_time": 1784444332, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr": { + "address": "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1780923034, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh" + ], + "birth_scan_exhausted": false + }, + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7": { + "address": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784462394, + "birth_edge": { + "sink": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 90000000, + "signature": "4jhAt2GJwyGRfe5sJkFB2HVjnUzLi86PVfucCvUM6u3JFRwegv57f4ZkhmRH6huyS8pNEZa8nbPs9Kb6PtXYUAqz", + "slot": 433891372, + "block_time": 1784462394, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99": { + "address": "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99", + "owner": null, + "executable": false, + "signatures": { + "Exact": 662 + }, + "first_seen": 1783864275, + "birth_edge": { + "sink": "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99", + "sources": [ + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT" + ], + "value": 16330335554, + "signature": "32dUmLfqYokcYLdCcE19JzJ8Y423ssL8GJ6qLEDaZtmWHsQtpTF4e9KVxmSuidihQAcV5cuPpsMZjhWWd8F149TB", + "slot": 432444959, + "block_time": 1783864275, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT" + ], + "funded": [ + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g" + ], + "birth_scan_exhausted": false + }, + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu": { + "address": "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1764 + }, + "first_seen": 1781821319, + "birth_edge": { + "sink": "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "sources": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "value": 400000000, + "signature": "t439hwXMQP6B4Yk83sUHquHMZR9q8bqQK4na6cWaxbvVCnQKw5hzceNSBXCJKRmcEzmJBFLd19bfcWsSDKGxhU6", + "slot": 427377732, + "block_time": 1781821319, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "funded": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "birth_scan_exhausted": false + }, + "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv": { + "address": "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze": { + "address": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 704 + }, + "first_seen": 1784674265, + "birth_edge": { + "sink": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 6040700317, + "signature": "3tGju22hVCi5Tn5mQv65Uokr3ahGwzYsU5urYkse9Bq4SgSRPmwiU8FzhX51HBdMCKyTor6i8G1uc2LnhHge4uRb", + "slot": 434392522, + "block_time": 1784674265, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9": { + "address": "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9", + "owner": null, + "executable": false, + "signatures": { + "Exact": 42 + }, + "first_seen": 1682118364, + "birth_edge": { + "sink": "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9", + "sources": [ + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j" + ], + "value": 11742708040, + "signature": "4fDKVyLL5y4Kzuedc8MGwhkkXd1oWbkMqBZTsHtc1H7NFTWijug7Lciv42HG6VkxfjZSemzGn6fCysTTxQPG2Zsb", + "slot": 189742975, + "block_time": 1682118364, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j" + ], + "funded": [ + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR" + ], + "birth_scan_exhausted": false + }, + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ": { + "address": "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894142, + "birth_edge": { + "sink": "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ", + "sources": [ + "3LKFtdjyaX773fYgnXShWhicr3ZcNaSWWz2ggQVBgtsC" + ], + "value": 849154919, + "signature": "3fTk4eCJFMtoe3jFJ4XhXYEHqurQ5DHnehPcQoWMQLXmPmQTdns183yrWX7C8YWCvrtV7GPaU1GJ7WZfpdB9KSo1", + "slot": 394707570, + "block_time": 1768894142, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3LKFtdjyaX773fYgnXShWhicr3ZcNaSWWz2ggQVBgtsC" + ], + "funded": [ + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz" + ], + "birth_scan_exhausted": false + }, + "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz": { + "address": "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894156, + "birth_edge": { + "sink": "4UEaVZfqH92tZheffRYcoWs2kVqDSe4t34PeYQXsLWYz", + "sources": [ + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ" + ], + "value": 849149919, + "signature": "ebF99xjMkDDNHUYqxCU6fukrRihQpvEHCgpii9dnf6AeBFGPYvk94S2cq7QnfBfhRooK1361Xddiaksk6hnVxQX", + "slot": 394707604, + "block_time": 1768894156, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4G4eUzBDGsnhubwxtB9CYK4k1t9xxs436f8mArvaMfHQ" + ], + "funded": [ + "2QfFzSwpYUMFmgwjJnDQwsTHXyCoEEZy7Jt3uybZ4DXH" + ], + "birth_scan_exhausted": false + }, + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr": { + "address": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9790 + }, + "first_seen": 1781265894, + "birth_edge": { + "sink": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 209692102518, + "signature": "2WnT866FtZdcXqRvfQoypXGhWSQRtqa4cCg453yjkGSuZA9fs8LJviugPbbGP9GYu3TDJhohtJeDwq1AuoeqJBFi", + "slot": 425977688, + "block_time": 1781265894, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16": { + "address": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9762 + }, + "first_seen": 1772531584, + "birth_edge": { + "sink": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "sources": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "value": 302066170, + "signature": "5A3SzsgcHRLJQUVBqDNdCW7M8XnW6jS7TBjiuERozS7a5YAXc4EieN5d58j5Ts7mqNssUsZZj3TKUTNAett3gqgK", + "slot": 403914286, + "block_time": 1772531584, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT": { + "address": "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT", + "owner": null, + "executable": false, + "signatures": { + "Exact": 273 + }, + "first_seen": 1782950807, + "birth_edge": { + "sink": "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT", + "sources": [ + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD" + ], + "value": 100000000, + "signature": "5xcQPdqkxyx3pQsyF85wNxj7b4TuW3nB3wqryzTVHLtMeDfKsGzjY64jXDCnnfvru4BqEunbdYQzBAHBBJKG3d6V", + "slot": 430196288, + "block_time": 1782950807, + "ambiguous_attribution": false + }, + "fee_payers": [ + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD" + ], + "funded": [ + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99" + ], + "birth_scan_exhausted": false + }, + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w": { + "address": "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1783188037, + "birth_edge": { + "sink": "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 100528380, + "signature": "5CdkjWty9v98DDGJPREJK7UpeGUaaBdQxo87kDxyqajMtFtbnzVuL2h9UCu4Ue4iVqu4vWgiBLbs8XCjnAswLrDR", + "slot": 430784309, + "block_time": 1783188037, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [ + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k" + ], + "birth_scan_exhausted": false + }, + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk": { + "address": "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1013 + }, + "first_seen": 1781819169, + "birth_edge": { + "sink": "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 25895028000, + "signature": "5e4gkh2xn451jv5rnKUJN81VDUN9bJTY3VESq2eQ7ACZJ51DuXZMFBaat5X5tVe5VBLzSnGbKri4KnpFezdqG3mu", + "slot": 427372317, + "block_time": 1781819169, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "birth_scan_exhausted": false + }, + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd": { + "address": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs": { + "address": "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1663976471, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "birth_scan_exhausted": false + }, + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ": { + "address": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1784823865, + "birth_edge": { + "sink": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "sources": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "value": 26325656111, + "signature": "4Fvr5kGDCyhHU3xmpCJvMRy4YAGLs93UAu2mbCG3V39pu9ASyDAqEeMqve3CmwgDUieLGp4q6uoGvFHWBmqt2hvK", + "slot": 434748892, + "block_time": 1784823865, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr": { + "address": "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr": { + "address": "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894220, + "birth_edge": { + "sink": "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "sources": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "value": 849094919, + "signature": "4MJQDBRmFT2jFhKZx7rY84rz4GThjUhU2twqk6URjTrCx1k6SQwZd4toBBR6bKnqS7GvPowPP17GnwJw8DGFqviH", + "slot": 394707768, + "block_time": 1768894220, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "funded": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "birth_scan_exhausted": false + }, + "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS": { + "address": "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t": { + "address": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 9235 + }, + "first_seen": 1638557855, + "birth_edge": { + "sink": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "sources": [ + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT" + ], + "value": 1500000000, + "signature": "54yv3HKUtdYAymSqK7g6Hv3Q3CX9ugxzGJ2SZSF2Mv5oq28tBAwGVdKC6d9NXfbfcxSdkxjaUWson8cdW2Hw2ruH", + "slot": 109908841, + "block_time": 1638557855, + "ambiguous_attribution": false + }, + "fee_payers": [ + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV": { + "address": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5586 + }, + "first_seen": 1774645255, + "birth_edge": { + "sink": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 500000000, + "signature": "3wVtJf5fiq7g5cSb8ynKPJswdRx5RQ7GV1oPF1BMiFYKpAkf6T4ZdEbrnfEMQR3DLusyex4JCeZ8aSr9xxYkiuuq", + "slot": 409285335, + "block_time": 1774645255, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za": { + "address": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 842 + }, + "first_seen": 1784934334, + "birth_edge": { + "sink": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "sources": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "value": 52977372793, + "signature": "4JY37vAAtVC9a5sQn4z8CY5mRJ5t8njqiBziNK9Ps8QtpG9m1qPsfCLFFo8HuGFjdPNTUtDaLQ9v2TF1auyUDWg7", + "slot": 435012131, + "block_time": 1784934334, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p": { + "address": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1783475831, + "birth_edge": { + "sink": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "sources": [ + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ" + ], + "value": 388393719000, + "signature": "5imCWUcQWCKj7vDdLUbDXDeE567zN2Eg4Le8AWi6v7f1ZnsbtijSC6i65rA6BpVCsK9kc9fRrBwF4jGBARwWPf1m", + "slot": 431495612, + "block_time": 1783475831, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BrGihgGjCmpu2p96rou6GQj3sQpwgeud937jf4RvZP9G" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3": { + "address": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 14 + }, + "first_seen": 1784433292, + "birth_edge": { + "sink": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 669228400, + "signature": "66Tc5f3Uko3nDvDySXyoV4rhTBSka9cPczYiReZ8upWdrXKNhRGUHTTsZizm9mdNDEYdTkUmfuynxX3QEPjthemd", + "slot": 433821901, + "block_time": 1784433292, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs": { + "address": "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783956150, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk" + ], + "birth_scan_exhausted": false + }, + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV": { + "address": "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u" + ], + "birth_scan_exhausted": false + }, + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9": { + "address": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784935158, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs", + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf", + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "birth_scan_exhausted": false + }, + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA": { + "address": "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 15633 + }, + "first_seen": 1739951269, + "birth_edge": { + "sink": "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "sources": [ + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR" + ], + "value": 3000000000, + "signature": "2GUhQXYjQ56ULyk5kFQ5pfduXNtqXhiikEMcLeZBaVDu2zrQfTDkt9bpVV6ETHzmmXaJn7oyGxu73eK9FqtRTF3g", + "slot": 321645004, + "block_time": 1739951269, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR" + ], + "funded": [ + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF" + ], + "birth_scan_exhausted": false + }, + "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7": { + "address": "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk": { + "address": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 142 + }, + "first_seen": 1784420501, + "birth_edge": { + "sink": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1488750000, + "signature": "5reLwzaWen3xeyYobmDJv4AWkboVwkmQea8aqnBXo6AW86tVotCN8aD4HVUseVngB1i8Nz7bWPVayfkXMjq2NZWd", + "slot": 433791379, + "block_time": 1784420501, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S": { + "address": "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894225, + "birth_edge": { + "sink": "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "sources": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "value": 849089919, + "signature": "5mpXMBqiqCUXVfjKe2fqnfr1yXBFt2MnSb5sU4PhDCru1KLnWw7Aji9tVP8ywUoP2X2yAAsgDnLsybmSY33VB9LJ", + "slot": 394707780, + "block_time": 1768894225, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "funded": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "birth_scan_exhausted": false + }, + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq": { + "address": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 59 + }, + "first_seen": 1784676427, + "birth_edge": { + "sink": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 49804000, + "signature": "2ksPaRqePKa3tLNgb6dfJ4xGxBvHsRJuNXeikfUEuupy8NvcTgf3AL8cq7AZRYALiWDeKz2BWxhNZdDHxdVEoDQg", + "slot": 434397667, + "block_time": 1784676427, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6ZPorXXoNedd3u2unPzZRg18LDrE4CQZcUarumuhZdbD": { + "address": "6ZPorXXoNedd3u2unPzZRg18LDrE4CQZcUarumuhZdbD", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9" + ], + "birth_scan_exhausted": false + }, + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx": { + "address": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1784813668, + "birth_edge": { + "sink": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "sources": [ + "DkzL477CEJQSynqqqStK378vfCjzxRMvotCz8xdoVzv9" + ], + "value": 246791375, + "signature": "4N7mvNBVzA7HcNpvcfeiHDkJ2U651AKYZpyMcQPpKfpDVCoSxw37tJaJq2njRNbs1kguudKXmp2YeXczfsazvWE5", + "slot": 434724624, + "block_time": 1784813668, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9": { + "address": "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19 + }, + "first_seen": 1780177153, + "birth_edge": { + "sink": "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9", + "sources": [ + "6ZPorXXoNedd3u2unPzZRg18LDrE4CQZcUarumuhZdbD" + ], + "value": 482662864, + "signature": "4pHdMusAtwq9ooccUsTDchzRvNCD82ykwieZy5sw65LF1dwTWjHZ652giexigGUd5qkTGu8abDzz55jdASP5hDBM", + "slot": 423239737, + "block_time": 1780177153, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "birth_scan_exhausted": false + }, + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY": { + "address": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 19398 + }, + "first_seen": 1774644767, + "birth_edge": { + "sink": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "sources": [ + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv" + ], + "value": 5972990500, + "signature": "2FGgEReXPwdXR3S6e4R5wxsotsqmfJU3EEC2QmGDtQF5WxGAspSae7s8GWY2FGx4o9u1oyWSsWMrPznZdTD7KNkn", + "slot": 409284086, + "block_time": 1774644767, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB": { + "address": "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT" + ], + "birth_scan_exhausted": false + }, + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S": { + "address": "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1310 + }, + "first_seen": 1781821301, + "birth_edge": { + "sink": "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "sources": [ + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk" + ], + "value": 600000000, + "signature": "3B7AsVriGEHPW4TRFBkaFhV6YD4RDZ1w7g4UwNtT7psQb95ZMifH6v4QDUwL1k42tLpqhGqiExaje5LTEMkMBwQ8", + "slot": 427377690, + "block_time": 1781821301, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk" + ], + "funded": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "birth_scan_exhausted": false + }, + "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB": { + "address": "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz": { + "address": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 963 + }, + "first_seen": 1774473115, + "birth_edge": { + "sink": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 34895500000, + "signature": "3omGYaNeXk9VjMv3rTp9aoaJrkED6b9jTiHoPx4UbRupiWmUn7op8udTBwguzph7YGJWQpNEhnv1FFDskSRsZANh", + "slot": 408844844, + "block_time": 1774473115, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g": { + "address": "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g", + "owner": null, + "executable": false, + "signatures": { + "Exact": 387 + }, + "first_seen": 1783864288, + "birth_edge": { + "sink": "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g", + "sources": [ + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99" + ], + "value": 15184373714, + "signature": "H1qHMYUqhmFjKH3uLfmAM4qZqHch53iJgKFsf93aSE4nfPZujKefZuX633Rn2aSk1PkWTbw341zXYNTC1ZNBTqT", + "slot": 432444990, + "block_time": 1783864288, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3hfQqc1Y7XVJnfomBpkkqTixrVSPL6ArzY8e64gr5E99" + ], + "funded": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "birth_scan_exhausted": false + }, + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE": { + "address": "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1750857325, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "birth_scan_exhausted": false + }, + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw": { + "address": "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 277 + }, + "first_seen": 1780094619, + "birth_edge": { + "sink": "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 2991500000, + "signature": "84Spr3goYUhDoyS5JCevCc1nDRjo6vWCWeKajzmd3qHWAmsNkBoEjw8322ajWKS5GJyVShK56h1ZUh2VdxtBeCz", + "slot": 423031442, + "block_time": 1780094619, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ" + ], + "birth_scan_exhausted": false + }, + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme": { + "address": "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1712133901, + "birth_edge": { + "sink": "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme", + "sources": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "value": 981006000, + "signature": "2718Lqzzrche69Pqhrt41GqkDBghW5SrqpxVVjrYV5fDNZ2tdipmhyYVKaXEj7Fex4h5mF5NMJ5QU8ohazEukjZG", + "slot": 258093459, + "block_time": 1712133901, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "funded": [ + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW" + ], + "birth_scan_exhausted": false + }, + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF": { + "address": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1758995033, + "birth_edge": { + "sink": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "sources": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "value": 10000000, + "signature": "5eJNQ4bhKNQYiTVSpUhrHjGpFSs7Ft4GKLrJWqAK5BTnkuzd1xqVV8P1FcpXKG6Zb77U9qdDkyVN6gz1UYzoeB1T", + "slot": 369652410, + "block_time": 1758995033, + "ambiguous_attribution": false + }, + "fee_payers": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x": { + "address": "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894183, + "birth_edge": { + "sink": "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x", + "sources": [ + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha" + ], + "value": 849124919, + "signature": "4b7V78kfU1AxK6fRrczLLEdLEkMQfF6AurV4jSBMBVLEKstbLTQ65VSPjVyWmyRmz1VuMQNDC7vV1gQDAiLtLdrV", + "slot": 394707672, + "block_time": 1768894183, + "ambiguous_attribution": false + }, + "fee_payers": [ + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha" + ], + "funded": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "birth_scan_exhausted": false + }, + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW": { + "address": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11302 + }, + "first_seen": 1728079811, + "birth_edge": { + "sink": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "sources": [ + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme" + ], + "value": 200000000, + "signature": "4rvwJT124GYcZAHHJJBqaZ9YRgnxYLF4nQ58wLbJSr1Z9BgH2NXyKvMRRCbN7CUWooZ9BMNPYAACSwPAqq7NgLvt", + "slot": 293725783, + "block_time": 1728079811, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG": { + "address": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 27 + }, + "first_seen": 1784565160, + "birth_edge": { + "sink": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "sources": [ + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "value": 232000000000, + "signature": "28bt62zYkiihXsM3o7rp2D6YS63G8CpZwUzpqqp2b8jNzGoUih1PWx9FGMdwfQFAEdRGTgz15pPQ8j9uZgDeyvw8", + "slot": 434133197, + "block_time": 1784565160, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs": { + "address": "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11896 + }, + "first_seen": 1682602307, + "birth_edge": { + "sink": "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 2443901080, + "signature": "4oBaFynpk5oq4YegVwsdYZei12eyBhFZXy1DHW264fAiQah9bA4Z22RLchZQeTyGsSXMSPbTuY5Hw83rUsMsuYNd", + "slot": 190783160, + "block_time": 1682602307, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "birth_scan_exhausted": false + }, + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j": { + "address": "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 72 + }, + "first_seen": 1682118021, + "birth_edge": { + "sink": "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j", + "sources": [ + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ" + ], + "value": 11744752320, + "signature": "pALYeH3rq18atGAUHgbqmMBXckY34TfyqKywTwxPzmeg23rXbtbqW9mf3NMct3WsizeZszfuwskkXvbGefvGRRA", + "slot": 189742217, + "block_time": 1682118021, + "ambiguous_attribution": false + }, + "fee_payers": [ + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ" + ], + "funded": [ + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9" + ], + "birth_scan_exhausted": false + }, + "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG": { + "address": "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP": { + "address": "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "owner": null, + "executable": false, + "signatures": { + "Exact": 999 + }, + "first_seen": 1784462436, + "birth_edge": { + "sink": "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "sources": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "value": 49648773129, + "signature": "3xd1Te2qtTYHjh2ohyorXsFLgxgWxaveB9tfyGzszJf9MmM1XHhFzQoi5C5ftnUWhXMPRvJpBuHpFidFgZVh2i3g", + "slot": 433891472, + "block_time": 1784462436, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "funded": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "birth_scan_exhausted": false + }, + "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai": { + "address": "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1908 + }, + "first_seen": 1732470817, + "birth_edge": { + "sink": "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai", + "sources": [ + "C8nKoCYa6vbtv51Gszak8W8UoMzCu32ks56rDYdMpwwr" + ], + "value": 1082181912, + "signature": "GrdeMQqkwcSyfBRLPEdpSJavrReG9wQ2mT9FbjmxSH7JqVWuM5UxfwvHUQya2UiuVUWxUUBCKEpWXaucYhUnepz", + "slot": 303378533, + "block_time": 1732470819, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FzZ77TM8Ekcb6gyWPmcT9upWkAZKZc5xrYfuFu7pifPn" + ], + "funded": [ + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v" + ], + "birth_scan_exhausted": false + }, + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ": { + "address": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 32 + }, + "first_seen": 1784389227, + "birth_edge": { + "sink": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "sources": [ + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb" + ], + "value": 807208726, + "signature": "3vny3LuBCtnjHmNBUw4YGWxGiJdB6MDgCTTwB85ixPF8urpfbhjUiR3DJvptVkoB82k8MLKxgudAvq8m5CPLHCG", + "slot": 433716525, + "block_time": 1784389227, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH": { + "address": "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1705 + }, + "first_seen": 1715894645, + "birth_edge": { + "sink": "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "sources": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "value": 106710780, + "signature": "xDgEvEFQw8Qer5vQHtG755NyT2FHXPnFV9CPvhuvZn4NfZ3b5tWrUL5wDcGVyBDVSSA13r7Y6Tgtdp2mjrmHZrH", + "slot": 266193828, + "block_time": 1715894645, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "funded": [ + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo" + ], + "birth_scan_exhausted": false + }, + "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH": { + "address": "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ": { + "address": "88xTWZMeKfiTgbfEmPLdsUCQcZinwUfk25EBQZ21XMAZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1697388134, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "7mmNdLVUXMwPXgBNYkmPfF6ayBgGRxo7GTKKcg84NX5j" + ], + "birth_scan_exhausted": false + }, + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u": { + "address": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784630445, + "birth_edge": { + "sink": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "sources": [ + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV" + ], + "value": 6831797746, + "signature": "4V6TatwrgYYdAXsbYZ58LgACqMKm51JVfQ6cgiJvjtXwvz8NPjZbhsrz9j2QvwKXXv18bkkgtJScAaw5wZy5sKZk", + "slot": 434288158, + "block_time": 1784630445, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5": { + "address": "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784379999, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "birth_scan_exhausted": false + }, + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7": { + "address": "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 176 + }, + "first_seen": 1731698151, + "birth_edge": { + "sink": "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7", + "sources": [ + "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs" + ], + "value": 1000000, + "signature": "4m5a1LNx7X8atKa6KpoaqkGVHX136UYXQA5CaaFLcfaWHthoVdR3an2dBPmuCvNezb7qcM8AQ38BLbKpNHeLXp9b", + "slot": 301741144, + "block_time": 1731760300, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4ritJBeodrzcSDDeAJbKafJniczjYhAfsoZRXTQq9h82", + "7h3fgsJgJGXkUtqvtApMJbvJugMfzS4yz9wYoqsMqjjs" + ], + "funded": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "birth_scan_exhausted": false + }, + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT": { + "address": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784049521, + "birth_edge": { + "sink": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "sources": [ + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB" + ], + "value": 2110033428, + "signature": "1tK2a5Q2E19ZBWkhkhMDf36cuv8NZD8pcRFbVhxkR4kedkEjLsxS7dD1QsKHuZ1T77XRbGiWQx9fnQWcDtgLQmD", + "slot": 432895720, + "block_time": 1784049521, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH": { + "address": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784564457, + "birth_edge": { + "sink": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 156610510360, + "signature": "3HmDQGGFDNXPquCgrBn4oFueH8EcudAUohYxWiRVekmuX53cZhFotqNnLLPzUEeBnnhHikzZWtUwuP2M6K8EZq1L", + "slot": 434131562, + "block_time": 1784564457, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U": { + "address": "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1782852080, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ": { + "address": "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p" + ], + "birth_scan_exhausted": false + }, + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx": { + "address": "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784217778, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC" + ], + "birth_scan_exhausted": false + }, + "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r": { + "address": "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r", + "owner": null, + "executable": false, + "signatures": { + "Exact": 10 + }, + "first_seen": 1753767029, + "birth_edge": { + "sink": "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r", + "sources": [ + "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf" + ], + "value": 15098148051, + "signature": "2fHx4G4K3zY2kCZJ1oh6S1yJ7EhDMvGZKWiwauLybaV8r74zoWQhxbCq8LmXjnD1GzzzgXQmsGGn3ZU7faY1A6df", + "slot": 356448276, + "block_time": 1753767029, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf" + ], + "funded": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "birth_scan_exhausted": false + }, + "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E": { + "address": "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1673079363, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1": { + "address": "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2157 + }, + "first_seen": 1684141322, + "birth_edge": { + "sink": "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "sources": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "value": 90000000, + "signature": "52ZPH7cfAzwauMYh529GgHWhTzRwReNdJyWYr5ZugsAB5gvSmP6CYuCV1U79B9SLxLjk6qy5nsDUmao8Xa5y5EBB", + "slot": 194024003, + "block_time": 1684141322, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "funded": [ + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6" + ], + "birth_scan_exhausted": false + }, + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1": { + "address": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5535 + }, + "first_seen": 1747156899, + "birth_edge": { + "sink": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "sources": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "value": 1000000000, + "signature": "2cATjnRUeA8sBSjhU4udUTHwqFk5cLQfx2mMZ7isJfKvdfGEJNn4q3Ex72Ww3fRNX7JUQTGpy25R6FVdfFwRP5dV", + "slot": 339786892, + "block_time": 1747156899, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb": { + "address": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1391 + }, + "first_seen": 1778270115, + "birth_edge": { + "sink": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 31543190000, + "signature": "23eCmHrxuyS6rMmjNNDsJtUZk4vesD5maoraeVjWmqKuLe1yeuELQgEDaqfBDUWSTrkM3iuQFUWAsPpkjAiD6meJ", + "slot": 418463518, + "block_time": 1778270115, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr": { + "address": "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1774937240, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "birth_scan_exhausted": false + }, + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha": { + "address": "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894180, + "birth_edge": { + "sink": "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha", + "sources": [ + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t" + ], + "value": 849129919, + "signature": "z18ostGmqULsMip19y3QrR6sRFfittsoYwNTF1SjPA5iLq1dJfQw8yJvyWKryxBGjhXnhfnVPiuUjpFyggjQj8v", + "slot": 394707664, + "block_time": 1768894180, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t" + ], + "funded": [ + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x" + ], + "birth_scan_exhausted": false + }, + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK": { + "address": "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 950 + }, + "first_seen": 1781405177, + "birth_edge": { + "sink": "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 55361142572, + "signature": "48U5vGEMeabvwxYjwxueLZukbtdRbGFKABsAVrmP9pViW24nMA2vTcgZLqZSqL9js1Muve2grFATYhgeEstyoCNp", + "slot": 426328548, + "block_time": 1781405203, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k" + ], + "birth_scan_exhausted": false + }, + "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja": { + "address": "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 8 + }, + "first_seen": 1670977110, + "birth_edge": { + "sink": "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja", + "sources": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "value": 4990000000, + "signature": "4XqtekWfG6hXY9Qbx1nR2FC44qNATqBD6uVDxJ5ByWRvavpCr6dMpGaoTFDXHqS2NHbbsdHBgqm4X3GpvNKxuoP8", + "slot": 166727018, + "block_time": 1670977110, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6" + ], + "funded": [ + "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP" + ], + "birth_scan_exhausted": false + }, + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu": { + "address": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20518 + }, + "first_seen": 1743263000, + "birth_edge": { + "sink": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "sources": [ + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X" + ], + "value": 770000000, + "signature": "rWZNiWUUErqSurTeKbooG5bPJgChg9SvYyYCsgNUy6AXuiHTsyVDYCyzCmYssFrs94PhG2ok9FwYAkVEDrK6efw", + "slot": 329977339, + "block_time": 1743263000, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu": { + "address": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 432 + }, + "first_seen": 1783530592, + "birth_edge": { + "sink": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "sources": [ + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o" + ], + "value": 3608900737, + "signature": "39zbFyzcd2pWwLEQBD1gB1qWrjTekKNiicL8TpyjTAoyLABpT518QVo9WVz8yxdzCJF1WiRcvuHzJRR85WFBXjfv", + "slot": 431630423, + "block_time": 1783530592, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn": { + "address": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784565684, + "birth_edge": { + "sink": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 841356800, + "signature": "4Y2A99s86tDM9Ef8DQ62ED34YhLejSy9dfkYDHR2rAi6kcnSNvg5pW1F83RyJuHK4DPoxkN5mAkvqvyA1EHJj4Wd", + "slot": 434134426, + "block_time": 1784565684, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh": { + "address": "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894217, + "birth_edge": { + "sink": "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "sources": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "value": 849099919, + "signature": "4UhWatoFQvHLdrg56s4qh3NjJaa9jpsS55YeGbi2FwyNHuoqfnZBLZx3npfoyjhFbvMaNm5vxYmYSAkjPdK2Gioi", + "slot": 394707760, + "block_time": 1768894217, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "funded": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "birth_scan_exhausted": false + }, + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp": { + "address": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 205 + }, + "first_seen": 1775579392, + "birth_edge": { + "sink": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 9131905000, + "signature": "3zWVxUN5PpQhBBHTb7q2iVdGYZWzYX96QFS1nC467YtQBSKuqjZzLFQEPh816DEVyZmtn6xdFvssDpQqdopjccPh", + "slot": 411667852, + "block_time": 1775579392, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi": { + "address": "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1780957515, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "birth_scan_exhausted": false + }, + "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY": { + "address": "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR": { + "address": "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784454004, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL" + ], + "birth_scan_exhausted": false + }, + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf": { + "address": "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1778790052, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "birth_scan_exhausted": false + }, + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW": { + "address": "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1782173460, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK", + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM" + ], + "birth_scan_exhausted": false + }, + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx": { + "address": "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894233, + "birth_edge": { + "sink": "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "sources": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "value": 849084919, + "signature": "4MQSbWiBDWsVRVVKMjprc9fMfevDFzvAJJDcTd7PPwkGKXTfqJtB5frc9naHWzJv1S5yi3XLnmKZPMEbQx95M7aU", + "slot": 394707800, + "block_time": 1768894233, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "funded": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "birth_scan_exhausted": false + }, + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ": { + "address": "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784653278, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16" + ], + "birth_scan_exhausted": false + }, + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW": { + "address": "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "owner": null, + "executable": false, + "signatures": { + "Exact": 711 + }, + "first_seen": 1663704019, + "birth_edge": { + "sink": "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 3079735480, + "signature": "24tTRqCdoMDLxwi41jhddFdaqydjZowSRXZHW2xuBqNttskX1ej72PhQUDqGoiF9jY5u9i8kbdyMcx5MMUrRWXsD", + "slot": 151573078, + "block_time": 1663704019, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq" + ], + "birth_scan_exhausted": false + }, + "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t": { + "address": "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894166, + "birth_edge": { + "sink": "Agiaa4qhKVtugGZ4WdpachVq7d65odGx5DPxnHLGhv8t", + "sources": [ + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe" + ], + "value": 849134919, + "signature": "2HfqS2otjA4GU4BjEiL2ei8YhTcqcwpSZYh7L5E7UfwfaigJ78sP6qi22gs9zZjcZFk8S3FkSK1tf7Zx5CSAKmYE", + "slot": 394707631, + "block_time": 1768894166, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3JpzxnLEQtYiTaK9xShkDAZBaetHw1RADgoqJKiJn7Qe" + ], + "funded": [ + "97AGx1pp3jrQAqAzwnA54TyrjmtP4RTkV6LycMrTdwha" + ], + "birth_scan_exhausted": false + }, + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ": { + "address": "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2412 + }, + "first_seen": 1781821309, + "birth_edge": { + "sink": "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "sources": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "value": 500000000, + "signature": "4wVPQe58DmcHwkdVmHuvqWFGnQZhQ4ndiumpcrvNSYx6bL2bBCk6CCNeWpKDPzvc8Y68RpfFKuCrfScRuL2VaE58", + "slot": 427377712, + "block_time": 1781821309, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "funded": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "birth_scan_exhausted": false + }, + "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo": { + "address": "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk": { + "address": "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785002824, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD" + ], + "birth_scan_exhausted": false + }, + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX": { + "address": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 16389 + }, + "first_seen": 1774739788, + "birth_edge": { + "sink": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3440555488, + "signature": "3YjE4YpSZT1wXeSk57dn8UrLTMQEWkLqF2r7LpApgEvjMt2h6k5GrkEQfeu4JtsHkPZJvVKqGZkhzKeDxFvroTJj", + "slot": 409527481, + "block_time": 1774739788, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ": { + "address": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 107 + }, + "first_seen": 1783458420, + "birth_edge": { + "sink": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 113580000, + "signature": "5ZgjZruTRMzF44tmPbZD6YJgg6LZQjkcbMBGyezVXdjbnb3BX77K2dUaVhG5gQDApdA3ufCKKDUZbqZtX6pMkvE3", + "slot": 431453303, + "block_time": 1783458619, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ": { + "address": "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 618 + }, + "first_seen": 1774728729, + "birth_edge": { + "sink": "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "sources": [ + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "value": 11650417543, + "signature": "5TnbPcr9zLALAWF82aL7PVBNbX7PkaUTzdXgAWEnvZAeE8n5cYzXhyEKh438w9uj6LrF316rj73McA84g5DHueHM", + "slot": 409499170, + "block_time": 1774728729, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "funded": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "birth_scan_exhausted": false + }, + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG": { + "address": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6 + }, + "first_seen": 1784519630, + "birth_edge": { + "sink": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "sources": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "value": 104889883544, + "signature": "5162f689Bxmi9PA5Fj9QVxBuxjHrWqbJnoHVVjnmUg4HB9j8XnMvUmLaugVAcyEnAbpiPQNQiukSiE2D2H2AUKaQ", + "slot": 434026767, + "block_time": 1784519630, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC": { + "address": "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1748177913, + "birth_edge": { + "sink": "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "sources": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "value": 1029000000, + "signature": "CfG62TFDb4cuNH7FNWz4Cr2Ga14r88NoTXbSDkWmGSDhFTqxdKxinZcyAeSJ33eE1VPiqfwfgcBcmyMRijYEDNb", + "slot": 342369414, + "block_time": 1748177913, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "funded": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "birth_scan_exhausted": false + }, + "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM": { + "address": "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1783098068, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm": { + "address": "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784580094, + "birth_edge": { + "sink": "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "sources": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "value": 50607243678, + "signature": "2h4gvshcwfRhkDXQhiLMAWYTWM4xMUnW8iGdJpEnhQRUYZy5DuMQma319GnL8wCprP7MTXGgb8ymBWvQ1jwTwoht", + "slot": 434168171, + "block_time": 1784580094, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "funded": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "birth_scan_exhausted": false + }, + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m": { + "address": "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3738 + }, + "first_seen": 1632342722, + "birth_edge": { + "sink": "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 2099995000, + "signature": "56mSUdyemWLDwZbWDjZCUhJDHGqgJaGiMGVKSDovzLsM54Lc26JshmZPgz4R3N6Se2B12z8CkeAQGsQz8ELb4XjJ", + "slot": 97853541, + "block_time": 1632342722, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "37Sr8FuzLEviyv8UD1Whz4eeY3ocyy7TXKqPEEpCRRmT" + ], + "birth_scan_exhausted": false + }, + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K": { + "address": "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 581 + }, + "first_seen": 1775667915, + "birth_edge": { + "sink": "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "sources": [ + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "value": 12399485120, + "signature": "1hqU1oga3ZT4F3uT5iAm3W4zB3eiH9vd2Rop2Rtyva35zubCfiYZCFgAaSaBCD48a3iTz1aL9zpTnZ4JRq6yZE5", + "slot": 411892813, + "block_time": 1775667915, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "funded": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "birth_scan_exhausted": false + }, + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE": { + "address": "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE", + "owner": null, + "executable": false, + "signatures": { + "Exact": 930 + }, + "first_seen": 1784212794, + "birth_edge": { + "sink": "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE", + "sources": [ + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g" + ], + "value": 23308100465, + "signature": "48hdxxJEtMvxPq47QrfdcsDqMDNP8FzBPgM3RN4YfsmFxFrnsRSuNHEdiXcnjYTxujSyVAooQqfo271w8BCoKFVk", + "slot": 433291812, + "block_time": 1784212794, + "ambiguous_attribution": false + }, + "fee_payers": [ + "762tKYCb7d8EDuCKnmcdjunrtSNGXe8yBwfufCQfWf9g" + ], + "funded": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "birth_scan_exhausted": false + }, + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38": { + "address": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 567 + }, + "first_seen": 1759849779, + "birth_edge": { + "sink": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "sources": [ + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "value": 1000000000, + "signature": "55aNfhpFmWyptpJ52kvWWSpaHePRjZLDNbf9kzwSKgUtvvcp4XFhGpKXbU5tVD4wYFh3DrtjJpfnKfLoyGKkadYN", + "slot": 371813843, + "block_time": 1759849779, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6": { + "address": "BmFdpraQhkiDQE6SnfG5omcA1VwzqfXrwtNYBwWTymy6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784392548, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja", + "79nbbtVw7yJwUajnDEEDRZXjjBebCUXBLP7EdvZJdLme" + ], + "birth_scan_exhausted": false + }, + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo": { + "address": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3597 + }, + "first_seen": 1736334578, + "birth_edge": { + "sink": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "sources": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "value": 170000000000, + "signature": "2MLS8L4uUc8L3nNZpej5csKZ3d5JuNqKGkUjpX1E1ebmqEBzcxBP3ZccC4FvbAgAFWchKPoey8mhH98JCnCxCQ9x", + "slot": 312653033, + "block_time": 1736334578, + "ambiguous_attribution": false + }, + "fee_payers": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw": { + "address": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 155 + }, + "first_seen": 1780608496, + "birth_edge": { + "sink": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3965000, + "signature": "2jPiYFrpAtgu9YXus8V7NPkAWW6xWy5zBdh42P7S5sticdDDVgPGo91ne8yDeLjXhZHyH6zxZnWg69yPXRApwheC", + "slot": 424324895, + "block_time": 1780608496, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ": { + "address": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2999 + }, + "first_seen": 1780098381, + "birth_edge": { + "sink": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "sources": [ + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw" + ], + "value": 800000000, + "signature": "3owWqGQL5cNVZcCTN235bbaS2gyez3LxGz663Gej6dtmqBhUyrbhJNfoP1VaVryXN47bdKWoxji34CAu6oUPsxdP", + "slot": 423040927, + "block_time": 1780098381, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P": { + "address": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 96 + }, + "first_seen": 1784854429, + "birth_edge": { + "sink": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "sources": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "value": 6000000000, + "signature": "5KA9mkbPhkRXKEhf1FeiRuxHphiMMkRgq3FsNjkKk2Ra7gRMMqmB7V5gEvocEESMeK24LVsUC24gWjBx7EyiX3Kp", + "slot": 434821643, + "block_time": 1784854429, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis": { + "address": "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD": { + "address": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 627 + }, + "first_seen": 1753997946, + "birth_edge": { + "sink": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "sources": [ + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "value": 123066991, + "signature": "5Rtx3JoWd3XaAGxkckRh6w7aeW4W9M2ZbG8NQt7SDLdunYiy5eHXiF3Kc9Dp8QBMJABzH2T2ctoAzCEZF57ckAAB", + "slot": 357026958, + "block_time": 1753997946, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA": { + "address": "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "C8nKoCYa6vbtv51Gszak8W8UoMzCu32ks56rDYdMpwwr": { + "address": "C8nKoCYa6vbtv51Gszak8W8UoMzCu32ks56rDYdMpwwr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1732470808, + "birth_edge": { + "sink": "C8nKoCYa6vbtv51Gszak8W8UoMzCu32ks56rDYdMpwwr", + "sources": [ + "FzZ77TM8Ekcb6gyWPmcT9upWkAZKZc5xrYfuFu7pifPn" + ], + "value": 2039280, + "signature": "5JvDwz1GpjepgZy57RRa3QLJETqzfAVFf2UGDcn3Qb5n47necpTwTHM5UvBppqmx1YtmwQYH1MbeaDmCMnNZc72b", + "slot": 303378506, + "block_time": 1732470808, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FzZ77TM8Ekcb6gyWPmcT9upWkAZKZc5xrYfuFu7pifPn" + ], + "funded": [ + "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai" + ], + "birth_scan_exhausted": false + }, + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr": { + "address": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1784599658, + "birth_edge": { + "sink": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "sources": [ + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW" + ], + "value": 440000000, + "signature": "4QJkfNCAWjNh2mfYrx9WN6EBe6cCpPUABueLgf4WfqJ5smBUdqbHDcsQXAHT6d8a6q4hFNMvf7jAozFE4jw1rXwj", + "slot": 434214781, + "block_time": 1784599658, + "ambiguous_attribution": false + }, + "fee_payers": [ + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob": { + "address": "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 134 + }, + "first_seen": 1784218241, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "AgmLJBMDCqWynYnQiPCuj9ewsNNsBJXyzoUhD9LJzN51" + ], + "funded": [ + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG" + ], + "birth_scan_exhausted": true + }, + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh": { + "address": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784649420, + "birth_edge": { + "sink": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "sources": [ + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "value": 1850143000, + "signature": "3YgFygisXK1X8kyUXV6LzPEcJ36tKUDkuyo7UvX3KdwULNGDe2wLYiB7KSCVcyM9NejVf2Q4Gr2KV2p11SSvGbCy", + "slot": 434333385, + "block_time": 1784649420, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb": { + "address": "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784389224, + "birth_edge": { + "sink": "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 807213726, + "signature": "2MwPJoYeQHsFvpTXyue8m776mx5fBtFDYgY7hcZpTuz641UR5R8xz7yoe7NXT8e1mRojMFpwKs6Pkdk1fFgSe6zr", + "slot": 433716518, + "block_time": 1784389224, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ" + ], + "birth_scan_exhausted": false + }, + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT": { + "address": "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1784838909, + "birth_edge": { + "sink": "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "sources": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "value": 6000000000, + "signature": "3wsTxnCcjxate2zoeFse3mstAwC5KUkvVH4AWjgi9FTKZmwvm7vjJb7N5EPGR5rpcDePeFVXxopoMKiWRsG67bTu", + "slot": 434784661, + "block_time": 1784838909, + "ambiguous_attribution": false + }, + "fee_payers": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "funded": [ + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P" + ], + "birth_scan_exhausted": false + }, + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB": { + "address": "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 44 + }, + "first_seen": 1768894237, + "birth_edge": { + "sink": "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "sources": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "value": 849079919, + "signature": "ZPtjQoLcno8LwEZaoxwJrAZfMfcHmszyxAA1V2FW6ohJxa3tbczaP1T4s4d5HgxHTxDS7tTjRK5GnV3x55nWPCQ", + "slot": 394707808, + "block_time": 1768894237, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "funded": [ + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG" + ], + "birth_scan_exhausted": false + }, + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN": { + "address": "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784377763, + "birth_edge": { + "sink": "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1299793806, + "signature": "wbcYZ4GZzni8ThU986zLwqQUmhcY4gZfGFBbC1ffpv6TwUkWtxPLvUt6FB3fT9DvuaEKu21bsm6RwpSBVgrkiEh", + "slot": 433689096, + "block_time": 1784377763, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9" + ], + "birth_scan_exhausted": false + }, + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU": { + "address": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784657908, + "birth_edge": { + "sink": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1996965000, + "signature": "5bJGTURSxfgDoe8QBCjFXtRwNcrBHqLyN8oJ3HjztNDMnbgtzNG11DtZ51MgkqAkcii2BWghA9KB3MitvWTQxF5d", + "slot": 434353532, + "block_time": 1784657908, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94": { + "address": "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894203, + "birth_edge": { + "sink": "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "sources": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "value": 849109919, + "signature": "2XXhJExg7yyA6WH34H5Q99ZtCVavER65hC3V7tf6oNm5onx4KDVoDEpSgAaoupvn721NrE7KdSiMQ4cjKZY1UfJy", + "slot": 394707725, + "block_time": 1768894203, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "funded": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "birth_scan_exhausted": false + }, + "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR": { + "address": "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12753 + }, + "first_seen": 1710763330, + "birth_edge": { + "sink": "CoBwyPttQPbAprmAqhgFQnXD4vxN9d6ERcz4XSNdEzrR", + "sources": [ + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9" + ], + "value": 1200000000, + "signature": "3BsEYvaLSedjLWzUCzbGUVGT33rwY35m6mzWnXSLit5zTTJ7vctb7oDjhv1mCdUZLWtRHcLMYSxYz5Dp4hhhc5Nw", + "slot": 254924622, + "block_time": 1710763330, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3vBekALpEMwf59ayddsgc8KJ423gPkxMsd1hwNAKBAN9" + ], + "funded": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "birth_scan_exhausted": false + }, + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz": { + "address": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12758 + }, + "first_seen": 1781801872, + "birth_edge": { + "sink": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "sources": [ + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe" + ], + "value": 100000000, + "signature": "2B1U3i2nZKDXancwuyt9UxUa7AJcqgiVyuXzZhECVSZwiy5CKYE7xe5KcEgGymmMS2FcifLQRD7PNgDhhE3zGEkJ", + "slot": 427328708, + "block_time": 1781801872, + "ambiguous_attribution": false + }, + "fee_payers": [ + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU": { + "address": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2660 + }, + "first_seen": 1777272559, + "birth_edge": { + "sink": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "sources": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "value": 2500000000, + "signature": "ETzNdupbU3xXhkPGEw9Hn8tPN6NDugSpsVob4iHjzcfzccdcUAisMiYbqkwSbCm6AxsfqxZvhjfCCUC3P1kEHRc", + "slot": 415950310, + "block_time": 1777272559, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA": { + "address": "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784868800, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "DkzL477CEJQSynqqqStK378vfCjzxRMvotCz8xdoVzv9" + ], + "birth_scan_exhausted": false + }, + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U": { + "address": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 272 + }, + "first_seen": 1757688961, + "birth_edge": { + "sink": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 93700000, + "signature": "3PeWiircHtHEH9T78i4FKAoUNP3568WEdnJr8PgTPdhPPi958X6NrtthHtGn2r21ovMKKWwCo8TkMtc6rmzw6odX", + "slot": 366350032, + "block_time": 1757688961, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR": { + "address": "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1776160820, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi": { + "address": "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18105 + }, + "first_seen": 1738500891, + "birth_edge": { + "sink": "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "sources": [ + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf" + ], + "value": 29400000000, + "signature": "4ChkDoLctkN81tVBKsZMZVqvdAZViy4zrsKb9K8FiiuD4zvuJnzXq2qjMZAnVNqReUqo7Tb12d3knN7qTDW96mZw", + "slot": 317992649, + "block_time": 1738500891, + "ambiguous_attribution": false + }, + "fee_payers": [ + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf" + ], + "funded": [ + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1" + ], + "birth_scan_exhausted": false + }, + "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX": { + "address": "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff": { + "address": "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784043065, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "DkzL477CEJQSynqqqStK378vfCjzxRMvotCz8xdoVzv9": { + "address": "DkzL477CEJQSynqqqStK378vfCjzxRMvotCz8xdoVzv9", + "owner": null, + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1784813668, + "birth_edge": { + "sink": "DkzL477CEJQSynqqqStK378vfCjzxRMvotCz8xdoVzv9", + "sources": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "value": 2039280, + "signature": "4aCLGjAGKpkimChSRq33MU7uy3sa1TV5aHA6tCKKeynpXDSdSgugjisTHUqALnAQoJCzJmMYBnm1zhaoexv8wvBD", + "slot": 434724624, + "block_time": 1784813668, + "ambiguous_attribution": false + }, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [ + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx" + ], + "birth_scan_exhausted": false + }, + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x": { + "address": "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784934326, + "birth_edge": { + "sink": "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "sources": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "value": 54374849153, + "signature": "4Y7SpKFVWPXmK1GJQMsZfuQnxiYyoi7NcJbchUzRemXMGt3DWRUWJBT7L8seY3MymYCvHhSv7XravPdS34KHgmpL", + "slot": 435012112, + "block_time": 1784934326, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "funded": [ + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za" + ], + "birth_scan_exhausted": false + }, + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn": { + "address": "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784443666, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9" + ], + "birth_scan_exhausted": false + }, + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K": { + "address": "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K", + "owner": null, + "executable": false, + "signatures": { + "Exact": 55 + }, + "first_seen": 1730861242, + "birth_edge": { + "sink": "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K", + "sources": [ + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF" + ], + "value": 50000000, + "signature": "BoLFuKgcg38xZSUt14Y5926pkU6LLbaXAKPHPqTzfCKUCYyRNa5T3msnqj7QtwrjP8FUFHxsTKELrjYKA1gUvtX", + "slot": 299749544, + "block_time": 1730861242, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF" + ], + "funded": [ + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs" + ], + "birth_scan_exhausted": false + }, + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq": { + "address": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 294 + }, + "first_seen": 1764868637, + "birth_edge": { + "sink": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "sources": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "value": 1390000000, + "signature": "42jLxFrfSKoLo8ZPnaMZfGU56WVo4mrSi1RUEweRK84j2R4vSSRetdHu9HErxgK6eR87R6vt2c7T2C4KUTaDjf4F", + "slot": 384466286, + "block_time": 1764868637, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do": { + "address": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1776858197, + "birth_edge": { + "sink": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "sources": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "value": 1007615782, + "signature": "2KPM9xqT2mfMAqEZDX51t6o3RgYoLnJZgU6NPzZ57YV14DZy8VsnyYxntqnKbhtYAZwE4puvnjUP9PmE5y4aUBa1", + "slot": 414903289, + "block_time": 1776858197, + "ambiguous_attribution": false + }, + "fee_payers": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW": { + "address": "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 549 + }, + "first_seen": 1778972678, + "birth_edge": { + "sink": "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 6632702930, + "signature": "vJcCHLLH6FaWPDarJWTvMdpKckbK9yPGhy9qgUgypRyheTmVdPiEMf5vCioqKT82iF8G7VZ95vXGuYWoECTAh2B", + "slot": 420215149, + "block_time": 1778972678, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr" + ], + "birth_scan_exhausted": false + }, + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH": { + "address": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 369 + }, + "first_seen": 1745361264, + "birth_edge": { + "sink": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "sources": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "value": 1000000000, + "signature": "5Ugmig4PTLRcf3GTuiY6G47gQn5bxj3UDp4YpKDsvY1JaPwwn1DMU1bQPnTXgrP8wQtrEZfmpLthv8gjADrp7mpu", + "slot": 335243820, + "block_time": 1745361264, + "ambiguous_attribution": false + }, + "fee_payers": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o": { + "address": "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu" + ], + "birth_scan_exhausted": false + }, + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn": { + "address": "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5289 + }, + "first_seen": 1702336727, + "birth_edge": { + "sink": "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 4372981634, + "signature": "5KeWCHfUdwtMws4e48ZDAqSa2K6bFWeiX4irurLzrFw1geWqtgjHvY1F8T8Cma4n6XuaJ3TbQBaKFZjeLGEK6Wau", + "slot": 235369057, + "block_time": 1702336727, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH" + ], + "birth_scan_exhausted": false + }, + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM": { + "address": "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 157 + }, + "first_seen": 1780522066, + "birth_edge": { + "sink": "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM", + "sources": [ + "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9" + ], + "value": 440000000, + "signature": "5JpzkAF9YrtSadSe8BhHaMYVFBBiugjYzeNr6qEYenDvBzjpckr5s5LQ1zKeGb1WC3ZbVmgWtQypaHJS4pcQLYEo", + "slot": 424109020, + "block_time": 1780522497, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q", + "6n5o3qNBAjqVjSGZ8qDWoWAHZdxWKpENVh4sJMLzmwL9" + ], + "funded": [ + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW" + ], + "birth_scan_exhausted": false + }, + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx": { + "address": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1150 + }, + "first_seen": 1737448881, + "birth_edge": { + "sink": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "sources": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "value": 672745485, + "signature": "64C1Msn6wiLA7U5x5ZjYhPx2cj813py9Pft9Bc41VYtbtWHinBJefXt3rj5KaWTuvXC7aoYwr3Y8tsfj1zed1ZSw", + "slot": 315391758, + "block_time": 1737448881, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ": { + "address": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 58 + }, + "first_seen": 1783645887, + "birth_edge": { + "sink": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 14433952357, + "signature": "4RbXiaGAmS7WfUmruWn3zBUTwaF2WzVDno2bSTiZFH7cbYSeVeUGgS184pvQaV3ySoRBNGkx6r68M8r5AA5ZbJTo", + "slot": 431912014, + "block_time": 1783645887, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp": { + "address": "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe": { + "address": "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785035302, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ" + ], + "birth_scan_exhausted": false + }, + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL": { + "address": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 89 + }, + "first_seen": 1784429559, + "birth_edge": { + "sink": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1987000000, + "signature": "22tiKy2Uhr5HbzaoUTkf5gTS2VHov1xMY998kBCQbYybACx6Y3fJtxRBaj8ppaMyahAGEgnC5SggnKt6HbxcwNRb", + "slot": 433813000, + "block_time": 1784429559, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B": { + "address": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 145 + }, + "first_seen": 1769758558, + "birth_edge": { + "sink": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 193300000, + "signature": "52ygQjkxX6CiTWcaT8KoncyGrbR97uAqzrJ91LySCtkZDCNDa3WTHpnvNSJkRXacynWy4D5j16sFCh1PWGdesPET", + "slot": 396868730, + "block_time": 1769758558, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt": { + "address": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11 + }, + "first_seen": 1784509948, + "birth_edge": { + "sink": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "sources": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "value": 14000000000, + "signature": "55y1RvP9p644eWZy6JypDF39fB4u7XCBXYmQhjDRX5AgytWCpsC2J4SiffzCo9gLPHpPoqs6AXrCXyb7mgUooZXD", + "slot": 434004156, + "block_time": 1784509948, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm": { + "address": "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894210, + "birth_edge": { + "sink": "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "sources": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "value": 849104919, + "signature": "2ga76DPJVD9CWDYmtpb17BURi9EcLNFxeNFi172x5aRN9es1qAh5HRHf9ZNCzGtADfp9LzzcF2t26MdDn5jEDT5C", + "slot": 394707744, + "block_time": 1768894210, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "funded": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "birth_scan_exhausted": false + }, + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor": { + "address": "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 856 + }, + "first_seen": 1783108022, + "birth_edge": { + "sink": "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "sources": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "value": 200000000, + "signature": "3XBCwvm2pUrPEp3PCUKm4NiNy7pGhpxqpy2u2eWnMBs5sJgoYk55DPp77RSEn4m2vL9C61sWiefBAiArFGEaUgFw", + "slot": 430586035, + "block_time": 1783108022, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "funded": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "birth_scan_exhausted": false + }, + "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf": { + "address": "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 996 + }, + "first_seen": 1752221038, + "birth_edge": { + "sink": "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf", + "sources": [ + "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf" + ], + "value": 3010000000, + "signature": "4iJnDGLdugCoiXCAoSMZ7FzxRcXA6T6WCNK8harksPvwxFUWU3BM4B4KnQNarzjcRVdRuNw5iytvfaSwTzf6wQmG", + "slot": 352550106, + "block_time": 1752221038, + "ambiguous_attribution": false + }, + "fee_payers": [ + "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf" + ], + "funded": [ + "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r" + ], + "birth_scan_exhausted": false + }, + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd": { + "address": "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 48 + }, + "first_seen": 1765645486, + "birth_edge": { + "sink": "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "sources": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "value": 88200000, + "signature": "sH5bnyJn2BNFN3TgD2isA2G5ygXEsGzWr9kpgN2PW5Ubxk3nAHyLRprFmS5M2FzdbTTZD2RjxfgH7xfbARZtdHc", + "slot": 386459128, + "block_time": 1765645486, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "funded": [ + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ" + ], + "birth_scan_exhausted": false + }, + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM": { + "address": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1784461923, + "birth_edge": { + "sink": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 990500000, + "signature": "9duBpzRRMAZ2cQv2n79HKMzurHUBWmDWdDwNR8y6U48bnG6HKY2HZnrQxXNFVFpg8RtSy3KPNEY4ByMKHEBJCEb", + "slot": 433890247, + "block_time": 1784461923, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ": { + "address": "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1670 + }, + "first_seen": 1784580105, + "birth_edge": { + "sink": "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "sources": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "value": 49209767318, + "signature": "2BVoGzFZrFnuRLqpW1EAHxkFXmnp7xWp1wog4n3EBnCbTgQLvSgFVZHB8z4Z1FgdzjYGBh9tTUFZ1aLF2XtYCuKU", + "slot": 434168198, + "block_time": 1784580105, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "funded": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "birth_scan_exhausted": false + }, + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN": { + "address": "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 18203 + }, + "first_seen": 1712861701, + "birth_edge": { + "sink": "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN", + "sources": [ + "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J" + ], + "value": 100000000, + "signature": "2YSSsjdWzcSHyrYYRJy7C6JT3pT8iZQGVbJPMpPVCGzKk48L3CWwuqTx9fMkmrYstCeQVX4p77wz4HmL2qyMHYVK", + "slot": 259584539, + "block_time": 1712861765, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J" + ], + "funded": [ + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe" + ], + "birth_scan_exhausted": false + }, + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7": { + "address": "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 48 + }, + "first_seen": 1784809669, + "birth_edge": { + "sink": "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 5973000000, + "signature": "3MSs2ea12TniywAz7iM9anGzcgJr8oB1kCVxVQm8YgQxqoCwwPpzBhg6EACKhpDuWoT6J723YZfrnDq8qqfLSTRJ", + "slot": 434715093, + "block_time": 1784809669, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "birth_scan_exhausted": false + }, + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k": { + "address": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 955 + }, + "first_seen": 1781405876, + "birth_edge": { + "sink": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "sources": [ + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK" + ], + "value": 55000000000, + "signature": "3NpN3bBydLQE7k375NJpiQnNumbTbwDBmNSZ3yjFR9UrXhkjoWQu93SAwyL3oBQjwq3Ngmmc9BW4xQJduKX3Z3sL", + "slot": 426330281, + "block_time": 1781405886, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B": { + "address": "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "owner": null, + "executable": false, + "signatures": { + "Exact": 15 + }, + "first_seen": 1737447329, + "birth_edge": { + "sink": "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "sources": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "value": 672750485, + "signature": "4gBVShePEtPdc8c9vLekxqxtKnHN1CaY2ECsfrU3Ysoo7AeQGVwwpqLDW9aAWYF3KSsekeoaA1aqHrTqAEHwSGuN", + "slot": 315387958, + "block_time": 1737447329, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [ + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx" + ], + "birth_scan_exhausted": false + }, + "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv": { + "address": "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1774644756, + "birth_edge": { + "sink": "Fs82mFGwmL36XREhYgQGpmb4JDiGWDdXm8ALTP3R7wwv", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 5973000000, + "signature": "5fTttEt3Pb3F4Sj5dKKrkqFCZEJqR37qyLLYVSA7GwBqbyn4MCv2LDEZBKuh9pGRhdxTJa7xNMKH6c53gXrno7RZ", + "slot": 409284059, + "block_time": 1774644756, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY" + ], + "birth_scan_exhausted": false + }, + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF": { + "address": "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF", + "owner": null, + "executable": false, + "signatures": { + "Exact": 253 + }, + "first_seen": 1730807547, + "birth_edge": { + "sink": "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF", + "sources": [ + "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP" + ], + "value": 704147548, + "signature": "5KG9RmaRtZiEhhjCLK3qbwhczgeFao4cCPCNFGAt9ZmyUeAqK3Rviq2g6QCrd5maMV1KuoBP1cds2Wr4BgyK77nk", + "slot": 299638304, + "block_time": 1730807663, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP" + ], + "funded": [ + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K" + ], + "birth_scan_exhausted": false + }, + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw": { + "address": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 14493 + }, + "first_seen": 1777091838, + "birth_edge": { + "sink": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 18571768434, + "signature": "44VV33bxUiT3rDmG3dtN2uxnDx4uBs6keq7PWCmx3rdqWhvPmPXJhrA7Sq7atABrqAkpaBZH5wdRRWMkFQ7j8kNA", + "slot": 415493545, + "block_time": 1777091838, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "FzZ77TM8Ekcb6gyWPmcT9upWkAZKZc5xrYfuFu7pifPn": { + "address": "FzZ77TM8Ekcb6gyWPmcT9upWkAZKZc5xrYfuFu7pifPn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1777383974, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "C8nKoCYa6vbtv51Gszak8W8UoMzCu32ks56rDYdMpwwr" + ], + "birth_scan_exhausted": false + }, + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs": { + "address": "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7899 + }, + "first_seen": 1731918662, + "birth_edge": { + "sink": "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs", + "sources": [ + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K" + ], + "value": 11000000000, + "signature": "4NrJoknq1Jx9gtAQ8bxTuhWoNxMWggLDQS4XBN1zsNRVXGfCvC21JBkKGsxLH9hppZBa6KxaMLve5iiowk75DVLb", + "slot": 302103526, + "block_time": 1731918662, + "ambiguous_attribution": false + }, + "fee_payers": [ + "E3D5kVEJbT2dnRgMknuMvz8n4cq8aT4stZ9YYy593N4K" + ], + "funded": [ + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf" + ], + "birth_scan_exhausted": false + }, + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G": { + "address": "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1781111107, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg" + ], + "birth_scan_exhausted": false + }, + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE": { + "address": "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784781784, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV" + ], + "birth_scan_exhausted": false + }, + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT": { + "address": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784758056, + "birth_edge": { + "sink": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "sources": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "value": 90000000000, + "signature": "2yFwMANAjHWBoCUWXwsF2NS8Vm24oSkE5oJ6RfsDe2jPVeo782fE98nePAJqpuxWL1VkA5iQXoXdDoU8SqopCTR2", + "slot": 434591833, + "block_time": 1784758056, + "ambiguous_attribution": false + }, + "fee_payers": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq": { + "address": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 65 + }, + "first_seen": 1784659136, + "birth_edge": { + "sink": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 32880718309, + "signature": "4wZbNhexVa96s82hAQbdZ9Pq1fqencGxxmKYCwghVjT6iwxMLyyKBssfwvWVJFXFMXxNwSfrDo8TqZ4AiJbEPC6U", + "slot": 434356458, + "block_time": 1784659136, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC": { + "address": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 298 + }, + "first_seen": 1783054209, + "birth_edge": { + "sink": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "sources": [ + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "value": 180834295, + "signature": "55tLEDwJyuDGaSo8c6yYz4bj5utz7zJiVtQnsQuwqKg7abdYWVoK1vFkLQd7pyJhjh4r8ku6i9oCyXRa8a6kX18z", + "slot": 430452695, + "block_time": 1783054209, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf": { + "address": "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894200, + "birth_edge": { + "sink": "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "sources": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "value": 849114919, + "signature": "5Gb3um1roTYvbjCFckDeFVPkU7QxKeShYSL3KWDxSEX8qhCrwgDEJgbSiuL3L4tCXzk1GaguKXBbmAU2yjAVmkdG", + "slot": 394707716, + "block_time": 1768894200, + "ambiguous_attribution": false + }, + "fee_payers": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "funded": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "birth_scan_exhausted": false + }, + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk": { + "address": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1154 + }, + "first_seen": 1777988933, + "birth_edge": { + "sink": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "sources": [ + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "value": 2362855000, + "signature": "Vdct3Y5hjgKy2gHHjimC9YE8faisFo7jz3EiFYjmb3yAYuHpY2tE5ZqJcXhMNtbrrXTRr5CxYpCz5djyYzwgJyb", + "slot": 417761237, + "block_time": 1777988933, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho": { + "address": "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "owner": null, + "executable": false, + "signatures": { + "Exact": 600 + }, + "first_seen": 1784462427, + "birth_edge": { + "sink": "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "sources": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "value": 51022180729, + "signature": "4udxkWqxkyLqBAZpUJHNMkZDcFMVTq1BpaC2A5YqNGbm6He6WAYpQGQXMY5J91YcUxxZATqVkJooVP9y3EXqpABd", + "slot": 433891452, + "block_time": 1784462427, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "funded": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "birth_scan_exhausted": false + }, + "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp": { + "address": "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J": { + "address": "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3385 + }, + "first_seen": 1634119967, + "birth_edge": { + "sink": "Gvy8F7L7JjaiFSmNpgCjpDrArXbtRQkRKwijdLRdEv6J", + "sources": [ + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "value": 310000000, + "signature": "5sRWZE4rpYG3LpEb1rGQKy7x2CJry6y2ekJukNkFE3NpgSX5PqN24oyoyJE5tDw6nrmcQkeAvcw961G3yUdYt2DA", + "slot": 102567198, + "block_time": 1634740692, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9JqkbkGecn7FtryKweonAT445Y8KaLaEQhutxPN7d7xN", + "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" + ], + "funded": [ + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN" + ], + "birth_scan_exhausted": false + }, + "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP": { + "address": "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP", + "owner": null, + "executable": false, + "signatures": { + "Exact": 105 + }, + "first_seen": 1671008446, + "birth_edge": { + "sink": "GyCwk4A6Hbszbw7H1VH4DZhjugmZRgAqAf5Gmcik27mP", + "sources": [ + "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja" + ], + "value": 750000000, + "signature": "3MPx7uhsdKLSamxE4Q5fGaK2ycW3DzFaMhLk92XmjhTa94bEE8Peg1DnebE8Edk4K3dGQw42DmJ9eQaYZsCJgg18", + "slot": 166798101, + "block_time": 1671008446, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9Kjd4PMdZFQrzuGvv7PuMA1uXTu433GP5CqHGNaJhtja" + ], + "funded": [ + "FtuidQt6GZ2L9y67rHMqskd4DceLDj2W9WpWMWvLSRxF" + ], + "birth_scan_exhausted": false + }, + "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF": { + "address": "H2PVM96jQomH864kZAAxRMFBZaHbdKQG2iG21v52jRxF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1744045119, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2ND3iffXP4SQ5NoivmjmeuNXe5LjFUjQuVwtPWS7CB2X" + ], + "birth_scan_exhausted": false + }, + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva": { + "address": "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1629 + }, + "first_seen": 1784212802, + "birth_edge": { + "sink": "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "sources": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "value": 22180583705, + "signature": "59BrgexB78Kj9fCJkHmKs2UZYsp5Ntc5ia4RpE3T1WS8xtwyJEhn49w5VcofBvhkHWa9AxfEQsR1L6qjNFKdZnhj", + "slot": 433291830, + "block_time": 1784212802, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "funded": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "birth_scan_exhausted": false + }, + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS": { + "address": "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784779719, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BMDvnhyfuNQpJNRrrDQ3yC8nR33YUfwd5hsB17HCfy7m", + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "birth_scan_exhausted": false + }, + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ": { + "address": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 20062 + }, + "first_seen": 1780029667, + "birth_edge": { + "sink": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 2442413156, + "signature": "2UXxvAd3GMF7t1ZMWhrXJcFP3q6iYYcZBEMeynG6PWWz8vrttyjdwXo1KSxrYhGU8zchaaM6979gnU1mz4d3dHKr", + "slot": 422867536, + "block_time": 1780029667, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe": { + "address": "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 737 + }, + "first_seen": 1784227892, + "birth_edge": { + "sink": "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "sources": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "value": 130000000, + "signature": "kTyjASGv9R4C1zjLJriyX96k2ZWgbAwPw3Qd2z3pCzb5cRPuZs3vt8uqzKH2bjr5AdqMDwf8SnxCqbwyt2cWwdm", + "slot": 433328336, + "block_time": 1784227892, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "funded": [ + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt" + ], + "birth_scan_exhausted": false + }, + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq": { + "address": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 14 + }, + "first_seen": 1784552253, + "birth_edge": { + "sink": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "sources": [ + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "value": 23698818508, + "signature": "3uywYCF5VuSzVQkMX6Pghx7SXTsJuW55Jv37zcHt1foh71Nuq6vGrb4keCz7JNFjLMRWkK5Aq2jNmWhqkWbXuH8y", + "slot": 434103135, + "block_time": 1784552253, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC": { + "address": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4402 + }, + "first_seen": 1776709519, + "birth_edge": { + "sink": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 4909585890, + "signature": "5VEpmW6pcMbLtJQHaJbctF8BUkixM7cH6gwV5yMHLtJtq5DaCpFaKRydWVjQ85d3uA9ErzyjYTkqyfHriUeN1D8E", + "slot": 414528392, + "block_time": 1776709519, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165": { + "address": "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1776477779, + "birth_edge": null, + "fee_payers": [], + "funded": [], + "birth_scan_exhausted": false + }, + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9": { + "address": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1784377766, + "birth_edge": { + "sink": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "sources": [ + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN" + ], + "value": 1299788806, + "signature": "DonAnKr8whXoDnWemm9bqSjoUQdEohd9sus4nhstSat4cF5HxAmnrHQqMEbbNW3s9KhRDYLvL28ifTpBj16tWha", + "slot": 433689104, + "block_time": 1784377766, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k": { + "address": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 112 + }, + "first_seen": 1783337142, + "birth_edge": { + "sink": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "sources": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w" + ], + "value": 2000000000, + "signature": "3TYxeVhY5FHcpE3BqdMtf6RUScLkjcsXBpZnPjc8YfGiTXw25vLWWvd3vZWPE9V6kBcLpzMrph82uRoprzHPNvKU", + "slot": 431153926, + "block_time": 1783337142, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v": { + "address": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 8839 + }, + "first_seen": 1769181912, + "birth_edge": { + "sink": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "sources": [ + "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai", + "44GW6aFire4Fd72h4QqjenNKrQLjfnApHhWYXo3S1gvp" + ], + "value": 2079130000, + "signature": "59iZNmvqD8XUZ7fth4tAHjCaoQMcBHFdeTFmXSvHD6kVmFTxzeAfRdgQu3njeW9Lew3EgoJv3DNwrcKw2QUco7MZ", + "slot": 395430963, + "block_time": 1769182419, + "ambiguous_attribution": true + }, + "fee_payers": [ + "BidtDwH9WbEvm9T6tqqsEgAscTzLJeX6H2rGbw22jR39", + "7xcCLxFxNxGdj8XPTveMh7gZ8vhEowe6Si9QpoFuCZai" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ": { + "address": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 51 + }, + "first_seen": 1783637441, + "birth_edge": { + "sink": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 22952461058, + "signature": "63UUpBFp2VbRkpjKsc3FaXXucqtzjTyPZCsqEtoXBxNiW263FxXHdr6Coo7FksLHC3amGnSZoV9rD9uR4G4yKMfo", + "slot": 431891370, + "block_time": 1783637441, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE": { + "address": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3053 + }, + "first_seen": 1761711549, + "birth_edge": { + "sink": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "sources": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "value": 10000000, + "signature": "42BSukNNZwdKRuESCNwP7Dr8xn7HmRc21PNP6PdSa36WrF1mbw2n3CatJwkBzviQiutmRPDn9oCR7bJo4jXDVtzM", + "slot": 376499867, + "block_time": 1761711549, + "ambiguous_attribution": false + }, + "fee_payers": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ": { + "address": "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894187, + "birth_edge": { + "sink": "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ", + "sources": [ + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x" + ], + "value": 849119919, + "signature": "5hopWZ3eVdGLYmfhGBcqbvTV2SGzmQc8X3KyyfBQ36QzCcyGtMkxBKhTLuYwftq866p9ZdaZFVMbrsRNNGjzE3Cm", + "slot": 394707684, + "block_time": 1768894187, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7Jx48Zct3x8Y3qikV6LXHZx4572pMoCY4VkPGDrXA86x" + ], + "funded": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "birth_scan_exhausted": false + }, + "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf": { + "address": "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 171 + }, + "first_seen": 1751927442, + "birth_edge": { + "sink": "fkY8mx6y5VYYsybgy3q2A5A8ZphJewgmBBhx4ZsEAQf", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 60735245700, + "signature": "SX1PR96BYugSoJvSnb2V1NN4kaC4wFtc4tt9RLpMa63gmdV38vfJuejYgMXnByaFg3qa8T1GAinuq8f7E69BsW4", + "slot": 351809035, + "block_time": 1751927442, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "FWKrAi8ZDaeKx9NQoJmLGyMoujLUUjsM8pqmghFqrtaf" + ], + "birth_scan_exhausted": false + }, + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu": { + "address": "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1784720951, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn" + ], + "birth_scan_exhausted": false + }, + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW": { + "address": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 108 + }, + "first_seen": 1784490766, + "birth_edge": { + "sink": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "sources": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "value": 150000000, + "signature": "2uKVQ2Do2Vandv4rqHhJQZEFKrKQGFQdt15BtdaknzdY8Rxas2Bx3smqkhK6D3Hz8urRCANByPKEJxDcCAKTaq3G", + "slot": 433959006, + "block_time": 1784490766, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD": { + "address": "inWVrrYJ38VihdE62LXNQvgV5CeRrdKEXpNtXLyqUWD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 24000 + }, + "first_seen": 1785032587, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4jewC6oZ3gN5HfU2eDzVmsQLQrRU86gEwV66BeyRc7pT" + ], + "birth_scan_exhausted": false + }, + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU": { + "address": "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 583 + }, + "first_seen": 1769032382, + "birth_edge": { + "sink": "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "sources": [ + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "value": 20000000, + "signature": "AG1dX11PZCL7yBeTVs4PuNNECWsZ7tuvE94MP16zRMdtgyqchb5gyD512vVb7bd5pk3rYHpfg1RFFCwSLaahc4w", + "slot": 395055111, + "block_time": 1769032382, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "funded": [ + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT" + ], + "birth_scan_exhausted": false + }, + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q": { + "address": "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q", + "owner": null, + "executable": false, + "signatures": { + "Exact": 9987 + }, + "first_seen": 1753767232, + "birth_edge": { + "sink": "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q", + "sources": [ + "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r" + ], + "value": 15080000000, + "signature": "4jUBNeaABoUS9e3JfuUfCdZSKJDoT21rHND3BBd9B59kmgbT2HM6EpRB3kVmgB1eRoqv1nnV8GruBtB5gZ84hd8D", + "slot": 356448864, + "block_time": 1753767260, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8d9UB1epGA22yxoRVxoe86njAwmA7a6AxW96mc9v5n6r" + ], + "funded": [ + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE" + ], + "birth_scan_exhausted": false + }, + "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf": { + "address": "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2651 + }, + "first_seen": 1737914051, + "birth_edge": { + "sink": "pJ8AaFpuMGoHhcrT6iJuTvdrLUcuUPxAP6SSwzWkArf", + "sources": [ + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs" + ], + "value": 50000000000, + "signature": "2rpBPJocSrWKt2G59e29e8Tj7MJDUAQLEKx2GaoAApyUBLbynToft6iDKYZKTWr2BL9UhfiwV7qr6E1exQn6mnAP", + "slot": 316536578, + "block_time": 1737914051, + "ambiguous_attribution": false + }, + "fee_payers": [ + "G4SZFKHdiNGsFmYHzJt79xMqcS6UmkGAXwoQtstjyfVs" + ], + "funded": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "birth_scan_exhausted": false + }, + "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe": { + "address": "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2006 + }, + "first_seen": 1762263640, + "birth_edge": { + "sink": "qNvqCj1bm5QU6mS2az6CuRx59jTpt5Bz48LvCrwVtZe", + "sources": [ + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN" + ], + "value": 10000000, + "signature": "2abx2yUwotMytWNz2EAiW6RTrAsz9otzWMXKPyVN8FjtaEa3hp4MTJYi2C3R8XrnUND8MyuMJ5T2yKEb4prkrBVJ", + "slot": 377877154, + "block_time": 1762263640, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FfTmAnvfoH1Jcki3t9xtknkbAneT11tnDgR64TgsrYXN" + ], + "funded": [ + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz" + ], + "birth_scan_exhausted": false + }, + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6": { + "address": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 531 + }, + "first_seen": 1783364451, + "birth_edge": { + "sink": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "sources": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ], + "value": 1100000000, + "signature": "4kLBV2LbExCtK85mRP4FnNGDaHVTBNNvvtyQjbFVqiqeLgvs3fcSUVbsxtmuZ6WzVUBYV9h9GJzyUuWpYf6nAxTD", + "slot": 431221166, + "block_time": 1783364451, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ], + "funded": [], + "birth_scan_exhausted": false + }, + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx": { + "address": "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 74 + }, + "first_seen": 1776857831, + "birth_edge": { + "sink": "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "sources": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "value": 1000000000, + "signature": "4mEmeFnTKjqyT3XM3UZbp7fGA5gWeMB8ny87kZJbBbGGW89NJv5i5GBSvAJqx4JQN4eKDKNUomka7gE4AvgLRm8v", + "slot": 414902368, + "block_time": 1776857831, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "funded": [ + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do" + ], + "birth_scan_exhausted": false + } + } +} \ No newline at end of file diff --git a/data/sample-privacycash.json b/data/sample-privacycash.json new file mode 100644 index 00000000..e4061bba --- /dev/null +++ b/data/sample-privacycash.json @@ -0,0 +1,4376 @@ +{ + "manifest": { + "endpoint": "https://solana-mainnet.g.alchemy.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1785013559, + "config": { + "scope": "Sol", + "depth_max": 8, + "min_edge_lamports": 500000, + "sig_page_cap": 8, + "page_size": 1000 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 1029, + "excluded_non_wallet": [ + "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp", + "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7", + "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB", + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr", + "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY", + "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv", + "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis", + "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX", + "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo", + "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG", + "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS", + "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA", + "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha", + "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp", + "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH" + ], + "ambiguous_attribution_rate": 0.2222222222222222 + }, + "chains": [ + { + "seed": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "visited": [ + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "visited": [ + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "visited": [ + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E", + "visited": [ + "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E" + ], + "stop": "PageCapHit" + }, + { + "seed": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "visited": [ + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "stop": "DepthExceeded" + }, + { + "seed": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "visited": [ + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "visited": [ + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "stop": "PageCapHit" + }, + { + "seed": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "visited": [ + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff", + "visited": [ + "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff" + ], + "stop": "PageCapHit" + }, + { + "seed": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "visited": [ + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "visited": [ + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "visited": [ + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v" + ], + "stop": "PageCapHit" + }, + { + "seed": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "visited": [ + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "visited": [ + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "stop": "PageCapHit" + }, + { + "seed": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "visited": [ + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf", + "visited": [ + "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf" + ], + "stop": "PageCapHit" + }, + { + "seed": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "visited": [ + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "stop": "PageCapHit" + }, + { + "seed": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "visited": [ + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "visited": [ + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "stop": "PageCapHit" + }, + { + "seed": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "visited": [ + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165", + "visited": [ + "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165" + ], + "stop": "PageCapHit" + }, + { + "seed": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "visited": [ + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw" + ], + "stop": "PageCapHit" + }, + { + "seed": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "visited": [ + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "stop": "PageCapHit" + }, + { + "seed": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "visited": [ + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu" + ], + "stop": "PageCapHit" + }, + { + "seed": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "visited": [ + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB" + ], + "stop": "LocalTerminal" + }, + { + "seed": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "visited": [ + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "visited": [ + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "visited": [ + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "visited": [ + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "visited": [ + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "visited": [ + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "visited": [ + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV" + ], + "stop": "LocalTerminal" + }, + { + "seed": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "visited": [ + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "visited": [ + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz" + ], + "stop": "PageCapHit" + }, + { + "seed": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "visited": [ + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "visited": [ + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr" + ], + "stop": "PageCapHit" + }, + { + "seed": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "visited": [ + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "stop": "PageCapHit" + }, + { + "seed": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "visited": [ + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "visited": [ + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "stop": "PageCapHit" + }, + { + "seed": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "visited": [ + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "visited": [ + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "stop": "PageCapHit" + }, + { + "seed": "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U", + "visited": [ + "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U" + ], + "stop": "PageCapHit" + }, + { + "seed": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "visited": [ + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ" + ], + "stop": "LocalTerminal" + }, + { + "seed": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "visited": [ + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "visited": [ + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "stop": "PageCapHit" + }, + { + "seed": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "visited": [ + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "stop": "PageCapHit" + }, + { + "seed": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "visited": [ + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t" + ], + "stop": "PageCapHit" + }, + { + "seed": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "visited": [ + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "visited": [ + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "visited": [ + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "stop": "PageCapHit" + }, + { + "seed": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "visited": [ + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "stop": "PageCapHit" + }, + { + "seed": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "visited": [ + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "visited": [ + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "visited": [ + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "stop": "PageCapHit" + }, + { + "seed": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "visited": [ + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "stop": "PageCapHit" + }, + { + "seed": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "visited": [ + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "visited": [ + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW" + ], + "stop": "PageCapHit" + }, + { + "seed": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "visited": [ + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "visited": [ + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16" + ], + "stop": "PageCapHit" + }, + { + "seed": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "visited": [ + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "visited": [ + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "visited": [ + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "stop": "PageCapHit" + }, + { + "seed": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "visited": [ + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o" + ], + "stop": "LocalTerminal" + }, + { + "seed": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "visited": [ + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "visited": [ + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "stop": "NoIncomingEdge" + }, + { + "seed": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "visited": [ + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "visited": [ + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "stop": "PageCapHit" + }, + { + "seed": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "visited": [ + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "stop": "PageCapHit" + }, + { + "seed": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "visited": [ + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "visited": [ + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX" + ], + "stop": "PageCapHit" + }, + { + "seed": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "visited": [ + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "stop": "DepthExceeded" + }, + { + "seed": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "visited": [ + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "stop": "PageCapHit" + }, + { + "seed": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "visited": [ + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ" + ], + "stop": "PageCapHit" + }, + { + "seed": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "visited": [ + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "stop": "PageCapHit" + }, + { + "seed": "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR", + "visited": [ + "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR" + ], + "stop": "PageCapHit" + }, + { + "seed": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "visited": [ + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn" + ], + "stop": "PageCapHit" + }, + { + "seed": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "visited": [ + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "visited": [ + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY" + ], + "stop": "PageCapHit" + }, + { + "seed": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "visited": [ + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "stop": "PageCapHit" + }, + { + "seed": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "visited": [ + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "visited": [ + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "stop": "PageCapHit" + }, + { + "seed": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "visited": [ + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "stop": "PageCapHit" + }, + { + "seed": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "visited": [ + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "stop": "PageCapHit" + }, + { + "seed": "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM", + "visited": [ + "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM" + ], + "stop": "PageCapHit" + } + ], + "facts": { + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E": { + "address": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1784615427, + "birth_edge": { + "sink": "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 110900000, + "signature": "5e6e31Ja1kF2DbV7qrcSW9RZYywU7TpJfxr667CtkwBe4toXGeyZnYtdT8NJeQzM1fTpQULLkDXkraeVcYxArg8W", + "slot": 434252353, + "block_time": 1784615427, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma": { + "address": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 607 + }, + "first_seen": 1783375005, + "birth_edge": { + "sink": "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 22913500000, + "signature": "2AkoeVHhVQwaNuxQEya9FmdWcho8YDPBUExnQwQ51LZCGAN81Xa6gmUiq5KufZD7VNapVbL566cGNQ54cHcQGDAZ", + "slot": 431247217, + "block_time": 1783375005, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z": { + "address": "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4277 + }, + "first_seen": 1647049347, + "birth_edge": { + "sink": "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z", + "sources": [ + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "value": 7244953950, + "signature": "419TeAWehDaugVDXtfT9GochWU2uzZfYE8Mj9KcRLxDtwZpVies6nT8ujSsqz5xcah5gEALomEeyeL5igrt1ZFeG", + "slot": 124535935, + "block_time": 1647049347, + "ambiguous_attribution": false + }, + "fee_payers": [ + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs" + ], + "funded": [ + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H" + ] + }, + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm": { + "address": "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784916184, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ] + }, + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ": { + "address": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 28 + }, + "first_seen": 1783722353, + "birth_edge": { + "sink": "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 12948500000, + "signature": "5rMkvoDiSrN16YHjCLekrebvkmsHxvssazWRbP2Fq5rZNhyyMcUTULMb136XBMrKVZzwRyhbj7qb3cx3sgGiWAoX", + "slot": 432098751, + "block_time": 1783722353, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha": { + "address": "2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9": { + "address": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784475307, + "birth_edge": { + "sink": "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9", + "sources": [ + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn", + "6tckHFBpiJ8YgYN8FUskvtvTpXQZ55g5LHeo1kvELoDQ" + ], + "value": 5010000000, + "signature": "4bs1AqpjFmhSM6Hgg7nGwN7FbytYnLRcGmiTMP6TCCRP2rhhT4hf8Bb62Jm7uTqxc4vs9scPgT3vbEb98uQfdNF3", + "slot": 433922248, + "block_time": 1784475307, + "ambiguous_attribution": true + }, + "fee_payers": [ + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn" + ], + "funded": [] + }, + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V": { + "address": "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "owner": null, + "executable": false, + "signatures": { + "Exact": 249 + }, + "first_seen": 1776070891, + "birth_edge": { + "sink": "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V", + "sources": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "value": 600000000, + "signature": "2ifPXJE5e8zqjQTqTP7duLXvDyDjTsJrqcf5iEdywn3Z29p3Zsr3RcgYFXPkkxZMhMNg3HQyeVHSqQHhCrDAYnPM", + "slot": 412912638, + "block_time": 1776070891, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ], + "funded": [ + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU" + ] + }, + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy": { + "address": "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1580 + }, + "first_seen": 1784752160, + "birth_edge": { + "sink": "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy", + "sources": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "value": 43881516584, + "signature": "3NEwDfuC73NVthq8zeasPw9Ud6qcWZiy65wFFZSWcbxP86UjAsc9ZPApAdjk7EYo88ptZcUZbSLdmQwZkgqSCcRc", + "slot": 434577818, + "block_time": 1784752160, + "ambiguous_attribution": false + }, + "fee_payers": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ], + "funded": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ] + }, + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg": { + "address": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1781285770, + "birth_edge": { + "sink": "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg", + "sources": [ + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "value": 1677937000, + "signature": "2TJSuukc2SNr9YL2qRHeNHmu37kfsE2cBnQkz7TJTxuRkVw48fefVYqxsGCV2ULsb1PnVvzmcQGJt5J7uouabgYZ", + "slot": 426027687, + "block_time": 1781285770, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G" + ], + "funded": [] + }, + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem": { + "address": "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "owner": null, + "executable": false, + "signatures": { + "Exact": 263 + }, + "first_seen": 1713736580, + "birth_edge": { + "sink": "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem", + "sources": [ + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "value": 12006763000, + "signature": "62g49CyyWTmom7Qxdnr64iSy7W8PDuxrZojz5q6ztpgYkM7WwwXkfcyeNVditM45iomtRpgqXUbLW8kXpScStkuL", + "slot": 261492401, + "block_time": 1713736580, + "ambiguous_attribution": false + }, + "fee_payers": [ + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE" + ], + "funded": [ + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq" + ] + }, + "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf": { + "address": "2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1781989038, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz": { + "address": "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1778370573, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38" + ] + }, + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS": { + "address": "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784567461, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ] + }, + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1": { + "address": "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 100 + }, + "first_seen": 1784818359, + "birth_edge": { + "sink": "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1", + "sources": [ + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7" + ], + "value": 6000000000, + "signature": "2StbhyBVwhP2wRhTYMM31x5qU3B2WBr1jFXx6KD6CGeXp9xpWQqN7RKoxa98X86h8v6SGprqMdi9CVGh9PLSjAQH", + "slot": 434735789, + "block_time": 1784818359, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7" + ], + "funded": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ] + }, + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr": { + "address": "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784752151, + "birth_edge": { + "sink": "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr", + "sources": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "value": 45278992944, + "signature": "LnCoQVyRCZyi9ktCp3JyZPKhGrTu19FzpmhP7SjvQ8TKYS7uu9dPE23AuzRQz32YWqaTQG9rabCkoAihw2swguS", + "slot": 434577797, + "block_time": 1784752151, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ], + "funded": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ] + }, + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt": { + "address": "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784444104, + "birth_edge": { + "sink": "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt", + "sources": [ + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "value": 5986856990, + "signature": "3k3C9SKrmZZ9aKwV75WzsqDnXRj1jnrfVoq6W5E4wxyjcAH7ZGiMbrDKVqStRdtpFm4Y2vzYA8WvEyUdSs67b1UN", + "slot": 433847718, + "block_time": 1784444104, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf" + ], + "funded": [ + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH" + ] + }, + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL": { + "address": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784544632, + "birth_edge": { + "sink": "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL", + "sources": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "value": 928815670, + "signature": "85PNojTrpgdkLHWP1CQRGD6G6CttqKUCr5zYDjLXkFsB4teH5D9kcZqZjTAWX3ydRqfVhwLAKLzC6zYsU3K1A8L", + "slot": 434085334, + "block_time": 1784544632, + "ambiguous_attribution": false + }, + "fee_payers": [ + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR" + ], + "funded": [] + }, + "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H": { + "address": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 528 + }, + "first_seen": 1734052375, + "birth_edge": { + "sink": "3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H", + "sources": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "value": 1020000000, + "signature": "4Mm83Hp6ciDRNzM3tSFJt6AyoXPc7kD4moyqFobEtqzXDAnC2k5hNt83wNGSsn61KQjaNdyYYqWHcJjaUA9qubwX", + "slot": 307120184, + "block_time": 1734052375, + "ambiguous_attribution": false + }, + "fee_payers": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ], + "funded": [] + }, + "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH": { + "address": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 277 + }, + "first_seen": 1784444332, + "birth_edge": { + "sink": "3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH", + "sources": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "value": 2985933011, + "signature": "4e1bYdz4z6QTzWFbSbjFRJpDdhuc2m2zaopi6x8N1w81fa6352rDi2VCzqyxKdRuvPKthVeikZXGj91o6bvCfeK4", + "slot": 433848260, + "block_time": 1784444332, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ], + "funded": [] + }, + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr": { + "address": "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1783493331, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh" + ] + }, + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7": { + "address": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784462394, + "birth_edge": { + "sink": "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 90000000, + "signature": "4jhAt2GJwyGRfe5sJkFB2HVjnUzLi86PVfucCvUM6u3JFRwegv57f4ZkhmRH6huyS8pNEZa8nbPs9Kb6PtXYUAqz", + "slot": 433891372, + "block_time": 1784462394, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu": { + "address": "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1764 + }, + "first_seen": 1781821319, + "birth_edge": { + "sink": "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu", + "sources": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "value": 400000000, + "signature": "t439hwXMQP6B4Yk83sUHquHMZR9q8bqQK4na6cWaxbvVCnQKw5hzceNSBXCJKRmcEzmJBFLd19bfcWsSDKGxhU6", + "slot": 427377732, + "block_time": 1781821319, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ], + "funded": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ] + }, + "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv": { + "address": "3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze": { + "address": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 695 + }, + "first_seen": 1784674265, + "birth_edge": { + "sink": "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 6040700317, + "signature": "3tGju22hVCi5Tn5mQv65Uokr3ahGwzYsU5urYkse9Bq4SgSRPmwiU8FzhX51HBdMCKyTor6i8G1uc2LnhHge4uRb", + "slot": 434392522, + "block_time": 1784674265, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr": { + "address": "4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1781571364, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16": { + "address": "4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1772633492, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w": { + "address": "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1783188037, + "birth_edge": { + "sink": "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 100528380, + "signature": "5CdkjWty9v98DDGJPREJK7UpeGUaaBdQxo87kDxyqajMtFtbnzVuL2h9UCu4Ue4iVqu4vWgiBLbs8XCjnAswLrDR", + "slot": 430784309, + "block_time": 1783188037, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [ + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k" + ] + }, + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk": { + "address": "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1013 + }, + "first_seen": 1781819169, + "birth_edge": { + "sink": "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 25895028000, + "signature": "5e4gkh2xn451jv5rnKUJN81VDUN9bJTY3VESq2eQ7ACZJ51DuXZMFBaat5X5tVe5VBLzSnGbKri4KnpFezdqG3mu", + "slot": 427372317, + "block_time": 1781819169, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ] + }, + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd": { + "address": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 86 + }, + "first_seen": 1784917747, + "birth_edge": { + "sink": "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3063734792, + "signature": "5iF2hZ9Pg77skU74ve2HwpkKpHnSjw2W13DmC67uSo2FAFaUC4FSLEZvv2BSwjwtF1NTfCVuBRKbghGoqpmtUmd7", + "slot": 434972545, + "block_time": 1784917747, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs": { + "address": "57vSaRTqN9iXaemgh4AoDsZ63mcaoshfMK8NP3Z5QNbs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1664905134, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "22spwq4CPtszGu3Ct2oakPbAiXSXB548ZQqtc78mMy1z" + ] + }, + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ": { + "address": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 17 + }, + "first_seen": 1784823865, + "birth_edge": { + "sink": "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ", + "sources": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "value": 26325656111, + "signature": "4Fvr5kGDCyhHU3xmpCJvMRy4YAGLs93UAu2mbCG3V39pu9ASyDAqEeMqve3CmwgDUieLGp4q6uoGvFHWBmqt2hvK", + "slot": 434748892, + "block_time": 1784823865, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ], + "funded": [] + }, + "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr": { + "address": "5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr": { + "address": "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894220, + "birth_edge": { + "sink": "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr", + "sources": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "value": 849094919, + "signature": "4MJQDBRmFT2jFhKZx7rY84rz4GThjUhU2twqk6URjTrCx1k6SQwZd4toBBR6bKnqS7GvPowPP17GnwJw8DGFqviH", + "slot": 394707768, + "block_time": 1768894220, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ], + "funded": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ] + }, + "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS": { + "address": "5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t": { + "address": "5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1643476251, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV": { + "address": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5586 + }, + "first_seen": 1774645255, + "birth_edge": { + "sink": "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV", + "sources": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "value": 500000000, + "signature": "3wVtJf5fiq7g5cSb8ynKPJswdRx5RQ7GV1oPF1BMiFYKpAkf6T4ZdEbrnfEMQR3DLusyex4JCeZ8aSr9xxYkiuuq", + "slot": 409285335, + "block_time": 1774645255, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE" + ], + "funded": [] + }, + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za": { + "address": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 616 + }, + "first_seen": 1784934334, + "birth_edge": { + "sink": "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za", + "sources": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "value": 52977372793, + "signature": "4JY37vAAtVC9a5sQn4z8CY5mRJ5t8njqiBziNK9Ps8QtpG9m1qPsfCLFFo8HuGFjdPNTUtDaLQ9v2TF1auyUDWg7", + "slot": 435012131, + "block_time": 1784934334, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x" + ], + "funded": [] + }, + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p": { + "address": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1783475831, + "birth_edge": { + "sink": "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p", + "sources": [ + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ" + ], + "value": 388393719000, + "signature": "5imCWUcQWCKj7vDdLUbDXDeE567zN2Eg4Le8AWi6v7f1ZnsbtijSC6i65rA6BpVCsK9kc9fRrBwF4jGBARwWPf1m", + "slot": 431495612, + "block_time": 1783475831, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BrGihgGjCmpu2p96rou6GQj3sQpwgeud937jf4RvZP9G" + ], + "funded": [] + }, + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3": { + "address": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 13 + }, + "first_seen": 1784433292, + "birth_edge": { + "sink": "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 669228400, + "signature": "66Tc5f3Uko3nDvDySXyoV4rhTBSka9cPczYiReZ8upWdrXKNhRGUHTTsZizm9mdNDEYdTkUmfuynxX3QEPjthemd", + "slot": 433821901, + "block_time": 1784433292, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs": { + "address": "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784665413, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk" + ] + }, + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV": { + "address": "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u" + ] + }, + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9": { + "address": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784983367, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ] + }, + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA": { + "address": "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1756724646, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF" + ] + }, + "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7": { + "address": "6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk": { + "address": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 142 + }, + "first_seen": 1784420501, + "birth_edge": { + "sink": "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1488750000, + "signature": "5reLwzaWen3xeyYobmDJv4AWkboVwkmQea8aqnBXo6AW86tVotCN8aD4HVUseVngB1i8Nz7bWPVayfkXMjq2NZWd", + "slot": 433791379, + "block_time": 1784420501, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S": { + "address": "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894225, + "birth_edge": { + "sink": "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S", + "sources": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "value": 849089919, + "signature": "5mpXMBqiqCUXVfjKe2fqnfr1yXBFt2MnSb5sU4PhDCru1KLnWw7Aji9tVP8ywUoP2X2yAAsgDnLsybmSY33VB9LJ", + "slot": 394707780, + "block_time": 1768894225, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ], + "funded": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ] + }, + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq": { + "address": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 54 + }, + "first_seen": 1784676427, + "birth_edge": { + "sink": "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 49804000, + "signature": "2ksPaRqePKa3tLNgb6dfJ4xGxBvHsRJuNXeikfUEuupy8NvcTgf3AL8cq7AZRYALiWDeKz2BWxhNZdDHxdVEoDQg", + "slot": 434397667, + "block_time": 1784676427, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx": { + "address": "6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3 + }, + "first_seen": 1784813668, + "birth_edge": null, + "fee_payers": [ + "D8cJRpXaCWVK8c3doDq7Ymoz2XE4WyhFhbgNytWwqptA" + ], + "funded": [] + }, + "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY": { + "address": "6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1780423820, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB": { + "address": "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT" + ] + }, + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S": { + "address": "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1310 + }, + "first_seen": 1781821301, + "birth_edge": { + "sink": "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S", + "sources": [ + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk" + ], + "value": 600000000, + "signature": "3B7AsVriGEHPW4TRFBkaFhV6YD4RDZ1w7g4UwNtT7psQb95ZMifH6v4QDUwL1k42tLpqhGqiExaje5LTEMkMBwQ8", + "slot": 427377690, + "block_time": 1781821301, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk" + ], + "funded": [ + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ" + ] + }, + "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB": { + "address": "74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz": { + "address": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 963 + }, + "first_seen": 1774473115, + "birth_edge": { + "sink": "75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 34895500000, + "signature": "3omGYaNeXk9VjMv3rTp9aoaJrkED6b9jTiHoPx4UbRupiWmUn7op8udTBwguzph7YGJWQpNEhnv1FFDskSRsZANh", + "slot": 408844844, + "block_time": 1774473115, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE": { + "address": "775QCcN3ZYXMx137YbtogqyoX9X82b8qf3FrzauqHLWE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1753297373, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ] + }, + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw": { + "address": "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 277 + }, + "first_seen": 1780094619, + "birth_edge": { + "sink": "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 2991500000, + "signature": "84Spr3goYUhDoyS5JCevCc1nDRjo6vWCWeKajzmd3qHWAmsNkBoEjw8322ajWKS5GJyVShK56h1ZUh2VdxtBeCz", + "slot": 423031442, + "block_time": 1780094619, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ" + ] + }, + "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF": { + "address": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1758995033, + "birth_edge": { + "sink": "7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF", + "sources": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "value": 10000000, + "signature": "5eJNQ4bhKNQYiTVSpUhrHjGpFSs7Ft4GKLrJWqAK5BTnkuzd1xqVV8P1FcpXKG6Zb77U9qdDkyVN6gz1UYzoeB1T", + "slot": 369652410, + "block_time": 1758995033, + "ambiguous_attribution": false + }, + "fee_payers": [ + "68x9JmFHPvunPDFJrSBiwXUhENN8RssLF1u8kg9UrrbA" + ], + "funded": [] + }, + "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW": { + "address": "7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1732758556, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG": { + "address": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784565160, + "birth_edge": { + "sink": "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG", + "sources": [ + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "value": 232000000000, + "signature": "28bt62zYkiihXsM3o7rp2D6YS63G8CpZwUzpqqp2b8jNzGoUih1PWx9FGMdwfQFAEdRGTgz15pPQ8j9uZgDeyvw8", + "slot": 434133197, + "block_time": 1784565160, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob" + ], + "funded": [] + }, + "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG": { + "address": "7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP": { + "address": "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "owner": null, + "executable": false, + "signatures": { + "Exact": 999 + }, + "first_seen": 1784462436, + "birth_edge": { + "sink": "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP", + "sources": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "value": 49648773129, + "signature": "3xd1Te2qtTYHjh2ohyorXsFLgxgWxaveB9tfyGzszJf9MmM1XHhFzQoi5C5ftnUWhXMPRvJpBuHpFidFgZVh2i3g", + "slot": 433891472, + "block_time": 1784462436, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ], + "funded": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ] + }, + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ": { + "address": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 32 + }, + "first_seen": 1784389227, + "birth_edge": { + "sink": "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ", + "sources": [ + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb" + ], + "value": 807208726, + "signature": "3vny3LuBCtnjHmNBUw4YGWxGiJdB6MDgCTTwB85ixPF8urpfbhjUiR3DJvptVkoB82k8MLKxgudAvq8m5CPLHCG", + "slot": 433716525, + "block_time": 1784389227, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb" + ], + "funded": [] + }, + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH": { + "address": "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1705 + }, + "first_seen": 1715894645, + "birth_edge": { + "sink": "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH", + "sources": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "value": 106710780, + "signature": "xDgEvEFQw8Qer5vQHtG755NyT2FHXPnFV9CPvhuvZn4NfZ3b5tWrUL5wDcGVyBDVSSA13r7Y6Tgtdp2mjrmHZrH", + "slot": 266193828, + "block_time": 1715894645, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2AQdpHJ2JpcEgPiATUXjQxA8QmafFegfQwSLWSprPicm" + ], + "funded": [ + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo" + ] + }, + "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH": { + "address": "88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u": { + "address": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784630445, + "birth_edge": { + "sink": "8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u", + "sources": [ + "5pVN5XZB8cYBjNLFrsBCPWkCQBan5K5Mq2dWGzwPgGJV" + ], + "value": 6831797746, + "signature": "4V6TatwrgYYdAXsbYZ58LgACqMKm51JVfQ6cgiJvjtXwvz8NPjZbhsrz9j2QvwKXXv18bkkgtJScAaw5wZy5sKZk", + "slot": 434288158, + "block_time": 1784630445, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [] + }, + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5": { + "address": "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784788976, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ" + ] + }, + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7": { + "address": "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7", + "owner": null, + "executable": false, + "signatures": { + "Exact": 176 + }, + "first_seen": 1731698151, + "birth_edge": null, + "fee_payers": [ + "4ritJBeodrzcSDDeAJbKafJniczjYhAfsoZRXTQq9h82" + ], + "funded": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ] + }, + "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT": { + "address": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784049521, + "birth_edge": { + "sink": "8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT", + "sources": [ + "6wWVbLeHDVHvCCsLprB85jkbU1JhS9VezABT2ZZFJ5BB" + ], + "value": 2110033428, + "signature": "1tK2a5Q2E19ZBWkhkhMDf36cuv8NZD8pcRFbVhxkR4kedkEjLsxS7dD1QsKHuZ1T77XRbGiWQx9fnQWcDtgLQmD", + "slot": 432895720, + "block_time": 1784049521, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH": { + "address": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784564457, + "birth_edge": { + "sink": "8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 156610510360, + "signature": "3HmDQGGFDNXPquCgrBn4oFueH8EcudAUohYxWiRVekmuX53cZhFotqNnLLPzUEeBnnhHikzZWtUwuP2M6K8EZq1L", + "slot": 434131562, + "block_time": 1784564457, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [] + }, + "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U": { + "address": "8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784407057, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ": { + "address": "8b9c7XAStj2dKpqk3U2SsXcxh5jPkuFTExUhnFZo4iFZ", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p" + ] + }, + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx": { + "address": "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784772255, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC" + ] + }, + "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E": { + "address": "8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1750860158, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1": { + "address": "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2156 + }, + "first_seen": 1684141322, + "birth_edge": { + "sink": "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1", + "sources": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "value": 90000000, + "signature": "52ZPH7cfAzwauMYh529GgHWhTzRwReNdJyWYr5ZugsAB5gvSmP6CYuCV1U79B9SLxLjk6qy5nsDUmao8Xa5y5EBB", + "slot": 194024003, + "block_time": 1684141322, + "ambiguous_attribution": false + }, + "fee_payers": [ + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ" + ], + "funded": [ + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6" + ] + }, + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1": { + "address": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5535 + }, + "first_seen": 1747156899, + "birth_edge": { + "sink": "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1", + "sources": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "value": 1000000000, + "signature": "2cATjnRUeA8sBSjhU4udUTHwqFk5cLQfx2mMZ7isJfKvdfGEJNn4q3Ex72Ww3fRNX7JUQTGpy25R6FVdfFwRP5dV", + "slot": 339786892, + "block_time": 1747156899, + "ambiguous_attribution": false + }, + "fee_payers": [ + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi" + ], + "funded": [] + }, + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb": { + "address": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1356 + }, + "first_seen": 1778270115, + "birth_edge": { + "sink": "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 31543190000, + "signature": "23eCmHrxuyS6rMmjNNDsJtUZk4vesD5maoraeVjWmqKuLe1yeuELQgEDaqfBDUWSTrkM3iuQFUWAsPpkjAiD6meJ", + "slot": 418463518, + "block_time": 1778270115, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr": { + "address": "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1780168602, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ] + }, + "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu": { + "address": "9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1772400244, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu": { + "address": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 428 + }, + "first_seen": 1783530592, + "birth_edge": { + "sink": "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu", + "sources": [ + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o" + ], + "value": 3608900737, + "signature": "39zbFyzcd2pWwLEQBD1gB1qWrjTekKNiicL8TpyjTAoyLABpT518QVo9WVz8yxdzCJF1WiRcvuHzJRR85WFBXjfv", + "slot": 431630423, + "block_time": 1783530592, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn": { + "address": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784565684, + "birth_edge": { + "sink": "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 841356800, + "signature": "4Y2A99s86tDM9Ef8DQ62ED34YhLejSy9dfkYDHR2rAi6kcnSNvg5pW1F83RyJuHK4DPoxkN5mAkvqvyA1EHJj4Wd", + "slot": 434134426, + "block_time": 1784565684, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh": { + "address": "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894217, + "birth_edge": { + "sink": "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh", + "sources": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "value": 849099919, + "signature": "4UhWatoFQvHLdrg56s4qh3NjJaa9jpsS55YeGbi2FwyNHuoqfnZBLZx3npfoyjhFbvMaNm5vxYmYSAkjPdK2Gioi", + "slot": 394707760, + "block_time": 1768894217, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ], + "funded": [ + "5NXwVuYB6rEHcka2Ey66aoQ7e3bjzC6oDr2a2NkVdwjr" + ] + }, + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp": { + "address": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 205 + }, + "first_seen": 1775579392, + "birth_edge": { + "sink": "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 9131905000, + "signature": "3zWVxUN5PpQhBBHTb7q2iVdGYZWzYX96QFS1nC467YtQBSKuqjZzLFQEPh816DEVyZmtn6xdFvssDpQqdopjccPh", + "slot": 411667852, + "block_time": 1775579392, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi": { + "address": "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1782119408, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ] + }, + "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY": { + "address": "9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR": { + "address": "A77HErqtfN1hLLpvZ9pCtu66FEtM8BveoaKbbMoZ4RiR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784812466, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL" + ] + }, + "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf": { + "address": "ABNL41SwMLVRaCq6okEWsWyvLwm56nazUNwMrTHgmuyf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1782850389, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "3CNLu4mPXbvcy3VzunxzUdXgxjQHeASYjCty8cBbnkGt" + ] + }, + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW": { + "address": "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1783714097, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3", + "3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze", + "4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd", + "2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ", + "6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk", + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb", + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma", + "6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq", + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "4tyoKRazcMQH4ZkZoKBU3TU9QuWPs5K1Pmg7G9krEKGk", + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7", + "9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp", + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM" + ] + }, + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx": { + "address": "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894233, + "birth_edge": { + "sink": "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx", + "sources": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "value": 849084919, + "signature": "4MQSbWiBDWsVRVVKMjprc9fMfevDFzvAJJDcTd7PPwkGKXTfqJtB5frc9naHWzJv1S5yi3XLnmKZPMEbQx95M7aU", + "slot": 394707800, + "block_time": 1768894233, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6SgPPUvPMVHSrnfmuD4XuW8KgArrGcxYmm8diuRsGH8S" + ], + "funded": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ] + }, + "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ": { + "address": "ASTyfSima4LLAdDgoFGkgqoKowG1LZFDr9fAQrg7iaJZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784873823, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ] + }, + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW": { + "address": "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "owner": null, + "executable": false, + "signatures": { + "Exact": 711 + }, + "first_seen": 1663704019, + "birth_edge": { + "sink": "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW", + "sources": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "value": 3079735480, + "signature": "24tTRqCdoMDLxwi41jhddFdaqydjZowSRXZHW2xuBqNttskX1ej72PhQUDqGoiF9jY5u9i8kbdyMcx5MMUrRWXsD", + "slot": 151573078, + "block_time": 1663704019, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq" + ] + }, + "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ": { + "address": "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2412 + }, + "first_seen": 1781821309, + "birth_edge": { + "sink": "AnW32XEjUw5179U7vvGgZPHAbMjoGUr2mPPtTp86LhyQ", + "sources": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "value": 500000000, + "signature": "4wVPQe58DmcHwkdVmHuvqWFGnQZhQ4ndiumpcrvNSYx6bL2bBCk6CCNeWpKDPzvc8Y68RpfFKuCrfScRuL2VaE58", + "slot": 427377712, + "block_time": 1781821309, + "ambiguous_attribution": false + }, + "fee_payers": [ + "6ymhGyyuuAuL15w3nkbBw6aERZnmEvHLsWA3otYFRV2S" + ], + "funded": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ] + }, + "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo": { + "address": "AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk": { + "address": "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1785002821, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD" + ] + }, + "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX": { + "address": "Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1779008689, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ": { + "address": "B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 107 + }, + "first_seen": 1783458420, + "birth_edge": null, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ": { + "address": "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 618 + }, + "first_seen": 1774728729, + "birth_edge": { + "sink": "BBRFSKHCnbtwZC2XRAw8w1tDb3Q5y5eNj9KnjzKyroEZ", + "sources": [ + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "value": 11650417543, + "signature": "5TnbPcr9zLALAWF82aL7PVBNbX7PkaUTzdXgAWEnvZAeE8n5cYzXhyEKh438w9uj6LrF316rj73McA84g5DHueHM", + "slot": 409499170, + "block_time": 1774728729, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8QCVZ7KL65pBhUxbvfwbyyg4ronxNAEXbDrGLYLrRNn5" + ], + "funded": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ] + }, + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG": { + "address": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 6 + }, + "first_seen": 1784519630, + "birth_edge": { + "sink": "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG", + "sources": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "value": 104889883544, + "signature": "5162f689Bxmi9PA5Fj9QVxBuxjHrWqbJnoHVVjnmUg4HB9j8XnMvUmLaugVAcyEnAbpiPQNQiukSiE2D2H2AUKaQ", + "slot": 434026767, + "block_time": 1784519630, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB" + ], + "funded": [] + }, + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC": { + "address": "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1748177913, + "birth_edge": { + "sink": "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC", + "sources": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "value": 1029000000, + "signature": "CfG62TFDb4cuNH7FNWz4Cr2Ga14r88NoTXbSDkWmGSDhFTqxdKxinZcyAeSJ33eE1VPiqfwfgcBcmyMRijYEDNb", + "slot": 342369414, + "block_time": 1748177913, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8QoTaGN2fBjLfeeT8QssfCAB77GbRoA1TvBg2mS8gxB7" + ], + "funded": [ + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd" + ] + }, + "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM": { + "address": "BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1783696023, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm": { + "address": "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784580094, + "birth_edge": { + "sink": "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm", + "sources": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "value": 50607243678, + "signature": "2h4gvshcwfRhkDXQhiLMAWYTWM4xMUnW8iGdJpEnhQRUYZy5DuMQma319GnL8wCprP7MTXGgb8ymBWvQ1jwTwoht", + "slot": 434168171, + "block_time": 1784580094, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ], + "funded": [ + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ" + ] + }, + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K": { + "address": "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 581 + }, + "first_seen": 1775667915, + "birth_edge": { + "sink": "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K", + "sources": [ + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "value": 12399485120, + "signature": "1hqU1oga3ZT4F3uT5iAm3W4zB3eiH9vd2Rop2Rtyva35zubCfiYZCFgAaSaBCD48a3iTz1aL9zpTnZ4JRq6yZE5", + "slot": 411892813, + "block_time": 1775667915, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8taRrDLR8XNqeMSzA9cKFHuanfiHe428MxxK6jFNQBWr" + ], + "funded": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ] + }, + "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38": { + "address": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 567 + }, + "first_seen": 1759849779, + "birth_edge": { + "sink": "BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38", + "sources": [ + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "value": 1000000000, + "signature": "55aNfhpFmWyptpJ52kvWWSpaHePRjZLDNbf9kzwSKgUtvvcp4XFhGpKXbU5tVD4wYFh3DrtjJpfnKfLoyGKkadYN", + "slot": 371813843, + "block_time": 1759849779, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2net6etAtTe3Rbq2gKECmQwnzcKVXRaLcHy2Zy1iCiWz" + ], + "funded": [] + }, + "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo": { + "address": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3597 + }, + "first_seen": 1736334578, + "birth_edge": { + "sink": "BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo", + "sources": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "value": 170000000000, + "signature": "2MLS8L4uUc8L3nNZpej5csKZ3d5JuNqKGkUjpX1E1ebmqEBzcxBP3ZccC4FvbAgAFWchKPoey8mhH98JCnCxCQ9x", + "slot": 312653033, + "block_time": 1736334578, + "ambiguous_attribution": false + }, + "fee_payers": [ + "848txtzQ713KF6PY9cQAtPTP2W6pbrrLntyYrZMsoDbH" + ], + "funded": [] + }, + "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw": { + "address": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 155 + }, + "first_seen": 1780608496, + "birth_edge": { + "sink": "Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 3965000, + "signature": "2jPiYFrpAtgu9YXus8V7NPkAWW6xWy5zBdh42P7S5sticdDDVgPGo91ne8yDeLjXhZHyH6zxZnWg69yPXRApwheC", + "slot": 424324895, + "block_time": 1780608496, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ": { + "address": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2999 + }, + "first_seen": 1780098381, + "birth_edge": { + "sink": "BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ", + "sources": [ + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw" + ], + "value": 800000000, + "signature": "3owWqGQL5cNVZcCTN235bbaS2gyez3LxGz663Gej6dtmqBhUyrbhJNfoP1VaVryXN47bdKWoxji34CAu6oUPsxdP", + "slot": 423040927, + "block_time": 1780098381, + "ambiguous_attribution": false + }, + "fee_payers": [ + "79PxaD5FvzcGioKAXQYJZSKr7B5fafL23yFeQzVPevBw" + ], + "funded": [] + }, + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P": { + "address": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 96 + }, + "first_seen": 1784854429, + "birth_edge": { + "sink": "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P", + "sources": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "value": 6000000000, + "signature": "5KA9mkbPhkRXKEhf1FeiRuxHphiMMkRgq3FsNjkKk2Ra7gRMMqmB7V5gEvocEESMeK24LVsUC24gWjBx7EyiX3Kp", + "slot": 434821643, + "block_time": 1784854429, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT" + ], + "funded": [] + }, + "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis": { + "address": "Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD": { + "address": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 627 + }, + "first_seen": 1753997946, + "birth_edge": { + "sink": "C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD", + "sources": [ + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "value": 123066991, + "signature": "5Rtx3JoWd3XaAGxkckRh6w7aeW4W9M2ZbG8NQt7SDLdunYiy5eHXiF3Kc9Dp8QBMJABzH2T2ctoAzCEZF57ckAAB", + "slot": 357026958, + "block_time": 1753997946, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AxiomRXZAq1Jgjj9pHmNqVP7Lhu67wLXZJZbaK87TTSk" + ], + "funded": [] + }, + "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA": { + "address": "C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr": { + "address": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5 + }, + "first_seen": 1784599658, + "birth_edge": { + "sink": "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr", + "sources": [ + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW" + ], + "value": 440000000, + "signature": "4QJkfNCAWjNh2mfYrx9WN6EBe6cCpPUABueLgf4WfqJ5smBUdqbHDcsQXAHT6d8a6q4hFNMvf7jAozFE4jw1rXwj", + "slot": 434214781, + "block_time": 1784599658, + "ambiguous_attribution": false + }, + "fee_payers": [ + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW" + ], + "funded": [] + }, + "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob": { + "address": "CDHhpcpZ6rBK9iurqeJsj8QWbBBVo9tiL85SLojLerob", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 108 + }, + "first_seen": 1784218241, + "birth_edge": null, + "fee_payers": [ + "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9" + ], + "funded": [ + "7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG" + ] + }, + "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh": { + "address": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784649420, + "birth_edge": { + "sink": "CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh", + "sources": [ + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "value": 1850143000, + "signature": "3YgFygisXK1X8kyUXV6LzPEcJ36tKUDkuyo7UvX3KdwULNGDe2wLYiB7KSCVcyM9NejVf2Q4Gr2KV2p11SSvGbCy", + "slot": 434333385, + "block_time": 1784649420, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3V11R3pEGSt5XeRaoLDcCdkAB8zVSaKRCm8y3uKBgnsr" + ], + "funded": [] + }, + "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb": { + "address": "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784389224, + "birth_edge": { + "sink": "CWp2pdKdv4KzX2XSHZcVQMTrXSSWpixzJzhuVK52GHfb", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 807213726, + "signature": "2MwPJoYeQHsFvpTXyue8m776mx5fBtFDYgY7hcZpTuz641UR5R8xz7yoe7NXT8e1mRojMFpwKs6Pkdk1fFgSe6zr", + "slot": 433716518, + "block_time": 1784389224, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ" + ] + }, + "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT": { + "address": "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 87 + }, + "first_seen": 1784838909, + "birth_edge": { + "sink": "CYuD3VzotR8NPczeP81UKXXiWCZkMNVpK5ga9L1w9VCT", + "sources": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "value": 6000000000, + "signature": "3wsTxnCcjxate2zoeFse3mstAwC5KUkvVH4AWjgi9FTKZmwvm7vjJb7N5EPGR5rpcDePeFVXxopoMKiWRsG67bTu", + "slot": 434784661, + "block_time": 1784838909, + "ambiguous_attribution": false + }, + "fee_payers": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ], + "funded": [ + "BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P" + ] + }, + "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB": { + "address": "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 44 + }, + "first_seen": 1768894237, + "birth_edge": { + "sink": "Ce4GMytgRiLRsHgRi4xU4fcDvmi2Ab2NqAfkmz1wHxvB", + "sources": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "value": 849079919, + "signature": "ZPtjQoLcno8LwEZaoxwJrAZfMfcHmszyxAA1V2FW6ohJxa3tbczaP1T4s4d5HgxHTxDS7tTjRK5GnV3x55nWPCQ", + "slot": 394707808, + "block_time": 1768894237, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AJeDo4ZxmC7Tjg1eF1gVymLhNxuSR1GyRb64vANCFNbx" + ], + "funded": [ + "BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG" + ] + }, + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN": { + "address": "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1784377763, + "birth_edge": { + "sink": "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1299793806, + "signature": "wbcYZ4GZzni8ThU986zLwqQUmhcY4gZfGFBbC1ffpv6TwUkWtxPLvUt6FB3fT9DvuaEKu21bsm6RwpSBVgrkiEh", + "slot": 433689096, + "block_time": 1784377763, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9" + ] + }, + "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU": { + "address": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 7 + }, + "first_seen": 1784657908, + "birth_edge": { + "sink": "CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1996965000, + "signature": "5bJGTURSxfgDoe8QBCjFXtRwNcrBHqLyN8oJ3HjztNDMnbgtzNG11DtZ51MgkqAkcii2BWghA9KB3MitvWTQxF5d", + "slot": 434353532, + "block_time": 1784657908, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94": { + "address": "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894203, + "birth_edge": { + "sink": "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94", + "sources": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "value": 849109919, + "signature": "2XXhJExg7yyA6WH34H5Q99ZtCVavER65hC3V7tf6oNm5onx4KDVoDEpSgAaoupvn721NrE7KdSiMQ4cjKZY1UfJy", + "slot": 394707725, + "block_time": 1768894203, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf" + ], + "funded": [ + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm" + ] + }, + "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz": { + "address": "CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784436054, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU": { + "address": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 2660 + }, + "first_seen": 1777272559, + "birth_edge": { + "sink": "D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU", + "sources": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "value": 2500000000, + "signature": "ETzNdupbU3xXhkPGEw9Hn8tPN6NDugSpsVob4iHjzcfzccdcUAisMiYbqkwSbCm6AxsfqxZvhjfCCUC3P1kEHRc", + "slot": 415950310, + "block_time": 1777272559, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2Q3W3BXL1M2yEfqqZkJifc9txBpNzSBAd2e2uVtW3a3V" + ], + "funded": [] + }, + "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U": { + "address": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 272 + }, + "first_seen": 1757688961, + "birth_edge": { + "sink": "DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 93700000, + "signature": "3PeWiircHtHEH9T78i4FKAoUNP3568WEdnJr8PgTPdhPPi958X6NrtthHtGn2r21ovMKKWwCo8TkMtc6rmzw6odX", + "slot": 366350032, + "block_time": 1757688961, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR": { + "address": "DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1781686102, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi": { + "address": "DGH8fu3Msz8u41o8VintuvcFSb3AXW47yw2gyvMf7YJi", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1743113748, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1" + ] + }, + "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX": { + "address": "DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff": { + "address": "DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784043386, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x": { + "address": "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "owner": null, + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1784934326, + "birth_edge": { + "sink": "Dp3XMDK2Tabg5jp2ikxTC6JGBsbzooHvKTiFMokkg14x", + "sources": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "value": 54374849153, + "signature": "4Y7SpKFVWPXmK1GJQMsZfuQnxiYyoi7NcJbchUzRemXMGt3DWRUWJBT7L8seY3MymYCvHhSv7XravPdS34KHgmpL", + "slot": 435012112, + "block_time": 1784934326, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy" + ], + "funded": [ + "5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za" + ] + }, + "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn": { + "address": "DuSs7rCr7oTLHjM29QQ8NwDViaahTU58qqxaJVyAkgbn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784827118, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9" + ] + }, + "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq": { + "address": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 294 + }, + "first_seen": 1764868637, + "birth_edge": { + "sink": "E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq", + "sources": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "value": 1390000000, + "signature": "42jLxFrfSKoLo8ZPnaMZfGU56WVo4mrSi1RUEweRK84j2R4vSSRetdHu9HErxgK6eR87R6vt2c7T2C4KUTaDjf4F", + "slot": 384466286, + "block_time": 1764868637, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2jLFUPYbX47drr7pp7kAGoxcsEVtdCSWPTqhMVzkPjem" + ], + "funded": [] + }, + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do": { + "address": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 203 + }, + "first_seen": 1776858197, + "birth_edge": { + "sink": "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do", + "sources": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "value": 1007615782, + "signature": "2KPM9xqT2mfMAqEZDX51t6o3RgYoLnJZgU6NPzZ57YV14DZy8VsnyYxntqnKbhtYAZwE4puvnjUP9PmE5y4aUBa1", + "slot": 414903289, + "block_time": 1776858197, + "ambiguous_attribution": false + }, + "fee_payers": [ + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx" + ], + "funded": [] + }, + "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW": { + "address": "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 531 + }, + "first_seen": 1778972678, + "birth_edge": { + "sink": "E9HSTWen7vEE42qLWKvVuS3ToWiEsXvmt2vzhgG76FnW", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 6632702930, + "signature": "vJcCHLLH6FaWPDarJWTvMdpKckbK9yPGhy9qgUgypRyheTmVdPiEMf5vCioqKT82iF8G7VZ95vXGuYWoECTAh2B", + "slot": 420215149, + "block_time": 1778972678, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr" + ] + }, + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH": { + "address": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 368 + }, + "first_seen": 1745361264, + "birth_edge": { + "sink": "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH", + "sources": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "value": 1000000000, + "signature": "5Ugmig4PTLRcf3GTuiY6G47gQn5bxj3UDp4YpKDsvY1JaPwwn1DMU1bQPnTXgrP8wQtrEZfmpLthv8gjADrp7mpu", + "slot": 335243820, + "block_time": 1745361264, + "ambiguous_attribution": false + }, + "fee_payers": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ], + "funded": [] + }, + "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o": { + "address": "EYj9xKw6ZszwpyNibHY7JD5o3QgTVrSdcBp1fMJhrR9o", + "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu" + ] + }, + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn": { + "address": "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 5289 + }, + "first_seen": 1702336727, + "birth_edge": { + "sink": "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn", + "sources": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "value": 4372981634, + "signature": "5KeWCHfUdwtMws4e48ZDAqSa2K6bFWeiX4irurLzrFw1geWqtgjHvY1F8T8Cma4n6XuaJ3TbQBaKFZjeLGEK6Wau", + "slot": 235369057, + "block_time": 1702336727, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS" + ], + "funded": [ + "EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH" + ] + }, + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM": { + "address": "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 157 + }, + "first_seen": 1780522066, + "birth_edge": null, + "fee_payers": [ + "7rtiKSUDLBm59b1SBmD9oajcP8xE64vAGSMbAN5CXy1q" + ], + "funded": [ + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW" + ] + }, + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx": { + "address": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1150 + }, + "first_seen": 1737448881, + "birth_edge": { + "sink": "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx", + "sources": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "value": 672745485, + "signature": "64C1Msn6wiLA7U5x5ZjYhPx2cj813py9Pft9Bc41VYtbtWHinBJefXt3rj5KaWTuvXC7aoYwr3Y8tsfj1zed1ZSw", + "slot": 315391758, + "block_time": 1737448881, + "ambiguous_attribution": false + }, + "fee_payers": [ + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B" + ], + "funded": [] + }, + "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ": { + "address": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 58 + }, + "first_seen": 1783645887, + "birth_edge": { + "sink": "F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 14433952357, + "signature": "4RbXiaGAmS7WfUmruWn3zBUTwaF2WzVDno2bSTiZFH7cbYSeVeUGgS184pvQaV3ySoRBNGkx6r68M8r5AA5ZbJTo", + "slot": 431912014, + "block_time": 1783645887, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp": { + "address": "F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe": { + "address": "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1785013251, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w", + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ" + ] + }, + "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL": { + "address": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 89 + }, + "first_seen": 1784429559, + "birth_edge": { + "sink": "F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 1987000000, + "signature": "22tiKy2Uhr5HbzaoUTkf5gTS2VHov1xMY998kBCQbYybACx6Y3fJtxRBaj8ppaMyahAGEgnC5SggnKt6HbxcwNRb", + "slot": 433813000, + "block_time": 1784429559, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B": { + "address": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 145 + }, + "first_seen": 1769758558, + "birth_edge": { + "sink": "FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 193300000, + "signature": "52ygQjkxX6CiTWcaT8KoncyGrbR97uAqzrJ91LySCtkZDCNDa3WTHpnvNSJkRXacynWy4D5j16sFCh1PWGdesPET", + "slot": 396868730, + "block_time": 1769758558, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt": { + "address": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 11 + }, + "first_seen": 1784509948, + "birth_edge": { + "sink": "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt", + "sources": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "value": 14000000000, + "signature": "55y1RvP9p644eWZy6JypDF39fB4u7XCBXYmQhjDRX5AgytWCpsC2J4SiffzCo9gLPHpPoqs6AXrCXyb7mgUooZXD", + "slot": 434004156, + "block_time": 1784509948, + "ambiguous_attribution": false + }, + "fee_payers": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ], + "funded": [] + }, + "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm": { + "address": "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894210, + "birth_edge": { + "sink": "FH7ffT537ehTR2Da9kejMM78w6dosdq1ZvnhUBJBnyxm", + "sources": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "value": 849104919, + "signature": "2ga76DPJVD9CWDYmtpb17BURi9EcLNFxeNFi172x5aRN9es1qAh5HRHf9ZNCzGtADfp9LzzcF2t26MdDn5jEDT5C", + "slot": 394707744, + "block_time": 1768894210, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ], + "funded": [ + "9ufYR8kSVuEhQav6YV8ZNjt4fXiLzHH9TJZ9G7fCQtQh" + ] + }, + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor": { + "address": "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 856 + }, + "first_seen": 1783108022, + "birth_edge": { + "sink": "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor", + "sources": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "value": 200000000, + "signature": "3XBCwvm2pUrPEp3PCUKm4NiNy7pGhpxqpy2u2eWnMBs5sJgoYk55DPp77RSEn4m2vL9C61sWiefBAiArFGEaUgFw", + "slot": 430586035, + "block_time": 1783108022, + "ambiguous_attribution": false + }, + "fee_payers": [ + "3i7rnk82B2fZXgQRrx2visk2D919YTdEwZqX22opdBfu" + ], + "funded": [ + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe" + ] + }, + "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd": { + "address": "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 48 + }, + "first_seen": 1765645486, + "birth_edge": { + "sink": "Fb9kYXyPX2pdkzn7RtscvHv4obLMZq1LjFCWasQnedMd", + "sources": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "value": 88200000, + "signature": "sH5bnyJn2BNFN3TgD2isA2G5ygXEsGzWr9kpgN2PW5Ubxk3nAHyLRprFmS5M2FzdbTTZD2RjxfgH7xfbARZtdHc", + "slot": 386459128, + "block_time": 1765645486, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BDPFerK9hZKUKHLoDYVwUifk9C9BdZQTid8Kdq1ac1eC" + ], + "funded": [ + "5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ" + ] + }, + "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM": { + "address": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12 + }, + "first_seen": 1784461923, + "birth_edge": { + "sink": "FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 990500000, + "signature": "9duBpzRRMAZ2cQv2n79HKMzurHUBWmDWdDwNR8y6U48bnG6HKY2HZnrQxXNFVFpg8RtSy3KPNEY4ByMKHEBJCEb", + "slot": 433890247, + "block_time": 1784461923, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ": { + "address": "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1670 + }, + "first_seen": 1784580105, + "birth_edge": { + "sink": "FcFhk1BshcZPmR7EU4cX9YFXKN9juvy9WNvaoHMRf6WQ", + "sources": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "value": 49209767318, + "signature": "2BVoGzFZrFnuRLqpW1EAHxkFXmnp7xWp1wog4n3EBnCbTgQLvSgFVZHB8z4Z1FgdzjYGBh9tTUFZ1aLF2XtYCuKU", + "slot": 434168198, + "block_time": 1784580105, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BLCkSaMKEPLaX1yvHiymRhSAF52mc5RMuUL1KpuxMPtm" + ], + "funded": [ + "31r21jLmyUXEyPdGCEQ3gqj66XcWLjvAqVcJttZHNxyr" + ] + }, + "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7": { + "address": "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 48 + }, + "first_seen": 1784809669, + "birth_edge": { + "sink": "Fm5haWEgwGveZU777yCoQRyJQ2L39qXQnMhC4FcRVYE7", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 5973000000, + "signature": "3MSs2ea12TniywAz7iM9anGzcgJr8oB1kCVxVQm8YgQxqoCwwPpzBhg6EACKhpDuWoT6J723YZfrnDq8qqfLSTRJ", + "slot": 434715093, + "block_time": 1784809669, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [ + "31kvzxJYHVUPBNqmzjLGBWHK6SiEjhVYGThEiovi9Bf1" + ] + }, + "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k": { + "address": "FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 944 + }, + "first_seen": 1781405876, + "birth_edge": null, + "fee_payers": [ + "9HGyyJnWK4b67E97bB4SXpjbxpYmTBMaKNmWmfmYe4DK" + ], + "funded": [] + }, + "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B": { + "address": "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "owner": null, + "executable": false, + "signatures": { + "Exact": 15 + }, + "first_seen": 1737447329, + "birth_edge": { + "sink": "Fr4tRypWcy46S5VX4wVENtEPagwPiC2REPxVquGXJ66B", + "sources": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "value": 672750485, + "signature": "4gBVShePEtPdc8c9vLekxqxtKnHN1CaY2ECsfrU3Ysoo7AeQGVwwpqLDW9aAWYF3KSsekeoaA1aqHrTqAEHwSGuN", + "slot": 315387958, + "block_time": 1737447329, + "ambiguous_attribution": false + }, + "fee_payers": [ + "2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS" + ], + "funded": [ + "F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx" + ] + }, + "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw": { + "address": "FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1781124441, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G": { + "address": "GB7SkZMTwZVZxdXfrsPpQFNqEWV88fK5jwQHsPKJU28G", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1782676910, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg" + ] + }, + "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE": { + "address": "GJRs4FwHtemZ5ZE9x3FNvJ8TMwitKTh21yxdRPqn7npE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784920545, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV" + ] + }, + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT": { + "address": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4 + }, + "first_seen": 1784758056, + "birth_edge": { + "sink": "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT", + "sources": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "value": 90000000000, + "signature": "2yFwMANAjHWBoCUWXwsF2NS8Vm24oSkE5oJ6RfsDe2jPVeo782fE98nePAJqpuxWL1VkA5iQXoXdDoU8SqopCTR2", + "slot": 434591833, + "block_time": 1784758056, + "ambiguous_attribution": false + }, + "fee_payers": [ + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU" + ], + "funded": [] + }, + "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq": { + "address": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 65 + }, + "first_seen": 1784659136, + "birth_edge": { + "sink": "GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq", + "sources": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW", + "4AV2Qzp3N4c9RfzyEbNZs2wqWfW4EwKnnxFAZCndvfGh" + ], + "value": 32880718309, + "signature": "4wZbNhexVa96s82hAQbdZ9Pq1fqencGxxmKYCwghVjT6iwxMLyyKBssfwvWVJFXFMXxNwSfrDo8TqZ4AiJbEPC6U", + "slot": 434356458, + "block_time": 1784659136, + "ambiguous_attribution": true + }, + "fee_payers": [ + "AF8VuwCncKd5ZBnLYYnMjqh4vLch8mjqE75sFe5ZjRFW" + ], + "funded": [] + }, + "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC": { + "address": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 292 + }, + "first_seen": 1783054209, + "birth_edge": { + "sink": "Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC", + "sources": [ + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "value": 180834295, + "signature": "55tLEDwJyuDGaSo8c6yYz4bj5utz7zJiVtQnsQuwqKg7abdYWVoK1vFkLQd7pyJhjh4r8ku6i9oCyXRa8a6kX18z", + "slot": 430452695, + "block_time": 1783054209, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8d9FNC7AgKLTCPKNd3MMkLLXZYLmiYFYR3vfXMBNJVNx" + ], + "funded": [] + }, + "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf": { + "address": "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "owner": null, + "executable": false, + "signatures": { + "Exact": 2 + }, + "first_seen": 1768894200, + "birth_edge": { + "sink": "Gfw9RerLqaQgHYoxCDXSF1xBSWyscZogeKisEPNPhSXf", + "sources": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "value": 849114919, + "signature": "5Gb3um1roTYvbjCFckDeFVPkU7QxKeShYSL3KWDxSEX8qhCrwgDEJgbSiuL3L4tCXzk1GaguKXBbmAU2yjAVmkdG", + "slot": 394707716, + "block_time": 1768894200, + "ambiguous_attribution": false + }, + "fee_payers": [ + "eESjJDBAvxZkEARQAnTcPiiif3NsxKdQSyy5LdSJmvZ" + ], + "funded": [ + "CmmQ3kMvdAmC6sgpQordubMP71ExikgCduFPbjeW9B94" + ] + }, + "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk": { + "address": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 1151 + }, + "first_seen": 1777988933, + "birth_edge": { + "sink": "GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk", + "sources": [ + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "value": 2362855000, + "signature": "Vdct3Y5hjgKy2gHHjimC9YE8faisFo7jz3EiFYjmb3yAYuHpY2tE5ZqJcXhMNtbrrXTRr5CxYpCz5djyYzwgJyb", + "slot": 417761237, + "block_time": 1777988933, + "ambiguous_attribution": false + }, + "fee_payers": [ + "5ndLnEYqSFiA5yUFHo6LVZ1eWc6Rhh11K5CfJNkoHEPs" + ], + "funded": [] + }, + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho": { + "address": "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "owner": null, + "executable": false, + "signatures": { + "Exact": 600 + }, + "first_seen": 1784462427, + "birth_edge": { + "sink": "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho", + "sources": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "value": 51022180729, + "signature": "4udxkWqxkyLqBAZpUJHNMkZDcFMVTq1BpaC2A5YqNGbm6He6WAYpQGQXMY5J91YcUxxZATqVkJooVP9y3EXqpABd", + "slot": 433891452, + "block_time": 1784462427, + "ambiguous_attribution": false + }, + "fee_payers": [ + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva" + ], + "funded": [ + "7u9DY46GaThvrRxCnaPESd2Q9NXvsApEpJ4ntF47A7hP" + ] + }, + "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp": { + "address": "GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp", + "owner": null, + "executable": false, + "signatures": { + "Exact": 0 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva": { + "address": "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "owner": null, + "executable": false, + "signatures": { + "Exact": 1629 + }, + "first_seen": 1784212802, + "birth_edge": { + "sink": "H5A9P6X933RbVuqaohgrPpuY9KhpSnoT87LB5CbHKeva", + "sources": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "value": 22180583705, + "signature": "59BrgexB78Kj9fCJkHmKs2UZYsp5Ntc5ia4RpE3T1WS8xtwyJEhn49w5VcofBvhkHWa9AxfEQsR1L6qjNFKdZnhj", + "slot": 433291830, + "block_time": 1784212802, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BYMyvenA3hVcNLKkYLpx2pLeSgFDrfzaq9CD1TnBebGE" + ], + "funded": [ + "GsTWfuRzhBDnjKeHjLYW7q6DKFgordHnGUCCLtEc8zho" + ] + }, + "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS": { + "address": "H8sMJSCQxfKiFTCfDR3DUMLPwcRbM61LGFJ8N4dK3WjS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784920243, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "En47we6eRGG3owJvGs2v2rsHZLVuvAC1cksEMqCSQFDn" + ] + }, + "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ": { + "address": "HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1783482692, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe": { + "address": "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 724 + }, + "first_seen": 1784227892, + "birth_edge": { + "sink": "HHVTQsCM8Dy5MGeJxpagzp1KqWXEQqS1oz2DAETkMvwe", + "sources": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "value": 130000000, + "signature": "kTyjASGv9R4C1zjLJriyX96k2ZWgbAwPw3Qd2z3pCzb5cRPuZs3vt8uqzKH2bjr5AdqMDwf8SnxCqbwyt2cWwdm", + "slot": 433328336, + "block_time": 1784227892, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FJapDp832EnGSyyi5WiJCzLnVd7n48CVgrW5QvvH4Hor" + ], + "funded": [ + "FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt" + ] + }, + "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq": { + "address": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 14 + }, + "first_seen": 1784552253, + "birth_edge": { + "sink": "HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq", + "sources": [ + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "value": 23698818508, + "signature": "3uywYCF5VuSzVQkMX6Pghx7SXTsJuW55Jv37zcHt1foh71Nuq6vGrb4keCz7JNFjLMRWkK5Aq2jNmWhqkWbXuH8y", + "slot": 434103135, + "block_time": 1784552253, + "ambiguous_attribution": false + }, + "fee_payers": [ + "AbPrRZG6CDhcd48XriyvDwMdrJobk4oSZSbRK1dyYEiW" + ], + "funded": [] + }, + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC": { + "address": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 4402 + }, + "first_seen": 1776709519, + "birth_edge": { + "sink": "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "sources": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "value": 4909585890, + "signature": "5VEpmW6pcMbLtJQHaJbctF8BUkixM7cH6gwV5yMHLtJtq5DaCpFaKRydWVjQ85d3uA9ErzyjYTkqyfHriUeN1D8E", + "slot": 414528392, + "block_time": 1776709519, + "ambiguous_attribution": false + }, + "fee_payers": [ + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu" + ], + "funded": [] + }, + "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165": { + "address": "HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1777633794, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9": { + "address": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1784377766, + "birth_edge": { + "sink": "Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9", + "sources": [ + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN" + ], + "value": 1299788806, + "signature": "DonAnKr8whXoDnWemm9bqSjoUQdEohd9sus4nhstSat4cF5HxAmnrHQqMEbbNW3s9KhRDYLvL28ifTpBj16tWha", + "slot": 433689104, + "block_time": 1784377766, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CkLTyEQW3xUxbb1z11zj9PwnYAPiLScLaeVrNwxmeDtN" + ], + "funded": [] + }, + "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k": { + "address": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 109 + }, + "first_seen": 1783337142, + "birth_edge": { + "sink": "HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k", + "sources": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w" + ], + "value": 2000000000, + "signature": "3TYxeVhY5FHcpE3BqdMtf6RUScLkjcsXBpZnPjc8YfGiTXw25vLWWvd3vZWPE9V6kBcLpzMrph82uRoprzHPNvKU", + "slot": 431153926, + "block_time": 1783337142, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4prmwkseFzz51H6Fb1AAsuispLPABrbqoyyK7mjBDM3w" + ], + "funded": [] + }, + "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v": { + "address": "J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1770644440, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ": { + "address": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 41 + }, + "first_seen": 1783637441, + "birth_edge": { + "sink": "JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ", + "sources": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "value": 22952461058, + "signature": "63UUpBFp2VbRkpjKsc3FaXXucqtzjTyPZCsqEtoXBxNiW263FxXHdr6Coo7FksLHC3amGnSZoV9rD9uR4G4yKMfo", + "slot": 431891370, + "block_time": 1783637441, + "ambiguous_attribution": false + }, + "fee_payers": [ + "F7p3dFrjRTbtRp8FRF6qHLomXbKRBzpvBLjtQcfcgmNe" + ], + "funded": [] + }, + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE": { + "address": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 3053 + }, + "first_seen": 1761711549, + "birth_edge": { + "sink": "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE", + "sources": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "value": 10000000, + "signature": "42BSukNNZwdKRuESCNwP7Dr8xn7HmRc21PNP6PdSa36WrF1mbw2n3CatJwkBzviQiutmRPDn9oCR7bJo4jXDVtzM", + "slot": 376499867, + "block_time": 1761711549, + "ambiguous_attribution": false + }, + "fee_payers": [ + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q" + ], + "funded": [] + }, + "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu": { + "address": "iGdFcQoyR2MwbXMHQskhmNsqddZ6rinsipHc4TNSdwu", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1784908428, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC", + "1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E", + "9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn" + ] + }, + "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW": { + "address": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 108 + }, + "first_seen": 1784490766, + "birth_edge": { + "sink": "iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW", + "sources": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "value": 150000000, + "signature": "2uKVQ2Do2Vandv4rqHhJQZEFKrKQGFQdt15BtdaknzdY8Rxas2Bx3smqkhK6D3Hz8urRCANByPKEJxDcCAKTaq3G", + "slot": 433959006, + "block_time": 1784490766, + "ambiguous_attribution": false + }, + "fee_payers": [ + "EoTqf7MM4NYyiFZD2idh6uy3eY3TbgEokpsV3HR6zPTM" + ], + "funded": [] + }, + "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU": { + "address": "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 583 + }, + "first_seen": 1769032382, + "birth_edge": { + "sink": "k1FM496vdPWxeNMigjNBxjTZ4U8S8Ut67o9bAGuPVgU", + "sources": [ + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "value": 20000000, + "signature": "AG1dX11PZCL7yBeTVs4PuNNECWsZ7tuvE94MP16zRMdtgyqchb5gyD512vVb7bd5pk3rYHpfg1RFFCwSLaahc4w", + "slot": 395055111, + "block_time": 1769032382, + "ambiguous_attribution": false + }, + "fee_payers": [ + "9yzDcVC569tYadQqmuNPGNNa3ZmHA6AY7tdgWnSEvDbi" + ], + "funded": [ + "GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT" + ] + }, + "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q": { + "address": "mmekwNde1Yh43CqecqAh6DW7GyvJvz4wjxDu3Kr9Q2q", + "owner": null, + "executable": false, + "signatures": { + "AtLeast": 8000 + }, + "first_seen": 1757619786, + "birth_edge": null, + "fee_payers": [], + "funded": [ + "LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE" + ] + }, + "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6": { + "address": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 531 + }, + "first_seen": 1783364451, + "birth_edge": { + "sink": "xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6", + "sources": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ], + "value": 1100000000, + "signature": "4kLBV2LbExCtK85mRP4FnNGDaHVTBNNvvtyQjbFVqiqeLgvs3fcSUVbsxtmuZ6WzVUBYV9h9GJzyUuWpYf6nAxTD", + "slot": 431221166, + "block_time": 1783364451, + "ambiguous_attribution": false + }, + "fee_payers": [ + "8hKxzjzh34MNV9WWvQs2XY98aNRSdi7TUPU2LCNDZjk1" + ], + "funded": [] + }, + "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx": { + "address": "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 74 + }, + "first_seen": 1776857831, + "birth_edge": { + "sink": "zd5ndEyiKnvJcZg3SkS9z98uDuUbRmJJuEvn3rQYDmx", + "sources": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "value": 1000000000, + "signature": "4mEmeFnTKjqyT3XM3UZbp7fGA5gWeMB8ny87kZJbBbGGW89NJv5i5GBSvAJqx4JQN4eKDKNUomka7gE4AvgLRm8v", + "slot": 414902368, + "block_time": 1776857831, + "ambiguous_attribution": false + }, + "fee_payers": [ + "BME6PqbfxUx2Ff4WzjE5AAboFy6AUFo6L9MmARWPzf3K" + ], + "funded": [ + "E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do" + ] + } + } +} \ No newline at end of file diff --git a/data/sample-smoke.json b/data/sample-smoke.json new file mode 100644 index 00000000..0cf86394 --- /dev/null +++ b/data/sample-smoke.json @@ -0,0 +1,400 @@ +{ + "manifest": { + "endpoint": "https://api.mainnet-beta.solana.com", + "first_available_block": 0, + "archival_probe_ok": true, + "collected_at": 1784970512, + "config": { + "scope": "Sol", + "depth_max": 5, + "min_edge_lamports": 500000, + "sig_page_cap": 20, + "page_size": 1000 + }, + "thresholds_hub_signatures": 5000, + "thresholds_distributor_fanout": 20, + "thresholds_cluster_min_size": 3, + "rpc_calls": 263, + "excluded_non_wallet": [], + "ambiguous_attribution_rate": 0.0 + }, + "chains": [ + { + "seed": "BGT8Vm1u5nyW255LgWjD8wzsRs8g3KxBnB3Pm1FjC9fV", + "visited": [ + "BGT8Vm1u5nyW255LgWjD8wzsRs8g3KxBnB3Pm1FjC9fV" + ], + "stop": "PageCapHit" + }, + { + "seed": "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV", + "visited": [ + "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV" + ], + "stop": "PageCapHit" + }, + { + "seed": "7Q77q5ai1bjDA9kkMRMWJEJV7KWhVoBV7NDYKsAbcTd7", + "visited": [ + "7Q77q5ai1bjDA9kkMRMWJEJV7KWhVoBV7NDYKsAbcTd7" + ], + "stop": "PageCapHit" + }, + { + "seed": "BcK2Fr53rJ1YU9CuRPewu6idyzsXqnDqc1iYzsJtnnEf", + "visited": [ + "BcK2Fr53rJ1YU9CuRPewu6idyzsXqnDqc1iYzsJtnnEf" + ], + "stop": "PageCapHit" + }, + { + "seed": "3FuCiEjR6iZ9P7A6hSF2VFFwRq1Q19Gok7JgHf6gZkcf", + "visited": [ + "3FuCiEjR6iZ9P7A6hSF2VFFwRq1Q19Gok7JgHf6gZkcf" + ], + "stop": "PageCapHit" + }, + { + "seed": "EPzKe9HueqCag9Ca7qKimrFn7EUMFxQtvcVCyC9YgYoV", + "visited": [ + "EPzKe9HueqCag9Ca7qKimrFn7EUMFxQtvcVCyC9YgYoV" + ], + "stop": "PageCapHit" + }, + { + "seed": "5Ktwj8p43RvMsHdyBsx1ZZZrao3CQo4uT6uWqE4FRB11", + "visited": [ + "5Ktwj8p43RvMsHdyBsx1ZZZrao3CQo4uT6uWqE4FRB11" + ], + "stop": "PageCapHit" + }, + { + "seed": "JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf", + "visited": [ + "JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf", + "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa", + "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P", + "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV", + "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1", + "85YGfmqnNpR3qs4i2Jie3PogFfqH8HKqiGmaKaDH7EVB" + ], + "stop": "DepthExceeded" + }, + { + "seed": "6TxjC5wJzuuZgTtnTMipwwULEbMPx5JPW3QwWkdTGnrn", + "visited": [ + "6TxjC5wJzuuZgTtnTMipwwULEbMPx5JPW3QwWkdTGnrn" + ], + "stop": "PageCapHit" + }, + { + "seed": "7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ", + "visited": [ + "7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ" + ], + "stop": "PageCapHit" + }, + { + "seed": "DRg3C1nVnvwugDW1J9gnhArcZpo7oyREwfugZCLjPJVc", + "visited": [ + "DRg3C1nVnvwugDW1J9gnhArcZpo7oyREwfugZCLjPJVc" + ], + "stop": "PageCapHit" + }, + { + "seed": "Fqwus6SoxhNzxESj6ftBRiDWvGMB2ZYStgtKtDwe9iyS", + "visited": [ + "Fqwus6SoxhNzxESj6ftBRiDWvGMB2ZYStgtKtDwe9iyS" + ], + "stop": "PageCapHit" + } + ], + "facts": { + "3FuCiEjR6iZ9P7A6hSF2VFFwRq1Q19Gok7JgHf6gZkcf": { + "address": "3FuCiEjR6iZ9P7A6hSF2VFFwRq1Q19Gok7JgHf6gZkcf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV": { + "address": "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV", + "owner": null, + "executable": false, + "signatures": { + "Exact": 508 + }, + "first_seen": 1784175985, + "birth_edge": { + "sink": "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV", + "sources": [ + "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1" + ], + "value": 1056265607849, + "signature": "514swBZDAqyDDLknQX94SaowFTEuGxXvyfEZLzFeZNGweAqHusmuAjeECZiZCZ8mcqHS1zcvZFGKXiQ8s2JPvj8A", + "slot": 433202358, + "block_time": 1784175985, + "ambiguous_attribution": false + }, + "fee_payers": [ + "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1" + ], + "funded": [ + "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P" + ] + }, + "5Ktwj8p43RvMsHdyBsx1ZZZrao3CQo4uT6uWqE4FRB11": { + "address": "5Ktwj8p43RvMsHdyBsx1ZZZrao3CQo4uT6uWqE4FRB11", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV": { + "address": "62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "6TxjC5wJzuuZgTtnTMipwwULEbMPx5JPW3QwWkdTGnrn": { + "address": "6TxjC5wJzuuZgTtnTMipwwULEbMPx5JPW3QwWkdTGnrn", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "7Q77q5ai1bjDA9kkMRMWJEJV7KWhVoBV7NDYKsAbcTd7": { + "address": "7Q77q5ai1bjDA9kkMRMWJEJV7KWhVoBV7NDYKsAbcTd7", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa": { + "address": "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa", + "owner": null, + "executable": false, + "signatures": { + "Exact": 530 + }, + "first_seen": 1784177508, + "birth_edge": { + "sink": "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa", + "sources": [ + "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P" + ], + "value": 941607555363, + "signature": "3c9CjJza7Ymcig6cN8b7X2ntiVDEDcYr4Sw1Rjs8GnmcJ5Nqc9eDt1XvkExXPTFtgX1re7HZSmMgf3Z1F7mRMpX8", + "slot": 433206066, + "block_time": 1784177508, + "ambiguous_attribution": false + }, + "fee_payers": [ + "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P" + ], + "funded": [ + "JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf" + ] + }, + "7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ": { + "address": "7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "85YGfmqnNpR3qs4i2Jie3PogFfqH8HKqiGmaKaDH7EVB": { + "address": "85YGfmqnNpR3qs4i2Jie3PogFfqH8HKqiGmaKaDH7EVB", + "owner": null, + "executable": false, + "signatures": { + "Exact": 610 + }, + "first_seen": 1784165318, + "birth_edge": { + "sink": "85YGfmqnNpR3qs4i2Jie3PogFfqH8HKqiGmaKaDH7EVB", + "sources": [ + "CRS4fEoMQDbYcUL97fi6FdMJMt862X7AsWd1UpXa7peg" + ], + "value": 977878830440, + "signature": "oNjG1piYcxazmjmHH7MCEPABsDjm8W22Mnx2LgoBVrtRzwGxuXxYkLaufZYSWTPugfhKqaQZx9jpJDk62cJCV8P", + "slot": 433176446, + "block_time": 1784165318, + "ambiguous_attribution": false + }, + "fee_payers": [ + "CRS4fEoMQDbYcUL97fi6FdMJMt862X7AsWd1UpXa7peg" + ], + "funded": [ + "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1" + ] + }, + "BGT8Vm1u5nyW255LgWjD8wzsRs8g3KxBnB3Pm1FjC9fV": { + "address": "BGT8Vm1u5nyW255LgWjD8wzsRs8g3KxBnB3Pm1FjC9fV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "BcK2Fr53rJ1YU9CuRPewu6idyzsXqnDqc1iYzsJtnnEf": { + "address": "BcK2Fr53rJ1YU9CuRPewu6idyzsXqnDqc1iYzsJtnnEf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "DRg3C1nVnvwugDW1J9gnhArcZpo7oyREwfugZCLjPJVc": { + "address": "DRg3C1nVnvwugDW1J9gnhArcZpo7oyREwfugZCLjPJVc", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "EPzKe9HueqCag9Ca7qKimrFn7EUMFxQtvcVCyC9YgYoV": { + "address": "EPzKe9HueqCag9Ca7qKimrFn7EUMFxQtvcVCyC9YgYoV", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P": { + "address": "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P", + "owner": null, + "executable": false, + "signatures": { + "Exact": 110 + }, + "first_seen": 1784177001, + "birth_edge": { + "sink": "FnRAkDK9i1FUbeJT7L51Uv4N1apEwiSPtraBGYH8d58P", + "sources": [ + "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV" + ], + "value": 1013755363812, + "signature": "4bCLrfEZQDfnnTB2ZtKjibJMGxc2i9dmQfBw3YwspS9nj7ECNGe6ZLKnvLBzwLs17rLfpazETh5jFj3NeKBR2m9S", + "slot": 433204823, + "block_time": 1784177001, + "ambiguous_attribution": false + }, + "fee_payers": [ + "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV" + ], + "funded": [ + "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa" + ] + }, + "Fqwus6SoxhNzxESj6ftBRiDWvGMB2ZYStgtKtDwe9iyS": { + "address": "Fqwus6SoxhNzxESj6ftBRiDWvGMB2ZYStgtKtDwe9iyS", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "AtLeast": 20000 + }, + "first_seen": null, + "birth_edge": null, + "fee_payers": [], + "funded": [] + }, + "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1": { + "address": "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1", + "owner": null, + "executable": false, + "signatures": { + "Exact": 281 + }, + "first_seen": 1784175331, + "birth_edge": { + "sink": "GowCUanu8Pn8eFwUwP8LhTKs5dqs2UcUCoNefrxPnin1", + "sources": [ + "85YGfmqnNpR3qs4i2Jie3PogFfqH8HKqiGmaKaDH7EVB" + ], + "value": 1013718534543, + "signature": "275rMzAXjBMFqoAbmxFDKbrCJhxKkvkTPr8NTkfRXef7jp77aLpLJ7ys64DrZoeNF6mRZCnv5nkcU5TwLt7RK4L4", + "slot": 433200756, + "block_time": 1784175331, + "ambiguous_attribution": false + }, + "fee_payers": [ + "85YGfmqnNpR3qs4i2Jie3PogFfqH8HKqiGmaKaDH7EVB" + ], + "funded": [ + "4FhqKqW5UndCQA9CdNBf99UXPvVz2UWADs3nWJDuxGqV" + ] + }, + "JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf": { + "address": "JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf", + "owner": "11111111111111111111111111111111", + "executable": false, + "signatures": { + "Exact": 12758 + }, + "first_seen": 1784184343, + "birth_edge": { + "sink": "JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf", + "sources": [ + "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa" + ], + "value": 31452400000, + "signature": "47b3ovtAmBQU129wgtij6M2qLZrQJszUK3gyZeaj9rNFLEobqFfsc9D4NjWnh3bG3DxmWo8iatDgy4Jpcu5SbcdL", + "slot": 433222637, + "block_time": 1784184343, + "ambiguous_attribution": false + }, + "fee_payers": [ + "7TH25K4sqPJVqoBqWjUx39bUU7V6SFePfvJ4jRji84qa" + ], + "funded": [] + } + } +} \ No newline at end of file diff --git a/data/seeds-marinade.txt b/data/seeds-marinade.txt new file mode 100644 index 00000000..ae036057 --- /dev/null +++ b/data/seeds-marinade.txt @@ -0,0 +1,100 @@ +H6Y3YXAyFY4bZUmLTYVosLn2d9hYps16HS48HUq3634R +2HVwBFmkq1HUfS2RBN3ixqGBL4NhKD5LhyyVX8bHjSu4 +FSE76cHsLGxJhpaUb9hVCeT6i8AqbWkGrqYQx9LN9fcf +umnovSeCExJ3ec1gypSne9cWQjetj45GnWuButiWPRQ +GBrVtJ9WxcsKGJKmvBDkZdqurGzDf293S1JKgqWWmpoG +3HtvC35XD2HEq1x3eNhDARwL7KTfBFePkykTrD4b7HEr +G9nsGzoDFETzX19tUvgVbit4BYVftngthzgSUJef4fb1 +7KLoH92Gm5nw7JetG3QAKa9RwwHNmoy6uwWtdTZH28No +Ah99tgyEJf7GkKNWWprkejhW1UejJwoDDsmR7hJHi8kX +9FEC1CgLMGE31RVwYLekqrQFtpfgDY1SUaRKaj4X6LQr +GcfeB9Gf1pBG27uAzePNJtUSExShPkBNtQpzoybZoEq +2et5etVQ1ypxTop3KkRrnNr6uyjPmzq8KyCHLaeYEbs7 +okXSZcokQCJXD2B6RywVR9KaQS2NeuUWVfCYuwmBq28 +E9wzrbCkKoxiNiYRUskKqS9ob8gfQAtgj8wE8sh1XVGq +9Y8V742EZCvKGJvAnmJFckn3QAaZNXhnYk2MdLGSzTdb +5E4pqCQBoXQoA3saK1gL4LaPxeGrQn7whwjZ2WTcXkCQ +EBNUgPBpAXf14QLeW26LXsqsMowc4Ej73XJNyxP9AQ7U +CEsP4bJmNnTcbe9Pyxm8nuAy3Xq8uWZA8L7zbNqiAEcm +71wa8sTfh6RBnsnF4LwWgwnTw2YxLaGFuwsVhRPQqmzm +Daq4W5wUTNw7sRXxFvLruk13wjpedVcgBB4rjTzx3DhK +2cSw92ybJWCZN93RLD2ZCxg3DMXS1v5u3H4BYRExBjbK +EADLiUN4qnDgsQdQyQn8A6hV1o8LtuWX6ZDR92Vuv5B9 +GeeYJ3UaPUjXQsuP7Jet14i1TtLd9tYYyPXY8qnApL5i +FRLHpC2U6fKVbPaN6GG6byW44LCJ9MjJFEy5o4FMo8Zq +6kqUt87GfNYvBxpi9WK8RjGyJMSV4mjt8Tr7n3ej3ybG +H28TRhAFrwYcjfEgdJWcVWybT1tg614SSn2M8rd2bsMx +2h5b8DXC4obG3Wrvy2tpv2fZ9K9o9zaRBfstUXpY6764 +B3wWqwtFZyU1xZM7rWEYan5oJsegs6Z4tkt2fnfBGG7i +6focMqS5RjDZUKcEbPYL2ThVm62e8Ljs3PKshkhANFN9 +93PSyNrS7zBhrXaHHfU1ZtfegcKq5SaCYc35ZwPVrK3K +4ju5foMCMknZiWQrYHjZNnimChCAurmBAejCCJP1C1oh +GgH9h9rsMuoduVrNeqfettdkPbBcMJpMJSd2KyJ9FBVb +FAShBHsY6cMvoyCTV1oopUBFKPEkftMTwP9SqCFuQCDo +AhsdvQTNjKRKRNoKwX72rU4iMfqUTXDPN5UZjTUQjJy4 +DxMTQxafDRzUpb1Xtursz3gndHtHwh6vn7fzr38qCLxa +4r11Baf8NPhvjbAXbDr11UYoXqV8DregFcFiJp47s7fh +759Th6hdAEChjN2hQdZ9YyTHx5TWtoxgFkWPzFxQXL6T +CfvWj5Zd6k4Tm864g61jy9QqMfSa5D7ZiCuEbbWoAcxt +Dbzbxkxpng2NBcUavsveZJpbfXDEbAagPRDrJ4J71fBi +9Ey7ic8KJQsuXG16RtQSi4wck5M2Mx7QNXFNjjCVoQck +G2uhJ73CLDt2DnodxEdR81HsHcZ53YonsHcL6J5DZxhu +8TRpWVAv9Mm4cuVCyiGMBvQ6icu37HjCoKb3FajYLB65 +41vrUt8avJ7ji5X69DHhB8wnf22Z8HMySm4oS8NzhCzR +7tgzfvXzXq1t1gYW5p8o4wqyK7rHxKEo4AEYPQHDxtdt +HM1mCH39pK2UB6jZHoBWoVQg1cqoYM11S1AuYvcD98Qw +JWe9oumM2S71bw3371v3gfKY2pQtNis6nGiFp2Wgi8n +7Q7NKBZs9cYE6mxrZLYnVBu2rQCbvcks6UawUVeGgRJg +GM8Qz8gmp9N3Rm94q9iTJeHobGBXoCYMhwZYY8zji3LA +DRhoK8JXn59s37fumzzPpWwST31TiaE2s7naZ6qmUh1Z +BRLeB4UANvMEPLqe76uFCyEA3wMTCPLkJqS7KsoYYCbZ +FJx61bqznoVfVDFoujYGgJoJsJq4DxDQ8K3YG5kgRm6G +AcXn5js7WNPTS4VvZ55k4mqZMbE8SyY9mBs8SZgxcdAa +FiSYxPca7TfUFFzsuZHaRN2DVbNDWoB1EqijcuZPtGhA +71FdNejCYQFpZ46a9QmAhghw72F6QJdYWRdtKrKQU1ip +2XuaACNi8Zz73BKPX2QFi7DAqwFWUQo7j39KYP6G86dh +CZRtotDXeMtvGcUcRUCvSMpXj8grJ7rJUrhRAxi1nQoG +GEoo2NGFq49Tt2Nx1188Rd7VdPZEB3S1ZoUgwALChCU9 +9qjDVFMBzDxg3cS6gMVjR6rFJAubMv51T3NwcrAu5VCV +BZfQxaepzR4pRLDTGMXSkvqGRh4R48o4TMMnHsXtPeEe +3C18CLMqYbfpmjmiKXwLtvLRcNYG7mGLdftHju64YmDM +5h14soshoerNL234NwnJjFYHPC4iCF1RwTCBnEQcUd4z +ChBw1Zu1j63pzmkAUNUXwgNos56RdYeb7Ls52HuJi6hj +6Yx4FmEpbWsyDyMRwdZsMLu47uzZ4CvqXvVSzN64o1BL +55gcso1fiGyKeqSXAi4Zr3Vmw9RotfF8GLYwouXSevMB +GxR4Sbw8xeHrh2pFrnG55ZR9JRGmUyhfoq4TG5ZU9fcv +D4et37m3txgA4vUVD7r1sW3VU54HxjQEJKeS8nzQbMf3 +3pxVaH5o275FjxxK1NDAoUULSSBqTE7GDHkTnBju64MF +DEZpwAb5wFu3yFcv9Gqu7Fg374gtt9KvNkNkrSwuKKx8 +DJ3WNbkGXqS9jJGXofzShz6hMm8FKhBt19pABdXd9TS8 +B1mQeDgFPifbD1soS5PhZG6H2uu3rkDZAZFsGUNuRprc +6gKd4wGwaB71Yy3BYLUjfV5XzeDWtEuRu5Q24egzEEzV +6bz1PfVhJfZmjBUEx6xkMQL5De7TMfSVqTEXdQRj4Rtv +4CpdzBYYVbUDQuSMxvJyvehS6EhcXzYeAytTLmGntvvL +DCarCCn8dB94WwE2U2hKXMWT7SUDEXmG7QgQpTQJ2whv +4aRt9qd2Zffwchw1zyLAPZkeQRgcnPLVpjjaR3JR36v3 +2cvCppkE6ng6FkgiZigjoFgKsc2t18Jo932HMoTWfg8o +GGW7fKri4agcKXic3dEuhDRQ3W6DN275HH6NM7cCSju2 +9fVYvwTCvHb1pWqiseEpAg9QC32vmvTRhWkHpqNbr879 +5L2WqG4H2x1mcpL9F39YAAZbTC1WdA8HjJA9sBBbm4YC +HMXoJu4fRNkBBy4HS8DBHonJFrVZNacpKAaogWqjYoEh +C2DNx61rvkUrUSqjb6VbU7wWziQbwxerwTGEksBnGRb +8XnjeyUaXkcUZaAV8ZnVFoEtJgeCyNhVFKuoT5QeTe7z +2uUTM3h7WqBsoj2UtV7sxwYfCz8wzaD321kv7gy9YKm2 +GRe9XvkvUF2FQ8jpBju4mmccjLrkQutmHTAqCkHTknZs +Cfcm21hnk84Kv7AmEm53jXaCXnHtm7XvCPmBLBcH5rxK +DFF4HX1SVvefEJxCVoAvKkjbeacjXuEopxiqwYxabiQN +3DJFUtrtvrjNWqxKrziAtWQZd1s7283z3Bv5yYyLUZWi +FtLwLfQPHLN1Ya1QfreEFkC6ggWBDX5Yej3VW6Kh4j6p +G6JnX6ziFFpXeSH4TdW2A2w3BDUYhvwEAyX1niP1eYx2 +3pQCKrU2S6DDNLmKNASNuTM9BUCfZx2hUycfBHL45Fu9 +BTKkA423gFDxXGxuWHGNHGXXtaJrTNUQpzmqDjcemsij +GspnWJp3hkvP9u6tg3DQtJfBM9udWF1QCLnF16tVCVWf +AkbDjkVX9zXWUzRpfbD8pZh7ZHcyZEDSTV3FDwyZgqxf +83ZgjvsVN5eBivbjmn8kqmb8upDeqVWPn1v3Jxr3iabg +CEsi1oBKdwwu2uAs2cc7YUFsQJ8x4N9XZrCSW8zSHbiJ +4UcxKrEt2RTRqXhPhGjKt4LBFYKGdKXkesQtosFB2Qn7 +86XYJKnU6fGECepioGn61AtHLxgeSamXDC6WKTJYoiE4 +B6jbBHAZjmD4cxALXRu7rdNNVQKAKtjTSGm496KWa5CM +HJuaALQ3srkxJ3bdj3GtaDcme4UXfhnq3nYFtEFPS99K +7pfNKw1sABa6Kq3BZCXxD5V81pHQTy4FEr6XtAxaKGKd diff --git a/data/seeds-privacycash.txt b/data/seeds-privacycash.txt new file mode 100644 index 00000000..98b64b55 --- /dev/null +++ b/data/seeds-privacycash.txt @@ -0,0 +1,100 @@ +FBSVzSJA9BpRPmtvsv5qVtHwBGkFsevvmn1Evtggo56B +5muie7qQ8uTXGM9uEHJyR3WYQoyHeRA9Npnkp3L6ibW3 +FmvvAVe9CN4GAXuQ9LmvceH4VqmGLmr79KidiMtSy51k +8fenZTDtD27NgQoApjRVTPnZyTEgdjuxkWcQZiPVRS4E +5ZPwW3GtoR8TsnPGdsDmFGd6eeJiaxBHQg8Di8C442Za +3v3yjUVK93vdoAdgZ5NuQPHC6ERXQ5fbduELSaYT5Kze +D3HSosDAbujBRb3GKcTkMn6K9hzhpoG9KM98SkCwPtVU +4vWvjT8n1tap7RPESBKq6qDyr6s1nrVK4fd8ERJWwGXd +DVMkhiQe1D8yenuEgsW44NjRn9LfVQjGEpZcez5x7Mff +2BXesxtW6sKLkBnSiWupFjfgZjauUycNxgzCioEhghHJ +6N77qEgunFqkU99DyZAaqNh1TENimfVVfSKegKm9a4qk +GsZHxEz792ibtNt6QzxbuFwQkEzvoo7HBsETSLbtgXcp +J1KXUDXsJ4voYtNKoQqDhwZsYJt72NmB1JfcQKJ1vK5v +5EiNo9MsuuKcVaDEezYsAGdkavoQYSYNRZYH1cnB4RtZ +C2Y1JPWufvGE3BkosqfRSRpJyWREcBhbH2RzysMDyXdD +6E4S3XAYuBbznNFrcGtWJu1u7UB5jT9K536zybvYxSd7 +GT7mTRv43hRBMQgkofHFfqQkqNoT61W3f3BWt97kqonq +2kpF5eiiZjPh3dySyb4eFHg2FFDDyxBAKtf8kox681Lf +74pBdqs9niFM5VUNwVMCQDK7TQhVB3ACKUEJ5DvmGThB +E96zNVAM8yq3wLiU6FKbgyPASEVtg4QGRrmpykGUn9Do +BvTuGbZfBr1faAT74jvM1JoP7CrwDSgRgFzP6CtQBe7P +7H9L8oAErukFwj4gEf4yzxUtfWrjWpW6gRDctzCkTLGF +DD5W46FGxDmo6R1VxT5PrbbfTcutfH1acCDg3fQVbY6U +2WQCfa31y6Qid5aBAbDE6arARchEochqGufAM6Y9Nsuy +HVZXVsbsnvNJuHj5xBCUppm2c5i2gVuryFGMRpFRu165 +FuasKFTCGY2EodUE7vDXkEf6a8TC3gFjCrW6DyLWyxSw +Gb2HfReRRLpp8w5zkKhu1SSTpkpWbTMdjwduvLiiDivC +9SMyYdEWbeu8beve9BShnWFDJeWw4hJ6Mmcd2i5TJPpu +5GPq99e8UGo5SCrXXCrzA7HtZwGeQFcCWP64H4uWCRDr +8Tg9Zn8ixfzcf3TetFi9sXJHexJ96CPPMfjsQ8wHdTtT +Hi9cLJjbBSpk7VbRSqich9TCiWYMxuyrWNcqgmWNprr9 +81SrfuuBA8DmnX5EofuHKxoMaK95ehbhQMbkY4rLpMWQ +Bqqa46ZcQKQn4Rj8nCV7hgPYWJ3TLaSbrP3HCUwbzWWw +9zfFDeoRj7DVfLouw8LMPdKkAMyStByNyvzAn1vRPhBY +HnTGgj9MgsHVEMNWfs2RQsDzQsaZLC9Ytbno7L6Q9u9k +HVDyeC7kC3iCqf5TEncLk5b2rKcqfXtBBhSqnLmQeXZC +6gHNr2kc8uaiRQry2ZJE8iE6ZhBsg2a6iz2JUNWAGjXx +8BuCVJzZnkbCYoqndQDbCsBqhRe3ZTyzQLTZNyM5ww4u +8saHrxj1e3BGeAEh8zh8ssrniGwE5JtJVxy5V9w94hrb +CrAWByBbF5qNRLS67cshtjenGvRmgSLCmAno9GRJqLqz +3kyvLN87RQhv4Gy1AyQgXTxGxa8pr448CiaGtPaoKzGv +F8FiqBchYuGpuThChPB22AJmsVcT5Aatko2MQCutfjjL +4XXUvTDdke6d4hJQ7XF9KwkkkUMYsTbjrNF3tSizbYjr +Bxj3wTgdx2sS2fM9FVFSYTibnuKE1VWkJfHuEk5VAPis +GJXuPrtuANNJ3xrSVQNQWwSHUjduSscwyKjqxD8jt4FT +DSmB6K1QuFSwXYcuwinqDQQgQ6aSoKuo3uTpuiGq78zX +22mLe7XtDZUsHph4YNkcTAK9MZzByXLbi4Mf28mQT9ma +5UkMq28tMYqtH3ybUzKoSXFxBKEYvoDPYLd9EZGEUCFV +AoRRRXMiRpZUqyQp4JjbuYes7kTrvgw4ZVn5uXsQbuXo +75kgx5QhMuCXB41uhorbYHfRFqEkVFQChTurtVAnwHJz +xukyMmDrvUreyVX2stb5DyFD7MopGzYfTisLFwg6Tf6 +8a9cyaJieNimjEtch36dF8eZSACQKUQKhg1V65vzcR7U +5cX6A4RZ3wJHxTdRMqxDRCkBtdo43ZA4orB2QRZxUb4p +BvDFyWV3SvDG4c56tvjdzPkfS29jEMpCdZdANrkNQ7DZ +7rMVWenGQ7YxEdv2eq5pyWx3jYL24E2Tjn9mVsaWkjcG +LPsefXkaaAqLMoEK3HhJWRhd6qk3xzeTUgmtQ727YEE +BnZAVY6xMaqTwwW85e2LyKchm8yJrvGv6eA3qBB8sAXo +5R2ry1tX8FTM27u5ChahmpHadK1pUd8KsGmPd19scR2t +iXQYQbH37U7YnvcmzwrCYm19BK6i1Zn8NYmD6J24JCW +6ZBSAUibYQVaHqvuaYqxK62jAaZhFzKgetSxoMYDRskq +BYSTYBFB8m4AWrqdEPzJKLYqWCVHp6o5AvRZp9HyHu38 +5PrefjTSrQGrojdYWsbcb1HwsRt7unDS9dDD8qfH64vS +8rccnjzBQFzPre8GJSLajAYvNzM17RbzASApb2x9rMo1 +B3oz9sgGTAbmyizp1WzxYvxkAueh1hioGyxpFXD5BbhJ +CmFmcBgTumLRGZfU4bNN4fynNnaJ125UgkWNhmmQX6hU +C4vQni1wLtq4QeME8aT6QbfE5G7oSiMD175puFsLkcRA +CNXERaCE3x5W2tz9io7RwRJ9utiXumvdXkiLg3AsJ1Gh +GkRhAmsDpHq6C2BaMRv3y8Q6X9vDX5ffohHtdndvqNk +E6Je9BGuv4SWCqwrRXFbkEuAgKp6fDPLiwrakWHio2Yq +7Ku4KXWtQXXSp3AQrN5VHZv8nSgCJmSmQ4sDLZXSGiUW +1kkC2ZFRxpfkYbMCp3NFbPsaUoTmkdGaTBSwxweKC1E +4bnaii1RywBu78QnxvBWQq7TQP5zGUNY26ESM1g7wF16 +2Ej2hAgZihAPV4JKYEXMGYwL1TvSaPQDS8KNGr9B22ha +FEkoSkBGCqgiduibgunL1VVL7x2cEFBat5dEWwoTbTTt +CBgkzioYTK6Esxjyt2LeFtbzdWKJALdq7rydGSDiA2jr +2fbzcJYZDNKURTR65dKBAkVwgnGNDAsbz8ykLAQ8Eapg +9dht891ABzDAy3tcvsffZNCenQKyDqFAyufTJLiFoBGu +9i1et2MVHNkMp7RLVCM3gBizxE4PoJkgbt7MRk2Q9Fdn +7Ropb1oWy9uZowkvaGWw88GepGaZ4MivexFrfAa4dJrG +8UZNFX1YJ1ohT7JEwyufr856h9QaFtRHJ5RMochELSUH +F7VxQHbhWgwkCLEt1zwsfHdLT6jaZdaw23szSZQ97NVp +HQwxajypJoUshau4FqqeFBHPBJfUodsDgdb3Dtgb8uSq +3HeLU9KQtGBDCVXMHCbkYKq1SFZrkWm7X2Yk1CvgeRhL +88dcs7UaNnNP49hMjoiiARwAJ51iWDyug7n1TwKh4DH +3eynayRMaDTLK3RYyF2yy34tunwqhWCg3sF2kvg1JGx7 +Azh97tUtsiFmLw4wLBiaC1cwABfbqg71ycmRVt8kkUyX +BCuDtrKy7MUBa1NpeRVt9aEKumZpavU3NEq7bEdEcdhG +EKnwZFKwiRRt5smKp4niv2mi9orJswAAzEdyWto1YFSH +HDz7F7kFk12bKxJVSZnJbdVnCySpQ5AFU9HBnn9N3HYQ +F3ZNeEia1bFKjwL4KcPYfkRsVu5MRiqBz48sThhR34gx +DEdwtjvCs6dSadA8b6EQwCP95mXebTqMDK6wh13xhdpR +2FsWwP7tmDyH2DTpvxRAxVqEyj84hU3qDmt238g65mp9 +9vZW7UvA7qUuJJBqn3KGtdQTCNsxW9hKbzwAPjt2sTmp +6oABnktxmqBX7S3aF64nzD3zYj7Dt6bjYDt8xTwYj6oY +JDmzz2bGQwjPAN5gkEDCKd9E4zdWVFHLDenY9NmrJQaQ +F5tKdkn183iM3f7Xs2FjS8JYFDkmrJEns1AFoT2TmupZ +FbSXcvGRhDdct2URYZkRZLYyaCbXNkRib6SbUzazTmAM +3MaDFqYf1M3296QvgBhYFZw7FhRd48mJP91jePnv8e8H +3THAf1scfXLY7JjNgqx38pUTkGjmGe1KEJNR7PBTHvpH +BKQqoatcqyoWoiUnHDJM2FW23rtwoMiCNnVbMECASGPM diff --git a/data/seeds-smoke.txt b/data/seeds-smoke.txt new file mode 100644 index 00000000..b1203cd6 --- /dev/null +++ b/data/seeds-smoke.txt @@ -0,0 +1,12 @@ +BGT8Vm1u5nyW255LgWjD8wzsRs8g3KxBnB3Pm1FjC9fV +62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV +7Q77q5ai1bjDA9kkMRMWJEJV7KWhVoBV7NDYKsAbcTd7 +BcK2Fr53rJ1YU9CuRPewu6idyzsXqnDqc1iYzsJtnnEf +3FuCiEjR6iZ9P7A6hSF2VFFwRq1Q19Gok7JgHf6gZkcf +EPzKe9HueqCag9Ca7qKimrFn7EUMFxQtvcVCyC9YgYoV +5Ktwj8p43RvMsHdyBsx1ZZZrao3CQo4uT6uWqE4FRB11 +JE9yvteYgfUagiYCgCCP9XTPsukrFRMXL8o34DAwF7hf +6TxjC5wJzuuZgTtnTMipwwULEbMPx5JPW3QwWkdTGnrn +7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ +DRg3C1nVnvwugDW1J9gnhArcZpo7oyREwfugZCLjPJVc +Fqwus6SoxhNzxESj6ftBRiDWvGMB2ZYStgtKtDwe9iyS diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..adbe4e97 --- /dev/null +++ b/deny.toml @@ -0,0 +1,81 @@ +# Supply-chain policy, enforced in CI by `cargo deny check`. +# +# A privacy protocol's dependency tree is part of its threat surface: a +# compromised transitive crate in the proving path sees the witness, and one in +# the client sees the note. The point of this file is not to reach a green tick +# — it is that every exception below has to be written down with a reason +# somebody can argue with. + +[advisories] +version = 2 +# No blanket ignores. Every entry below is an *unmaintained* notice — not a +# vulnerability — and each carries the reason it does not reach anything this +# protocol depends on. An advisory with a security impact gets fixed, not listed. +ignore = [ + # ansi_term — terminal colour codes, reached only through the CLI's argument + # parser. It touches no key, no note and no proof, and its whole surface is + # writing escape sequences to a terminal this project controls. + { id = "RUSTSEC-2021-0139", reason = "unmaintained; terminal colouring in the CLI, not on any cryptographic or custody path" }, + + # derivative — a proc-macro arkworks uses to derive traits. It runs at + # compile time and emits no code of its own into the binary, so + # "unmaintained" here means the macro will not gain features, not that + # anything ships. + { id = "RUSTSEC-2024-0388", reason = "unmaintained; compile-time proc-macro from arkworks, contributes no runtime code" }, + + # paste — the same situation: a compile-time token-pasting macro pulled in + # transitively. Nothing of it exists at runtime. + { id = "RUSTSEC-2024-0436", reason = "unmaintained; compile-time proc-macro, contributes no runtime code" }, + + # bincode 1.3 — this one *is* on the path, and is listed rather than waved + # away: it serializes transactions in `chain.rs`. It stays because the wire + # format it implements is fixed by the Solana runtime and cannot change + # without the cluster changing, and because every crate in the ecosystem that + # builds a transaction depends on the same version. "Unmaintained" for a + # frozen format is a statement about the crate's future, not its behaviour. + { id = "RUSTSEC-2025-0141", reason = "unmaintained; implements a wire format frozen by the Solana runtime, and is the version the whole ecosystem pins" }, + + # libsecp256k1 — arrives through `solana-program`'s secp256k1 recovery + # support. This program verifies Groth16 over BN254 and never calls a + # secp256k1 entry point; `grep` for one across the workspace finds nothing. + { id = "RUSTSEC-2025-0161", reason = "unmaintained; transitive through solana-program's secp256k1 support, which this workspace never calls" }, +] + +[licenses] +version = 2 +# Permissive only. This repository is MIT and a copyleft dependency anywhere in +# the tree would make that claim false. +allow = [ + "MIT", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "ISC", + "Unicode-3.0", + "Zlib", + "CC0-1.0", + "MPL-2.0", + # The Mozilla CA root store, carried by `webpki-roots`. CDLA-Permissive-2.0 + # is a *data* licence — it governs the certificate list, not code, imposes no + # copyleft and no attribution requirement on downstream use. It is here + # because a TLS client needs roots from somewhere, and taking them from + # Mozilla's published store is better than pinning our own. + "CDLA-Permissive-2.0", +] +confidence-threshold = 0.9 + +[bans] +multiple-versions = "warn" +wildcards = "deny" +# The wildcards this would otherwise reject are the workspace's own crates +# depending on each other by path. They are in this repository, they are built +# from this commit, and there is no registry version for them to drift to. +allow-wildcard-paths = true + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +# Every dependency comes from crates.io. A git dependency is a version nobody +# else can resolve and an audit nobody else can repeat. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 00000000..d31c1cf9 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,319 @@ +# Architecture + +## What the protocol is + +An anonymity set for *actions*. Members deposit a fixed denomination; later, a +member proves in zero knowledge that they own some note in the set and directs +the pool to act. The pool executes. An observer sees that an action happened and +cannot say which member asked for it. + +Four crates and one program: + +``` +mirror-core field, Poseidon, Merkle accumulator, notes (linked on-chain) +mirror-circuit R1CS gadget, membership circuit, prover (host only) +mirror-pool the on-chain program +mirror-provenance funding-provenance measurement (host only) +mirror-cli members: init-pool, note-new, deposit, tree, spend, settle, + disclose, disclose-verify + operators: setup, verify-setup, soak, crowd, close-table + measuring: check-endpoint, seeds, collect, analyze, + compare, selection +``` + +`mirror-core` is shared by the program and the host deliberately: a commitment, +a nullifier and an action binding each have exactly one implementation, so the +two sides cannot compute different answers and discover it in production. + +## The note model + +``` +note = (k, r) +commitment = H3(k, r, denom_tag) the Merkle leaf +nullifier = H1(k) revealed on spend, spent once ever +``` + +**The denomination is a pool constant, not a field in the note.** One pool serves +one denomination, so the escrowed lamports and the hidden commitment cannot +disagree. This is not a stylistic choice — it makes a class of drain +unrepresentable rather than merely untested, and the class is worth stating +because a shielded pool built the obvious way falls into it. Carry the amount as +a note field and fail to bind it to the commitment, and a depositor of one +lamport withdraws the entire pool holding a valid proof. Scope the nullifier to +an epoch — the natural move once epochs are how batches form — and a single +deposit pays out once per epoch, forever. + +Nullifiers here are spend-once, never epoch-scoped. + +### Domain separation by arity + +Poseidon instances of different width are different permutations, so arity is +itself a domain separator and a free one: + +| value | arity | +|---|---| +| nullifier | 1 | +| Merkle node | 2 | +| note commitment | 3 | + +The action binding is not in this table. Its payload is variable length and +Poseidon is a fixed-arity compression, so the binding is a keccak digest under +the domain tag `mirror-pool:action:v2`, masked into the field. + +An integer tag was the first design and it was wrong: with a small tag constant, +a Merkle node whose left child equals the tag collides with a nullifier. +Reaching that state needs a Poseidon preimage, so it was not exploitable — but +arity separation removes the question rather than bounding it. + +## The accounting invariant + +``` +vault.lamports >= denomination × (deposits − settled_spends) + rent +``` + +The amount owed is a function of two counters and the pool's constant +denomination. Nothing a prover supplies can influence it. It is re-read from the +vault *after* lamports move rather than inferred from the arithmetic that moved +them, and the spend counter refuses to exceed the deposit counter outright. + +Escrow lives in its own vault PDA holding no data, so the invariant reads against +a balance containing nothing but escrow and its own rent. Nothing else is ever +credited to it, and pool creation refuses a nonzero entry fee, so there is no +second category of lamports anywhere that could be mistaken for backing for an +unspent note. + +`docs/PROOF.md` carries the devnet numbers: five notes settled, 100,000,115 +lamports owed and 100,000,115 paid, and a vault that came to rest on its +rent-exempt floor with a remainder of zero. The soak asserts that rather than +printing it, so a run that disagreed would fail instead of publishing. + +## The circuit + +*I know `(k, r, denom_tag)` such that `H3(k, r, denom_tag)` is a leaf of the tree +with root `R`, my nullifier is `H1(k)`, and this proof is bound to `action`.* + +Three public inputs, and that is a cost decision. On-chain verification measures +as `74,179 + 5,661 × N` compute units, so each input costs about 5.7k CU. See +`GROTH16_INTEGRATION.md`; the figure this repository reproduces directly is the +whole `submit_spend` instruction at about 101,000 CU. + +| public input | why it cannot be a witness | +|---|---| +| `root` | the program checks it against its own root history — the last `ROOT_HISTORY = 128` roots, so a proof stays valid for 128 deposits after the one it was built against, and no longer | +| `nullifier` | the program records it to prevent replay | +| `action_binding` | the program recomputes it from the action it executes | + +`denom_tag` stays a witness because Merkle membership already constrains it: a +pool's tree only ever contains leaves committed at that pool's denomination. + +The action binding is squared under constraint. A Groth16 public input +participates in verification only through the R1CS columns that reference it; an +input used in no constraint has an all-zero column, its `gamma_abc` term is the +identity, and *any* value satisfies the equation. Without that one constraint a +relay could swap the action after proving and the proof would still verify. +`crates/mirror-circuit/tests/onchain_layout.rs` tampers with that exact input and asserts the real +verifier rejects it, so the property is checked rather than reasoned about. + +### Three-way parity + +The gadget, the host and the syscall must compute one function. `solana-poseidon` +is the only Poseidon entry point, and it is cfg-gated upstream to the syscall +on-chain and to light-poseidon off-chain, so host and program agree by +construction. The R1CS gadget then reads light-poseidon's published round +constants rather than re-deriving them. + +The gadget and the host are each checked against circomlib's published +`poseidon([1,2])` vector rather than against each other, and the syscall is then +checked against the host on-chain — the end-to-end suite asserts the root the +deployed program builds equals the root the host built. A gadget whose native and +in-circuit hashes are different functions is the classic failure here: nothing +catches it until proving time, and the symptom — proofs that verify nowhere — +points at everything except the hash. This is the test that catches it. + +A pure-Rust Poseidon on SBF overflows the 4 KB stack frame and costs roughly +1,500× the syscall even where codegen lets it complete, so no arkworks code is +linked into the program. + +## Instructions + +**`init_pool`** — permissionless. One pool per denomination, globally: splitting +deposits of the same size across pools splits the anonymity set, and a split set +is worse for every member in it. There is no privileged authority, so no key +whose loss freezes the escrow. + +**`deposit`** — escrows exactly the pool's denomination, read from the pool and +never from the instruction, and appends the commitment to the accumulator. The +tree is `TREE_DEPTH = 20`, so a pool holds up to 1,048,576 notes; the program +keeps only the frontier — one node per level — which is enough to append a leaf +and produce a root, and not enough to prove any particular leaf is in the tree. +Recovering the leaves is the client's job, and `mirror tree` does it from the +transaction history. + +**`submit_spend`** — verifies the Groth16 proof on-chain, burns the nullifier, +records the authorised action. Pays out nothing. + +The action binding is never transmitted. It is recomputed on-chain from the +selector, the target program, the beneficiary, the relay, the relay fee, the +declared account count and the payload, and used as the third public input, +so a relay that alters any of them produces a different binding and the pairing +fails. There is no separate field that could be checked incorrectly. + +The relay is taken from the account that signed, never from anything the caller +states. A proof is therefore spendable only by the relay the member made it for, +which is what stops a bystander from lifting it out of an unlanded transaction +and landing it first under their own key. + +The relay signs, never the member. A member paying their own fee would sign with +their own wallet and destroy their own anonymity, so no member key appears on +chain on this path. + +One limit follows and `docs/THREAT_MODEL.md` states it: the binding fixes *how +many* accounts an action takes but not *which* ones. + +### Funding or signing, and why the member picks + +| selector | | | +|---|---|---| +| 0 | transfer | pay the beneficiary, no CPI | +| 1 | invoke | fund the beneficiary, **then** call | +| 2 | invoke signed | call with the vault as **signer**, then pay | + +Selector two is what lets the pool act as a delegated authority rather than only +as a funder — the thing a stake delegation or a governance vote needs and a +transfer does not. + +The split is forced by the runtime rather than chosen. This program moves the +vault's lamports by direct mutation; an account mutated that way and then handed +across a CPI boundary makes the runtime reject the whole instruction as +`UnbalancedInstruction`. So paying first and signing are mutually exclusive, and +which one an action needs is a property of the action. The selector is inside +the action binding, so the choice belongs to the member and settlement cannot +revise it. + +That constraint was measured, not reasoned about: the earlier design refused the +vault outright and documented the refusal as a property of the runtime. It is a +property of the *ordering*. + +It is also a property of the **batch**, which only a live cluster showed. The +runtime objects to any lamport this program moved anywhere in the same +instruction, so a signed call settled behind other members' payouts fails where +the same call alone succeeds. Settlement runs every signed call first and pays +afterwards — which it must, because a signed action that could only settle alone +would have to wait out the timeout instead of joining a crowd. + +`docs/PROOF.md` carries the case the selector exists for: a real stake +delegation on devnet, `DelegateStake` signed by the vault as staker authority, +settled in the same transaction as three plain transfers and a memo. + +**`settle_epoch`** — executes a batch in one transaction so every payout shares a +timestamp and an ordering. + +The crowd rule is conditional: a batch needs `k_floor` spends, **or** every spend +in it must have waited out an hour. Requiring the crowd unconditionally is a +liveness hazard — a quiet pool could hold a member's funds until a crowd that +never comes. Dropping it makes "synchronised" a word rather than a property. + +### The permissionless exit + +There is no `self_spend` instruction because none is needed. A member acts as +their own relay with a zero fee, and settlement is already permissionless, so +they settle their own batch once the timeout passes. Nothing in the protocol can +hold their escrow. + +The cost is the expected one: their own wallet signs, giving up the anonymity the +relay path provides. It is an escape hatch, not a mode of operation. + +## What the k floor does and does not do + +`k_floor` bounds **program-visible membership**: how many notes the tree holds. +That is all a program can check, because the thing that actually shrinks an +anonymity set is not visible on chain. + +An observer can partition members by where their capital came from. Learning a +member's funding class leaves only that class to guess within, so the anonymity +that survives is the size of the class rather than `k`. No deposit pool controls +where its users' money came from. + +So the protocol does two things about it, and claims exactly those two: + +1. **The action side is closed.** Actions are executed by the pool's vault PDA, so the + on-chain funding trace of an action leads to the pool and is identical for + every member. +2. **The membership side is measured.** `mirror-provenance` computes it from real + chain data, and the method and its limits are published with the number. + +## The measurement + +Two passes, and the split is the point. + +**Pass one** walks each member's funding chain by the birth edge — the oldest +value credit, the event that created the account — and writes everything it +observed to a sample file. It is the only networked step. + +**Pass two** classifies over the complete sample, offline. Two of the five +terminal rules are properties of the *set* rather than of an address, so +classifying during traversal would make a member's class depend on visit order. +Given the same sample, pass two always produces the same partition, which is what +lets someone else check a published number without RPC access. + +Design choices that exist to avoid specific published defects: + +- Edges come from **balance deltas**, not instruction parsing, which is blind to + every program that moves lamports by direct account mutation. +- The **birth edge** is the oldest credit, so the walk reaches the *start* of a + wallet's history. Scanning the most recent transactions instead is the wrong + end of the record for any wallet with more than a handful of them. +- The **hub threshold is decoupled from the paging cap**. Making them the same + number is an easy collapse, since both answer "how many signatures do we look + at" — and it turns "reaches an attributable origin" into a synonym for "hit + the RPC page cap". +- **RPC failures are never evidence.** They are counted separately and excluded + from the distribution, and above a 1% failure rate the run refuses to print a + headline rather than printing a warning above one. +- The endpoint is **checked before the run**. A truncated endpoint returns `null` + rather than an error for pruned history, so a collection against one would look + healthy and report every old funding event as absent. +- Seeds that are not wallets are excluded on a **definitional** criterion and the + count is published. Excluding addresses for *looking hard to trace* is a + different thing entirely — it drops exactly the members that would have + widened the class distribution, and inflates the result in the flattering + direction. + +The headline is the loss factor `ρ = 2^−H(C)` rather than effective-k, because it +is independent of `k` and therefore comparable across pools. Effective-k measured +at small `k` systematically understates the steady-state loss and cannot be +extrapolated upward. + +### Three uncertainties, kept apart + +They answer different questions, and collapsing any two of them into one number +is how a provenance figure comes to mean less than it appears to. + +| | question | mechanism | +|---|---|---| +| unresolved bracket | what if the unresolved had landed differently? | exact bound over both extremes | +| sampling spread | how much of `ρ` is *which* members we drew? | bootstrap over members, seeded and published | +| selection | are the resolved members a fair draw of the classes? | one frame at two budgets, cheap vs expensive to trace (see `README.md` for which published pair is a genuine budget margin) | + +The third is the one usually left as an assumption. `mirror selection` tests it, +and **separation is the bad outcome**: it would mean the unresolved are not +missing at random, that the resolved subset is biased toward whatever is cheap to +trace, and that no extra budget repairs it. Measured on both populations here, it +does not separate. + +`mirror compare` then bootstraps the *difference* between two populations rather +than subtracting point estimates, and refuses to rank them when the interval +contains zero or when either side resolves under half its members. It has refused +on both grounds — on the first for one pool measured at two budgets, which ought +not to separate, and on the second for the cross-population comparison this +project most wanted. + +One bias is not fixed and runs against us: plug-in entropy is biased low at small +`n`, so `ρ` is biased **high** and the pools plausibly leak less than reported. +It falls the same way on every population measured the same way, which is what +keeps a difference meaningful where an absolute number is shaky. + +`2^H(C)` — entropy over the class-size distribution — is widely quoted as the +effective anonymity set and is **inverted**: it is maximised when every member +stands alone, which is total deanonymisation. It is the leakage. The anonymity is +`2^H(X|C)`. diff --git a/docs/CROWD.md b/docs/CROWD.md new file mode 100644 index 00000000..691b5a06 --- /dev/null +++ b/docs/CROWD.md @@ -0,0 +1,118 @@ +# Different members, different validators, one timestamp + +A batch whose members all do the same thing is the easy case for an anonymity set: there is nothing to tell them apart to begin with. This run does the hard one. Each member delegates stake to a **different validator**, and all of it settles in a single transaction. + +Validator choice is the behavioural pattern worth hiding. It is stable, it is public, and it fingerprints a staker across epochs far more reliably than an amount does. What an observer gets from the transaction below is a set of delegations landing at one timestamp with no way to say which member asked for which. + +Generated by `mirror crowd`. Pool [`Cqg4gj4zwHZGfp1P2v6j6pB4dLbWgsL1vJB7YkjsFWAK`](https://explorer.solana.com/address/Cqg4gj4zwHZGfp1P2v6j6pB4dLbWgsL1vJB7YkjsFWAK?cluster=devnet), vault [`6NrJ3id157J7qMi5veukujtvX6T5rJz1WZT1m6gd8eMZ`](https://explorer.solana.com/address/6NrJ3id157J7qMi5veukujtvX6T5rJz1WZT1m6gd8eMZ?cluster=devnet), denomination 43000007 lamports. + +## The settlement + +[`5SqtqpuJw3pAoBMMB9DmXaqFr93rWsnqWMyacRZ3ZpP5eQpacLTAjrYugAW2ni3PMucAzDLJ4TsLZU3aQd3ZVMPZ`](https://explorer.solana.com/tx/5SqtqpuJw3pAoBMMB9DmXaqFr93rWsnqWMyacRZ3ZpP5eQpacLTAjrYugAW2ni3PMucAzDLJ4TsLZU3aQd3ZVMPZ?cluster=devnet) + +| | | +|---|---| +| members | 6 | +| distinct validators | 6 | +| wire size | 1194 of 1232 bytes | +| compute | 142856 of 200000 CU | + +## Who got what + +Read back from the cluster after settlement, not assumed from what was requested. A member's proof binds how many accounts their call takes and never *which*, so the stake account's own state is the only place the answer exists — this table is the check that limit needs, and the run fails if any row disagrees. + +Every member has their own relay, and no relay key appears twice. That is the worst case for the packet and the case a settler has to plan against: a batch whose members shared a relay would name fewer distinct keys and fit more of them. + +| member | stake account | delegated to | relay | +|---|---|---|---| +| 0 | [`5P9AHY2tGoQ9xedLeyvC5WsU4FXxxH8LgtC2kzRUMZtT`](https://explorer.solana.com/address/5P9AHY2tGoQ9xedLeyvC5WsU4FXxxH8LgtC2kzRUMZtT?cluster=devnet) | [`vgcDar2pryHvMgPkKaZfh8pQy4BJxv7SpwUG7zinWjG`](https://explorer.solana.com/address/vgcDar2pryHvMgPkKaZfh8pQy4BJxv7SpwUG7zinWjG?cluster=devnet) | [`7GC9vjEJTUk1d3DLfb9ufBuSo4ooU5HzAmzeGdFejtBX`](https://explorer.solana.com/address/7GC9vjEJTUk1d3DLfb9ufBuSo4ooU5HzAmzeGdFejtBX?cluster=devnet) | +| 1 | [`DrrzXbAmLdgLfmcGtN1mAjgEuRK5mPyRSVcwazUtUWaT`](https://explorer.solana.com/address/DrrzXbAmLdgLfmcGtN1mAjgEuRK5mPyRSVcwazUtUWaT?cluster=devnet) | [`i7NyKBMJCA9bLM2nsGyAGCKHECuR2L5eh4GqFciuwNT`](https://explorer.solana.com/address/i7NyKBMJCA9bLM2nsGyAGCKHECuR2L5eh4GqFciuwNT?cluster=devnet) | [`CDNhhfH3qspD6Bgwsd6i7T6EGjE3r7yWPGBwaHyi5TXM`](https://explorer.solana.com/address/CDNhhfH3qspD6Bgwsd6i7T6EGjE3r7yWPGBwaHyi5TXM?cluster=devnet) | +| 2 | [`EgGXn9y2ea9bDqGoUpU6Z8ET2JNm6zNaFu1Ux2x6RNNx`](https://explorer.solana.com/address/EgGXn9y2ea9bDqGoUpU6Z8ET2JNm6zNaFu1Ux2x6RNNx?cluster=devnet) | [`5ZWgXcyqrrNpQHCme5SdC5hCeYb2o3fEJhF7Gok3bTVN`](https://explorer.solana.com/address/5ZWgXcyqrrNpQHCme5SdC5hCeYb2o3fEJhF7Gok3bTVN?cluster=devnet) | [`2UWeNWf8yg3UPbeycv6SMoKLjmbtD2XgAX8wiQ92RouF`](https://explorer.solana.com/address/2UWeNWf8yg3UPbeycv6SMoKLjmbtD2XgAX8wiQ92RouF?cluster=devnet) | +| 3 | [`FgWdYn2gN9oUxN18NJ958BkgR5zoCFagWp73pQ1YHc9x`](https://explorer.solana.com/address/FgWdYn2gN9oUxN18NJ958BkgR5zoCFagWp73pQ1YHc9x?cluster=devnet) | [`23AoPQc3EPkfLWb14cKiWNahh1H9rtb3UBk8gWseohjF`](https://explorer.solana.com/address/23AoPQc3EPkfLWb14cKiWNahh1H9rtb3UBk8gWseohjF?cluster=devnet) | [`D1oCaiaGCJGyi2Co7mE7W5nMpcATdDnGtGMSGrk8Qcpw`](https://explorer.solana.com/address/D1oCaiaGCJGyi2Co7mE7W5nMpcATdDnGtGMSGrk8Qcpw?cluster=devnet) | +| 4 | [`Fa8khDvR3arVezDmDZpLPHA4VVwRuSwzfJ2gcDSKQmDo`](https://explorer.solana.com/address/Fa8khDvR3arVezDmDZpLPHA4VVwRuSwzfJ2gcDSKQmDo?cluster=devnet) | [`7AETLyAGJWjp6AWzZqZcP362yv5LQ3nLEdwnXNjdNwwF`](https://explorer.solana.com/address/7AETLyAGJWjp6AWzZqZcP362yv5LQ3nLEdwnXNjdNwwF?cluster=devnet) | [`DtoAEYygmCWw156gn4DB1ZCUTJ9szUbT7mLxqNs5bTos`](https://explorer.solana.com/address/DtoAEYygmCWw156gn4DB1ZCUTJ9szUbT7mLxqNs5bTos?cluster=devnet) | +| 5 | [`B5unNLodBUxcsggqV4g1KzoyAXz4oNHN3bEnRTJ1Fmkw`](https://explorer.solana.com/address/B5unNLodBUxcsggqV4g1KzoyAXz4oNHN3bEnRTJ1Fmkw?cluster=devnet) | [`2u83Dx5qPV4QnujjJQv8v2SoqG1ixuAxPK5Jwhtkovd1`](https://explorer.solana.com/address/2u83Dx5qPV4QnujjJQv8v2SoqG1ixuAxPK5Jwhtkovd1?cluster=devnet) | [`3dYe9vTAVYpsrSYtxLRrawFYQaMNQsLhqhscmFhRKobY`](https://explorer.solana.com/address/3dYe9vTAVYpsrSYtxLRrawFYQaMNQsLhqhscmFhRKobY?cluster=devnet) | + +## What divergence costs + +Divergence is not free, and the price is anonymity-set size. A transaction names each distinct account once, so a member who picks their own validator adds a vote account nobody else in the batch names. The 1232-byte packet is reached sooner. + +| batch | members per settlement | +|---|---| +| all delegating to the same validator | 7 | +| each delegating to a different one | 6 | + +At 6 members the settlement weighs 1194 bytes with 38 to spare; one more member weighs 1332 bytes, 100 over the limit. Both figures come from serializing the real instruction, and the settlement that landed above is 1194 bytes — the same number, which is what makes the measurement a prediction rather than a description. + +## And compute, which is closer than it is for payments + +This settlement burned **142856 CU of the 200000** a single instruction gets by default — 71% of the budget, for 6 payouts and 6 cross-program invocations. That is a different regime from a batch of plain transfers: `ten_spends_fit_in_one_settlement_and_the_packet_is_what_stops_the_eleventh` settles ten of those in 19,545 CU, where compute is nowhere in the conversation. A delegation costs roughly an order of magnitude more per member than a payment does. + +Each member's Groth16 proof was verified earlier, in their own `submit_spend`, which costs about 101,000 CU. That is why the two phases exist: verifying 6 proofs here would cost over 600,000 CU — comfortably past the 200,000 a single instruction gets by default, and a large fraction of the 1.4M a whole transaction may ever request. + +The packet binds first — 6 members is where the bytes run out, and the budget is not exhausted there — but for a **legacy** transaction the two limits are barely independent, and that is worth stating plainly. The usual answer to a settlement that runs out of compute is to ask for more with a `SetComputeUnitLimit` instruction. Measured against this very batch, that instruction costs **40 bytes**, and a full legacy settlement has 38 to spare. In a legacy transaction, raising the budget means dropping a member. + +**A lookup table lifts that, and here is how far.** Naming accounts by one byte each takes the packet out of the way — `mirror settle` does it automatically, and a batch of twenty plain transfers settled that way on devnet at 332 bytes of 1232. What takes over for *delegations* is the 64-account lock limit, and it is a different kind of limit: bytes are spent naming an account, locks are held per **distinct** account. + +| batch | legacy packet | through a lookup table | +|---|---|---| +| all delegating to the same validator | 7 | **18** | +| each delegating to a different one | 6 | **13** | + +A full divergent batch through a table holds 61 of the 64 locks a transaction may take. Both ceilings roughly double, and the gap between them widens from one member to 5 — because a shared vote account is named once either way but locked only once too, so agreeing on a validator is worth more here than it was in the packet. + +**The compute budget instruction is counted in those two figures, because at this size it is not optional.** A batch of 13 delegations costs on the order of 309400 CU at the per-member rate this run measured, well past the 200,000 a transaction is given by default. Asking for more brings the compute-budget program along, and a program is an account — so raising the budget still costs a member. In the legacy packet that cost was 40 bytes; through a table it is one lock. The escape from one limit is paid out of the other in both regimes, which is the finding rather than the inconvenience. + +**What kind of number these two are.** They are computed the same way the packet ceilings above are — by building the real instruction and counting what it names — and not by settling a batch of that size. The 64-account limit itself is not a guess: it was found on devnet, where 77 accounts returned `TooManyAccountLocks`, and the twenty-transfer settlement cited above landed at exactly 64. What has not been done is a delegation batch of 13 settled through a table on a live cluster, and this document does not claim one. + +## Every step + +| step | signature | note | +|---|---|---| +| init_pool | [`5dPVS1efe2JcqJxV26Lxk5QwnTdsy8qfxc6wbFJXKNM9ES16qx6gG7P53c9RLnuMkzswjM9yoW4JEScrwYYg4HSN`](https://explorer.solana.com/tx/5dPVS1efe2JcqJxV26Lxk5QwnTdsy8qfxc6wbFJXKNM9ES16qx6gG7P53c9RLnuMkzswjM9yoW4JEScrwYYg4HSN?cluster=devnet) | denomination 43000007, k_floor 6 | +| deposit | [`4eTFg35LP21D3HCQYn2DE7WExrhNZsmyfh39i7GMYe9bxfsyEhdJJ2STDt2c6SmaeEGAB1whQbRtqbr71kRoMfDr`](https://explorer.solana.com/tx/4eTFg35LP21D3HCQYn2DE7WExrhNZsmyfh39i7GMYe9bxfsyEhdJJ2STDt2c6SmaeEGAB1whQbRtqbr71kRoMfDr?cluster=devnet) | note 1 | +| deposit | [`2BqmBu6anyCMhyvexeVsuH9zLB847bW1xBNndxeidCU7FYma3VyxcqTUEmRRVvJgH95MtTzsuEbwcRuxD4K25VQm`](https://explorer.solana.com/tx/2BqmBu6anyCMhyvexeVsuH9zLB847bW1xBNndxeidCU7FYma3VyxcqTUEmRRVvJgH95MtTzsuEbwcRuxD4K25VQm?cluster=devnet) | note 2 | +| deposit | [`7RwN4jc54ioVS7Y8m8p9PKGnU2vPrwPpK7jRZ4RvfmF4TWCniBxzNrxzbXpkFt3R6VWhfKnvP4d5sypGrCCXq2E`](https://explorer.solana.com/tx/7RwN4jc54ioVS7Y8m8p9PKGnU2vPrwPpK7jRZ4RvfmF4TWCniBxzNrxzbXpkFt3R6VWhfKnvP4d5sypGrCCXq2E?cluster=devnet) | note 3 | +| deposit | [`3drHxm9YgHi4VUy45HRVbmtZQe76oaPF7dxYWh6VAXKiJhUG7uBscPuDhmZVzRdnmFHtvg72PR9qwMU4RizpKPiE`](https://explorer.solana.com/tx/3drHxm9YgHi4VUy45HRVbmtZQe76oaPF7dxYWh6VAXKiJhUG7uBscPuDhmZVzRdnmFHtvg72PR9qwMU4RizpKPiE?cluster=devnet) | note 4 | +| deposit | [`2YB3RHGPCu3cY3tXjnRkFisd7q2JYZUnYB2z8hC11FHbX5YAsGjSiAs7BJbGTg4JHXE3FVwSVpz9t9NFevdQ5Gxh`](https://explorer.solana.com/tx/2YB3RHGPCu3cY3tXjnRkFisd7q2JYZUnYB2z8hC11FHbX5YAsGjSiAs7BJbGTg4JHXE3FVwSVpz9t9NFevdQ5Gxh?cluster=devnet) | note 5 | +| deposit | [`2UHgtUdLYJQmqBXcJWPJPK7VM6uBLKqaZdcMucXWoUUVpYV4Cnk8ox1jMUSZx9DJk6Xp6EKEQtxL9WLdWP4jT2ZL`](https://explorer.solana.com/tx/2UHgtUdLYJQmqBXcJWPJPK7VM6uBLKqaZdcMucXWoUUVpYV4Cnk8ox1jMUSZx9DJk6Xp6EKEQtxL9WLdWP4jT2ZL?cluster=devnet) | note 6 | +| create stake account | [`28djx5Y9hNmg58XbTzd4if4N6H2kZUwfREBKtdrCsFnV6Gu6bb6ptrGtMzL6VoZnVYSFKRXQTDNcKHdLUiQoGHwq`](https://explorer.solana.com/tx/28djx5Y9hNmg58XbTzd4if4N6H2kZUwfREBKtdrCsFnV6Gu6bb6ptrGtMzL6VoZnVYSFKRXQTDNcKHdLUiQoGHwq?cluster=devnet) | 1100000000 lamports, staker = the pool's vault | +| submit_spend | [`5D6VC6czzJ79fzuvvXuNHX5xcV5p7Gbv6hxDwHzgt5QtHHKScu11hYSBkdPPe7kQoUhhQEBoyiDPzjWGGVnroyFT`](https://explorer.solana.com/tx/5D6VC6czzJ79fzuvvXuNHX5xcV5p7Gbv6hxDwHzgt5QtHHKScu11hYSBkdPPe7kQoUhhQEBoyiDPzjWGGVnroyFT?cluster=devnet) | note 0, relay-signed, delegate to vgcDar2pryHvMgPkKaZfh8pQy4BJxv7SpwUG7zinWjG | +| create stake account | [`2Tv4CZSFD8wxpuhiihsw2xEd53bxTE7i6ka1dpZvzhcfDqXxdCL8k1jydgPCjJ7pUuL4CuPHP11BnJHPqjsawK6V`](https://explorer.solana.com/tx/2Tv4CZSFD8wxpuhiihsw2xEd53bxTE7i6ka1dpZvzhcfDqXxdCL8k1jydgPCjJ7pUuL4CuPHP11BnJHPqjsawK6V?cluster=devnet) | 1100000000 lamports, staker = the pool's vault | +| submit_spend | [`4gpxQ7UzGNKBwft1Y8dmDszs2jRz1S1Q2RZsFkLf4AjmyY1B3YNSyPoLPA5uqbRonWx2SkYZCYFtyS5AZN2EKsGK`](https://explorer.solana.com/tx/4gpxQ7UzGNKBwft1Y8dmDszs2jRz1S1Q2RZsFkLf4AjmyY1B3YNSyPoLPA5uqbRonWx2SkYZCYFtyS5AZN2EKsGK?cluster=devnet) | note 1, relay-signed, delegate to i7NyKBMJCA9bLM2nsGyAGCKHECuR2L5eh4GqFciuwNT | +| create stake account | [`3znGocR1LKMkffXQ1yHm9BKfhbM1o4Y6r22J3vyKjGLK76fAfArMxe7CeoP8sk4umStTt7f7EtSKbe29zaz4iges`](https://explorer.solana.com/tx/3znGocR1LKMkffXQ1yHm9BKfhbM1o4Y6r22J3vyKjGLK76fAfArMxe7CeoP8sk4umStTt7f7EtSKbe29zaz4iges?cluster=devnet) | 1100000000 lamports, staker = the pool's vault | +| submit_spend | [`2YBakbrJy1CXTaJpkxwAr54EW5PdWytG4P2ycJqFyRx48tdKKMqMuejEjS9JaMGmxGHKY9uiJ623tjb8ErDUFHS1`](https://explorer.solana.com/tx/2YBakbrJy1CXTaJpkxwAr54EW5PdWytG4P2ycJqFyRx48tdKKMqMuejEjS9JaMGmxGHKY9uiJ623tjb8ErDUFHS1?cluster=devnet) | note 2, relay-signed, delegate to 5ZWgXcyqrrNpQHCme5SdC5hCeYb2o3fEJhF7Gok3bTVN | +| create stake account | [`MhASpmqysCWXNrS5B36RVopqKnQKFcSRanQBd1nueD2bCck4SQBvJEqYy98ajhb9JC8UcvvncjRQcghnDyXYqzf`](https://explorer.solana.com/tx/MhASpmqysCWXNrS5B36RVopqKnQKFcSRanQBd1nueD2bCck4SQBvJEqYy98ajhb9JC8UcvvncjRQcghnDyXYqzf?cluster=devnet) | 1100000000 lamports, staker = the pool's vault | +| submit_spend | [`uEZXvq615hGxgeKKYmrpP4YPp5B3xygRUNAgZ4ddCH47q6NypgQqR49B8U1vMB9XVWnZQaPjqcqbV1JeQgAKFvN`](https://explorer.solana.com/tx/uEZXvq615hGxgeKKYmrpP4YPp5B3xygRUNAgZ4ddCH47q6NypgQqR49B8U1vMB9XVWnZQaPjqcqbV1JeQgAKFvN?cluster=devnet) | note 3, relay-signed, delegate to 23AoPQc3EPkfLWb14cKiWNahh1H9rtb3UBk8gWseohjF | +| create stake account | [`3JYyJ1ZnuGUdX888cV4zkqmhqTd42zE8QAbo3x8jJ6bfnC4MZT2RkiQkLHnqtjkNJmTQSAeQDLbEVwWRXaMmS5ES`](https://explorer.solana.com/tx/3JYyJ1ZnuGUdX888cV4zkqmhqTd42zE8QAbo3x8jJ6bfnC4MZT2RkiQkLHnqtjkNJmTQSAeQDLbEVwWRXaMmS5ES?cluster=devnet) | 1100000000 lamports, staker = the pool's vault | +| submit_spend | [`5KE1wc2VZh6GTLiiVNQ8Xad92hHoKNARZ8AEWQvwJeBsfLJ93Cc6GkvVtieTdwCh5ZjPcDTwk31Jjzwshtemr7XN`](https://explorer.solana.com/tx/5KE1wc2VZh6GTLiiVNQ8Xad92hHoKNARZ8AEWQvwJeBsfLJ93Cc6GkvVtieTdwCh5ZjPcDTwk31Jjzwshtemr7XN?cluster=devnet) | note 4, relay-signed, delegate to 7AETLyAGJWjp6AWzZqZcP362yv5LQ3nLEdwnXNjdNwwF | +| create stake account | [`2fRNA4wLYzoJceT2HmAXEPrvK1Sv1haqfRJK7vDDcyKCLQPa65ebcE9u6Lm8DZbdgfWm2LiaS5nDUzvxaCNrwecE`](https://explorer.solana.com/tx/2fRNA4wLYzoJceT2HmAXEPrvK1Sv1haqfRJK7vDDcyKCLQPa65ebcE9u6Lm8DZbdgfWm2LiaS5nDUzvxaCNrwecE?cluster=devnet) | 1100000000 lamports, staker = the pool's vault | +| submit_spend | [`4haLJna7fmp85ahKppvXR8bVgGSFmhsftxy1XEfuztZ8mKVKxdVzdwLVwS6CedD2fmzdMwPWc5Na2DAaNvUZdgQM`](https://explorer.solana.com/tx/4haLJna7fmp85ahKppvXR8bVgGSFmhsftxy1XEfuztZ8mKVKxdVzdwLVwS6CedD2fmzdMwPWc5Na2DAaNvUZdgQM?cluster=devnet) | note 5, relay-signed, delegate to 2u83Dx5qPV4QnujjJQv8v2SoqG1ixuAxPK5Jwhtkovd1 | +| settle_epoch | [`5SqtqpuJw3pAoBMMB9DmXaqFr93rWsnqWMyacRZ3ZpP5eQpacLTAjrYugAW2ni3PMucAzDLJ4TsLZU3aQd3ZVMPZ`](https://explorer.solana.com/tx/5SqtqpuJw3pAoBMMB9DmXaqFr93rWsnqWMyacRZ3ZpP5eQpacLTAjrYugAW2ni3PMucAzDLJ4TsLZU3aQd3ZVMPZ?cluster=devnet) | 6 delegations to 6 different validators, one transaction, 1194 bytes | + +## Reproducing this document + +Every value above was written by the run that produced it, and the run recorded them in `data/crowd-result-43000007.json`. `mirror crowd --render-only` rebuilds this file from that record without touching a cluster, so the prose around a number can be improved without re-running a measurement — and a number cannot be changed without re-running one. + +Every address and signature here is on devnet and can be checked against the cluster rather than against this file. + +## What this run's own anonymity was, by our own metric + +It would be easy to publish this section's numbers and let a reader take them for a privacy result. They are not one, and the honest way to show that is to run the measurement this repository is built around against *this run* rather than only against somebody else's pool. + +| quantity | this run | +|---|---| +| nominal k | 6 | +| provenance classes | 1 | +| ρ, the loss factor | 1.0000 | +| effective k (Shannon) | 6.00 | +| effective k (min-entropy) | 6.00 | + +**ρ = 1.0000 is the best value the metric can return, and it is meaningless here.** Every note in this pool was deposited by the same wallet, so the partition has one class holding all 6 members; an adversary who learns a member's funding class learns nothing, and the metric correctly reports no loss *through that channel*. What it cannot report is that the single class is the operator, who funded every deposit and every relay and therefore knows which member is which. Against that adversary the anonymity set is **one**, and no funding-provenance number will ever say so, because provenance is not the channel that failed. + +This is the shape of the tautology `PROVENANCE_METHOD.md` §9.0 warns about, met head-on: a metric applied to a population constructed by the person reading it returns whatever that construction implies. The published headline in `README.md` avoids it by pointing at a pool this project does not control and did not fund — which is the only reason that number means anything and this one does not. + +## Scope + +Devnet, and one operator. This is a functional and quantitative result, not an anonymity claim about a live crowd: the relays here were funded from the same wallet that made the deposits, which is exactly the linkage `USAGE.md` tells a real member to avoid. What the run establishes is that a batch of *divergent* actions settles as one, that every member reached the validator they chose, and what such a batch costs in packet space. + +The withdraw authority on every stake account above is the operator, never the pool. The pool's signature is available to every member, so an authority the vault holds is an authority every member holds: delegation is safe on those terms — the worst a member can do is re-delegate somebody else's stake — and withdrawal is not. That is `THREAT_MODEL.md` applied rather than repeated. diff --git a/docs/GROTH16_INTEGRATION.md b/docs/GROTH16_INTEGRATION.md new file mode 100644 index 00000000..ec382cf3 --- /dev/null +++ b/docs/GROTH16_INTEGRATION.md @@ -0,0 +1,117 @@ +# arkworks 0.5 → `groth16-solana` 0.2: integration reference + +Every claim here was verified by execution against the pinned versions, not taken +from documentation. The published `groth16-solana` docs are stale (they show an +API removed in 0.0.3 and arkworks 0.3 traits that no longer exist), so this file +is the authority for our conversion code. + +Pinned: `ark-groth16 0.5`, `ark-bn254 0.5`, `groth16-solana 0.2`, +`solana-program 4.0`, `solana-bn254 2.2.2`. + +## Byte layouts + +| Item | Layout | Size | +|---|---|---| +| G1 | `x_be ‖ y_be` | 64 | +| G2 | `x.c1_be ‖ x.c0_be ‖ y.c1_be ‖ y.c0_be` | 128 | +| Public input | canonical `Fr`, big-endian | 32 | +| Point at infinity | all zero bytes | 64 / 128 | + +The G2 **cross order** is the single easiest thing to get wrong. `solana-bn254`'s +`PodG2::from_be_bytes` reads `c1` before `c0` (its own source comments it "note +the cross order"). arkworks serializes `Fq2` as `c0_le ‖ c1_le`, so reversing the +whole 64-byte block flips limb endianness *and* swaps the components in one step. +G1 therefore reverses 32-byte chunks; G2 reverses **64-byte** chunks. + +## `proof_a` must be pre-negated + +`Groth16Verifier::new` performs length checks only — no arithmetic — and +`verify_common` feeds `proof_a` directly into the four-pair product +`e(A,B)·e(Σic,γ)·e(C,δ)·e(α,β) == 1`, which holds only when `A = −A_proof`. +Serialize `-proof.a`. Nothing negates it for you; the crate's own negative test +passes a non-negated `proof_a` specifically to assert failure. + +## Verifying key + +```rust +pub struct Groth16Verifyingkey<'a> { + pub nr_pubinputs: usize, + pub vk_alpha_g1: [u8; 64], + pub vk_beta_g2: [u8; 128], + pub vk_gamme_g2: [u8; 128], // the typo is the real field name + pub vk_delta_g2: [u8; 128], + pub vk_ic: &'a [[u8; 64]], +} +``` + +`vk_ic.len() == n + 1` for `n` public inputs; `vk_ic[0]` is the constant term and +`vk_ic[i+1]` multiplies input `i`, in the order inputs were allocated in the +circuit. `nr_pubinputs` is **never read** by any verification path, and the +upstream JS generator sets it to `n + 1` rather than `n` — do not rely on it. The +const generic `NR_INPUTS` on `Groth16Verifier` is the real input count, and +`public_inputs` is `&[[u8; 32]; NR_INPUTS]`, a fixed-size array reference rather +than a slice. + +`verify()` returns `Result<(), Groth16Error>`; there is no `Ok(false)`. + +## Compute units + +Measured in LiteSVM against a real SBF build, with a scratch circuit per input +count that is not part of this repository. The figure this repository does +reproduce is the whole `submit_spend` instruction at three inputs — about +101,000 CU, printed by `cargo test -p mirror-pool-program --test end_to_end -- +--nocapture`. + +The instruction's cost is not identical run to run. Each run derives the spend +record's address from a freshly generated nullifier, and `find_program_address` +searches a different number of bumps to get there, which moves the total by a +few thousand CU. So the test asserts a bound — under 110,000 CU, against the +200,000 a single instruction gets by default — rather than pinning a figure that +would fail on nothing. + +| Public inputs | `verify()` | +|---|---| +| 1 | 79,840 | +| 2 | 85,500 | +| 4 | 96,822 | +| 8 | 119,466 | + +`verify() ≈ 74,179 + 5,661·N`. The pairing itself is a fixed 73,612 CU; each +additional public input costs one G1 multiplication (3,840), one addition (334), +allocation overhead (~510) and a canonical-range check (~977). + +**Design consequence:** public inputs are the only knob. Every input we can fold +into a hash saves ~5.7k CU, so the circuit binds a single digest wherever several +values would otherwise be exposed separately. + +`verify_unchecked` saves ~977 CU per input by skipping the `< r` range check. It +is safe only for inputs we constructed ourselves from `Fr`; never for +attacker-supplied bytes. We use the checked form on anything that crosses the +instruction boundary. + +## Pitfalls + +1. **Serialize coordinates, not the point.** arkworks packs a y-sign flag into + the top bit of y's most significant byte even under `Compress::No` — it fires + on roughly half of all points. Verification still succeeds (deserialization + masks flags), but the bytes are non-canonical, which silently breaks anything + that hashes or compares serialized proofs and keys. Write `p.x` and `p.y` + separately. +2. **Infinity encodes as all zeros** in the syscall ABI, but arkworks writes flag + `0x40`. An explicit infinity branch is required. Honest keys never contain + infinity; adversarial input can. +3. **Uncompressed sizes are 64 and 128**, not 65/129. A trailing byte appears in + some upstream examples as arkworks-0.3 residue; it is vestigial. +4. **Compressed input is not accepted.** Decompression costs 398 CU for G1 but + **13,610** for G2, so compressing to save transaction bytes is rarely worth it. +5. **`ark-bn254` needs `features = ["curve"]`** when `default-features = false`; + `scalar_field` alone gives `Fr` but not the curve groups. +6. **Duplicate arkworks in the lockfile is expected.** `groth16-solana` pulls + `solana-bn254`, which pins arkworks 0.4 — but only under + `cfg(not(target_os = "solana"))`, so it is host-only and never linked into the + `.so`. Types from different arkworks majors never unify; keep ours on 0.5. +7. **Subgroup and curve checks happen inside the syscall**, not in `new()`. They + cannot be skipped and need not be duplicated. +8. **`cargo-build-sbf` resolves dependencies with the host cargo.** A host + toolchain older than 1.85 fails on transitive `edition2024` crates. Our + `rust-toolchain.toml` pins 1.97.1, which covers this. diff --git a/docs/INCENTIVES.md b/docs/INCENTIVES.md new file mode 100644 index 00000000..5a4cdcc8 --- /dev/null +++ b/docs/INCENTIVES.md @@ -0,0 +1,150 @@ +# Incentives + +A pool that nobody stays in has an anonymity set of one, so the question of what +keeps members in it is a design question and not a marketing one. This document +answers it in three parts: what the protocol actually does to align a member's +interest with everyone else's, what it deliberately does *not* pay for, and what +the missing piece would have to look like to be worth shipping. + +The short version: **the incentives here are structural, not monetary.** Nothing +in this protocol pays you. Several things in it make the cooperative move the +only one available, or the cheapest one, and those are enforced by the program +rather than recommended by a README. + +## The four that are enforced + +Each of these is a rule in the on-chain program, not a convention. The citation +is where to check it. + +### You cannot act until a crowd exists + +`processor.rs:342` refuses `submit_spend` when the pool holds fewer notes than +its `k_floor`: + +```rust +if deposit_count < k_floor as u64 { + return Err(MirrorProgramError::BelowAnonymityFloor.into()); +} +``` + +This is the load-bearing one. In a pool with no floor, the first member to act +acts alone, gets nothing from the pool, and learns that arriving early is +punished — so nobody arrives early and the pool never starts. The floor inverts +that: your deposit is what lets *other* people act, and theirs is what lets you. +Waiting is not patience, it is the protocol. + +What it bounds is program-visible membership — how many notes the tree holds. It +is not the effective anonymity set, which is smaller, and `THREAT_MODEL.md` says +so at length rather than letting the floor stand in for a guarantee. + +### Waiting is never a hostage situation + +A floor with no escape is coercion, not an incentive: it would mean a quiet pool +holds your escrow indefinitely and no authority can release it. So +`SETTLE_TIMEOUT_SECONDS` (`processor.rs:510`) is one hour, after which a batch +settles whether or not it reached the floor. + +The two rules only work together. The floor is what makes waiting valuable; the +timeout is what makes waiting safe. Removing either one turns the other into a +reason to leave. + +The timeout has a cost and `THREAT_MODEL.md` argues it rather than hiding it: a +batch that settles on the clock has no floor, so a batch of one is reachable by +anyone willing to wait an hour. `mirror settle` warns when it is about to publish +one. + +### Somebody else is paid to sign for you + +A member who signs their own spend publishes the link the pool exists to break. +So spends are relay-signed, and the relay is paid out of the denomination — the +member receives `denomination - relay_fee`. + +That fee is the only value transfer in the protocol, and it exists to make the +anonymity-preserving path economically available rather than merely permitted. +Relaying is permissionless: no allowlist, no registration, no authority whose +absence freezes the pool. + +This is also why the relay is inside the action binding. A fee that can be +sniped by whoever lands the transaction first is a fee no relay can count on, and +a pool with no relays is a pool where members submit from their own wallets and +deanonymise themselves. `THREAT_MODEL.md` has that attack in full. **Protecting +the incentive layer is the same work as protecting the privacy layer** — that is +not an analogy, it is the same code. + +### Paying what everybody else pays is enforced, not advised + +A member is paid `denomination - relay_fee`, and that figure lands in a public +account balance. A batch mixing fees therefore pays visibly different amounts and +an observer partitions it by value without breaking a proof. + +`processor.rs:634` refuses such a batch outright with `FeeNotUniform`, and +`mirror settle` groups pending spends by fee and settles the largest group rather +than assembling a transaction the program will reject. + +So the incentive to converge on a common fee is not a suggestion in a usage +guide. Deviating does not get you a worse anonymity set; it gets your batch +refused until you settle with members who paid what you did. + +## The one that is not there + +**Nothing pays a member for dwell** — for leaving a note unspent longer than they +needed to, which is the behaviour that makes everyone else's set larger. + +`PLAN.md` designed exactly that: entry fees accumulating in a reward pool, paid +pro-rata to dwell, capped per epoch and gated on the floor. None of it shipped, +and `Pool::initialise` now refuses a nonzero entry fee outright +(`state.rs:208`), so the fee that would have funded it cannot even be collected. + +The reason the fee went too is worth stating, because it is the smaller mistake +that would have looked like the safer one. A fee with no payout path is not a +half-built feature, it is a fund trap: lamports every depositor pays, that no +instruction can return, and that no authority exists to release — because this +program deliberately has no such authority. Shipping the fee and documenting the +gap would have left the trap armed behind a paragraph. + +## Why the obvious fix is the wrong one + +A reward has to be paid to somebody. Paying somebody on Solana means naming an +address in a transaction. And the entire claim of this protocol is that **no +member key appears on chain at any point after the deposit** — spends are +relay-signed, settlements are settler-signed, and actions execute from the pool's +vault. + +So a dwell reward paid to a member's address does not cost a little anonymity. It +costs all of it, for that member, permanently, and it does so at exactly the +moment they are being rewarded for having protected everyone else's. The +mechanism would pay people to destroy the thing it exists to reward. + +This is not hypothetical, and it is the shape the problem takes wherever it is +attempted: a reward path that pays an identity only functions on a path that +*has* identities — which is the path without anonymity. An anonymous path and a +per-identity reward counter are mutually exclusive by construction, not by +oversight. + +## What would actually work, specified + +The anonymity-preserving version is a second nullifier, and it is a real design +rather than a hand-wave: + +- A note commits to a second secret alongside its spend secret, so a member holds + two independent nullifiers for one note. +- `claim_reward` takes a Groth16 proof of the same membership statement the spend + path uses, over the *reward* nullifier, and pays a fresh address the prover + names in the action binding. +- The claim is gated on the same `k_floor`, for the same reason: a reward + claimable by a crowd of one is a refund with extra steps, and it would let a + lone participant recycle their own fee back to themselves. +- Dwell is measured from the note's leaf index and the claim's slot, both already + on chain, so no per-identity counter is stored and none can be read. + +That is a second value-bearing instruction, a second nullifier domain, a changed +note format, and a changed circuit — and every one of those is a place where the +audit trail in this repository found somebody else's bug. This repository's +standard for a value-bearing path is that it is exercised against a real SVM with +negative cases carrying the program's own error codes, and against a live cluster +with the signatures published. That standard is the reason to defer this rather +than the obstacle to it. + +**So it is scoped, not vague, and absent rather than half-present.** The pool +ships with the incentives it can enforce, and without the one it cannot yet pay +safely. diff --git a/docs/INTEGRATING.md b/docs/INTEGRATING.md new file mode 100644 index 00000000..f356e9eb --- /dev/null +++ b/docs/INTEGRATING.md @@ -0,0 +1,127 @@ +# Integrating a protocol + +Nothing in the on-chain program knows what a stake delegation is. It knows how to +verify a proof, how to burn a nullifier, and how to invoke an instruction it was +handed. Adding a protocol is therefore a client-side exercise: **no program +change, no redeploy, no new circuit, and no governance.** + +This document is the whole procedure, with a worked example that runs on devnet. + +## The three shapes an action can take + +A spend carries a selector, and there are only three. + +| selector | what the pool does | what it is for | +|---|---|---| +| `0` transfer | pays the beneficiary from the vault | moving lamports; the degenerate case | +| `1` invoke | calls your program, funded by the vault | anything where the pool is the *payer* | +| `2` invoke-signed | calls your program with the vault as a **signer** | anything where the pool must be the *authority* | + +The distinction between 1 and 2 is the one that matters, and it is not a +convenience. A stake delegation requires the staker authority's signature; a +governance vote requires the voter's. No member can supply that signature without +appearing on chain and undoing the point of being in the pool — so the pool +supplies it, from seeds only the program holds. + +## The procedure + +**1. Work out the instruction you want the pool to issue.** Its program id, its +instruction data, and how many accounts it takes. This is ordinary Solana work and +this repository has no opinion about it. + +**2. Decide whether the pool must sign.** If the callee requires an authority +signature, you need `--pool-signs`. If it only needs lamports, you do not — and +you should not ask for it, because the pool's signature is available to every +member and `docs/THREAT_MODEL.md` is explicit that an authority the vault holds is +an authority every member holds. + +**3. Spend, naming the call instead of a payee.** + +``` +mirror spend --program $P --note m1.json \ + --to \ + --relay relay.json --relay-fee 100000 \ + --invoke \ + --payload \ + --accounts \ + [--pool-signs] +``` + +**4. Settle.** Whoever settles supplies the accounts that fill the declared slots. + +That is all of it. The proof is generated locally, the relay signs, and the +action executes from the vault beside everyone else's at one timestamp. + +## A worked example: delegating stake + +This is the example the repository actually runs, and +[`docs/PROOF.md`](PROOF.md) has it on devnet. + +`StakeInstruction::DelegateStake` is a bare `u32` discriminant of `2` — four +bytes, `02000000` — and it takes six accounts: the stake account, the vote +account, the clock and stake-history sysvars, the stake config, and the staker +authority. The authority is the last of the six, and it must sign. + +``` +mirror spend --program $P --note m1.json \ + --to \ + --relay relay.json --relay-fee 200000 \ + --invoke Stake11111111111111111111111111111111111111 \ + --payload 02000000 \ + --accounts 6 \ + --pool-signs +``` + +The stake account's **staker** is the pool's vault, which is what makes the +delegation possible. Its **withdrawer** is deliberately not the pool, for the +reason in the threat model: delegation is safe to hand every member, because the +worst a member can do is re-delegate. Withdrawal is not. + +The same shape covers a governance vote, a liquid-staking deposit, or any +`CpiContext`-style call a program exposes — change the program id, the payload +and the account count. + +## What the proof promises, and what it does not + +**It binds the selector, the target program, the payload, the beneficiary, the +relay, the relay fee, and the number of accounts.** A relay handed your proof +cannot change the program being called, the data being sent, how many accounts it +takes, or who is paid. Any of those alterations produces a different action +binding and the pairing fails. + +**It does not bind *which* accounts fill the declared slots.** Settlement is +permissionless, so whoever settles chooses them. For a target that takes its +destination in instruction data this costs nothing, because the payload is bound. +For a target that takes it in an account slot — `DelegateStake` names the +validator in slot 1, not in its four bytes — the settler chooses, and a member +cannot prove in advance which validator they will get. + +This is a real limit and it is not papered over. What the repository does about +it is check rather than assert: [`docs/CROWD.md`](CROWD.md) settles six members +delegating to six *different* validators and then reads every stake account back +off the cluster to confirm each member got what the plan said. The read-back is +what turns the limit into a checked claim instead of a hope. + +If your integration needs that promise cryptographically rather than by +after-the-fact check, the account list has to enter the action binding — which is +a circuit change and is not what this version does. + +## Two constraints worth knowing before you design + +**Account count is the currency.** Every account your action names costs the batch +space, and space is what the anonymity set is made of. A settlement holds 64 +account locks; three go to the pool, three per member to their record, beneficiary +and relay, and the rest to whatever your action declares. An action naming six +accounts fits fewer members per batch than one naming zero — which is why +[`docs/CROWD.md`](CROWD.md) measures the ceiling per action shape rather than +quoting one number. + +**Compute is not free either.** A cross-program invocation costs roughly an order +of magnitude more per member than a plain payment. A batch of delegations large +enough to be worth a lookup table needs a `SetComputeUnitLimit` instruction, and +that instruction brings its own program — which is another account, which is +another lock. The escape from one limit is paid out of the other. + +Neither is a reason not to integrate. They are the reason to measure your shape +before promising a crowd size for it, and `mirror crowd` is the tool that does +that measuring. diff --git a/docs/MEASUREMENT_LOG.md b/docs/MEASUREMENT_LOG.md new file mode 100644 index 00000000..8c6ca7a0 --- /dev/null +++ b/docs/MEASUREMENT_LOG.md @@ -0,0 +1,643 @@ +# Measurement log + +Every collection run, including the ones that produced nothing. A measurement +project that only records its successful runs is not reporting, it is selecting. + +## The artifacts, so every run below is checkable offline + +| run | sample | frame | +|---|---|---| +| 1 | `data/sample-smoke.json` | `data/seeds-smoke.txt` | +| 2 | *not committed* — above the RPC-failure limit | `data/seeds-privacycash.txt` | +| 3 | `data/sample-privacycash.json` | `data/seeds-privacycash.txt` | +| 4 | `data/sample-privacycash-run4.json` | `data/seeds-privacycash.txt` | +| **6** | **`data/sample-privacycash-run6.json`** — the headline | `data/seeds-privacycash.txt` | +| 5 | `data/sample-marinade.json` | `data/seeds-marinade.txt` | +| 7 | `data/sample-marinade-run7.json` | `data/seeds-marinade.txt` | +| 8 | `data/sample-marinade-run8.json` | `data/seeds-marinade.txt` | + +``` +mirror analyze --sample data/sample-privacycash-run6.json +mirror compare --sample data/sample-privacycash-run6.json --against data/sample-marinade-run8.json +mirror selection --earlier data/sample-privacycash.json --later data/sample-privacycash-run6.json +mirror selection --earlier data/sample-marinade.json --later data/sample-marinade-run7.json +``` + +The two `selection` runs are the two rows of the table in `README.md`, and only +the first is a budget margin — the marinade pair used identical parameters and +differs by the tracer fix. The manifests carry the parameters, so which is which +is checkable here rather than asserted. + +All of them are pure and offline. Nothing below needs our endpoint, our key, or +our word for how a run behaved. + +--- + +## Run 1 — 2026-07-25, pipeline validation, no publishable result + +**Purpose.** End-to-end validation of collect → analyze against live mainnet. + +**Frame.** 12 addresses credited at least 0.001 SOL in a recent finalised block, +filtered to accounts owned by the system program and currently existing. + +**Endpoint.** `api.mainnet-beta.solana.com`, first available block 0, archival +probe at slot 50,000,000 passed. 263 RPC calls, 0 failures. + +**Result.** + +``` +attempted 12 | resolved 0 | evidence-unresolved 0 | budget-unresolved 12 + | scope-unresolved 0 | rpc failures 0 (0.00%) +``` + +No headline. The tool reported nothing rather than reporting something. + +### What went wrong, and it was the frame + +Eleven of twelve seeds hit the signature page cap at 20,000 lifetime +transactions. They are system-owned wallets, so they passed the frame filter, but +they are not people: at that volume they are market makers, arbitrage bots and +exchange hot wallets. + +The cause is the sampling design, not the collector. **Sampling addresses because +they appear credited in a block is transaction-weighted, not member-weighted.** +An address that transacts a thousand times a day is a thousand times more likely +to appear in any given block than one that transacts daily, so the frame is +size-biased toward exactly the addresses whose funding history is most expensive +to walk. It is the same error as estimating how often people travel by asking +people at a bus stop. + +For measuring a pool, the frame is the pool's depositors, each counted once — +which is member-weighted by construction. + +### What this run does establish + +- The endpoint precondition, the collector, the two-pass split and the metric + ladder all work against live mainnet. +- Page-capped addresses are reported as **budget-unresolved**, kept distinct from + evidence-unresolved and from RPC failure. The distinction is what makes this + run diagnosable instead of a number. +- The tool refused to print a headline from a run where nothing resolved. + +### A defect this run caught + +An earlier attempt returned 14 RPC calls for 12 seeds and reported everything +unresolved. Frame validation fetches each seed's owner before tracing, and the +collector's observation cache treated "we know the owner" as "we have observed +this address", so it skipped signature paging entirely and never looked for a +birth edge. + +The bug was visible only because the call count was reported and the census was +honest. A collector that defaulted a failed or skipped lookup to "no history" — +as a published tracer in this space does — would have produced a full set of +unresolved members and a plausible-looking headline, with nothing to indicate +anything was wrong. + +--- + +## Run 2 — 2026-07-25, member-weighted frame, refused on failure rate + +**Frame.** 100 depositors of Privacy Cash (`9fhQBbumKEFuXtMBDw8AaQyAjCorLGJQiS3skWZdQyQD`), +enumerated by `mirror seeds` from the program's own deposit transactions and +strided across signature pages so the sample spans the pool's history rather than +its most recent minute. 13 excluded as non-wallets before tracing; 87 attempted. + +**Endpoint.** Alchemy, archival probes passed. Depth 8, page cap 60. 4,852 calls. + +``` +attempted 87 | resolved 47 | evidence-unresolved 8 | budget-unresolved 19 + | scope-unresolved 0 | rpc failures 13 (14.94%) +``` + +**No headline.** The failure rate is 14.94%, so `analyze` refused. This was the +frame working and the endpoint not: 47 of 87 members reached a class, against +zero under Run 1's transaction-weighted frame. + +**What the failures actually were.** The collector reported every failure as +`RpcFailure` with no cause, which made the census honest and the run +undiagnosable. Instrumenting it showed HTTP 429 arriving at **0.7 requests per +second** — far below any documented rate limit. Providers meter by compute units, +not request count, and a 1,000-signature page is expensive in those terms. So the +cause was not the request rate, and lowering it would not have helped; the cause +was a page cap of 60, set on the mistaken belief that paging deeper would resolve +more chains. + +It would not have. The volume-hub rule needs enough history to clear its +threshold and estimate an age — about eight pages. The other fifty-two were +waste that bought nothing and spent the budget that made the endpoint refuse. + +## Run 3 — 2026-07-25, clean census, honest bracket + +**Frame.** The same 100 depositors. 16 excluded as non-wallets; 84 attempted. + +**Endpoint.** Alchemy, archival probes passed. Depth 8, **page cap 8**. 1,029 +calls — a fifth of Run 2 — at 1.5 requests per second. + +``` +attempted 84 | resolved 40 | evidence-unresolved 5 | budget-unresolved 39 + | scope-unresolved 0 | rpc failures 0 (0.00%) +``` + +**Zero infrastructure failures.** Nothing in the unresolved bucket is ours. + +| quantity | value | +|---|---| +| resolved members | 40 | +| provenance classes | 17 | +| **loss factor ρ (point)** | **0.1219** | +| **ρ (unresolved bracket)** | **0.0253 … 0.1837** | +| effective-k, Shannon | 4.88 | +| effective-k, min-entropy | 2.35 | +| Shannon leakage | 3.04 bits | +| Good–Turing coverage | 0.65 | +| Chao1 richness | 108 classes, against 17 observed | + +**The tool declines to call this a result, and it is right.** Two gates fire: + +*Not informative.* 40 of 84 members reached a class — just under half. The +bracket's two readings, unresolved merged into one class versus split into +singletons, differ by more than sevenfold. Quoting either alone would describe +the sampling budget rather than the pool. + +*Under-sampled.* Chao1 estimates 108 provenance classes against 17 observed, and +Good–Turing coverage is 0.65. Most of the class distribution was never seen, and +effective-k measured at small k understates the steady-state loss and does not +extrapolate upward. + +**What this run does establish.** The pipeline works end to end against live +mainnet with a clean census; the member-weighted frame resolves a near-majority +where the transaction-weighted one resolved nothing; and the honesty machinery is +load-bearing rather than decorative. Three consecutive runs produced no headline +and each for its own reason: Run 1 resolved nothing at all, with zero RPC +failures, so there was no figure to refuse; Run 2 was refused by the failure gate +at 14.94%; and Run 3 was refused by the informativeness gate, 40 resolved against +a threshold of 42. Six of the eight runs in this document end without a published +figure, and the two that do not are Runs 4 and 6. + +**What a publishable ρ would need.** More resolution, not more members: 39 of the +44 unresolved are budget outcomes, chains that ran out of depth or paging before +reaching a class. That is a bigger call budget spent on depth rather than on +sample size, which is a straightforward thing to buy and not something this +run claims to have bought. + +## Run 4 — pre-registered before collection, 2026-07-25 + +This section was written and committed **before the run started**, so the budget +below is a declaration and not a description. Run 3 missed the informativeness +gate by two members — 40 resolved against a threshold of 42 — and a gate that +close is exactly where the temptation to tune until it opens is strongest. +Declaring the budget in advance and publishing whatever comes out is what makes +this a fourth measurement rather than a search for a fourth answer. + +**Frame.** Unchanged: the same 100 Privacy Cash depositors as Runs 2 and 3, from +`data/seeds-privacycash.txt`. Not re-drawn, not extended. Changing the frame and +the budget together would make the two effects impossible to separate. + +**What changes, and only this.** Run 3 left 39 members in the budget bucket — +chains that ran out of depth or pages before reaching a class. That is the one +bucket a bigger budget can move. So: + +| parameter | Run 3 | Run 4 | +|---|---|---| +| depth | 8 | 16 | +| signature page cap | 8 | 24 | +| endpoint | Alchemy | Helius | +| request rate | 1.5/s | 5/s | + +**Prediction, recorded in advance.** The budget bucket shrinks and resolution +clears the 42-member gate. The under-sampling flag most likely still fires: +Good–Turing coverage was 0.65 and Chao1 estimated 108 classes against 17 +observed, and resolving more members raises coverage slowly. A publishable ρ +carrying an explicit sampling caveat is the expected outcome, not a clean one. + +**Stopping rule.** This is the last run against this frame. Whatever it returns +is what this document reports — including a refusal, and including a ρ that sits +worse for the argument than Run 3's. If it fails on the RPC gate, that is +recorded as a failed run and not retried into success. + +### Result + +Helius, archival probes passed. 1,613 calls at 3.5 requests per second, 456 +seconds wall clock. + +``` +attempted 84 | resolved 50 | evidence-unresolved 6 | budget-unresolved 28 + | scope-unresolved 0 | rpc failures 0 (0.00%) +``` + +| quantity | Run 3 | Run 4 | +|---|---|---| +| resolved members | 40 | **50** | +| budget-unresolved | 39 | **28** | +| rpc failures | 0 | 0 | +| provenance classes observed | 17 | 22 | +| **loss factor ρ (point)** | 0.1219 | **0.1032** | +| **ρ (unresolved bracket)** | 0.0253 … 0.1837 | **0.0316 … 0.1318** | +| bracket width (ratio) | 7.3× | **4.2×** | +| effective-k, Shannon | 4.88 | 5.16 | +| Good–Turing coverage | 0.65 | **0.62** | +| Chao1 richness | 108 | **193** | + +**The informativeness gate clears.** 50 of 84 resolved, against a threshold of +42. The bracket narrows from a 7.3-fold span to a 4.2-fold one, and both +readings now sit on the same side of 0.15. This is the first run in this +document that produces a headline. + +**The under-sampling flag still fires, and it got worse.** This is the part +worth reading twice. Resolving ten more members did not improve coverage — it +*degraded* it, from 0.65 to 0.62, and pushed the Chao1 richness estimate from +108 classes up to 193. + +That is not a defect and not noise. The additional members did not land in the +classes already observed; they landed in new ones, mostly alone. Under +Good–Turing, coverage falls when the share of singletons rises, so a sample that +keeps discovering fresh singleton classes reports *less* confidence as it grows. + +The consequence matters for the conclusion. Under-sampling here is **a property +of the provenance distribution, not an artifact of our budget.** Run 3 left it +open whether more resolution would close the tail; Run 4 answers that, and the +answer is no. Spending more calls would raise the resolved count and lower the +coverage further. There is no budget at which this frame's class distribution +becomes well-observed, because the tail is where the mass is. + +So the honest statement of what was measured is: **ρ ≈ 0.10 on this pool, inside +0.032 … 0.132, from a sample whose class distribution is demonstrably +heavy-tailed and two-thirds unobserved — and the second fact is now a finding +rather than a caveat.** + +**Stopping rule honoured.** No further run against this frame. The Run 3 +artifact stays committed beside the Run 4 one; both are in `data/`, and the +numbers above are recomputable from either without RPC access. + +## Run 5 — pre-registered before collection, 2026-07-26 + +Committed before the collection started, like Run 4. + +**Why a second population, and why this one.** Run 4 produced ρ = 0.1032 for a +privacy pool's depositors. On its own that number has no scale: a reader cannot +tell whether 0.10 is concentrated or ordinary, because there is nothing to +compare it against. ρ was chosen as the headline precisely because it is +independent of `k` and therefore comparable across populations — and so far that +property has been asserted and never exercised. + +The comparison that gives the number a scale is not a second privacy pool. It is +a population that **is not seeking privacy at all**, measured by the identical +pipeline. If ordinary users show the same provenance concentration, then 0.10 +describes Solana rather than the pool. If the privacy pool is more concentrated, +that is a finding about who privacy tools attract. Either answer is worth more +than a second point on the same curve. + +**Frame.** Depositors of Marinade liquid staking, +`MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD`, enumerated by `mirror seeds` from +the program's own transactions, member-weighted and strided across signature +pages exactly as the Privacy Cash frame was. Target 100 depositors. + +This is a **control, not a privacy pool**, and it is labelled as one everywhere. +Staking SOL is an ordinary, publicly-attributable act; nobody does it for +deniability. + +**What a feasibility probe already established, and what it did not.** A probe of +178 transactions returned 5 distinct depositors — a yield near 3%, against about +12% for the privacy pool, because most Marinade program traffic is unstaking and +bot activity rather than deposits. So the frame is constructible but costs +roughly four times as many fetches per member. That is a fact about the budget. +The probe was not run through `analyze` and nothing about the outcome is known +at the time of writing. + +**Prediction, recorded in advance.** Genuinely uncertain, which is the reason to +write it down. The expectation is that the control is **less** concentrated — +lower ρ — because a privacy pool is plausibly reached through a narrower set of +funding routes. A control that came back at or above 0.10 would say the +concentration is a property of Solana's funding graph rather than of the pool, +and that would be the more interesting result of the two. + +The under-sampling flag is expected to fire again. Nothing about the tail found +in Run 4 suggests a different population would have a lighter one. + +**Stopping rule.** One run at this frame size. Whatever it returns is reported, +including a result that undercuts the argument for measuring privacy pools at +all, and including a refusal. + +## Runs 6 and 7 — pre-registered re-collections, forced by a bug in our own tracer + +Committed before either collection started. + +**Why these exist.** Run 5's control produced an unresolved bucket six times +larger than the privacy pool's, in the *evidence* category. Checking two of those +seeds by hand found the cause, and it was ours: the tracer implemented "the +oldest transaction, if it is a credit" while the documented rule — in the README, +in the method, and in the module's own comment — is **the oldest credit**. An +address whose first transaction merely references it, which is common, was +reported as having no funding at all. + +That is an infrastructure limit reported as evidence about the chain, which §6 of +the method forbids in as many words. It is fixed, with the exhausted case given +its own outcome so it counts as budget and never as evidence. + +**Every `ρ` published before this point was computed with the broken tracer**, +including the Run 4 headline. So both populations are collected again. + +| | frame | parameters | +|---|---|---| +| **Run 6** | the same 100 Privacy Cash depositors as Runs 2–4 | depth 16, page cap 24, birth scan 24 | +| **Run 7** | the same 100 Marinade depositors as Run 5 | depth 16, page cap 24, birth scan 24 | + +Identical parameters to Run 4 and Run 5 respectively, save the birth scan the fix +introduces. Same frames, not re-drawn. + +**Prediction, recorded in advance.** Resolution rises in both, and by more in the +control, because that is where the misdiagnosed bucket was concentrated. The +direction of the *comparison* is genuinely unknown, and that is the point of +running both: the bug suppressed resolution in whichever population had more +addresses whose first transaction was not their funding, and there is no reason +to assume that is the one that flatters us. + +`ρ` itself may move in either direction. Members who were previously dropped will +land in classes, and whether they land in the crowded ones or in new singletons +decides the sign. + +**Stopping rule.** One collection per frame at these parameters. Both are +reported whatever they say — including a corrected headline worse than the one +already published, and including the comparison failing to separate. + +**What is not being re-run.** Runs 1 and 2, which produced no headline: one on a +size-biased frame, one above the RPC-failure limit. Neither's conclusion depends +on the birth-edge rule, and both remain in this document as they were. + +### Run 6 — the privacy pool, re-collected + +Helius, archival probes passed. 1,776 calls, 364 seconds. + +``` +attempted 83 | resolved 54 | evidence-unresolved 0 | budget-unresolved 29 + | scope-unresolved 0 | rpc failures 0 (0.00%) +``` + +| quantity | Run 4 (broken) | Run 6 (fixed) | +|---|---|---| +| resolved | 50 | **54** | +| **evidence-unresolved** | 6 | **0** | +| budget-unresolved | 28 | 29 | +| **ρ (point)** | 0.1032 | **0.0955** | +| ρ (unresolved bracket) | 0.0316 … 0.1318 | **0.0350 … 0.1136** | +| bracket width | 4.2× | **3.2×** | +| ρ (95% sampling interval) | — | 0.0848 … 0.1790 | +| classes observed | 22 | 23 | +| Good–Turing coverage | 0.62 | 0.65 | + +**The evidence bucket went to zero, and that is the finding.** Chain stop reasons +before and after: + +| stop reason | Run 4 | Run 6 | +|---|---|---| +| `PageCapHit` | 69 | 76 | +| `NoIncomingEdge` | **10** | **0** | +| `LocalTerminal` | 4 | 5 | +| `BirthScanExhausted` | — | 1 | +| `DepthExceeded` | 1 | 1 | + +Ten addresses were previously reported as having **no funding credit at all** — a +claim about the chain, not about us — and every one of them was wrong. One +address now honestly reports that we stopped reading before finding its credit, +which is a claim about us and is counted as budget. + +**The corrected headline is ρ = 0.0955**, lower than the number published before, +and the bracket is a third narrower. The correction happened to move our own +figure in the flattering direction; it was made because the code disagreed with +its own documentation, and the direction was not known until the run finished. + +The under-sampling flag still fires, and Run 4's finding about the tail survives +the fix: coverage remains near 0.65 with Chao1 estimating 108 classes against 23 +observed. + +### Run 7 — the control, re-collected + +Helius, archival probes passed. 1,887 calls, 387 seconds. + +``` +attempted 92 | resolved 38 | evidence-unresolved 0 | budget-unresolved 54 + | scope-unresolved 0 | rpc failures 0 (0.00%) +``` + +| | Run 5 (broken) | Run 7 (fixed) | +|---|---|---| +| resolved | 16 | **38** | +| **evidence-unresolved** | 35 | **0** | +| `NoIncomingEdge` | **36** | **0** | +| ρ (point) | 0.0743 | 0.0362 | +| classes observed | 14 | 30 | +| Good–Turing coverage | 0.25 | 0.37 | + +The bug bit the control more than twice as hard, which is what surfaced it: +36 of 92 members were reported as having no funding at all, and every one was +wrong. Resolution more than doubled. + +**Run 7 still refuses.** 38 of 92 is 41%, under the informativeness gate's half. +The bracket spans 0.0124 … 0.1289, a tenfold range. + +### The comparison, and why it is refused + +``` +population members rho resampled 2.5-97.5% bias +privacy pool 54 0.0955 0.0848 .. 0.1790 +0.0276 +staking control 38 0.0362 0.0463 .. 0.0708 +0.0203 + +difference (privacy pool − staking control): +0.0592 95% +0.0259 .. +0.1229 +``` + +**The interval on the difference excludes zero.** Taken at face value that says +the privacy pool is the more provenance-concentrated population — which is the +direction that supports this project's entire argument. + +**`compare` refuses to report it**, because the control resolves fewer than half +its members. The reasoning is not a formality: + +> What survives after the unresolved are dropped is each population's *traceable* +> subset, and traceability is not independent of provenance class. A wallet funded +> straight from an exchange resolves in one hop; a wallet funded through fresh +> intermediaries exhausts the budget. So the resolved subsets of two populations +> can differ in provenance concentration purely because the *unresolved* ones were +> different, and nothing in the numbers above would reveal it. + +This gate did not exist when `compare` was written — it checked the RPC-failure +gate and not the informativeness one, which was an inconsistency between the two +commands. It was added on finding that the control fell on the wrong side of it, +and the honest way to say that is plainly: **we built the check that refuses our +own favourable result, after seeing that the result was favourable.** The code +and this paragraph are both in the repository; a reader can weigh that as they +see fit. + +**What would close it** is resolution above half on the control — 46 of 92, from +38 — which is a bigger traversal budget, not a different metric. 54 of its 92 +members are budget-unresolved, so the headroom exists. It is not attempted here, +because Run 7's pre-registered stopping rule was one collection per frame, and a +stopping rule that bends when the result is close is not a stopping rule. + +### What the two runs establish, and what they do not + +**Established.** The tracer bug was real, symmetric across populations, and it is +fixed: the evidence-unresolved bucket went to zero in both. The corrected +headline is ρ = 0.0955. The comparison machinery exists, is tested, and refuses +correctly in two different ways — it declines to separate Runs 3 and 4, which are +one pool at two budgets, and it declines to rank two populations when one is +under-resolved. + +**Not established.** That a privacy pool's depositors are more +provenance-concentrated than ordinary users. The point estimates say so and the +sample does not support saying it. `ρ`'s comparability across populations remains +**demonstrated as machinery and unproven as a finding.** + +## Run 8 — pre-registered, and the weakest pre-registration in this document + +Committed before the collection started, like Runs 4 to 7. It needs a disclosure +the others did not. + +**The problem with this run, stated first.** Run 7's comparison already told us +the direction: the difference favours the privacy pool, and the only thing +standing between that and a publishable finding is the control's resolution rate. +So this run is being made **with knowledge of which outcome would suit us**, which +is exactly the condition pre-registration exists to neutralise and cannot fully +neutralise here. Runs 4 and 6 did not have that problem; this one does. + +What can be done about it is done: the budget and the stopping rule are fixed in +advance, this is the final run of the programme whatever it returns, and this +paragraph is committed alongside. What cannot be done about it is the knowledge +itself. A reader should discount this run relative to the others, and the reason +is written here rather than left for them to notice. + +**Why it is worth running anyway.** The refusal in Run 7 rested on a suspicion — +that resolvability correlates with provenance class — and that suspicion has since +been **tested and not supported**, on both populations, by the selection check +above. The specific objection that blocked the comparison is now the objection +with evidence against it, so raising resolution is no longer papering over a +confound; it is removing the one gate that remains. + +**Frame.** The same 100 Marinade depositors as Runs 5 and 7. Not re-drawn. + +**What changes, and only this.** 87 of 92 chains in Run 7 ended at the signature +page cap. That is the binding constraint and the only one being moved. + +| parameter | Run 7 | Run 8 | +|---|---|---| +| signature page cap | 24 | **48** | +| depth | 16 | 16 | +| birth scan | 24 | 24 | + +Depth is unchanged because it was not binding: Run 7 had zero depth-exceeded +outcomes. + +**Prediction, recorded in advance.** Resolution rises above the 46 needed, but not +by much — the page cap is being doubled against a population where nearly every +chain hit it, so the marginal member is expensive. ρ for the control most likely +falls further, because the members still missing are the ones with the longest +funding chains and those are the least likely to share a class with anyone. + +If the control's ρ falls, the difference widens and the comparison separates. **We +are predicting the result that suits us, having already seen a version of it**, +and it is on the record so that a reader can hold us to it either way. + +**Stopping rule, absolute.** This is the last collection in this document. If the +control still resolves below half, the comparison is reported as unachieved and +stays unachieved. If it resolves above half and the difference fails to separate, +that is reported as the finding. No Run 9 under any outcome. + +**Also pre-specified:** the selection check will be run again at the new margin +(Run 7 → Run 8). If it *does* detect selection there, the comparison is refused +regardless of the resolution rate, because that would mean the members this run +added are not a fair draw and the extra resolution bought nothing but a +better-looking denominator. + +### Run 8 — result: the prediction was wrong and the comparison stays unachieved + +Helius, archival probes passed. 3,133 calls, 699 seconds. + +``` +attempted 92 | resolved 42 | evidence-unresolved 0 | budget-unresolved 50 + | scope-unresolved 0 | rpc failures 0 (0.00%) +``` + +| | Run 7 | Run 8 | +|---|---|---| +| signature page cap | 24 | 48 | +| rpc calls | 1,887 | 3,133 | +| resolved | 38 | **42** | +| needed for the gate | 46 | 46 | +| ρ (point) | 0.0362 | 0.0335 | +| classes observed | 30 | 33 | + +**The prediction failed.** It said resolution would rise above the 46 needed. It +rose to 42. Doubling the page cap bought **four members for 1,246 calls** — about +311 calls each, against an average of 50 in Run 7. The prediction that ρ would +fall was right, and the one that mattered was not. + +**So the comparison is refused again, and this time it is final.** + +``` +privacy pool 54 ρ 0.0955 resampled 0.0848 .. 0.1790 bias +0.0276 +staking control 42 ρ 0.0335 resampled 0.0428 .. 0.0657 bias +0.0188 + +difference: +0.0619 95% +0.0307 .. +0.1267 +``` + +The difference still excludes zero and still points our way. The gate still holds +it back. Run 8's stopping rule was absolute and is honoured: there is no Run 9. + +**The selection check declined to run at the new margin**, and correctly: only 4 +members were newly resolved, below the 5 it requires, so it reported nothing +rather than computing a number from four points. The check at the earlier margin +stands and is the evidence on record. + +### What the marginal cost says, which is the actual finding here + +The interesting number in Run 8 is not `ρ`. It is **311 calls per additional +resolved member, against 50 for the population as a whole** — a sixfold +deterioration from doubling the budget once. + +That reframes the refusal. The control is not under-resolved because we were +stingy; it is under-resolved because the members still missing have genuinely +long funding chains, and each further one costs more than the last. Reaching 46 +would plausibly cost as much again as the entire run, and reaching a comfortable +margin above it, several times that. + +**A depositor population that resists provenance tracing this hard is itself a +result**, and it is the opposite of what one would guess: the *staking* pool — +where nobody is seeking deniability — is markedly harder to trace than the +privacy pool, whose depositors resolved at 65% for two-thirds of the cost per +member — 1,776 calls for 54 resolved against 1,887 for 38. + +We do not claim to know why. Two candidates we cannot separate with this data: +staking attracts older wallets with deeper histories, or privacy-pool depositors +disproportionately fund from exchanges, which terminate in one hop. The second +would, if true, sharpen the concentration finding rather than soften it — which +is precisely why we are not asserting it. + +## What we do not conclude + +**Nothing about how private that pool is, and the headline does not become that +claim by clearing a gate.** ρ = 0.0955 is a point estimate inside an unresolved +bracket spanning 0.0350 to 0.1136, drawn from one frame of one pool at one +moment, and its class distribution is demonstrably heavy-tailed and mostly +unobserved. It is published because the method is published, not because it +settles anything. + +Three things it specifically does not support: + +- **A ranking of the two pools measured.** ρ is designed to be comparable across + pools, and the machinery was exercised: Runs 5, 7 and 8 collected a staking + control and ran `compare` against it. The tool **refused** to report the + difference, because the control resolved fewer than half its members and the + gate that catches exactly that failure fired. Comparability is demonstrated as + machinery and unachieved as a result. +- **An extrapolation to larger `k`.** Effective-k measured at small `k` + understates the steady-state loss, and the heavy tail is a reason to expect + that gap to widen rather than close. +- **A statement about any individual member.** The metric is a property of a + distribution. Nothing here identifies anyone, and the worst-case class of size + one is a feature of heavy-tailed provenance in general, not a finding about a + person. + +What the eight runs do support is narrower and, we think, more useful: that this +channel is measurable from live Solana data with a published method, that the +measurement is expensive and the tail does not close, and that a pipeline built +to refuse is one that refuses — before it produced a number, and again after, +including on a comparison this document would have preferred to report. diff --git a/docs/PLAN.md b/docs/PLAN.md new file mode 100644 index 00000000..b50ef526 --- /dev/null +++ b/docs/PLAN.md @@ -0,0 +1,224 @@ +# The design as decided, and where the protocol departs from it + +This is the design record: what was decided before the protocol was built, and — +in the last section — the six things that did not ship and why each was a +decision rather than an overrun. It is kept because the departures are the +interesting part; `ARCHITECTURE.md` describes what exists today. + +## The thesis + +`mirror-pool` is meant to be a crowd-sourced privacy set: users pool their +activity so that an observer sees an action happened but cannot say who +initiated it. The hard part is not the proof system. It is that **an anonymity +set on a public ledger can be partitioned by where each member's capital came +from**, and once you sort a set of `k` members into funding-provenance classes, +the anonymity that remains is the size of the actor's class, not `k`. + +It is the problem a privacy pool is most often built around rather than through: +the proof system gets the attention, the funding graph is conceded in a sentence, +and nobody measures what the concession costs. So it is the problem this +contribution takes as its subject. + +We do not claim to hide provenance. Value moves one way on a ledger, and no +deposit pool controls where its users' money came from. What we claim is +narrower and defensible: + +1. **The action side is closed.** Actions are executed by the pool's vault PDA, so the + on-chain funding trace of an action leads to the pool and is identical for + every member. +2. **The membership side is measured, not asserted.** Effective anonymity is + computed from real mainnet chain data at several label resolutions, and the + method and its limits are published with the number. +3. **The measurement is load-bearing.** A pool that cannot demonstrate an + effective-`k` above a floor refuses to settle. The metric is a protocol + parameter, not a marketing line. + *(Withdrawn during implementation — see "What actually got cut". A program + cannot check provenance, so this claim was not deliverable.)* + +If we cannot support a claim with a measurement whose method we publish, we do +not make the claim. + +## What we will not claim + +- Not "unlinkable", not "untraceable", not "anonymous" without a named adversary + and a stated population. +- Not that the funding-provenance channel is closed. It is reduced on the action + side and measured on the membership side. +- Not that a single-contributor trusted setup is secure. It is reproducible, + which is a different and lesser property, and we say which one we have. +- No number in any document may come from a synthetic fixture presented as a + measurement. Every reported figure names its data source. + +## Architecture + +### Pool model — fixed denomination, note-based + +One pool instance serves exactly one denomination `D`. A deposit escrows exactly +`D` plus an entry fee and inserts a note commitment into an incremental Poseidon +Merkle accumulator. A spend proves membership of some note, publishes its +nullifier, and directs the pool to execute one action disbursing exactly +`D − relay_fee`. + +``` +note = (k, r) secret nullifier preimage, blinding +commitment = Poseidon(k, r) the Merkle leaf + (shipped as Poseidon(k, r, denom_tag) — + binding the denomination in is cheap + defence in depth) +nullifier = Poseidon(k) revealed on spend, spent once ever +``` + +The denomination is a pool constant, so it never needs to be bound into the +commitment and can never disagree with the escrowed amount. + +**Accounting invariant**, asserted in tests: +`vault.lamports >= D × (deposits − spends) + rent_exempt_minimum`. + +This is deliberate, and it targets two drains that a shielded pool reaches by +building in the obvious direction. Carry the amount as a note field without +binding it to the hidden commitment, and a depositor of one lamport withdraws +the pool holding a valid proof. Scope the nullifier to an epoch — natural once +epochs are how batches form — and a single deposit pays out once per epoch, +forever. A fixed denomination with spend-once nullifiers makes both +unrepresentable rather than merely untested. + +### Circuit — 3 public inputs + +The statement: *I know `(k, r)` such that `Poseidon(k, r)` is a leaf of the tree +with root `R`, my nullifier is `Poseidon(k)`, and this proof is bound to +`action`.* + +| Public input | Why it must be public | +|---|---| +| `root` | the program checks it against its own root history | +| `nullifier` | the program records it to prevent replay | +| `action_binding` | the program recomputes it, so a relay cannot redirect or re-price | + +Measured cost is `74,179 + 5,661 × N` CU, so three inputs land near 91k CU. That +is the going rate for on-chain Groth16 on Solana, and the third input buys the +relay binding rather than being spent on a value that could have been folded in. +Any further value we need to commit to gets folded into `action_binding` rather +than added as a fourth input. See `GROTH16_INTEGRATION.md` for the verified +conversion path and its pitfalls. + +The action binding covers the action selector, its parameters, the beneficiary, +the relay and the relay fee, so every economically meaningful field is inside +the proof. + +### Two-phase epochs — synchronization without a CU explosion + +The premise is synchronized crowds: many identical actions landing +together so that timing and ordering carry no signal. Verifying `N` proofs in one +transaction does not fit — three proofs exhaust the transaction size limit long +before the compute limit. + +So the protocol splits it: + +- **Phase 1, any time during the epoch.** A member submits their proof in its own + relay-signed transaction. The program verifies it, burns the nullifier and + writes a ticket PDA recording the bound action. Nothing executes yet. +- **Phase 2, at epoch close.** The pool executes every ticket's action in one + settlement, sharing a single timestamp and ordering. + +The two phases also close a structural leak that a single-phase design walks +into: if settlement is one transaction that every participant must sign, then +that transaction publishes the entire membership set by pubkey, and the +anonymity set is disclosed by the very step meant to protect it. Here no member +key ever appears on chain. + +### Relays, and never holding users hostage + +A member who pays their own fee signs with their own wallet and destroys their +own anonymity, so spends are relay-signed and the relay is paid out of `D`. + +Two rules follow, and both are easy to lose by accident: + +- **Relaying is permissionless.** Any key may relay. There is no single immutable + authority whose loss freezes the pool. Baking a relay authority into the PDA + seeds is the tempting shortcut, and it is a trap: seeds cannot be changed, so + without a rotation instruction the authority is permanent and its loss is + terminal. + + > **Shipped narrower, and deliberately:** any key may relay, but a given proof + > names the relay it was made for, because the relay is part of the action + > binding. The property this rule was protecting — no authority whose absence + > freezes the pool — is untouched: there is still no allowlist and no + > registration. What changed is that the member chooses their relay instead of + > the choice going to whoever lands the transaction first. `THREAT_MODEL.md` + > has the attack that forced it. +- **There is always an exit.** A member may always self-spend, paying their own + fee and accepting the privacy loss, so funds are never hostage to a relay's + liveness. + +### Incentives + +Entry fees accumulate in a reward pool paid pro-rata to *dwell* — how long a note +stayed unspent — which is the behaviour that makes everyone else's set larger. +Payouts are capped per epoch and gated on the `k` floor, so a lone participant +cannot recycle their own fee back to themselves — a reward scheme that pays out +without a crowd gate is not an incentive, it is a refund with extra steps. + +> **Shipped instead:** none of this. The dwell mechanism was cut, and once it +> was, the fee funding it had no recipient — so the fee was cut as well, by +> refusing any nonzero value at pool creation. See *What actually got cut*. +> +> What did ship is four incentives the program enforces rather than pays for, and +> the reason the monetary one is harder than it looks: a reward has to name an +> address, and naming a member's address is the one thing this design spends +> everything else avoiding. `INCENTIVES.md` has all four, the gap, and the +> second-nullifier design that would close it. + +### Provenance measurement + +A separate crate collects real mainnet funding data and reports effective +anonymity at several label resolutions, with the raw sample committed so results +reproduce without RPC access. The methodology is `docs/PROVENANCE_METHOD.md`, and +it is built around three failure modes that make a provenance number read better +than it is: selection that drops whatever is expensive to trace, which inflates +the untraceable bucket in the flattering direction; a sample spanning seconds of +chain time presented as a population; and a class key at raw-address resolution, +which splits two members funded by the same exchange into different classes and +so reports a larger anonymity set than exists. + +## What was cut, and why + +This document is the design as it was decided, so the places where the shipped +protocol departs from it are the interesting part. Six things here did not ship, +and each was a decision rather than an overrun. + +- **`open_epoch` and explicit epoch state.** Folded into `submit_spend` and + `settle_epoch`, which need neither: a spend records its own timestamp and + settlement reads the clock. Four instructions instead of seven, and one fewer + account whose lifecycle could disagree with the pool's. +- **`claim_reward`, dwell rewards, and the entry fee with them.** The rewards + went first. The fee that funded them went second, and for a sharper reason: a + fee with no payout is not a simplification, it is a fund trap. Fees would + accrue on the pool account, no instruction would pay them out, and none could + be added without an authority this program deliberately does not have. + `Pool::initialise` now refuses any nonzero entry fee, so the trap is + unrepresentable rather than documented. The field stays in the layout for a + version that ships a real payout path. +- **`self_spend`.** Not built because it is not needed: a member relays for + themselves at zero fee and settles their own batch once the timeout passes. + The same exit, one fewer instruction, less surface. Pinned by + `a_member_can_always_exit_without_any_relay`. +- **The `audit` command.** Shipped as `analyze`, alongside `compare` and + `selection`, which the design did not anticipate needing. +- **"The measurement is load-bearing."** Withdrawn rather than descoped. The + design above claimed a pool would refuse to settle below a measured effective + anonymity. A program cannot check funding provenance — the data is off-chain + and the classification is a judgement — so the on-chain `k_floor` bounds + program-visible membership only, and the measurement lives beside the protocol + instead of inside it. Descoping the claim while keeping the language would have + been the marketing line this document opens by disavowing. +- **Mainnet.** Deliberately not deployed. The trusted setup is reproducible + rather than secure, so a live pool would be inviting deposits it cannot + protect. `README.md` states the reasoning where a reader will meet it. + +`EFFECTIVE_K` shipped as `docs/PROVENANCE_METHOD.md`. + +Two things shipped that the design did not contain at all: a selector that lets +the pool sign a call as a member's **authority**, which is what a stake +delegation needs and a transfer does not, and the measurement programme that +produced the eight runs in `docs/MEASUREMENT_LOG.md`. Both are described where +they live rather than here. diff --git a/docs/PROOF.md b/docs/PROOF.md new file mode 100644 index 00000000..9633437c --- /dev/null +++ b/docs/PROOF.md @@ -0,0 +1,83 @@ +# Live-cluster evidence + +Every line here is a transaction that landed. Nothing is simulated: the proof is produced by the host prover and verified by the deployed program's own Groth16 syscall. + +- cluster: `devnet` +- program: `8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa` +- pool: `JBvD5u5foKCThTfSx1TozGHGCcfWu5gDNy1u2FphP51q` +- vault: `EwiXhCnLcg6jEaHMumo5H4tZnVyoCtBPHU5R6hE798R5` + +## Flows + +| step | signature | note | +|---|---|---| +| init_pool | [`4Ru5RVJ1pyoFSYKrf58Rj43LsawpHQymEwW9zQgKNPpGuv5MdSBzT1Fyxpo8dtdXmcCxCZZN2SwEZVvnkSQXM5dn`](https://explorer.solana.com/tx/4Ru5RVJ1pyoFSYKrf58Rj43LsawpHQymEwW9zQgKNPpGuv5MdSBzT1Fyxpo8dtdXmcCxCZZN2SwEZVvnkSQXM5dn?cluster=devnet) | denomination 20000023, k_floor 4 | +| deposit | [`2z4zzRhA98HJcMHCMF9wzqYMjYCbBNX8K52ASWjhcFAQ887hCzHd1woURxLt2REgsTsLRMn32NubEiXqpGRTCHhZ`](https://explorer.solana.com/tx/2z4zzRhA98HJcMHCMF9wzqYMjYCbBNX8K52ASWjhcFAQ887hCzHd1woURxLt2REgsTsLRMn32NubEiXqpGRTCHhZ?cluster=devnet) | note 1 | +| deposit | [`45uwVLTFs81kU5rv4LgKHWS4apiDoThVRMrq8LziKr5iX9papXySRC3S1fXumZ8UEn4otMzG6iyT6LhcgRSYxu5d`](https://explorer.solana.com/tx/45uwVLTFs81kU5rv4LgKHWS4apiDoThVRMrq8LziKr5iX9papXySRC3S1fXumZ8UEn4otMzG6iyT6LhcgRSYxu5d?cluster=devnet) | note 2 | +| deposit | [`4QaHJBxGD1St4hiLyqmrmJmztTbmam1ssGrSABFE3S6sM6Q4JfSY1oqG5onXty17RT7KNaARXjTM2HYJMsyvur6D`](https://explorer.solana.com/tx/4QaHJBxGD1St4hiLyqmrmJmztTbmam1ssGrSABFE3S6sM6Q4JfSY1oqG5onXty17RT7KNaARXjTM2HYJMsyvur6D?cluster=devnet) | note 3 | +| deposit | [`5ZtoW7nNqVwSYJuzmQqwBiEm52tRgcQdYYGLbGMmD8cN1cqtbqh3mdjRqQzKBqWeetnnoQhTHBaUebTq8SxmBovW`](https://explorer.solana.com/tx/5ZtoW7nNqVwSYJuzmQqwBiEm52tRgcQdYYGLbGMmD8cN1cqtbqh3mdjRqQzKBqWeetnnoQhTHBaUebTq8SxmBovW?cluster=devnet) | note 4 | +| deposit | [`5TdTHdRJXddC1JP6uW4C993LY7ifSoi4ZxbavwhK95Wq96MyGUmHuQm88tkRRykhz4pzpaCQhJC3TR2A7Y843jxB`](https://explorer.solana.com/tx/5TdTHdRJXddC1JP6uW4C993LY7ifSoi4ZxbavwhK95Wq96MyGUmHuQm88tkRRykhz4pzpaCQhJC3TR2A7Y843jxB?cluster=devnet) | note 5 | +| create stake account | [`WmqHSUXx71nm81RzbhjgRZir1hzTMzGxg6k45fgPCi8cbyt1D3FVR5DKAETSapCmeQojM1TzMgAGbotReLBW4Kz`](https://explorer.solana.com/tx/WmqHSUXx71nm81RzbhjgRZir1hzTMzGxg6k45fgPCi8cbyt1D3FVR5DKAETSapCmeQojM1TzMgAGbotReLBW4Kz?cluster=devnet) | 1100000000 lamports, staker = the pool's vault, withdrawer = the operator | +| submit_spend | [`42bLZCNNwSo82r3Zwq1VVB4PqQCFm5ETjiFBai9QZYjNvzrkeJBwiYWb47RRMyXJ3Q9w22yV88GdSUFZ2CRKfGMK`](https://explorer.solana.com/tx/42bLZCNNwSo82r3Zwq1VVB4PqQCFm5ETjiFBai9QZYjNvzrkeJBwiYWb47RRMyXJ3Q9w22yV88GdSUFZ2CRKfGMK?cluster=devnet) | note 0, relay-signed | +| submit_spend | [`4jJwmRta9miD3yQgvhWSzZysZTS5wsKPM4E1ZPnHMnUCa3pPxXew4DQQAG3Y7Luk1bECD9V3A39dSBDrXxY3Wegw`](https://explorer.solana.com/tx/4jJwmRta9miD3yQgvhWSzZysZTS5wsKPM4E1ZPnHMnUCa3pPxXew4DQQAG3Y7Luk1bECD9V3A39dSBDrXxY3Wegw?cluster=devnet) | note 1, relay-signed | +| submit_spend | [`4fpZU88zDAeu2ySvjdit7My1FTzp9P7MZbRHHzUDD3V53nBLMruw5vb1WPG2zmGUnt9AFD1j6uimGmzKsYiLDF8A`](https://explorer.solana.com/tx/4fpZU88zDAeu2ySvjdit7My1FTzp9P7MZbRHHzUDD3V53nBLMruw5vb1WPG2zmGUnt9AFD1j6uimGmzKsYiLDF8A?cluster=devnet) | note 2, relay-signed | +| submit_spend | [`3gEhEPza2ryHiJuxPo8fZktqyhwyh2fwCwx18Bw7q95NPrZaszqpLtZq6KfrXefD7RR5eSbiR4Di5etv6HAWGaYL`](https://explorer.solana.com/tx/3gEhEPza2ryHiJuxPo8fZktqyhwyh2fwCwx18Bw7q95NPrZaszqpLtZq6KfrXefD7RR5eSbiR4Di5etv6HAWGaYL?cluster=devnet) | note 3, relay-signed, action: pool-signed CPI to SPL Memo | +| submit_spend | [`XLZJ3wDgJXe9YhiVD2akpEKHhwMziExkMntUtbW86TkKn6ktw5hWNrmqYG7FZ51jiYuGr6PhnE87v4kvEacViBA`](https://explorer.solana.com/tx/XLZJ3wDgJXe9YhiVD2akpEKHhwMziExkMntUtbW86TkKn6ktw5hWNrmqYG7FZ51jiYuGr6PhnE87v4kvEacViBA?cluster=devnet) | note 4, relay-signed, action: pool-signed stake delegation | +| settle_epoch | [`4T6MYo8rMW6wYZb6FdKSQUSrinLGFoo6gpq5YMQ4RAqCnFbHdeSueeMosEkoBf5uYEhcQRtiCJA16BtvKAKZ58km`](https://explorer.solana.com/tx/4T6MYo8rMW6wYZb6FdKSQUSrinLGFoo6gpq5YMQ4RAqCnFbHdeSueeMosEkoBf5uYEhcQRtiCJA16BtvKAKZ58km?cluster=devnet) | 5 spends in one transaction, 2 of them a CPI the pool signed | +| deposit | [`2jXf1wQ3J3And4TjAS47oUggAzwGFc2wVGy4v4xDyBeoVopNfa6RdW4SCBrNcva3ayjQQcFSZLdRtA8FJockosZ5`](https://explorer.solana.com/tx/2jXf1wQ3J3And4TjAS47oUggAzwGFc2wVGy4v4xDyBeoVopNfa6RdW4SCBrNcva3ayjQQcFSZLdRtA8FJockosZ5?cluster=devnet) | note 6 | + +## Vault accounting + +The accounting invariant is a statement about the vault's lamports, so here are the lamports. The vault holds escrow and carries no data, which is what makes its floor the rent-exempt minimum for a zero-byte account — read from the cluster during the run, not assumed. + +| quantity | lamports | +|---|---| +| denomination | 20000023 | +| notes settled | 5 | +| relay fee (taken out of the denomination, not added) | 200000 | +| vault before settlement | 100890995 | +| vault after settlement | 890880 | +| rent-exempt minimum, 0 bytes | 890880 | +| **paid out** | **100000115** | +| **owed** (denomination × notes) | **100000115** | + +Paid out equals owed, and the vault came to rest on its floor with a remainder of 0 lamports. The soak asserts both and fails the run otherwise, so this table cannot record a discrepancy and still exit successfully. + +## The pool signed an action, and the callee said so + +The settlement above carried 5 spends, and 2 of them were not a transfer: the pool invoked SPL Memo as one member's **authority**, in the same transaction as the other 4. That is the capability a stake delegation or a governance vote needs and a payment does not. + +A signature only proves the transaction landed. It says nothing about who signed the instruction the pool made *inside* it, so the evidence has to come from the callee. SPL Memo refuses any account handed to it that has not signed, and names the ones that did: + +``` +Program log: Signed by EwiXhCnLcg6jEaHMumo5H4tZnVyoCtBPHU5R6hE798R5 +``` + +That is the pool's vault, `EwiXhCnLcg6jEaHMumo5H4tZnVyoCtBPHU5R6hE798R5`, which has no private key — it signed through seeds only the program holds. The soak reads this line back from the cluster and fails the run if it is absent, so this section cannot appear without the callee having said it. + +## The pool delegated stake, as a member's authority + +The same settlement carried a second signed action, and this one is the case the design exists for: a **real stake delegation**. Stake account [`CMMwt1SgrJyEfdBsxxUNSwsPwNiU94ZNkVGMUzvMU1Ri`](https://explorer.solana.com/address/CMMwt1SgrJyEfdBsxxUNSwsPwNiU94ZNkVGMUzvMU1Ri?cluster=devnet) is now delegated to validator [`2f9C9AU8nFRKUub8NHToNiZzcwmYiNeipVuP8akKgRVv`](https://explorer.solana.com/address/2f9C9AU8nFRKUub8NHToNiZzcwmYiNeipVuP8akKgRVv?cluster=devnet). + +`DelegateStake` requires the **staker authority** to sign. No member can be that authority without appearing on chain and undoing the point, so the pool is, and the pool signed. The account state is read back after settlement: a stake account only reaches the `Stake` variant by being delegated — an initialised but undelegated one is a different variant — so the check distinguishes "the instruction landed" from "the delegation took", and the validator's key is read out of the account rather than assumed from what was requested. + +**The withdraw authority is deliberately not the pool.** The pool's signature is available to every member, so an authority the vault holds is an authority every member holds. Delegation is safe on those terms — the worst a member can do is re-delegate to another validator. Withdrawal is not, and it stays with the operator. That is `docs/THREAT_MODEL.md` applied rather than repeated. + +What is hidden here is precisely one thing: **which member asked**. The stake account, the validator, the amount and the timing are all public, and the anonymity set is the 5 members who settled together. What an observer cannot recover is which of them authorised this delegation rather than one of the plain transfers beside it. + +## Rejections + +A negative case is only evidence if the program's own error code is what rejected it. A bare runtime failure proves nothing about this program. + +| case | error code | what the rejection establishes | +|---|---|---| +| replayed nullifier | `0xf` | a nullifier is spent once, ever -- not once per epoch | +| redirected beneficiary | `0x12` | a relay cannot send a member's payout somewhere the member did not choose | +| inflated relay fee | `0x12` | a relay cannot re-price the work after the member authorised it | +| front-run relay | `0x12` | a proof is spendable only by the relay the member made it for | + +The last three attack a note that is still live, deposited after settlement precisely so that they would have to. Against an already-spent note the replay guard fires first and the rejection would say nothing about the check under test — which is how a negative case comes to pass for the wrong reason. + +## Scope + +Devnet is devnet. This is a live-cluster functional proof, not a claim of mainnet operation or of an anonymity crowd: the run is scripted by one operator with a handful of notes. What it establishes is that the circuit, the prover, the byte layout and the deployed program agree on a real validator. diff --git a/docs/PROVENANCE_METHOD.md b/docs/PROVENANCE_METHOD.md new file mode 100644 index 00000000..fc4706e2 --- /dev/null +++ b/docs/PROVENANCE_METHOD.md @@ -0,0 +1,1497 @@ +# Funding-Provenance Effective-k — measurement specification + +Status: specification, v1 — and `crates/mirror-provenance` was built against it. + +Read it as the method rather than as a description of the code. Most of it +shipped; three things did not, and each is marked where it appears rather than +quietly dropped: + +- **`verify-labels`** (§5.4) was specified to re-check every curated anchor + against the chain. The anchor set exists in `classify.rs`; the command that + falsifies it does not, so Tier-2 labels rest on their cited sources alone. +- **The multi-file artifact layout** (§7.3) became one JSON document per run. + What shipped is described there. +- **The L0–L3 label-resolution ladder** (§5.1, §5.6). The classification rules + R1–R5 shipped and are what produce every published label. Reporting the *same* + measurement at four label granularities, and the monotonic bracket that would + come out of it, did not: the crate has no notion of a resolution rung, so the + published headline is a single figure at the resolution the R-rules give, + neither claimed nor claimable as "L2". +- **The `n = 1,100` baseline frame** (§3) was not collected. The published runs + are the smaller ones in `docs/MEASUREMENT_LOG.md`, and what that costs the + estimate is stated there rather than here. + +Every empirical number below names its source. Numbers tagged **[M 2026-07-25]** were +measured directly against Solana mainnet on that date (probe method stated inline); +numbers tagged **[V]** were verified against a primary document. Everything else is +design and must not be reported as a finding. + +--- + +## 0. Purpose and scope + +A privacy pool advertises `k` members. On a public ledger an observer can partition +those members into **funding-provenance classes** — where each member's capital came +from. If the partition is informative, the anonymity a member actually receives is +below `k`. + +This document specifies how we measure that gap: the sampling frame, the tracing +algorithm, the metric, the label resolutions, the failure accounting, and the on-disk +artifacts that let a third party reproduce every published number without network +access. + +It also specifies, in §9, what our own protocol may and may not claim about reducing +the gap — including which framings would be tautological if measured naively. + +**This crate measures. It makes no privacy claim by itself.** A number produced by +this tool describes one channel under one stated adversary at one stated label +resolution, at one pinned slot. It is not a security proof and must never be +presented as one. + +### 0.1 Conventions + +| symbol | meaning | +|---|---| +| `S` | snapshot slot. Nothing with `slot > S` is visible to any stage. | +| `K` | number of members in the measured anonymity set (after §5.2 collapse) | +| `m` | number of provenance classes observed | +| `n_c` | size of class `c`; `Σ_c n_c = K` | +| `X` | random variable: which member performed the action | +| `C` | random variable: the observed provenance class, `C = λ(X)` | +| `λ_L` | labelling function at resolution `L` (§5) | + +--- + +## 1. Adversary model + +Every reported number is meaningless without this section printed beside it. The tool +MUST emit the adversary identifier and label resolution in the same object as the +metric. + +### 1.1 `A_prov` — passive, global, retrospective, chain-only + +**Knows:** + +- The finalized Solana ledger up to snapshot slot `S`. +- The complete member set `A = {x_1 … x_K}` of the measured round. Membership is + public by construction: a deposit is an on-chain event. +- The labelling function `λ_L`, which we publish and ship. The adversary is granted + our labels exactly, no more. + +**Observes:** + +- One action `a`, known to have been produced by exactly one member. +- An action-side class `μ(a) ∈ Labels ∪ {⊥}`, computed by applying the *same* `λ_L` + to the action's funding trace. + +**Inference rule:** eliminate every `x_i` with `λ_L(x_i) ≠ μ(a)`; uniform posterior +over the survivors. Prior over `X` is uniform on `A`. + +**Explicitly denied.** The adversary has none of: + +- off-chain identity (KYC records, exchange cooperation, subpoena); +- network-layer observation (gossip, mempool, RPC-timing correlation); +- timing correlation between deposit and action; +- amount correlation between deposit and action; +- behavioural fingerprints (wallet software, compute-budget settings, fee patterns); +- active Sybil deposits into the measured pool; +- compromise of any party. + +Those are separate channels. Folding any of them in inflates the number and destroys +comparability with the published Ethereum results we benchmark against (§10.2). + +### 1.2 The two-sidedness rule + +> A partition is admissible only if the adversary can compute the same label on the +> **member side** and on the **action side**. + +This rule is load-bearing, and it is the single design decision the rest of the +method is built around. + +Entropy over a partition decreases monotonically under refinement. Therefore **finer +labels always yield a lower effective-k**, and a *weaker* tracer that fails to merge +members reports a *worse* number than a strong one. A metric with that property is not +measuring the pool; it is measuring the tracer's budget. + +Raw-address partitioning violates two-sidedness: "funded by Binance hot wallet #7" is +not observable of an action whose trace reaches a *different* Binance hot wallet. The +adversary cannot exploit a distinction they cannot match on both sides. The headline +resolution is therefore the finest **two-sided** one — entity level, not address level +(§5). + +Because monotonicity runs the other way from intuition, the tool MUST NOT report a +single scalar. It reports the ladder (§5.5) and the bracket (§2.6). + +### 1.3 What the number proves + +**Proves.** Under `A_prov` at resolution `L`, at slot `S`, the measured set's +advertised `k` overstates the adversary's residual uncertainty by a factor of +`2^{H_L(C)}`. + +**Does not prove.** + +1. That any individual was deanonymized. We attempt no linkage and name no member. + The tool MUST NOT emit member addresses in any published artifact. +2. That the pool is broken. One channel, one adversary, one slot. +3. Anything composable. Effective-k values for different channels do not multiply or + add. The joint is bounded above by the minimum; computing it requires the joint + partition. +4. A durable protocol property. It is a property of the measured set at slot `S`. +5. A bound on real-world anonymity. A real adversary holds the denied channels, so + **real effective-k ≤ ours** at fixed `L`. + +**The one monotonicity we may claim:** adding channels only refines the partition, so +our number is an **upper bound on privacy against any strictly stronger adversary at +the same label resolution**. It is *not* a bound in the label-resolution direction. +State both halves. Stating only the first is the common error, and it inverts the +claim: it lets a number measured at coarse labels be read as a guarantee against +an adversary holding finer ones. + +--- + +## 2. Metrics + +### 2.1 The core identity + +`C` is a deterministic function of `X` (each member belongs to exactly one class), so +`H(C|X) = 0` and the chain rule collapses: + +``` +log2 K = H(C) + H(X|C) +``` + +which gives the definition used throughout: + +``` +H(X|C) = Σ_c (n_c/K) · log2(n_c) residual anonymity, in bits +eff_k_shannon = 2^{H(X|C)} = K / 2^{H(C)} residual anonymity, in members +``` + +`2^{H(C)}` is the *effective number of classes*. **Effective-k is nominal k divided by +the effective number of classes.** + +Two identities worth surfacing in output, because they are exact and quotable: + +``` +Shannon leakage I(X;C) = H(C) bits, exactly +min-entropy leakage = log2 m bits, exactly (Smith 2009, Thm. 1) +``` + +> **Implementation warning.** `2^{H(C)}` — entropy over the *class-size distribution* — +> is the folklore formula and it is inverted: it is maximised at total deanonymization. +> It is the **leakage**, not the anonymity. Do not compute it as the headline. A unit +> test MUST pin `H(C) + H(X|C) == log2 K`. + +### 2.2 Attribution (the widely-repeated version is wrong) + +Serjantov & Danezis, *Towards an Information Theoretic Metric for Anonymity*, PET 2002, +LNCS 2482, pp. 41–53. **[V]** Definition 2, verbatim: + +> "We define the **effective size S** of an r anonymity probability distribution U to be +> equal to the entropy of the distribution. In other words `S = − Σ_{u∈Ψ} p_u log2(p_u)` +> where `p_u = U(u, r)`." + +So `S` is **in bits**, and `p_u` ranges over **users**, not classes. The paper does +convert to a member count in its own §5 worked examples ("equivalent to a threshold mix +with `N = 2^7.127 ≈ 140` inputs") **[V]**, but that is an interpretation, not +Definition 2. The formal definition of `A = 2^{H(P)}` as a *quantity* is Andersson & +Lundin, *On the Fundamentals of Anonymity Metrics*, IFIP AICT 262, 2008, Def. 1 +("scaled anonymity set size"), who explicitly dispute the folklore attribution. + +**Required wording in any write-up:** + +> the effective anonymity set size, i.e. `2^H` where `H` is the Serjantov–Danezis +> entropy metric [S&D 2002, Def. 2]; the exponentiated form is due to Andersson & +> Lundin [2008, Def. 1] and is standard in the mixnet literature [Shmatikov & Wang, +> WPES 2006]. + +Do **not** write "Serjantov and Danezis define the effective anonymity set size as +`2^H`." + +For each observation `C = c` the posterior is uniform on class `c`, whose S&D effective +size is `log2 n_c` bits. `H(X|C)` is therefore the **expectation of the S&D effective +size over the adversary's observation**. That sentence is the whole justification and +it is unattackable; use it. + +### 2.3 The reporting ladder + +Report all of these, always. Never a scalar. + +| # | quantity | formula | interpretation | +|---|---|---|---| +| 1 | **loss factor `ρ`** | `ρ = 2^{−H(C)}` | **headline.** k-independent fraction of nominal k that survives | +| 2 | Shannon effective-k | `2^{H(X\|C)} = Π_c n_c^{n_c/K}` | membership-weighted **geometric** mean of class sizes | +| 3 | Shannon leakage | `H(C)` bits | exact | +| 4 | min-entropy effective-k | `K/m` | Bayes vulnerability; unweighted **arithmetic** mean of class sizes | +| 5 | min-entropy leakage | `log2 m` bits | exact | +| 6 | worst-case class | `min_c n_c` | **must be reported with its null distribution** (§2.5) | +| 7 | class-size CCDF | `P(my class ≤ t)`, `t ∈ {1,2,4,8,16,…}` | the distribution, not a summary | +| 8 | guessing entropy | `G(X\|C) = (1/K)·Σ_c n_c(n_c+1)/2` | expected guesses; baseline `(K+1)/2` | +| 9 | Good–Turing coverage | `Ĉ = 1 − f₁/K` | fraction of class mass observed | +| 10 | Chao1 richness | `m + f₁(f₁−1)/(2(f₂+1))` | saturation diagnostic | + +`f₁`, `f₂` = number of classes of size exactly 1, 2. + +**Ordering invariant** (verified over 200,000 random partitions, zero violations — +assert it in a property test): + +``` +min_c n_c ≤ K/m ≤ Π_c n_c^{n_c/K} ≤ K +worst min-ent Shannon advertised +``` + +Report min-entropy alongside Shannon because Shannon averages and hides the tail. The +canonical counterexample: uniform over 20 users and a 101-user distribution where the +true sender has p = 0.5 both give `H = 4.3219` bits, but the adversary succeeds one +time in twenty in the first case and one time in two in the second (Tóth, Hornák & +Vajda, NordSec 2004). + +Guessing entropy is included because it is what the canonical "advertised vs effective" +paper uses — Möser et al., *An Empirical Analysis of Traceability in the Monero +Blockchain*, PoPETs 2018(3), define effective anonymity set size as `1 + 2·Ge`. +**Indexing trap:** their `Ge = Σ_{0≤i≤M} i·p_i` starts at `i = 0` (expected *wrong* +guesses), so `Ge = G_Massey − 1`. Using 1-indexed Massey gives `M+3` where the paper +says `M+1`. Pin this in a test. + +Do **not** report Díaz et al.'s normalised degree `d = H(X)/log2 N` as a headline: it +reports ≈1.0 for a large but badly-partitioned pool, which is the opposite of what we +are measuring. Secondary metric only. + +### 2.4 `ρ` is the headline, not effective-k + +For a fixed class prior, `eff_k(k)/k` decreases toward `2^{−H(C)}` from above. Measured +by simulation over a Zipf-ish 60-class prior **[M 2026-07-25, 400 resamples per k]**: + +| nominal k | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 4096 | +|---|---|---|---|---|---|---|---|---|---| +| median `eff_k/k` | 0.177 | 0.118 | 0.085 | 0.065 | 0.055 | 0.049 | 0.046 | 0.045 | 0.043 | + +(asymptote `2^{−H(C)} = 0.0431`) + +**A measurement at small k systematically understates the steady-state loss and cannot +be extrapolated to a large pool.** `ρ` is k-independent, estimable with CIs, and +comparable across pools of different sizes. Publish `ρ` plus the `eff_k(k)` curve for +`k ∈ {8,16,32,64,128,256,512,1024}` with 5th/95th percentiles from `B = 10,000` +resamples of the measured class prior. + +### 2.5 Worst case must carry its null + +In the same simulation, `P(min_c n_c = 1) ≈ 1.00` for every `k ≤ 512` and 0.93 at +`k = 1024` **[M 2026-07-25]**. Under any heavy-tailed provenance prior *somebody is +always alone*. "Worst case is 1" is therefore not a finding about a pool; reported +bare, it is theatre. + +The tool MUST emit `worst_case_observed` together with `worst_case_null_p50` and +`worst_case_null_p05` computed by resampling the fitted class prior at the same `k`. + +### 2.6 The unresolved bracket + +Members whose trace terminates without a class are **not** a class. Merging them +assumes they are identical (charitable to the pool, raises k); splitting them into +singletons assumes they are all distinct (charitable to the adversary, lowers k). +Neither is known. + +Emit three values: + +- `eff_k_upper` — unresolved merged into one class; +- `eff_k_lower` — unresolved split into singletons; +- `eff_k_imputed` — `B = 10,000` draws imputing each unresolved member's class from the + class distribution measured on the **resolved** members. State the missing-at-random + assumption explicitly and emit an MNAR sensitivity sweep (impute instead from the + tail of the distribution) alongside. + +A point estimate without this bracket is not publishable output. + +### 2.6a Sampling error, which the bracket does not cover + +The bracket answers *what if the unresolved members had been something else*. It +says nothing about the other uncertainty, which is that the members measured are +a **draw** from a much larger population. Both are needed and neither substitutes +for the other: + +| | question | shape | +|---|---|---| +| bracket | what if the unresolved had landed differently? | exact bound, computed | +| bootstrap | how much of `ρ` is which depositors we drew? | percentile interval, resampled | + +**The estimator.** Resample the resolved members with replacement, `n` draws for +a sample of `n`, recompute `ρ` on the resampled class tally, repeat `B = 10,000` +times, and take the 2.5th and 97.5th percentiles. A class that no resampled +member landed in is **absent** from that replicate, not a class of size zero — +which is the whole reason the interval is asymmetric under a heavy tail: +resampling merges singletons, and fewer classes means higher `ρ`. + +**Reproducibility.** The generator is a splitmix64 implemented in-tree, seeded +from a published constant, because `analyze` is a pure offline pass whose output +a third party must be able to reproduce byte for byte. An external RNG makes that +promise depend on a dependency's version. + +#### The bias this does *not* remove, stated because it runs the wrong way for us + +Plug-in entropy — estimating `H(C)` by counting — is the maximum-likelihood +estimator, and it is **biased downward** when classes are many and members are +few. That is the regime every run in this project operates in. + +Since `ρ = 2^{−H(C)}`, understating `H(C)` means **overstating `ρ`**. So: + +> Every `ρ` published here is biased **high**. The true loss factor is plausibly +> smaller — the pools plausibly leak *less* than we report. + +A bootstrap resamples the same estimator, so its interval is centred on the +biased value: it measures the estimator's spread, not its distance from the +truth. Correcting this needs Miller–Madow or a coverage-adjusted estimator, and +neither is implemented here. + +It is stated this loudly for two reasons. First, it is the direction that makes +our own headline look worse rather than better, and a bias disclosed only when it +flatters is not a disclosure. Second, it is what makes **comparison** valid where +individual numbers are shaky: the bias falls in the same direction on every +population measured the same way, so a difference between two of them survives a +bias that neither absolute number does. + +#### Comparing two populations + +`ρ` is the headline because it is independent of `k` and therefore comparable +across pools. Exercising that means bootstrapping the **difference**, resampling +each population independently within a replicate, and reporting the interval on +`ρ(A) − ρ(B)`. + +**If that interval contains zero, the two populations are not distinguishable at +those sample sizes, and neither may be called the more concentrated.** Subtracting +two point estimates and reporting the sign is the error this exists to prevent: +two samples of the same underlying shape always differ by *something*. + +The unit test that matters here is not that a stark difference separates — that +is easy. It is that two identically shaped populations do **not**. + +### 2.6b Testing the assumption the bracket rests on + +The unresolved bracket bounds what the unresolved members *could* have been. Every +number computed from the resolved ones alone additionally assumes those resolved +members are a **fair draw of the classes present** — that resolvability is +independent of provenance class. + +That assumption is usually stated and left there. It is testable. + +**The design.** Collect one frame at two budgets. Partition the larger run's +resolved members into + +- those the smaller budget also reached — *cheap to trace*, and +- those only the larger budget reached — *expensive to trace*, + +and bootstrap the difference in `ρ` between the two groups. + +**Separation is the bad outcome.** If expensive-to-trace members carry a different +class distribution from cheap ones, the unresolved are not missing at random, the +resolved subset is biased toward whichever classes happen to be cheap, and no +amount of extra budget repairs it — more budget moves the boundary without +removing it. Every cross-population comparison would then be uninterpretable. + +**Measured, both populations, on the runs in `MEASUREMENT_LOG.md`:** + +| population | cheap | expensive | difference, 95% | +|---|---|---|---| +| staking control | 16 members, ρ 0.0743 | 22 members, ρ 0.0585 | −0.0144 … +0.0786 | +| privacy pool | 39 members, ρ 0.1179 | 15 members, ρ 0.1250 | −0.1507 … +0.0704 | + +Neither separates. At the margin these budgets test, being resolvable is not +picking out particular provenance classes. + +**What that licenses, exactly.** It is evidence that the members *just beyond* a +cheaper budget resemble those inside it. It says nothing about members beyond the +larger budget, where a heavier tail could still sit, and it is a statement about +these two populations at these budgets rather than a general law. It is reported +as evidence, never as the assumption being discharged. + +### 2.7 Reference vectors for unit tests + +Exact values, computed at full double precision. Assert to 1e-9. + +**Vector A** — `sizes = [50, 20, 10, 10, 5, 3, 1, 1]`, `K = 100`, `m = 8` + +``` +H(C) = 2.1295115772 bits +H(X|C) = 4.5143446126 bits +H(C) + H(X|C) = 6.6438561898 == log2(100) +eff_k_shannon = 22.8535219812 +eff_k_minent = 12.5 +minent_leakage = 3.0 bits (= log2 8) +worst_case = 1 +G(X|C) = 16.18 (uniform baseline 50.5) +good_turing_C = 0.98 (f1=2, f2=0) +chao1 = 9.0 +``` + +**Vector B** — `sizes = [19, 1×11]`, `K = 30`, `m = 12` + +``` +H(C) = 2.2165365038 bits +H(X|C) = 2.6903540918 bits +eff_k_shannon = 6.4547181110 +eff_k_minent = 2.5 +minent_leakage = 3.5849625007 bits +worst_case = 1 +G(X|C) = 6.7 (uniform baseline 15.5) +good_turing_C = 0.6333333333 (f1=11, f2=0) +chao1 = 67.0 +``` + +**Vector C** — `sizes = [1×30]` (total deanonymization): `H(X|C) = 0`, +`eff_k_shannon = 1.0`, `eff_k_minent = 1.0`, `worst = 1`, `good_turing_C = 0.0`. + +**Vector D** — `sizes = [30]` (nothing partitioned): `H(C) = 0`, +`eff_k_shannon = 30.0`, `eff_k_minent = 30.0`, `worst = 30`, `G = 15.5`. + +**Vector E** — `sizes = [4, 4]`: `H(C) = 1.0`, `H(X|C) = 2.0`, `eff_k_shannon = 4.0`, +`eff_k_minent = 4.0`. + +**Negative control test (mandatory).** Inject a partial leak into a synthetic uniform +set and assert the metric drops below nominal. A metric that has never produced a bad +number for our own system has not been validated. See §9.0. + +--- + +## 3. Sampling design + +### 3.1 Two populations, two claims — never conflate + +**P1 — pool census.** All distinct depositors of pool `P` with `S₀ ≤ slot ≤ S`. If the +population is enumerable, **census it**; there is then zero sampling error and §3.4 does +not apply. + +> **Failure mode.** Sampling *n* depositors from a pool's most recent signatures and +> then setting *advertised k = n* is a category error that is easy to commit and hard +> to see afterwards: advertised k is the pool's member count, and the sample size is a +> property of the budget. Reporting the second as the first makes the anonymity claim +> a restatement of how long the collector ran. +> +> The scale involved, measured **[M 2026-07-25]**: an active pool emits ~1,000 +> signatures per 1.2 days, so a 300-signature scan covers **the most recent ≈10 hours** +> of pool activity. A 90-day census of the same pool is ≈75 pages of +> `getSignaturesForAddress`, ≈75,000 signatures — verified reachable by `before`-cursor +> paging **[M 2026-07-25]**. The census is affordable; the shortcut is not necessary. + +**P2 — population prior.** All addresses receiving a value credit ≥ threshold in window +`W`. This estimates the class prior *any* pool inherits, and yields `ρ` and the +`eff_k(k)` curve. This is the generalizable claim and it is the one to lead with. + +### 3.2 Frame construction for P2: sample slots, not consecutive blocks + +`getBlock` with `transactionDetails: "accounts"` returns exactly +`{transaction:{accountKeys,signatures}, meta:{err,fee,preBalances,postBalances, +preTokenBalances,postTokenBalances,status}}` — precisely the projection the edge +extractor needs — at **2.73 MB/block vs 6.41 MB for `"full"`**, 1,056 transactions, +1.6 s fetch **[M 2026-07-25, slot ≈435,066,350]**. + +**Procedure.** Draw `N_blocks` slots uniformly at random across `W` using the seeded +PRNG (§3.5), `getBlock` each, extract all value edges. 1,000 sampled blocks ≈ 1M +transactions ≈ 2.7 GB, ~1,000 calls. This is a genuine probability sample of chain time. + +> **Failure mode.** A sample drawn from *consecutive* slots is not a sample of chain +> time. An n=1,181 sample spanning 9 consecutive slots covers ~3.2 seconds of chain +> time; the large n makes it look powerful, and binomial Wilson intervals computed over +> it look rigorous, but the observations are neither independent nor representative of +> anything but that instant. Sampling slots uniformly across the window costs the same +> number of calls and fixes it, so there is no efficiency argument for the shortcut. + +### 3.3 Time stratification + +- Window `W = [S − 19,440,000, S]` ≈ **90 days = 45 epochs**. Solana fixes an epoch at + **432,000 slots** with a ~400 ms nominal slot **[V]**; Alpenglow had not reached + mainnet as of mid-2026 and slot times are unchanged. Do **not** assume 400 ms — + compute the realized mean from `blockTime` deltas over `W` and record it in the + manifest. +- **45 epoch strata** (or 90 daily strata). Allocation proportional to stratum activity; + record the allocation vector in the manifest. +- Canonical total order within a stratum: `(slot, transactionIndex, signature)`. + `getSignaturesForAddress` returns a `transactionIndex` field **[M 2026-07-25]** (not + in the RPC reference) which gives deterministic intra-slot ordering at no cost. + +### 3.4 Sample size + +`n = z²p(1−p)/w²`, finite-population correction `n/(1 + (n−1)/K)`: + +| 95% half-width | n (p=0.5) | FPC K=2,000 | FPC K=10,000 | +|---|---|---|---| +| ±10 pp | 97 | 92 | 96 | +| ±5 pp | 385 | 323 | 370 | +| **±3 pp** | **1,068** | **697** | **965** | +| ±2 pp | 2,401 | 1,092 | 1,937 | +| ±1 pp | 9,604 | 1,656 | 4,900 | + +**Baseline `n = 1,100`; stretch `n = 2,400`.** + +For scale: a published 11/30 root-hit rate carries a Wilson 95% CI of +**[21.9 %, 54.5 %] — 32.6 percentage points wide**. + +**Confidence intervals.** + +- Effective-k has no closed-form CI. Use a **stratified block bootstrap resampling + whole clusters** (funder-cluster or slot), `B = 10,000`, BCa intervals. Report the + design effect. +- **CI width must be a function of data collected, never of loops run.** The failure + looks like this: a published interval of `[+0.308, +0.325]` turns out to be exactly + `2·1.96·√(p(1−p)/B)` for `B` the resampling count — so the interval narrows as the + loop count rises and can be made arbitrarily tight without collecting one extra + byte. It is easy to ship because a tighter interval reads as a better measurement. + Write a test that fails if the reported width moves when only the resample count + does. + +**Entropy bias.** Plug-in `Ĥ` is downward-biased by ≈`(m−1)/(2n ln2)` bits. Emit +plug-in, Miller–Madow, and Chao–Shen (coverage-adjusted) side by side. Emit Good–Turing +coverage and Chao1 as saturation diagnostics; on Vector B they read 63.3 % coverage and +67 estimated classes from a sample of 30, which is how you say "this sample is nowhere +near saturating" in one number. + +### 3.5 Seeding + +``` +seed = blockhash(S) // public, fixed before we chose it — un-grindable +prng = ChaCha20(seed) +``` + +Record `S`, `blockhash(S)`, and the derivation rule in the manifest. + +### 3.6 Never filter the frame on the outcome + +> **Failure mode.** Discarding every candidate depositor with ≥1,000 signatures looks +> like a reasonable cost control — those are the expensive ones to walk — but it drops +> exactly the wallets with deep, traceable histories. Whatever remains is then +> disproportionately untraceable, and a headline like "63 % untraceable" is measuring +> the exclusion rule. **An exclusion criterion correlated with the outcome is not a +> filter, it is the finding.** + +**Rule: nothing is excluded from the frame.** High-activity members are stratified and +reported, never dropped. If a member turns out to be a relayer or a program, that is a +finding, labelled as such, kept in the denominator. + +Related: attribute deposits by **value flow** (the account whose lamport delta went +negative into the pool), not by `accountKeys[0]`. `accountKeys[0]` is the *fee payer*; +any relayer-paid deposit is otherwise attributed to the relayer. Emit the +fee-payer/value-source disagreement rate as a statistic. + +--- + +## 4. Edge extraction and tracing + +### 4.1 Edge extraction: balance deltas, not instruction parsing + +Parsing `parsed.type == "transfer" && program == "system"` misses: + +1. programs that move lamports by direct account mutation + (`**acct.lamports.borrow_mut()`), which emit no system-transfer instruction at all; +2. `createAccount`, `createAccountWithSeed`, `transferWithSeed`, `withdrawNonceAccount`; +3. `closeAccount` lamport returns; +4. all SPL token flow. + +**Verified [M 2026-07-25]:** with `encoding: "jsonParsed"`, `accountKeys` *does* include +lookup-table-loaded addresses — a probed v0 transaction had 11 `source:"transaction"` + +9 `source:"lookupTable"` = 20 keys — and `preBalances`/`postBalances` both have length +20, aligning with the **full resolved key list**. `meta.loadedAddresses` is absent under +`jsonParsed` (folded into `accountKeys`). The RPC reference text implies otherwise; the +empirical result is authoritative. **Pin this in a test against a committed fixture.** + +``` +for each account index i in accountKeys: + Δ_i = postBalances[i] − preBalances[i] + (meta.fee if i == 0 else 0) +sources = { i : Δ_i < 0 } +sinks = { i : Δ_i > 0 } +``` + +Token flow: diff `preTokenBalances` / `postTokenBalances` by `(accountIndex, mint)`. +Each entry carries `owner`, giving the owner wallet directly from `meta`. + +Attribution within a transaction: single-source ⇒ unambiguous. Multi-source ⇒ record the +source *set* and set `ambiguous_attribution = true`. **Emit the ambiguity rate.** Use +instruction parsing only as corroboration, never as the primary extractor. + +Shape note: under `transactionDetails: "accounts"` the path is +`transaction.accountKeys`; under `"full"` it is `transaction.message.accountKeys`. + +### 4.2 The SPL blind spot — scope it explicitly + +`getSignaturesForAddress` indexes on `accountKeys` only **[V]**. A plain SPL transfer +into an existing ATA does **not** name the recipient wallet. Verified on three real +mainnet USDC transfers **[M 2026-07-25]**: the destination token account was in +`accountKeys` in 3/3 cases; the destination's **owner wallet was in 0/3**. Helius's own +documentation states it: *"Does not include associated token accounts — use +getTransactionsForAddress for complete token history."* + +**Consequence.** A wallet funded in USDC/USDT — the dominant CEX withdrawal path on +Solana — may have no signature history at its wallet address for the funding event. A +SOL-only tracer is structurally blind to it and the resulting "unresolved" is an +artifact, not a finding. + +Two supported scopes. **The manifest MUST record which one produced the headline.** + +- `scope = "sol"` — native SOL only. Cheaper; the blind spot is a stated limitation. +- `scope = "sol+spl"` — enumerate `getTokenAccountsByOwner` per address and page + `getSignaturesForAddress` on each ATA. **2.5–3× the call count** (§8). + +**Honest limitation to print in the output, either way:** a wallet that received tokens +into an ATA it later closed is invisible to `getTokenAccountsByOwner`. Bound the +residual by cross-checking against the block-sampled frame (§3.2) and report it. + +### 4.3 The edge rule: the birth edge + +**Primary rule.** For each address, follow the **oldest** value credit — the event that +created the account. Deterministic, single-valued, budget-independent, semantically +clean ("who created this wallet"), and one RPC call for most addresses. + +`getSignaturesForAddress` returns **newest-first**, and the only cursors are `before` +(page backwards) and `until` (stop early); there is no forward cursor and `limit` caps +at 1,000 **[V]**. So for an address with fewer than 1,000 lifetime signatures, the +**last element of the first page** is the oldest transaction. + +**The oldest transaction is not the birth edge.** It is where the search for the birth +edge starts. An address routinely appears as a passive participant in someone else's +transaction — an associated-token-account creation, a multisig configuration, a program +call that merely references it — *before* it ever receives value, and in that case its +oldest transaction carries a lamport delta of exactly zero for it. + +So the walk continues **forward** from the oldest until a crediting transaction appears, +bounded by `BIRTH_SCAN_CAP`. Exhausting that budget without finding a credit is +`birth-scan-exhausted`, which is **budget-unresolved**, and it is a separate outcome +from `no-incoming-edge` for a reason that is the whole discipline of §6 in miniature: + +| outcome | claim | about | +|---|---|---| +| `no-incoming-edge` | this address has no funding credit | the chain | +| `birth-scan-exhausted` | we stopped reading before finding one | us | + +> **Failure mode, and this one was ours.** The first implementation here fetched *only* +> the oldest transaction and, if it was not a credit, reported `no-incoming-edge`. Two +> seeds checked by hand had 6,457 and 11,491 lifetime signatures, were plainly funded, +> and were reported as having no funding at all — because one transaction out of eleven +> thousand had a zero delta. The measured cost was a **six-fold** inflation of the +> evidence-unresolved bucket in the population where it bit hardest, and the reason it +> survived review is that the output was indistinguishable from a real finding. +> +> It is recorded here rather than quietly repaired because a document that lists other +> people's failure modes and omits its own is not a method, it is marketing. + +> **Failure mode.** Scanning an address's most recent transactions to find its funder. +> `getSignaturesForAddress` returns newest-first, so taking the first handful is the +> path of least resistance — and funding is by definition among an address's *oldest* +> transactions. For any address with more history than the scan window, this reads the +> wrong end of the record, and it fails **silently**: the output is "unresolved", which +> is indistinguishable from a genuinely unresolvable wallet. The bias falls hardest on +> active wallets, which are the ones a provenance study most needs to resolve. + +**Independent corroboration of the rule.** Dune Spellbook contains +`addresses_events_solana.first_funded_by`, described in its own `schema.yml` as *"Table +showing who first funded each Solana address in SOL"* — i.e. the canonical open +implementation of this question also resolves to the *first* funding event. It sources +`system_program_call_Transfer` and is therefore **native-SOL-only**, inheriting exactly +the blind spot in §4.2. See §7.4 for how we use it (cross-check, not collection path). + +**Secondary rule, for sensitivity:** the **max-value incoming edge within `W`**. Run +both; emit the disagreement rate. + +**Do not use a set-valued class key.** A key built from "the set of hubs reached", under +a per-address funder cap and node budget, makes two identical wallets receive different +keys purely from budget-exhaustion ordering. + +### 4.4 Traversal + +``` +trace(addr, depth): + if depth > DEPTH_MAX: return Unresolved(DepthExceeded) + if terminal(addr): return Terminal(rule, id) # §4.5 + edge = birth_edge(addr) # §4.3 + if edge is None: return Unresolved(NoIncomingEdge) + if edge.value < MIN_EDGE: return Unresolved(BelowThreshold) + return trace(edge.source, depth + 1) +``` + +Single-edge following means no branching factor and no node budget — both of which were +sources of nondeterminism in prior work. Emit the **depth distribution**, not just the +mean. + +### 4.5 Terminal detection (`terminal(addr)`) + +Evaluate in order. **Record which rule fired** — the class label carries it, so every +rule can be ablated in the sensitivity table (§5.5). + +| rule | test | class label | +|---|---|---| +| **R1 program/PDA** | `getAccountInfo(addr).owner ≠ 11111111111111111111111111111111`, or `executable == true` | `program:` | +| **R2 curated anchor** | hit in the Tier-2 anchor set (§5.4) | `entity:` | +| **R3 structural cluster** | member of a fee-payer / sweep cluster of size ≥ 3 (§5.3) | `cluster:` | +| **R4 volume hub** | lifetime signatures ≥ `T_HUB` (measured, bounded — §4.6) **and** account age ≥ 30 d | `busy-unlabelled:` | +| **R5 distributor** | has funded ≥ `F_FANOUT` distinct previously-unseen addresses | `distributor:` | +| — | none fired, budget exhausted | `unresolved(reason, depth, flags)` | + +**R1 is definitional and cheap** — one `getAccountInfo` — and it is what separates +"funded by a Raydium vault" from "funded by a person". Skip it and those two collapse +into one class, which corrupts the distribution the headline is computed over. + +**`busy-unlabelled` is not "an attributable origin". Never call it one.** + +> **Failure mode.** Setting `HUB_THRESHOLD == SIG_LIMIT` — one constant for "how many +> signatures make this a hub" and "how many signatures will we fetch" — is a natural +> collapse, because both answer the same-sounding question. It makes "reaches an +> attributable origin" mean literally "**the address hit the RPC page cap**", which +> admits every DEX program, AMM vault, MEV bot and staking pool as an origin, while +> excluding a genuine CEX withdrawal address with 800 transactions. The two constants +> answer different questions and must be allowed to disagree. +> +> R4 here decouples the hub test from the page cap by measuring the count with bounded +> paging, and requires corroboration from R1/R2/R3/R5 before any class is called an +> entity. + +### 4.6 Pagination handled honestly + +For an address with `N` lifetime signatures, reaching the oldest costs `⌈N/1000⌉` calls. +Page up to `SIG_PAGE_CAP`. If the cap is hit, the address is by construction +high-activity and becomes a **terminal hub candidate** — classified by R1/R2/R3/R5, and +labelled `busy-unlabelled` only if nothing else fires. Set `flags.page_cap_hit = true` +and record the observed signature count as a **lower bound** (`sigs ≥ 10000`), never as +an exact value. + +The page cap becomes a *classification signal with a named rule*. It never becomes a +silent "unresolved". + +Measured page-cap incidence on a naive sample of SOL-credited destinations from one +mainnet block: **4/9 resolved in a single call, 5/9 page-capped** **[M 2026-07-25, +n = 9 — small; treat as an order-of-magnitude estimate]**. Depositor wallets are +typically fresher than raw transfer destinations, so measure and report the rate for the +actual population rather than assuming. + +### 4.7 Parameters (v1) + +| parameter | value | rationale | +|---|---|---| +| `SNAPSHOT_SLOT S` | last finalized slot of a named epoch | pins the ledger; its blockhash seeds the PRNG | +| `WINDOW` | 19,440,000 slots ≈ 90 days = 45 epochs | spans regimes; ≫ one CEX operations cycle | +| `DEPTH_MAX` | 6 | observed mean depth ≈1–2; headroom is cheap under single-edge following | +| `MIN_EDGE_SOL` | 1,000,000 lamports (0.001 SOL) | above the 890,880-lamport rent-exempt floor; excludes dust-spam | +| `MIN_EDGE_SPL` | ≈$1 at a **pinned, committed** price table | prices must be pinned or results drift | +| `SIG_PAGE_CAP` | 10 pages (10,000 signatures) | bounded; flagged, never silent | +| `T_HUB` | 5,000 lifetime sigs **and** age ≥ 30 d | decoupled from the page cap; sweep 1k/5k/20k in sensitivity | +| `F_FANOUT` | 50 distinct fresh fundees | distributor detection | +| `N_BLOCKS` | 1,000 | frame construction (§3.2) | +| `B_BOOTSTRAP` | 10,000 | CIs | +| `scope` | `"sol"` \| `"sol+spl"` | §4.2 — MUST appear in manifest | + +--- + +## 5. Label tiers and multi-resolution reporting + +A single-resolution number is the structural weakness of most provenance metrics: +report one figure and it is unclear whether it describes an adversary who sees raw +addresses or one who sees named entities, and those differ by orders of magnitude. +Reporting the full ladder is what makes the claim falsifiable, so this section is +specified in full. + +### 5.1 Four resolutions, strictly nested + +| L | resolution | derived from | what merges | +|---|---|---|---| +| **L0** | raw address | nothing | nothing. Finest ⇒ **lowest** eff-k ⇒ strongest adversary | +| **L1** | wallet-entity | ATA→owner (from `meta.*TokenBalances.owner`); co-signer clustering; R1 program/PDA detection | a wallet with its token accounts | +| **L2** | named entity | fee-payer clustering + sweep clustering + Tier-2 anchors | Binance hot wallets #3 and #7 → `Binance` | +| **L3** | entity category | hierarchy over L2 | CEX / bridge / DEX-AMM / lending / launchpad / MEV-bot / staking / unlabelled-hub / unresolved | + +Enforce the hierarchy in the type system so `L0 ⊑ L1 ⊑ L2 ⊑ L3` holds by construction. +Then + +``` +eff_k(L0) ≤ eff_k(L1) ≤ eff_k(L2) ≤ eff_k(L3) +``` + +is a theorem, not a hope, and the ladder is a genuine bracket. **Assert it at runtime**; +a violation means the hierarchy was broken and the run must fail. + +**Headline at L2** — the finest two-sided resolution (§1.2). L0/L1 are published as the +strong-adversary bound, L3 as the weak. + +*Not shipped.* The crate classifies each address once, by the R-rules of §5.3, +and reports one ρ. It does not re-label the same sample at four granularities, so +there is no L-rung bracket and no run has ever asserted the monotonicity above. +The published headline carries the resolved/unresolved bracket of §2.6 instead, +which brackets a different uncertainty: how much the members that failed to +resolve could move the number, not how much a coarser labeller would. + +### 5.2 Atoms vs crowds — the two-stage pipeline + +`2^{H(C)}` and `2^{H(X|C)}` are complements, and which is correct depends on whether +class members are mutually anonymizing: + +| the class means | members are | correct metric | +|---|---|---| +| **crowd** — distinct users sharing a funder (all withdrew from one CEX hot wallet) | mutually anonymizing | `2^{H(X\|C)}` (residual) | +| **atom** — one principal operating many addresses | **not** mutually anonymizing | `2^{H(C)}` (the class *is* the secret) | + +Pick wrong and the headline inverts. With `K = 100`: a partition of one class of 91 plus +9 singletons gives `2^{H(C)} = 1.65` and `2^{H(X|C)} = 60.6`; total deanonymization +(100 singletons) gives `2^{H(C)} = 100` and `2^{H(X|C)} = 1.0`. + +**Both kinds occur in our data.** L1 clustering produces **atoms** — those addresses +genuinely are one principal. L2 classes are **crowds** — "funded by Binance" is +thousands of distinct people. Therefore: + +1. **Collapse stage (atoms).** Apply L0→L1 clustering to reduce `K` raw member addresses + to `K'` distinct principals. Emit `K'/K` as the **Sybil deflation factor**: advertised + k is already overstated before provenance enters. All downstream metrics use `K'`. +2. **Partition stage (crowds).** Partition the `K'` principals by L2/L3 provenance class + and compute §2. + +State the assumption in one sentence in the output: *"we treat co-signing / ATA-linked +addresses as a single principal, and same-funder addresses as distinct principals; the +effect of each assumption is reported separately."* + +### 5.3 Tier 0 and Tier 1 — derived, zero license risk + +**Tier 0 — definitional, exact, from chain:** + +- ATA → owner, read directly from `meta.pre/postTokenBalances[i].owner`. +- R1 program/PDA/executable detection via `getAccountInfo`. + +**Tier 1 — structural, derived by our own committed code:** + +- **Fee-payer clustering.** On Solana `accountKeys[0]` is both fee payer and a required + signer. Exchanges pay withdrawal fees from a small set of fee-payer accounts + regardless of which hot wallet sources the value. Clustering on fee payer **collapses + an exchange's hot wallets into one entity for free, with no third-party label list.** + This is the Solana-specific unlock, and it is the merge most easily missed: without + it an exchange appears as a dozen unrelated classes, which inflates the measured + class count and flatters the pool. +- **Co-signer clustering.** A transaction with signers `{A, B}` means one party controls + both. +- **Sweep clustering.** If addresses `A_1 … A_n` each send their full balance to `H`, + they are deposit addresses of `entity(H)` — the Solana analogue of common-input- + ownership clustering. + +All three are deterministic, auditable, reproducible, and MIT because they are our code +and our derived artifact. + +### 5.4 Tier 2 — the shippable anchor set (~418 entries, all MIT-verified) + +| source | license | content | +|---|---|---| +| `solana-foundation/explorer` → `public/verified-programs.json` | MIT | **288** verified programs `{address,name,repoUrl,verifiedAt}` | +| `helius-labs/xray` → `config.ts` | MIT | 106 address→name mappings | +| `ashpoolin/gelato.sh` | MIT | 24 Solana CEX addresses | +| `0xB10C/ofac-sanctioned-digital-currency-addresses` | MIT | `sanctioned_addresses_SOL.json` | + +The specification's record shape, one per address — the anchor set that shipped +lives in `classify.rs` rather than in a file: + +```json +{ + "address": "…", + "entity": "Binance", + "category": "cex", + "source_url": "https://github.com/…", + "source_license": "MIT", + "evidence": "fee payer for withdrawals from 5tzFki… and 9WzDXw…", + "verified_at_slot": 435071454, + "confidence": "high" +} +``` + +The specification called for `verify-labels`, re-checking each anchor against the +chain (e.g. that a claimed exchange fee payer still pays for withdrawals from its +claimed hot wallets), because **an anchor list must be falsifiable, not +asserted**. *This did not ship.* The anchor set is in `classify.rs` and every +entry cites its source, but nothing re-derives it from the chain, so a stale +anchor would go unnoticed. It is the largest unclosed gap in the label ladder +and the reason Tier-2 results are reported beside Tier-1 rather than instead of +them. + +**OFAC.** Use the **XML** feed, not the CSV: the CSV export omits them. +`https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.XML` +(28.9 MB, publish date 2026-07-24, 19,254 records) contains 963 crypto addresses — XBT +524, TRX 195, ETH 96, USDT 93, LTC 14, XMR 11, **SOL 3** **[M 2026-07-25]**. Public +domain under 17 U.S.C. §105. Three addresses is not a labelling strategy; it is a +high-confidence anchor and nothing more. + +### 5.5 Tier 3 — used for sensitivity, never shipped, never in the headline + +Anything whose provenance or license we cannot stand behind. Specifically: + +- **Dune Spellbook `cex_solana.addresses`** — Business Source License 1.1 (Licensor: Dune + Analytics AS; Change Date 2027-03-03 → GPLv3+; "you may not use the Licensed Work for a + Data or Analytics Platform") **[V]**. **Not MIT-compatible; do not vendor.** The Solana + content was added after the MIT→BSL switch, so no MIT snapshot exists; after March 2027 + it is GPL, still incompatible with an MIT crate. It holds 166 rows and is noisy + (contains a hex string, a Bitcoin bech32 address, uppercase-mangled entries). Note also + that Spellbook's `labels_cex.sql` unions **only EVM chains — there is no Solana in + Dune's `labels.cex`**, so "just use Dune's labels" does not survive contact regardless + of licensing. +- **`apostleoffinance/Solana-Forensic-Analysis-Tool` → `solana_cex_labels.csv`** — MIT as + published, 99,999 valid base58 addresses of which 99,986 are `deposit_wallet`, across 19 + exchanges. Deposit-address coverage at that scale is exactly what L2 wants and no free + alternative has it. **But the provenance does not hold up:** the columns are Flipside's + `solana.core.dim_labels` schema verbatim and the row count is exactly 100,000 + header, + the signature of a `LIMIT 100000` export. A third party applied MIT to someone else's + data. Flipside is defunct (see §8.3), so practical risk is low, but "the licensor is + defunct" is not a provenance story that belongs under a headline number. +- **Commercial labels** (Arkham, Nansen, Solscan) — Solscan's ToS forbids redistribution; + the others are proprietary. `solscanofficial/labels` is first-party with 1,169 addresses + but `license: null` **[V]** — worth opening an issue requesting MIT. + +**Tier-3 output is a single sensitivity line**, e.g. *"with a 100k-row third-party +deposit-address set of uncertain provenance, the L2 effective-k moves from X to Y"* — +with the set not redistributed. The *size* of that movement is the most informative +statement we can make about how much a free-label result understates a funded adversary. + +### 5.6 The sensitivity table (specified, not produced) + +No command emits this table. It is kept because it states what a complete report +of this method looks like, and because the gap between it and what +`docs/MEASUREMENT_LOG.md` actually publishes is the honest measure of how far +the implementation got. The ablation rows are the more valuable half: they say +how much of the headline rests on each rule, and nothing in the runs answers +that. + +``` +resolution classes m ρ eff_k_shannon eff_k_minent worst coverage +L0 raw address … … … … … … +L1 wallet-entity … … … … … … +L2 named entity ←hl … … … … … … +L3 category … … … … … … + +ablations (at L2): + −R2 anchors … … … … … … + −R3 clusters … … … … … … + −R4 volume hubs … … … … … … + T_HUB = 1k / 5k / 20k … + Tier-3 labels on … … … … … … + scope = sol / sol+spl … +``` + +Each row also carries the §2.6 bracket. The monotonicity assertion of §5.1 applies down +the first four rows. + +--- + +## 6. Fail-closed failure accounting + +**Principle: an infrastructure limit must never read as an absence of evidence.** + +> **Failure mode.** `.unwrap_or(0)` on a signature count and `.unwrap_or_default()` on a +> signature list. Both are the idiomatic way to keep a traversal running past an error, +> and together they are silently catastrophic: a rate-limited call makes an address look +> like it has *zero* signatures, so it escapes hub detection and is admitted to the +> sample; and it makes a traced address yield no funders, so the walk terminates and the +> member is recorded **unresolved**. +> +> The result is that **an infrastructure failure is laundered into a data point**, and +> in the direction that inflates the unresolved bucket. Given the 429 behaviour measured +> in §8.1, aggressive inter-call pacing against a metered endpoint produces exactly the +> large unresolved bucket that systematic rate limiting would manufacture — which is +> indistinguishable, in the output, from a genuinely hard-to-trace population. +> +> Counting the failures and printing a warning is not sufficient. If the metric function +> never consults the count before reporting, the headline is still unconditioned on +> whether the run worked. Here the count gates the headline (§6) rather than annotating +> it. + +### 6.1 Startup preconditions (hard) + +``` +assert getFirstAvailableBlock() == 0 +assert getTransaction(CANARY_2021_SIG) != null +record endpoint, commitment, and both results in manifest.json +``` + +Refuse to run if either fails. + +Rationale **[M 2026-07-25]**: the Solana Labs public endpoint **is** archival — +`getFirstAvailableBlock = 0`, `getBlock(50,000,000)` OK at blockTime 2020-11-19, and +`getSignaturesForAddress(addr, before=)` returns *older* 2021 signatures, +so the signature index is archival too. But third-party "public" endpoints are not: +PublicNode reports `getFirstAvailableBlock = 434,525,787` against current slot +435,068,692 — a **2.51-day window** — and `getTransaction` on a 2021 signature returns +**`{"result": null}`, not an error**. A collector pointed at it records "transaction not +found" and produces a silently truncated graph that looks like a finding. + +### 6.2 Failure taxonomy + +Every terminal state is one of these and is counted separately. There is no "other". + +| state | meaning | counts toward | +|---|---|---| +| `Terminal(rule, id)` | classified | resolved | +| `Unresolved(NoIncomingEdge)` | genuine: address has no qualifying incoming value edge | unresolved — **evidence** | +| `Unresolved(BelowThreshold)` | incoming edge below `MIN_EDGE` | unresolved — evidence | +| `Unresolved(DepthExceeded)` | hit `DEPTH_MAX` | unresolved — **budget** | +| `Unresolved(PageCapHit)` | hit `SIG_PAGE_CAP` without terminating | unresolved — budget | +| `Unresolved(RpcFailure)` | any RPC error, 429 exhaustion, or timeout | **failure — not evidence** | +| `Unresolved(SplBlindSpot)` | SOL scope, address has token accounts with inflow | unresolved — scope | + +### 6.3 Reporting rules + +1. `Unresolved(RpcFailure)` members are reported on a **separate census line** and are + excluded from the class distribution entirely. They are neither merged nor split. +2. **If the RPC failure rate exceeds 1 %, the run refuses to print a headline.** It + prints the census and exits non-zero. +3. Budget-unresolved members (`DepthExceeded`, `PageCapHit`) enter the §2.6 bracket, not + a class. +4. The manifest records total calls, failures by type, retries, and the observed 429 + rate. +5. Emit `reliable: failures == 0` as a machine-readable field, and never print a + headline number in the same object as `reliable: false`. + +--- + +## 7. Determinism, artifacts, and replay + +### 7.1 Snapshot semantics + +Everything is filtered client-side by `slot ≤ S`. `minContextSlot` is a freshness +guarantee, not a filter **[V]**, so it cannot do this. Finalized history below `S` is +immutable, so the filter is deterministic and a replay run at any later date reproduces +the same set. + +### 7.2 Record / replay cache + +- `MIRROR_RPC=record` — hits the network, appends to the store. +- `MIRROR_RPC=replay` — runs **entirely offline** from the committed store. This is the + default in CI. + +Content-addressed: `data/raw/.json`, with an index mapping +`(method, canonical_params) → sha256`. Canonical params = JSON with sorted keys, no +whitespace. + +*Specified, not shipped.* `rpc.rs` implements the `slot ≤ S` filter, the paging +and the failure taxonomy below; the on-disk cache is not built, because no run +here was large enough to need one. The runs are reproducible from their +committed sample files instead — see §7.3. + +### 7.3 On-disk format + +A `jsonParsed` `getTransaction` is 10–60 KB; 50k of them is ~1.5 GB, which does not +belong in git. **Commit the projection plus the hash of the original.** + +`data/tx/.json` (projection, ~1–3 KB): + +```json +{ + "sig": "…", "slot": 435066575, "tx_index": 530, "block_time": 1784957226, + "err": null, "fee": 5190, + "account_keys": [{"pubkey":"…","signer":true,"writable":true,"source":"transaction"}], + "pre_balances": [], "post_balances": [], + "pre_token_balances": [{"account_index":3,"mint":"…","owner":"…","amount":"…"}], + "post_token_balances": [], + "raw_sha256": "…" +} +``` + +**What shipped.** One file per run rather than the several this section +originally specified, because the runs are small enough that splitting them buys +nothing and costs a reader a join. `mirror collect` writes a single JSON +document with three top-level keys: + +| key | contents | +|---|---| +| `manifest` | §7.5 — endpoint, archival probe, collection time, every threshold, the RPC call count, and the exclusion and ambiguity rates | +| `chains` | one traced funding chain per sampled address: the path, the edges, the terminal class, the rule that fired, and the failure flags | +| `facts` | the sampled address set, in selection order | + +The runs published here are in `data/sample-*.json` — around 200 KB each at +n ≈ 80–100 traced chains, which is small enough to commit whole. `mirror +analyze` reads one of these and computes every metric in §2 from it, so a reader +can rerun the analysis without touching an RPC endpoint, and `mirror compare` +takes two. + +The record/replay design in §7.2 exists so that a bigger collection could ship +its raw responses separately with checksums recorded in-repo. No run here is +large enough to need that. + +### 7.4 `first_funded_by` as cross-check, not collection path + +Dune's `addresses_events_solana.first_funded_by` precomputes our birth edge for every +Solana address. It does **not** become the collection path, for three reasons: + +1. It sources `system_program_call_Transfer` — **native SOL only** — so it inherits the + §4.2 blind spot and cannot cover the USDC/USDT funding path either. +2. Spellbook is BSL-1.1 (§5.5). Querying the hosted table is use, not redistribution, and + is fine; vendoring the model is not. +3. A headline derived from a BSL-licensed SQL model we cannot ship or audit trades away + the one thing that distinguishes this work. + +**Correct use:** derive edges ourselves from RPC, then query `first_funded_by` for the +same sampled addresses and **publish the agreement rate as an external validation +statistic**. Two independently-implemented derivations of the same edge agreeing at X % +is stronger evidence than either alone, and each disagreement is individually +inspectable — it is either our bug or theirs. `solana.account_activity` (one row per +account per transaction, with `balance_change` and `token_balance_owner`) serves the same +cross-check on the SPL side, where `first_funded_by` cannot reach. + +Dune free tier: 2,500 credits/month, 20 credits/MB export (~125 MB/month) **[V]** — enough +for a subsample cross-check, not for a full export. Join gotcha: `labels.*` stores +`address` as VARBINARY while `solana.*` uses base58 VARCHAR; use `from_base58()`. + +**Do not use BigQuery as the substrate.** `bigquery-public-data.crypto_solana_mainnet_us` +has sufficient schema but: documented gaps of 13,602 missing blocks plus 18,879 blocks +with missing or duplicate transactions; `blockchain-etl/solana-etl` last pushed +2024-09-27; recurring silent stalls (froze 2025-03-31; a 6-day lag reported 2025-11-25 +with no vendor response); and a documented case of a single Solana query billing $5,000. +If used at all, partition-filter everything and set `maximum_bytes_billed`. Google's +maintained `goog_blockchain_*` datasets cover nine chains and do not include Solana. + +### 7.5 Manifest + +```json +{ + "tool": "mirror-provenance", "version": "…", "git_commit": "…", + "snapshot_slot": 0, "snapshot_blockhash": "…", "snapshot_block_time": 0, + "window_slots": [0, 0], "realized_mean_slot_ms": 0.0, + "population": "P1_pool_census | P2_population_prior", + "pool_program": "…", + "strata": "epoch", "strata_allocation": [], + "seed_rule": "blockhash(snapshot_slot)", "seed": "…", + "scope": "sol | sol+spl", + "params": { "DEPTH_MAX": 6, "MIN_EDGE_SOL": 1000000, "SIG_PAGE_CAP": 10, + "T_HUB": 5000, "F_FANOUT": 50, "N_BLOCKS": 1000, "B_BOOTSTRAP": 10000 }, + "label_resolution_headline": "L2", + "endpoint": "…", "commitment": "finalized", + "precondition_first_available_block": 0, + "precondition_canary_ok": true, + "rpc_calls": 0, "rpc_failures": {"http_429": 0, "timeout": 0, "jsonrpc_error": 0}, + "reliable": true, + "index_sha256": "…" +} +``` + +What shipped instead is `mirror analyze `: it recomputes every published +number for a run from the committed file and touches no network, so any figure in +`docs/MEASUREMENT_LOG.md` can be re-derived from the artifact beside it. It is not +wired into CI, because the runs are data rather than code — a change to +`metrics.rs` that moved a published number would be caught by the §2.7 reference +vectors, which are. + +--- + +## 8. RPC feasibility + +### 8.1 Public endpoint — documented vs measured + +Documented **[V]**: 100 req/10 s per IP, 40 req/10 s per IP for a single method, 40 +concurrent connections, 100 MB/30 s, and *"not intended for production applications"*. + +Measured against `getSignaturesForAddress` **[M 2026-07-25]**, two independent probes: + +| pacing | result | +|---|---| +| concurrency 8, unpaced | **24/24 HTTP 429** | +| concurrency 4, unpaced | **24/24 HTTP 429** | +| concurrency 1, ~0.45 s gap (2.2 req/s offered) | 9 ok / **15 × 429** (62.5 % failure) | +| 1.0 s gap | 11 ok / 4 × 429 (27 % failure) | +| **2.0 s gap** | **15/15 ok** → 0.41 req/s clean | +| 3.0 s gap | 15/15 ok → 0.28 req/s | +| well-behaved, honoring `Retry-After`, 180 s | 99 ok / 2 × 429 → **0.55 req/s** | + +**Sustainable rate: 0.28–0.55 req/s ≈ 1,000–2,000 req/hour, per IP** — roughly 7–10× +below the documented figure. Concurrency does not help; the cap is per-IP. + +Report the measured range with the pacing method stated. Do not cite the documented +40 req/10 s, which neither probe could reproduce. + +Other findings **[M 2026-07-25]**: `getProgramAccounts` returns HTTP 403 (we do not use +it). The 100 MB/30 s data cap is not binding — at 0.55 req/s the request cap binds ~30× +earlier. + +### 8.2 Provider table + +Call budget: `scope="sol"` ≈ 17k calls at n=1,100 / 30k at n=2,000; +`scope="sol+spl"` ≈ 45k at n=1,100 / 75–90k at n=2,000 (§4.2). + +| provider | free allowance | effective rate | 45k calls | 90k calls | +|---|---|---|---|---| +| Solana Labs public | unmetered | 0.28–0.55 req/s **[M]** | ~23 h | ~45 h | +| **Helius Free** | 1M credits/mo, **1 credit/call**, archival genesis→present **[V]** | 10 rps | **1.3 h** (4.5 % quota) | 2.5 h (9 %) | +| **Alchemy Free** | 30M CU/mo, **40 CU/call** ⇒ 750k calls, full archive **[V]** | 500 CU/s ⇒ 12.5 calls/s | **1.0 h** (6 % quota) | 2.0 h (12 %) | +| QuickNode | 10M credits **one-month trial only**, 30 credits/call ⇒ 333k calls **[V]** | 15 rps | 0.8 h (14 %) | 1.7 h (27 %) | +| dRPC / Ankr keyless | **Solana blocked on free** **[M]** | — | — | — | +| Chainstack / GetBlock | archive **excluded** from free **[V]** | — | — | — | +| Blockdaemon (5 rps) / Shyft (1 rps) | — | unusable | — | — | +| Triton One | **no free tier**; $125 non-refundable minimum **[V]** | — | ~$0.90 at $10/M | — | + +**Recommendation: Alchemy Free or Helius Free for the published run** — 1–2 hours, under +12 % of a monthly allowance, no payment. Retain the public endpoint as the zero-key +reproducibility fallback and the replay cache as the zero-network one. + +### 8.3 Do not build on + +- **Flipside** — defunct. `flipsidecrypto.xyz`, `.com` and `docs.` all 301 to + `edisyl.com`; `api-v2.flipsidecrypto.xyz` fails to connect; `solana.core.dim_labels` no + longer exists; `FlipsideCrypto/solana-models` is 404. Blockchain business sold May 2026. +- **PublicNode for history** — 2.51-day window, silent nulls (§6.1). +- **BigQuery without `maximum_bytes_billed`** (§7.4). +- **SolanaFM** — `api.solana.fm` returns 502 on every endpoint. + +--- + +## 9. Honest-claims analysis + +Our protocol intends to *reduce* this attack's effect. This section states what each +candidate mechanism actually closes, what it leaves open, and the experiment that would +honestly demonstrate it. + +### 9.0 The anti-pattern, stated so it cannot be repeated + +The tautological metric is the defining failure of this genre, and it is worth writing +out because it does not look like cheating while you are writing it. The shape is a +harness that branches on the scenario label *inside* the metric: + +```rust +if scenario == Scenario::MirrorPool { + return vec![0usize; k]; // "Provenance broken: one indistinguishable class." +} +``` + +Everything downstream is then an identity: the posterior is `vec![1.0; k]` and +`2^{H(Uniform(k))} = k`. The favourable column comes out as exactly 16.00 / 32.00 / +64.00 against a ragged baseline, and a unit test pinning that to 1e-6 reads as a +regression guard while actually pinning the tautology in place. The damning detail is +that the data structure typically *contains* the k distinct funding roots — the code +branches on the label and discards the field it should have read. + +It is worth being precise about why this happens, because "they were dishonest" is the +least useful explanation. A harness is built scenario by scenario; the favourable +scenario is stubbed first to get the plumbing running; the stub returns the answer the +author expects; and nothing downstream ever fails, because a tautology cannot fail. + +**Three tells a reader can check in thirty seconds**, and which no honest report produces: + +1. a literal `if scenario == X { return }` inside a metric; +2. every cell in the favourable column being an exact integer while the unfavourable + column is ragged; +3. a unit test asserting the favourable number equals nominal. + +**The structural rule that prevents it.** The adversary MUST be a pure function of the +public transcript and MUST NOT receive the scenario label: + +```rust +fn posterior(transcript: &[PublicRecord], target: ActionId) -> Vec; +``` + +No `Scenario` type may appear anywhere in the metric's call graph — enforce with a module +boundary. Every channel stays **on** and is **measured** to carry ≈0 bits, rather than +being gated off by a boolean. That converts an assumption into a testable property and +catches the case where the batch is not actually uniform. Ship a **negative control**: +inject a partial leak and assert the metric drops below nominal. + +### 9.1 (a) Provenance-homogeneous cohort formation + +*Only settle a round whose members share a provenance class.* + +**Sound: yes.** It is the only one of the three that attacks the **membership-side** +channel. If every member of a settled round shares class `c`, then `μ(a) = c` is constant +across members, `I(X; μ) = 0` within the round, and `eff_k = k_round` exactly. + +**Tautology risk: HIGH.** Measuring effective-k of homogeneous cohorts *with the labeller +that formed them* is `k_round` by definition. That is §9.0's defect written more +elegantly. + +**Leaves open:** + +1. **The round becomes the label.** Round `r` is now "the Binance round". No new + intra-round leakage, but a user acting in two rounds is correlated across time by + class. The intra-round leak is converted into an inter-round linkage. +2. **Minority members can never settle.** Under a heavy-tailed class prior most classes + are singletons — the very members the mechanism was meant to protect cannot form a + cohort at all. +3. **The guarantee is relative to a named labeller, not absolute.** If the adversary's + `λ'` is strictly finer than our `λ_form`, the cohort is not homogeneous and the + guarantee evaporates. Against a funded adversary this is a strong and probably false + assumption. + +**Honest experiment.** Using the measured mainnet class distribution, run formation policy +`π(k_min, W_max)` and report: + +- (i) effective-k under `λ_form` — stating **up front** that this is `k_round` by + construction and is not a finding; +- (ii) **the actual deliverable:** effective-k under a strictly finer, **held-out** + labeller `λ_adv` never used for formation (adversarial-refinement stress test). This + can be `< k_round` and is the real number; +- (iii) the **cost curve:** fraction of deposits settled, median and p95 wait by class, + realized `k_round` distribution vs. the unconstrained pool. + +The headline is a trade curve, not a point. Template — every letter is a placeholder to +be filled from our own measurement, never from anyone else's published figure: +*"at `k_min=8`, `W=24 h`, we settle X % of deposits at median k = Y with +adversarial-refinement effective-k of Z, versus an unconstrained pool at nominal k = A / +effective-k B."* + +### 9.2 (b) Pool-executed actions + +*The action is executed by the pool PDA, so the action's on-chain funding trace is the +pool, identical for all members.* + +**Sound: yes — the strongest of the three**, but it closes a *different* channel from the +one being measured. Fee payer, signer, and the action's immediate funding source all +become the pool PDA. `μ(a)` is constant across members, so `I(X; μ(a)) = 0` and the +backward trace of the action is dead. + +**Tautology risk: MEDIUM.** "All actions share the pool PDA as funder" *is* +near-definitional. It is not a tautology if and only if all three of these hold: + +- the tracer is our general-purpose binary run **unmodified**, same parameters; +- there is a **negative control** — the same N members performing the same action + *without* the pool, traced by the same binary, showing high recovery; +- the report is a **leakage decomposition across all channels**, not the single zero. + +A number that is zero by construction is only interesting standing next to the numbers +that are not. + +**Leaves open:** + +1. **The forward trace.** The action has a beneficiary `D`; `D`'s subsequent behaviour and + consolidation remain observable. (b) closes the backward trace and opens nothing new, + but does nothing about the fate of the proceeds. +2. **Amount and timing.** If a member deposited 7.31 SOL and the pool later sends 7.31 + SOL, the linkage is trivial. **Once (b) is in place, amount/timing is the dominant + channel** — the Tornado lesson. Fixed denominations, batching and delay are required + and the residual must be measured, not assumed. +3. **Account-key co-occurrence.** If the beneficiary ATA is member-owned, the member is + literally in `accountKeys`. Check explicitly. +4. **Who pays the fee.** If the member submits the transaction even though the PDA + executes the action, `accountKeys[0]` *is* the member — total deanonymization. This is + the number-one practical failure mode on Solana, and it is how a sampler harvests + depositors from a pool that looks otherwise sound: the fee payer is in the clear on + every transaction, so no proof system anywhere in the design helps. A relayer or + pool-paid fees is mandatory, and the design must make member-paid submission + **impossible**, not merely discouraged. + +**Honest experiment.** Deploy, execute N actions from N distinct members, run the +unmodified tracer, and report per-channel leakage in bits with `provenance = 0.00` sitting +beside non-zero amount/timing/fee-payer figures, plus the no-pool control. + +### 9.3 (c) Pool-as-funder + +*Wallets funded by the pool all share one provenance class.* + +**Sound: partially, with a sharp ceiling.** `λ(D) = "mirror-pool"` for every pool-funded +wallet, so the provenance partition over pool-funded wallets is a single class. That is +real, and it is the primitive any decoy-based design needs, because the +common-funder graph is what collapses a decoy set: decoys funded from one wallet +share a provenance class with each other and not with the member. + +**But there is an exact bound, and it should be stated as a theorem:** + +> Let `R` be funded by a single pool payout `π`, and let `A_π` be the set of members who +> could have caused `π`. `R`'s provenance is a deterministic function of `π`, so by the +> **data-processing inequality** the adversary's uncertainty about "who ultimately funded +> `R`" cannot exceed their uncertainty about "who caused `π`". Therefore +> +> **`eff_k(R's provenance) ≤ eff_k(the pool's membership set)`.** + +**Pool-as-funder transfers the pool's anonymity downstream; it cannot manufacture +anonymity.** That is a genuinely useful service and an honest deflation of the pitch. + +**Leaves open:** + +1. **(c) is derived from (b), not independent.** The class is "everyone the pool ever + funded" only if payouts are mutually indistinguishable. Distinct amounts and slots + sub-partition it; without fixed denominations, batching and delay, the class collapses + to one member per payout. +2. **Taint concentration.** One shared anonymity class is also one shared *taint* class. + Pool-funded wallets inherit "funded by a mixer", which many exchanges flag. An + adversary can deliberately deposit and withdraw to make the class conspicuous. This + trades deanonymization risk for compliance risk and must be stated. +3. **Membership becomes maximally visible.** "Funded by the privacy pool" is itself highly + informative — it says the recipient wanted privacy. (c) maximizes anonymity *within* + the pool population while maximizing the visibility of *belonging to* it. Against the + question "is this user privacy-seeking?" it increases leakage to 1 bit while decreasing + it on "which user". It is stated here because a method that only reports the + channel it improves is not a method. + +**Tautology risk: MEDIUM-HIGH** if measured as "all pool-funded wallets have class = +pool" (definitional). Not a tautology if measured as: + +- **the ceiling test** — does realized class size equal the pool's effective-k, or does it + collapse toward 1 under amount/timing sub-partitioning? +- **an A/B against a decoy-based design** — run the tracer over the same decoy set + *before* (funded from one wallet) and *after* (pool-funded), and report both + effective-k values from the same binary. Hard to fake and easy to check, because + the only thing that changed between the two numbers is the funding path. + +--- + +## 10. Implementation + +### 10.1 What a reader should check first + +`metrics.rs` is §2 as pure functions over class-size multisets — the §2.7 reference +vectors, the ordering invariant and the negative control, with no RPC, no scenario +parameter and no I/O. It is the file to read first, because every number this +method reports passes through it and nothing in it depends on which chain the +data came from. + +The claim that matters is not a smaller number than anyone else's. It is that a +reader can tell **which direction the error goes**, which is why the unresolved +and failure census (§6) is reported beside every estimate rather than after it. + +### 10.2 Prior art, and where this sits in it + +The funding-provenance channel is **not novel**. Wang et al., *On How Zero-Knowledge Proof +Blockchain Mixers Improve, and Worsen User Privacy*, WWW 2023, Heuristic H4 "Intermediary +Deposit Address" is this heuristic, published for Tornado Cash: + +> "given two addresses `d⁽¹⁾` and `d⁽²⁾`, if all `d⁽¹⁾`'s coins are transferred from +> `d⁽²⁾` and `d⁽²⁾` is a user account, then `Link(d⁽¹⁾, d⁽²⁾) = 1`." + +Measured effect on TC 0.1 ETH (|OAS| = 11,941): H4 alone −4.20 %; all five heuristics +combined −30.68 %. Their metric is Bayes vulnerability `Adv = 1/|SAS|` — identical to our +min-entropy rung. + +Three things here are new, and each is stated so that a reader can check it rather than +take it: + +1. **This is the first such measurement on Solana.** DBLP's full index returns six Solana + blockchain papers — phishing, rug detection, transaction failure, Jito MEV, the NFT + ecosystem, SolRPDS — and **none** on privacy, anonymity, deanonymization, address + clustering, mixers or shielded pools. arXiv full-text agrees. Of the protocols + themselves: Elusiv sunset on 2024-02-29 (its team moved to Arcium and general MPC) and + was never measured; Light Protocol pivoted to ZK Compression; Privacy Cash, launched + 2025-08-27 and the most-used Solana ZK mixer, has never been measured. The search is + reproducible and a counter-example would settle it. +2. **The label ladder is entity-level, with its sensitivity reported.** Prior work, + Wang et al. included, fixes a single resolution and reports the number it produces. +3. **`ρ = 2^{−H(C)}` is a k-independent headline.** Prior work reports a percentage + reduction for one pool at one size, which cannot be compared across pools or + extrapolated to a larger one. + +For scale: SPL Token-2022 confidential transfers hide *amounts and balances only* — sender +and receiver addresses stay public — so the advertised anonymity set is exactly 1 by +construction. Solana's flagship privacy primitive has no anonymity set, and the one +protocol class where an advertised-versus-effective gap could exist had not been studied. + +**Comparanda for our result:** Tutela (arXiv:2201.06811) −37 % ± 15 %; Wang et al. −27.34 % +(ETH) / −46.02 % (BSC); Béres et al. (IEEE DAPPS 2021) anonymity set 400 → ~12 under a +one-day timing assumption; Kappos et al. (USENIX Security 2018, Zcash) −69.1 % **of value, +not of members**; Möser et al. (PoPETs 2018, Monero) ring size 11 → effective 1.16–1.80. + +One paper is deliberately absent from those comparanda. arXiv:2510.09433 (Cristodaro, +Kraner & Tessone, Tornado Cash cross-chain clustering) was **withdrawn** at v3 on +2025-11-18 — *"This paper has been withdrawn by the author due to mistakes in the +references"*. Its numbers still surface in search results and are easy to pick up +second-hand, so the withdrawal is recorded here rather than the paper being silently +left uncited. + +**Terminology.** "Provenance class" is not standard. Define it once against the +established vocabulary: *"we partition the anonymity set into* **provenance classes**, +*the equivalence classes induced by the common-funder relation; these correspond to* +clusters *in the address-clustering literature (Meiklejohn et al., IMC 2013; Victor, FC +2020) and to the blocks of a* partition gain function *in the QIF sense (Alvim et al., +CSF 2012, §III-B-2)."* + +Attribution note: common-input-ownership is **not** Meiklejohn's — they explicitly +disclaim it. The chain is Nakamoto §10 (observation) → Reid & Harrigan 2011 (graph +contraction) → Androulaki et al., FC 2013 (change addresses) → Meiklejohn et al., IMC 2013 +(refined change heuristic, active re-identification, **peel chain** — that coinage is +theirs). For the account model the right citation is **Victor, FC 2020, deposit-address +reuse**, the direct ancestor of what we are doing. + +### 10.3 Structural template + +Huseynov, Shahzaib, Seres & Tapolcai, *A Tattered Cloak of Invisibility: Measuring +Anonymity Loss in Railgun on Ethereum*, arXiv:2606.25926 (June 2026) is the closest +existing work in form: it uses "nominal vs effective", cites both PET 2002 papers, defines +an optimistic upper bound `log2|D(w)|` beside the measured value, and reports a **3.42-bit +median anonymity loss** — a distribution, in bits, not a scalar. Imitate its structure. diff --git a/docs/THREAT_MODEL.md b/docs/THREAT_MODEL.md new file mode 100644 index 00000000..5a915596 --- /dev/null +++ b/docs/THREAT_MODEL.md @@ -0,0 +1,416 @@ +# Threat model + +## What this protects + +An observer sees that an action happened and cannot say which member asked for +it. That is the whole claim, and everything below is either how it is achieved or +where it stops. + +## The adversary + +Passive, global, retrospective, chain-only. They read every transaction ever +made, run any analysis they like over it, and never need to compromise a key or +a machine. They may also label addresses using off-chain knowledge — exchange +deposit addresses, published attributions, their own records. + +They cannot break BN254 discrete log, invert Poseidon or find keccak collisions. + +## What holds + +**Deposit and action are unlinkable through the proof.** A spend proves +membership in the accumulator without naming a leaf. Against an adversary who +sees only the chain, the posterior over which member acted is uniform on the +pool's notes. + +**No member key appears on chain.** Spends are relay-signed and settlements are +settler-signed. A member's wallet never touches the protocol after depositing. + +**A relay cannot alter what was authorised.** The action binding covers the +selector, the target program, the beneficiary, the relay, the relay fee, the +declared account count and the payload, under a domain tag, and is recomputed +on-chain rather than transmitted. + +**A proof is spendable only by the relay it was made for.** The relay in that +binding is read from the account that signed, so a proof cannot be carried by a +key the member did not name. + +**Actions carry one caller.** Every action is invoked by the pool program on a +member's behalf and funded out of the pool's vault, so the on-chain trace of a +stake made through the pool is identical whoever asked for it. Under +`SELECTOR_INVOKE_SIGNED` the vault also signs the call, so the pool can be the +*authority* for an action and not only its funder — with a consequence stated +below. + +**Payouts share a timestamp.** Settlement batches, so arrival time does not +separate members within a batch. + +**Escrow cannot be drained.** The denomination is a pool constant and nullifiers +are spend-once, so `vault ≥ denomination × outstanding` is a function of two +counters that nothing a prover supplies can influence. + +**Nothing can hold a member's funds.** A member spends as their own relay and +settles their own batch after the timeout. No key's absence freezes anything. + +## What does not hold + +### Funding provenance — the open channel + +An adversary can partition members by where their capital came from. Learning a +member's class leaves only that class to guess within, so the anonymity that +survives is the size of the class rather than `k`. + +**This is not closed and cannot be by a better circuit.** No deposit pool +controls where its users' money came from. What we do instead: + +- the *action* side is closed, because actions execute from the pool's vault PDA; +- the *membership* side is measured from real chain data, and the method, the + failure census and the sampling frame are published beside the number. + +`k_floor` bounds program-visible membership only. That is all a program can check. + +### The trusted setup is not secure + +It is *reproducible*, which is a different and lesser property. The seed is +public, so the toxic waste is public, so **proofs are forgeable by anyone who +runs the setup**. + +`mirror verify-setup` is what reproducibility buys. It re-derives the key from the +public seed and this circuit and compares it **element by element** — alpha, beta, +gamma, delta and every IC point — against the key compiled into the program. The +digest it should print is + + b0165d5eac6fe8273b6564c78e8ba548c97e6050ae785e9142de63c81aa905b7 + +Checking the whole key matters, and it is a place where a ceremony verifier is +easy to get subtly wrong: comparing only `delta` — the element a contribution +actually changes — leaves `alpha`, `beta`, `gamma` and the `IC` vector +unchecked, so the verifier would happily certify a key belonging to an entirely +different circuit. This one compares every element. Reproducibility is worth +having and it is not security. + +Production needs a multi-party ceremony. The scaffolding for one is not in this +repository and we do not claim it is. + +### The program is upgradeable + +Whoever holds the upgrade authority can replace the code, including with code +that steals escrow. This is a named trust assumption, not a property. +`solana program set-upgrade-authority --final` removes it and correspondingly +removes the ability to fix anything. + +### The pool's signature is available to every member + +`SELECTOR_INVOKE_SIGNED` hands the vault to the callee as a signer, so the pool +can act as a delegated authority — a stake authority, a governance voter — +rather than only as a source of funds. That is the capability the behavioural +case needs, and it comes with a property worth stating plainly: + +> **Any member can make the pool sign anything, at any target program.** + +That is safe here only because the vault owns nothing but its own lamports, and +those can be debited by this program alone. The signature therefore grants +authority over nothing. It stops being safe the moment the pool is made an +authority over shared state: make the vault the withdraw authority of a stake +account, and any member can withdraw it. Anyone integrating this pool as an +authority is inheriting that, and no on-chain check here can prevent it, because +the payload is opaque by design. + +The obvious attack is tested rather than argued. +`the_pools_signature_cannot_be_turned_against_its_own_vault` points the pool's +own signature at the System Program with a well-formed transfer draining the +vault to an address the member picked. Every ingredient is legitimate — genuine +proof, owned note, offered selector — and this program never inspects the +payload, so nothing here refuses it. The runtime does: +`ExternalAccountLamportSpend`, *instruction spent from the balance of an account +it does not own*. The attack reaches the System Program, which is the proof that +the signature really was granted, and dies on the ownership rule. That rule is +what the safety rests on, which is worth knowing precisely, because it stops +holding the moment the vault acquires a second owner. + +The ordering constraint behind the two selectors is real and was measured rather +than reasoned about. `SELECTOR_INVOKE` funds the beneficiary *before* invoking, +so the target sees the value; the runtime then rejects the vault crossing the CPI +boundary with `UnbalancedInstruction`, because this program mutated its lamports +directly beforehand. `SELECTOR_INVOKE_SIGNED` pays *after*, which leaves the +balance untouched at the moment of the call. Both orderings cannot hold at once, +so the member picks, and the selector is inside the action binding — a settler +cannot obtain the pool's signature for a proof that did not ask for it, and is +refused by name if it tries. + +The constraint is a property of the **batch** and not of the spend, which a live +cluster established and the tests had missed. The runtime objects to any lamport +this program moved anywhere in the same instruction, so a signed call settled +behind three transfers fails even though the same call settled alone succeeds. +Settlement therefore runs every signed call before any payout in the batch. +`a_signed_action_settles_inside_a_batch_of_plain_transfers` is the regression +test, and the shape matters on its own: a signed action that could only settle +alone would have to wait out `SETTLE_TIMEOUT_SECONDS` instead of joining a crowd, +surrendering the shared timestamp that makes the crowd worth standing in. + +`the_pool_signs_an_action_as_its_own_authority` asserts the capability against +the real SPL Memo program, which refuses any account handed to it that has not +signed and names its signers in its logs. The test reads that log for the +vault's own pubkey, so the claim rests on a third-party program's behaviour +rather than on ours. `docs/PROOF.md` carries the same evidence from devnet, read +back off the cluster by the soak rather than asserted by it. + +The devnet run also applies this section rather than restating it. It delegates +a real stake account with the vault as **staker** authority and the operator as +**withdraw** authority, because delegation survives being available to every +member — the worst any of them can do is re-delegate to another validator — and +withdrawal does not. An integrator who gives the vault a withdraw authority has +given it to the whole pool. + +### The action's account list is chosen by the settler + +The proof binds the selector, the target program, the beneficiary, the relay +fee, the payload and **how many** accounts the action takes. It does not bind **which** accounts fill +those slots — settlement is permissionless, so whoever settles picks them. + +For a target whose destination is instruction data this changes nothing. For a +target whose destination is an *account* — an SPL token transfer, for instance — +a settler could point the action at accounts the member did not choose. The +member's own escrow is not at risk, because only this program can debit the +vault, but anything the action itself would move is. + +Binding an account-list commitment into the proof would close this. It is not +implemented, and the claim elsewhere that "a relay cannot redirect an action" is +about the selector, target, fee and payload, not about the account list. + +### The submission phase is public, and it is the weaker half + +Settlement is one transaction, one signer and one timestamp, and that is the +property the design is built around. It is also only half of what an observer +sees, and the other half deserves stating plainly rather than being left implicit +in a claim carefully scoped to the settled transaction. + +`submit_spend` is **one transaction per member**, at a moment of the relay's +choosing, and it publishes in cleartext the beneficiary, the selector, the target +program, the payload and the fee — everything about the action except who asked +for it. Three things follow, and all three are real: + +- **Timing.** A relay that submits immediately on request leaks when the member + asked. This is relay policy, not a protocol guarantee. +- **Ordering.** Settlement executes the batch in the order the settler passes the + records, and nothing shuffles them. A settler who preserves submission order + makes position in the settled batch a restatement of submission order, and + arrival order is public. +- **The signer.** The relay signs, so `accountKeys[0]` of a `submit_spend` is the + relay. If a member relays for themselves — which the protocol permits, and + which `USAGE.md` documents as the escape hatch — that transaction names them + beside the action they are about to take, and the settlement's anonymity is + worth nothing to them. + +The last one is the sharpest, because it is not a subtle statistical channel: it +is one public transaction that ends the question. **The tool refuses the version +of this mistake it can detect** — a relay key that has also deposited into the +pool — and cannot detect the rest, because nothing on chain distinguishes a +member's own fresh key from a genuine third-party relay. Funding is where it +usually goes wrong: a relay topped up from the depositing wallet leads back in +one hop. + +So the honest statement of what the pool provides is narrower than "one signer, +therefore anonymous". It is: **given that the member never signs and never funds +their own relay, the settled action cannot be attributed to them.** The first +clause is a discipline the member keeps, not a property the program enforces, and +a threat model that omits it is describing a smaller adversary than the one that +exists. + +### The relay market is attackable even though the relay's fee is not + +Everything in a `submit_spend` travels in clear text, which the section above +treats as a disclosure problem. It is also a transferability problem, and that +half is worth stating on its own because the fix is recent and the reasoning +behind it is easy to get backwards. + +A bystander watching an unlanded `submit_spend` can copy the proof and every +field around it. Until the relay joined the action binding, they could name +themselves as the relay and land it first: the recomputed binding was unchanged, +the pairing succeeded, and the fee settled to them. The member's payout was never +reachable — the beneficiary and the amount have always been bound — so this was +theft from the relay, not from the member. + +**It was never a profitable theft, and that is the part worth being precise +about.** Whoever lands the transaction funds the spend record's rent, and that +record is never closed, because it *is* the replay guard. At the fee levels this +repository has actually used, an attacker sank roughly twenty times what they +collected. Anyone presenting this as a drain would be overstating it. + +The reason to close it anyway is that **an attacker does not need to be paid to +be effective**. Front-running every spend costs them rent each time and denies +every relay their fee. A relay whose fee can be sniped at will is a relay nobody +runs, and a pool with no relays is a pool where members submit from their own +funded wallets — which is precisely the disclosure the section above calls the +sharpest one available. The attack never touched the cryptography. It made the +honest path uneconomic and let the members deanonymise themselves. + +So the relay is now read from the account that signed and folded into the +binding, and a proof is spendable only by the relay it was made for. What remains +open is unchanged and stated where it belongs: a member who relays for themselves +still names themselves, and no binding can prevent that. + +### A large settlement publishes its participant list early + +A batch that outgrows the 1232-byte packet settles through an address lookup +table, and that table is an account: created by the settler, holding every +address the settlement is about to touch, and **on chain before the settlement +lands**. It discloses nothing the settlement does not disclose a slot later — the +same records, beneficiaries and relays, in the same order — but it discloses it +*earlier*, and while it exists it is a durable, queryable index of who settled +together, tied to the key that created it. + +Two consequences worth stating rather than discovering: + +- **Timing.** An observer watching the lookup table program sees the batch + assembling before it executes. That is a warning, not a linkage: the addresses + in the table are the same public addresses the settlement names. +- **Persistence.** A table left behind outlives the transaction that needed it, + and one per batch accumulates into a permanent record of every cohort a pool + ever settled. + +So settlement deactivates the table immediately and `mirror close-table` removes +it once the runtime's cooldown has passed, which returns the rent and — the +reason that matters here — deletes the list. The cooldown means there is a window +in which the table exists and cannot yet be closed; nothing shortens it. + +Legacy settlement publishes no table at all, which is why it stays the default +for any batch that fits without one. + +### The relay fee is a payout amount, and a mixed batch is a partitioned one + +The denomination is uniform by construction, but a member receives +`denomination - relay_fee`, and that figure lands in a public account balance. So +the fee is not a private arrangement between a member and their relay: it is a +number an observer reads off the settlement. + +A batch whose members paid different fees settles into visibly different payouts, +and an observer partitions it by value. No proof is broken and no secret is +learned — the balances are simply different, and the crowd rule, the shared +timestamp and the single settling signature are all defeated by arithmetic. + +**The program refuses such a batch** (`FeeNotUniform`, code 25). The check is in +settlement rather than submission because it is a property of the batch and not +of any record: a member may agree any fee with their relay, and settles with the +members who agreed the same one. `mirror settle` groups pending spends by fee and +settles the largest group. + +What this does *not* fix: a fee that is unusual is still a small crowd. A member +who negotiates a fee nobody else pays settles alone, or with the few who match — +and a batch of one is not an anonymity set whatever the program allows. The +uniform-fee rule turns a silent partition into a visible one; choosing a common +fee is still the member's job, and a pool whose members all pay the tool's +default is better off than one where they do not. + +### Amounts are public + +Fixed denominations mean the amount is a pool constant rather than a secret. A +member who needs an unusual amount is identifiable by the pool they chose. There +is no confidential-value layer here. + +### The crowd rule is threshold-or-timeout, and the timeout side has no floor + +A batch settles if it carries `k_floor` spends **or** if every spend in it has +waited out `SETTLE_TIMEOUT_SECONDS` (an hour). The second clause has no minimum +size. **A batch of one settles, and executes.** + +This is the standard trade in mix design, and the standard analysis of it is +Serjantov, Dingledine and Syverson, *From a Trickle to a Flood: Active Attacks on +Several Mix Types* (Information Hiding 2002), which examines +threshold, timed, and threshold-or-timed batching and finds the disjunction +inherits the weakness of its weaker half. The argument for our case does not need +the paper, though — it follows from the code: + +- **Settlement is permissionless**, so an adversary may be the settler. They + choose the moment and the composition of every batch they send. +- A spend submitted at `t` becomes settleable **alone** at `t + 3600`, + regardless of what else is pending. +- So for any member whose spend outlives the timeout without company, an + adversary can settle it by itself, and that member's anonymity set is one. + +They do not even have to be adversarial. On a quiet pool this is simply what +happens, and nothing in the program prevents it: `k_floor` bounds a batch that +settles *by crowd* and bounds nothing about a batch that settles by clock. + +**Why it is still the right trade.** The alternative is an unconditional floor, +and an unconditional floor means a member's escrow is held hostage to the arrival +of strangers. A pool that never reaches `k_floor` again would freeze every note +in it, permanently, with no authority able to release them — the program has no +such authority by design. Given the choice between "your action may be +attributable" and "your money may be unrecoverable", this design takes the first +and says so, rather than advertising a floor it would have to break to keep +anyone solvent. + +**What a member can do about it.** The protection is traffic, not the program. +Submitting into a pool that already has spends pending is what buys a crowd; +submitting into an empty one and waiting is what does not. The tool reports the +pending count before it settles and says plainly when a batch is below the floor, +because a member who is about to settle alone should know that is what they are +doing. What the tool cannot do is manufacture other members. + +**What would fix it properly**, and is not built: a batch that fails to reach the +floor could *refund* the member rather than execute — the escape hatch would then +cost the member their action instead of their anonymity. That is a different +protocol, with a different nullifier lifecycle, and it is named here because it +is the honest answer to this section rather than left for a reader to think of. + +### Small crowds + +`k_floor` is enforced against notes in the tree, and a pool whose deposits are +mostly Sybils of one actor has a large nominal `k` and a small real one. + +Nothing in this program prevents that, and the entry fee that was meant to price +it does not exist: it would have accrued on the pool account with no instruction +able to pay it out, so pool creation refuses any nonzero value. What remains as a +cost to a Sybil is the denomination itself, which is recoverable, plus rent and +fees, which are not — a weak deterrent, stated as one. + +The provenance measurement is the honest reading of what a set is actually worth, +and it is the reason this limitation is measurable rather than merely admitted. + +### Not audited + +No external review. The end-to-end suite runs against the compiled program on a +real SVM, and every negative case but two carries this program's own error code. +The two exceptions are caught by the runtime before this program can rule on +them, and they are marked as such rather than counted as our checks: a truncated +account list, and the attempt to turn the pool's signature against its own vault, +which dies on the System Program's ownership rule. That is evidence of behaviour +and not a substitute for an audit. + +## Deliberate non-goals + +**Hiding funds** — with a precision this deserves, because the protocol plainly +touches value and a flat "not a mixer" would be too convenient. + +What is here: a fixed-denomination escrow whose purpose is to make members +interchangeable and to fund the actions they authorise. Selector one invokes an +arbitrary program, which is the point of the design; selector zero is a plain +transfer, kept because expressing "pay this account" should not require a target +program. That selector does mean a member can deposit a denomination and have it +paid to an address of their choosing, unlinked to the deposit. Calling that +anything other than what it is would be dishonest. + +What is *not* here, and is what the word "mixer" usually means: confidential +amounts, a value-shielding layer, or any attempt to obscure how much moved. +Denominations are pool constants and public. Nothing hides quantity. + +And what the design is *for* is the behavioural case. The measurement, the +crowd rule, the shared settlement timestamp and the CPI dispatch all exist to +make a stake or a vote unattributable. A design that wanted a value mixer +would not need any of them. + +**Defeating an adversary with off-chain data.** Someone who knows a member +deposited — because they watched them do it, or because the member told them — +is not in scope. The proof hides which member acted, not that a given person is +a member. + +**Compute-optimal proving.** The circuit is three public inputs at about 91k CU +because that is what binding everything that matters costs. It has not been +tuned further. + +## Claim language + +Words this project does not use about itself: *anonymous*, *untraceable*, +*unlinkable* without a named adversary and a stated population. Every quantitative +claim names the data it came from, and `docs/MEASUREMENT_LOG.md` records the runs +that produced nothing alongside the ones that did. diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 00000000..ee58ac3e --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,424 @@ +# Using the pool + +Every command below was run against devnet to produce the output shown. Nothing +here is illustrative. + +The tool needs no server, no indexer and no account with anybody. It reads what +it needs from the chain each time, which is why a member can act from a machine +that has never seen this pool before, carrying nothing but their note file. + +``` +cargo build --release # the binary is target/release/mirror +``` + +Every command defaults to `--url https://api.devnet.solana.com` and to the Solana +CLI's own keypair at `~/.config/solana/id.json`, so the common case needs neither +flag. + +## The shape of it + +``` +note-new → deposit → ( wait for a crowd ) → spend → settle +``` + +A note is a secret you generate locally. Depositing it puts its *commitment* into +the pool's tree and escrows the denomination. Later you prove you own some note +in that tree — without saying which — and the pool acts. Settlement executes +everybody's action together. + +## 1. A pool + +One pool per denomination, globally, and anybody can create one. Splitting +deposits of the same size across two pools splits the anonymity set, and a split +set is worse for everyone in it. + +``` +$ mirror init-pool --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa \ + --denomination 31000001 --k-floor 2 +pool DQ17r5reCu5P4efUzHQZq7Ye6D6vt72ThxatNdLBqcKt +vault 81odk482H6VpRQMk8tQaoThYr2ffJtugcJXjmKX2faco +signature 3Tbf4zMGDHW89bi3F7yhaGMAB6RqveDi5WTJAYKEe3Zr2F8eTAeT8zSTp6V3B4kWE4ZSXmpMdxpx6UayvdsiNNiw +``` + +`--k-floor` is the number of notes the pool must hold before it will act at all. +It bounds *program-visible* membership, which is all a program can check — see +`THREAT_MODEL.md` for what it does not bound. + +## 2. A note + +``` +$ mirror note-new --denomination 31000001 --out m1.json +wrote m1.json + denomination 31000001 + commitment 1ca8f208a35a6327c7871ee6d38268527260f53299c21b25133b32178989701c + +This file is the note. Treat it exactly as you would a keypair: +anyone holding it can spend the deposit, and losing it loses the +deposit with no way back. + +Next: mirror deposit --note m1.json +``` + +The file is plain JSON and unencrypted, deliberately. Encrypting it would put a +password between you and your funds and imply a security property this tool +cannot deliver by itself. Back it up the way you back up a keypair. + +It will not overwrite an existing note file, and there is no `--force`: an +overwrite here destroys a deposit. + +## 3. Deposit + +``` +$ mirror deposit --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa --note m1.json +deposited 31000001 lamports into DQ17r5reCu5P4efUzHQZq7Ye6D6vt72ThxatNdLBqcKt +leaf 0 +signature JpCxFU4ipaBap15AWRxNVFoy8rskWZnUTFoBTLx1JBs5V2TKDCx7HhhzQ4AtYxL46yvfS8U1yXzSVLNg2au89hS +``` + +The deposit is public and it is signed by you. That is fine and unavoidable — +what the pool hides is not that you joined, but which member later acted. + +The escrowed amount is read from the pool, never from your instruction, so a +deposit cannot claim a size the pool did not set. + +## 4. Check the tree — optional, and worth doing once + +``` +$ mirror tree --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa --denomination 31000001 +pool DQ17r5reCu5P4efUzHQZq7Ye6D6vt72ThxatNdLBqcKt +vault 81odk482H6VpRQMk8tQaoThYr2ffJtugcJXjmKX2faco +denomination 31000001 +k floor 2 +notes 2 deposited, 0 settled, 2 outstanding + +rebuilding the accumulator from chain history: + 3 transactions touched this pool + + leaves recovered 2 + pool reports 2 + rebuilt root 0c77cb909067c1a57811be8c05237aff2715c65c6250fdde764ed768096cd732 + on-chain root 0c77cb909067c1a57811be8c05237aff2715c65c6250fdde764ed768096cd732 + + the rebuilt tree matches the chain — proofs built from it will verify +``` + +This is the piece the rest stands on. The program stores only the accumulator's +*frontier* — one node per level — which is enough to append a leaf and produce a +root, and not enough to prove any particular leaf is in the tree. The leaves are +not lost: every commitment was an argument to a `Deposit` instruction, so the +whole set is in the transaction history in insertion order. + +Rebuilding it and finding the same root the program holds proves the recovered +set is complete and correctly ordered, which is exactly the precondition a +membership proof needs. `spend` does this rebuild itself; this command just lets +you watch it. + +## 5. Spend + +**The relay signs, never you.** A member who pays their own fee signs with their +own wallet, and `accountKeys[0]` is then the member — which publishes the link +the pool exists to break. Use a key that is not your wallet and has no history +with it. + +The tool refuses outright if the relay you name has also deposited into this +pool, because that is the same mistake wearing a different key: the deposit and +the spend would both carry it, an observer joins them by reading two public +transactions, and the proof stays sound while protecting nothing. + +Funding the relay matters too, and no tool can check it for you. A relay topped +up from the wallet that deposited leads back to it in one hop. + +``` +$ mirror spend --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa \ + --note m1.json --to BQ6piLqJD4CWn4V3VyDBh3RpU1FtsPh63P9y4wtwBxJg \ + --relay relay.json --relay-fee 100000 +rebuilding the accumulator so this note can be proved a member: + 3 transactions touched this pool + this note is leaf 0 of 2 +deriving the proving key from the published seed (this takes a moment) +proving membership + +submitted. The note is spent and the action is recorded. + nullifier 02218a1c2f8fe73a88e856ee9cf3c7e01508107490dca23a56af54166566d54e + record 59jcYijM67FYybt6MH36CU9YUMqQQ7Q5Lg6JiTXRXxfz + signature d5Y6CxbrNxu74u88AGT5NU1KqfLb4JgjtBXzT2TyXyvAGqJq2qgf5NftQwKoAH5TfHdh3fTQcbjkwudSDX8tj7U + +Nothing has been paid out yet — settlement executes the batch, which is +what gives every member's action one timestamp. Run `mirror settle`, or +wait for anyone else to. +``` + +The relay fee comes *out of* the denomination, never in addition to it, and a fee +at or above the denomination is refused on-chain. + +**Pay what everyone else pays.** You receive `denomination − relay_fee`, and that +number is public. A batch whose members paid different fees settles into visibly +different amounts, so an observer partitions it by value without breaking +anything — which is why the program refuses a mixed batch outright and `settle` +groups pending spends by fee. A fee nobody else pays is a crowd of one, and no +rule in the program can fix that for you. + +### Doing something other than paying + +The interesting case is not moving lamports. `--invoke` calls any program with +any payload: + +``` +mirror spend ... --invoke --payload --accounts +``` + +`--accounts` is how many accounts the call takes, and it is bound into the proof +so a settler cannot add or drop one. Which accounts fill those slots is chosen at +settlement — a real limit, stated in `THREAT_MODEL.md`. + +Add `--pool-signs` to hand the pool's vault to the callee as a **signer**, so the +pool acts as your authority rather than only as your funder. That is what a stake +delegation or a governance vote needs and a payment does not; `PROOF.md` has a +real stake delegation done this way on devnet. + +A word on what the proof does and does not promise here. It binds the selector, +the target program, the beneficiary, the fee, the payload and the **number** of +accounts — not which accounts fill the slots. For `DelegateStake` the validator +lives in an account slot rather than in the payload, so *the settler chooses your +validator*, and nothing on chain records which one you asked for. Check the +result: read the stake account back and see who it backs. `CROWD.md` is a devnet +run of six members delegating to six different validators that does exactly +that, for every member. + +## 6. Settle + +Permissionless. Anyone can settle, so no operator's absence can strand you, and +you can always settle your own batch. + +Below the crowd floor it tells you what it is waiting for rather than failing +with an error code: + +``` +$ mirror settle --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa --denomination 31000001 +looking for spends waiting to settle: + 4 transactions touched this pool + + 1 spend(s) pending, and this pool's floor is 2. + A batch below the floor may settle once every spend in it has waited 3600s; + the youngest has waited 16s, so 3584s remain. + + This is a liveness guarantee rather than a restriction: nobody can + hold a member's funds waiting for a crowd that never arrives. +``` + +Once the crowd is there: + +``` +$ mirror settle --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa --denomination 31000001 +looking for spends waiting to settle: + 5 transactions touched this pool + +settled 2 spends in one transaction + signature 4EA7SszoGBWC1EKzgGn8XdLWvhMiWxp6v6Gbcmd7czzn7LfiUmoBvKwAJsM3XPt4Y2abm5P85M7w939ftRTvi6XC + +Every payout in that batch shares one timestamp and one ordering, which +is what stops arrival time from telling the members apart. +``` + +Both beneficiaries received `31000001 − 100000 = 30900001` lamports, in one +transaction, at one timestamp. + +`settle` executes plain transfers on its own. A pending CPI action is left alone +and reported, because the record binds *how many* accounts the call takes and +never *which*, so no tool can infer the account list its callee expects. + +## 7. Proving it was you — to one person, later, if you want to + +Anonymity that cannot be given up on purpose is a liability. At some point a +member may need to show an exchange, an accountant or a counterparty that a +particular action was theirs — and the usual answer to that is a viewing key or +an auditor, which means a standing capability somebody else holds. + +There is none here. A disclosure is a **file you hand to one person you chose**: + +``` +mirror disclose --program --note m1.json --out disclosure.json +``` + +Give them the file. They check it against the chain, and nothing in it is taken +on trust: + +``` +$ mirror disclose-verify --file disclosure.json +rebuilding the pool from chain history: + 14 transactions touched this pool + +disclosure for leaf 0 of Cqg4gj4zwHZGfp1P2v6j6pB4dLbWgsL1vJB7YkjsFWAK + nullifier 25609bc4fe513e50fcc8874e1dbe8d7a556ff8b95724c606baa429aa6fdcaee2 + record 4beEKJNuU4pHM3rUqLAm8ocVkf7kzRdLP2XMECCMwy77 + + the secrets recompute to the commitment PASS + H3(k, r, denom_tag) = 13833afd2062da2c5a0217dd53b14c8118a10ded98d84f8af71853383509f2fd + the pool matches the denomination PASS + Cqg4gj4zwHZGfp1P2v6j6pB4dLbWgsL1vJB7YkjsFWAK is the pool for 43000007 lamports + the commitment is the stated leaf PASS + leaf 0 of 6 is 13833afd2062da2c5a0217dd53b14c8118a10ded98d84f8af71853383509f2fd + the rebuilt root matches the chain PASS + 6 leaves rebuild to 039bbb3012b6ff6554141437df6da9c12db6a5333c3c38e00146c85df87bfe08 + the secrets recompute to the nullifier PASS + H1(k) = 25609bc4fe513e50fcc8874e1dbe8d7a556ff8b95724c606baa429aa6fdcaee2 + the record address is the nullifier's PDA PASS + 4beEKJNuU4pHM3rUqLAm8ocVkf7kzRdLP2XMECCMwy77 is the record for H1(k) + the spend record exists on chain PASS + the spend record is settled PASS + settled + the spend record belongs to this pool PASS + the record matches the claimed action PASS + selector 2 paid 5P9AHY2tGoQ9xedLeyvC5WsU4FXxxH8LgtC2kzRUMZtT, fee 200000, 4 payload byte(s) + +VERIFIED. Every value in this file was recomputed from the secrets or read off the +cluster. The holder of this note is whoever asked the pool for the action above. +``` + +That one is a real disclosure of a **stake delegation** — selector 2, the +pool-signed action from `CROWD.md` — proved by its member after the fact. + +Every check is reported separately and a check that cannot be completed is a +failure, never a silence. A file whose stated nullifier disagrees with what your +secrets produce fails on that check while the rest still pass, which tells the +verifier exactly what was tampered with rather than merely that something was. + +**It only works after settlement, and the tool refuses before it.** The disclosure +carries the note's secrets, and before the note is spent those secrets *are* the +money — anyone holding them can prove membership and send the payout wherever +they like. After the nullifier is burnt they authorise nothing, and all that is +left in them is the ability to demonstrate the link. That is the whole difference +between a disclosure and handing over a deposit. + +**Disclosing costs the other members, and the tool says so before you do it.** +Proving one action was yours removes you as a candidate for every other action in +the pool. If that would leave the remaining set below the pool's floor, the +command refuses and tells you what it would cost: + +``` +Error: REFUSING: this pool has settled 6 spend(s) and its floor is 6. Naming one +of them as yours leaves 5 unattributed, which is below the floor. + +The people that costs are not you. Every settled action is a candidate for every +member; removing one narrows the guess for all the rest, and they did not agree +to it and will not be told. + +If you have weighed that and still want to, pass --i-accept-the-cost-to-others. +Nothing here can stop you disclosing out-of-band anyway — the secrets are yours. +This exists so the cost is visible at the moment it is paid. +``` + +The gate is advisory by construction, and the message says so rather than +pretending otherwise. + +## How many members settle together + +It depends on what the members are doing: + +| the batch | members per settlement | +|---|---| +| plain payments | 10 | +| stake delegations, everyone to the same validator | 7 | +| stake delegations, a different validator each | 6 | + +Those are the numbers for a **legacy** transaction, which names every account by +its full 32 bytes. That is what you get with no setup at all, and the 1232-byte +packet is what stops it. + +**Bigger batches settle through a lookup table, and `settle` does it for you.** +When a batch will not fit legacy, the command publishes a table naming the +accounts, settles a v0 transaction that refers to them by one byte each, and +takes the table back down: + +``` +$ mirror settle --program 8H3cYoiAA9LM36cyPr4UEv38dhHasSu2XPSdiBfyrLEa --denomination 5000003 +looking for spends waiting to settle: + 49 transactions touched this pool + + 24 spend(s) pending; settling 20 of them, which is what fits under the + 64-account lock limit. Run this again for the rest — the cost is a + second timestamp, which is a real cost to the anonymity of both halves. + + 20 spends do not fit a legacy transaction: 2218 bytes, 986 over the 1232-byte packet. + Settling through a lookup table instead. + lookup table ia9oUXMgArZhGPWyETroygf6bvULHQWBodgpwB43gQ8 + 62 addresses published + settlement is 332 bytes of 1232, one signature + table deactivated. Close it after ~513 slots to reclaim the rent and remove + the published address list: + mirror close-table --table ia9oUXMgArZhGPWyETroygf6bvULHQWBodgpwB43gQ8 + +settled 20 spends in one transaction + signature enxa9fztmzEHMLsvhfzJwFVRsNWha7WiSEUEeNn7UPk8KAdpnWQDzEHarGL8d4ckyBvtWrEGCkuvgW7UFgFAHzp +``` + +**The packet stops mattering entirely** — twenty members weigh 332 of 1232 +bytes. What binds instead is the number of accounts one transaction may lock: +three per member plus three for the pool, so twenty members sit at exactly 64. +`settle` counts them and defers the rest rather than building a transaction the +cluster refuses. + +**Close the table afterwards.** It costs rent, but the reason to close it is what +it is while it exists: a public, durable account listing every address the +settlement touched, published before the settlement landed. Leaving one behind +per batch builds a permanent on-chain index of who settled together. + +``` +$ mirror close-table --table ia9oUXMgArZhGPWyETroygf6bvULHQWBodgpwB43gQ8 +closed ia9oUXMgArZhGPWyETroygf6bvULHQWBodgpwB43gQ8 + signature 1x3Uv5k8j8MnfWsD6rTksUkV9Mcgwvg6PjfTDJXFHgQ9J6CQ7wih51ANeBtaNXCDktstjBvupR2b5aHZPnoYuFp + reclaimed 15084280 lamports, and the published address list is gone +``` + +**Do not set a crowd floor above what one settlement can carry.** `init-pool` +refuses it now, because a pool whose floor exceeds the per-transaction ceiling +can never meet it by crowd and can only settle through the hour-long timeout — +and the floor is fixed at creation, so the fix is a different pool. + +For a legacy batch the limit is the packet in every row. Each spend brings +accounts nobody else shares — its record, its beneficiary, its relay — so a +payment costs about 99 bytes per member, and a call costs more because it also +names its callee and the callee's accounts. + +**What you ask for changes how many people you can hide among.** A member who +delegates to their own choice of validator adds a vote account nobody else in +the batch names, and the batch loses a member. That is worth knowing before you +choose: a crowd that converges on one validator is both larger and less +distinguishable than a crowd that does not. + +For payments compute is nowhere near binding — ten settle in 19,545 of the +200,000 compute units a single instruction gets, and twenty through a lookup +table in 35,895. For delegations it is much closer: on devnet the six-member +divergent batch used 142,856. In a *legacy* transaction there is no way out of +that, because the two limits shut together — asking for a larger compute budget +costs a second instruction worth 40 bytes and the batch has 38 to spare. Through +a table the bytes are there; how many delegations then fit is unmeasured, and +`CROWD.md` says so rather than assuming. + +These are ceilings per *transaction*, not per epoch. Settlement is +permissionless, so a pool with thirty pending spends settles in three batches; +the cost is three timestamps rather than one, which is a real cost to the +anonymity and the reason the numbers are worth knowing. + +`ten_spends_fit_in_one_settlement_and_the_packet_is_what_stops_the_eleventh` and +`every_account_an_action_names_costs_the_batch_a_member` pin them, and +`CROWD.md` is a live devnet settlement of the six-member divergent case. + +## Escaping without a relay + +There is no `self-spend` command because none is needed. Relay for yourself with +`--relay-fee 0` and settle your own batch once the timeout passes. The cost is +the expected one — your own wallet signs, so you give up the anonymity the relay +path provides. It is an escape hatch, not a mode of operation, and it exists so +that nothing in the protocol can hold your escrow. + +## What can go wrong + +| | | +|---|---| +| `no pool exists at …` | Nobody has created that denomination yet. `init-pool` does, permissionlessly. | +| `this note is not a leaf of the pool` | The note was never deposited, or it belongs to a different denomination. | +| `this note file is inconsistent` | The file was edited or corrupted. Spending it would burn a nullifier against a leaf that is not in the tree, so it is refused first. | +| `the rebuilt root does not match the pool's` | The endpoint's history is incomplete — usually pruning. `mirror check-endpoint` tests for exactly that. | +| `this pool holds N notes and its floor is M` | The pool refuses to act below its floor. Wait for more members, or use a pool with a floor you can meet. | +| `the relay … has also deposited into this pool` | The worst mistake available, refused rather than warned about. The relay signs the spend, so a key that also signed a deposit links the two and this action's anonymity set collapses to one. Use a key with no history with the pool. | diff --git a/docs/a-behavioural-anonymity-set-for-solana.pdf b/docs/a-behavioural-anonymity-set-for-solana.pdf new file mode 100644 index 00000000..b334477d Binary files /dev/null and b/docs/a-behavioural-anonymity-set-for-solana.pdf differ diff --git a/programs/mirror-pool/Cargo.toml b/programs/mirror-pool/Cargo.toml new file mode 100644 index 00000000..a5997ae4 --- /dev/null +++ b/programs/mirror-pool/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "mirror-pool-program" +version.workspace = true +edition.workspace = true +# Not published to crates.io: these crates are built from this repository, and a +# registry copy would be a second source of truth for the same code. +publish = false +license.workspace = true + +[lib] +crate-type = ["cdylib", "lib"] + +[dependencies] +mirror-core.workspace = true +solana-program.workspace = true +solana-system-interface.workspace = true +groth16-solana.workspace = true + +[features] +no-entrypoint = [] + +[dev-dependencies] +mirror-circuit.workspace = true +litesvm.workspace = true +solana-keypair.workspace = true +solana-signer.workspace = true +solana-transaction.workspace = true +solana-message.workspace = true +ark-std.workspace = true +sha2.workspace = true +hex.workspace = true +solana-system-interface.workspace = true + +# The entrypoint! macro emits these; declaring them keeps `-D warnings` honest +# rather than silencing the lint wholesale. +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(target_os, values("solana"))', + 'cfg(feature, values("custom-heap", "custom-panic"))', +] diff --git a/programs/mirror-pool/src/error.rs b/programs/mirror-pool/src/error.rs new file mode 100644 index 00000000..dc90ce12 --- /dev/null +++ b/programs/mirror-pool/src/error.rs @@ -0,0 +1,100 @@ +//! Program errors. +//! +//! Every variant is a distinct code so that a failing transaction says which +//! invariant it violated. Devnet evidence records these codes alongside the +//! signature, which is what makes a negative test checkable by a third party +//! rather than a claim in a README. + +use solana_program::program_error::ProgramError; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum MirrorProgramError { + /// The instruction data was empty, truncated, or carried an unknown tag. + MalformedInstruction = 1, + /// An account was not the PDA the program derives for that role. + InvalidPda = 2, + /// A required signature was absent. + MissingSignature = 3, + /// An account was owned by the wrong program. + InvalidOwner = 4, + /// The pool account has the wrong length or an unrecognised version. + InvalidPoolAccount = 5, + /// The pool is already initialised. + AlreadyInitialised = 6, + /// A pool parameter was outside its permitted range. + InvalidParameter = 7, + /// A 32-byte value was not a canonical BN254 scalar. + NonCanonicalField = 8, + /// Poseidon hashing failed. + PoseidonFailed = 9, + /// The accumulator is full. + TreeFull = 10, + // + // 11 is retired. It was `WrongDepositAmount`, and it was unreachable: a + // deposit's size is read from the pool account, never from the instruction, + // so there is no caller-supplied amount left to disagree with. Deleting the + // variant rather than leaving it unconstructed keeps the enum an accurate + // list of what this program can actually reject. The discriminant is left + // unused rather than reassigned, so every code below stays stable for + // anything already reading them. + // + /// Arithmetic overflowed or underflowed. + ArithmeticOverflow = 12, + /// The vault does not hold enough to cover every unspent note. + /// + /// This is the accounting invariant. It is checked rather than assumed + /// because both standard drains in this design space surface exactly here, + /// and an invariant that is only assumed is not an invariant. + InsolventVault = 13, + /// The spend account has the wrong length or an unrecognised version. + InvalidSpendAccount = 14, + /// This nullifier has already been recorded: the note is spent. + NullifierAlreadySpent = 15, + /// The spend has already been executed. + AlreadySettled = 16, + /// The proof references a root the pool does not retain. + UnknownRoot = 17, + /// The Groth16 proof did not verify. + ProofVerificationFailed = 18, + /// The pool holds fewer notes than its anonymity floor requires. + BelowAnonymityFloor = 19, + /// The relay fee is not less than the denomination. + RelayFeeTooLarge = 20, + /// The batch is below the crowd size and has not waited out the timeout. + CrowdTooSmall = 21, + /// The action selector is not one this program implements. + UnknownSelector = 22, + /// An action tried to invoke this program. Refused: re-entering settlement + /// around a lamport-moving loop is not a property to leave to careful + /// reading. + SelfInvocationRefused = 23, + /// The action payload exceeds the maximum a spend record can carry. + PayloadTooLarge = 24, + /// Two records in one settlement carried different relay fees. + /// + /// A member is paid `denomination - relay_fee`, and that payout is public. + /// A batch whose members paid different fees settles into visibly different + /// amounts, so an observer partitions it by value without breaking anything + /// — which costs the members the exact property the batch exists to give + /// them. Refused rather than documented. + FeeNotUniform = 25, +} + +impl From for ProgramError { + fn from(e: MirrorProgramError) -> Self { + ProgramError::Custom(e as u32) + } +} + +impl From for MirrorProgramError { + fn from(e: mirror_core::MirrorError) -> Self { + use mirror_core::MirrorError as E; + match e { + E::NonCanonicalField | E::BadFieldLength => MirrorProgramError::NonCanonicalField, + E::Poseidon => MirrorProgramError::PoseidonFailed, + E::TreeFull => MirrorProgramError::TreeFull, + E::LeafIndexOutOfRange => MirrorProgramError::MalformedInstruction, + } + } +} diff --git a/programs/mirror-pool/src/instruction.rs b/programs/mirror-pool/src/instruction.rs new file mode 100644 index 00000000..36f501e6 --- /dev/null +++ b/programs/mirror-pool/src/instruction.rs @@ -0,0 +1,373 @@ +//! Instruction encoding. +//! +//! Every variant parses at an exact length. A trailing byte, a missing byte, or +//! an unknown tag is rejected rather than tolerated — there is no "read what you +//! need and ignore the rest", because that is how a caller ends up believing it +//! sent a field the program never read. +//! +//! Encoding is hand-rolled rather than borsh: the instruction data is part of +//! the on-chain ABI, the shapes are small and fixed, and a hand-rolled decoder +//! is one place to audit for length handling. + +use crate::error::MirrorProgramError; + +/// Instruction tags. Stable across versions; new instructions take new tags +/// rather than reusing a retired one. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum Tag { + InitPool = 0, + Deposit = 1, + SubmitSpend = 2, + SettleEpoch = 3, +} + +impl Tag { + fn from_u8(v: u8) -> Result { + match v { + 0 => Ok(Tag::InitPool), + 1 => Ok(Tag::Deposit), + 2 => Ok(Tag::SubmitSpend), + 3 => Ok(Tag::SettleEpoch), + _ => Err(MirrorProgramError::MalformedInstruction), + } + } +} + +/// `SubmitSpend` carries a 256-byte proof, so it is far larger than the other +/// variants. Boxing it — clippy's usual remedy — would move it to the heap, and +/// a heap allocation inside an on-chain program costs compute units to avoid a +/// stack cost we can comfortably afford: 368 bytes against a 4 KB frame, decoded +/// once per transaction. The size difference is deliberate. +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Instruction { + /// Creates the pool and its vault, and seeds the accumulator to an empty + /// tree. + InitPool { + denomination: u64, + entry_fee: u64, + k_floor: u32, + }, + /// Escrows exactly `denomination + entry_fee` and appends `commitment` to + /// the accumulator. + /// + /// The amount is not a parameter. It is read from the pool, so a deposit + /// cannot claim a size the pool did not set. + Deposit { commitment: [u8; 32] }, + /// Proves membership, burns the nullifier, and records the authorised + /// action. Nothing is paid out here — settlement executes the batch. + /// + /// The action binding is **not** transmitted. It is recomputed on-chain from + /// `selector`, `beneficiary` and `relay_fee` and used as the third public + /// input, so a relay that alters any of them produces a different binding + /// and the pairing simply fails. There is no separate field to forget to + /// check. + SubmitSpend { + proof_a: [u8; 64], + proof_b: [u8; 128], + proof_c: [u8; 64], + root: [u8; 32], + nullifier: [u8; 32], + selector: u64, + /// The program the pool will invoke on the member's behalf. + target_program: [u8; 32], + beneficiary: [u8; 32], + relay_fee: u64, + /// How many accounts that invocation expects. + action_accounts: u8, + /// Instruction data for the invocation, stored in the spend record so a + /// settle transaction carries only account references and several + /// actions still fit in one transaction. + payload: Vec, + }, + /// Executes a batch of pending spends in one transaction, so every payout in + /// an epoch shares a timestamp and an ordering. + /// + /// `count` is the number of spend records that follow in the account list. + /// Permissionless: anyone may settle, so no operator's absence can strand a + /// member's funds. + SettleEpoch { count: u8 }, +} + +/// `InitPool`: tag + u64 + u64 + u32. +pub const INIT_POOL_LEN: usize = 1 + 8 + 8 + 4; +/// `Deposit`: tag + one field element. +pub const DEPOSIT_LEN: usize = 1 + 32; +/// `SubmitSpend` without its payload. The encoding is variable length. +pub const SUBMIT_SPEND_BASE_LEN: usize = 1 + 64 + 128 + 64 + 32 + 32 + 8 + 32 + 32 + 8 + 1 + 2; +/// `SettleEpoch`: tag + count. +pub const SETTLE_EPOCH_LEN: usize = 1 + 1; + +fn read_u64(data: &[u8], at: usize) -> u64 { + let mut b = [0u8; 8]; + b.copy_from_slice(&data[at..at + 8]); + u64::from_le_bytes(b) +} + +fn read_u32(data: &[u8], at: usize) -> u32 { + let mut b = [0u8; 4]; + b.copy_from_slice(&data[at..at + 4]); + u32::from_le_bytes(b) +} + +impl Instruction { + pub fn unpack(data: &[u8]) -> Result { + let tag = Tag::from_u8( + *data + .first() + .ok_or(MirrorProgramError::MalformedInstruction)?, + )?; + + match tag { + Tag::InitPool => { + if data.len() != INIT_POOL_LEN { + return Err(MirrorProgramError::MalformedInstruction); + } + Ok(Instruction::InitPool { + denomination: read_u64(data, 1), + entry_fee: read_u64(data, 9), + k_floor: read_u32(data, 17), + }) + } + Tag::Deposit => { + if data.len() != DEPOSIT_LEN { + return Err(MirrorProgramError::MalformedInstruction); + } + let mut commitment = [0u8; 32]; + commitment.copy_from_slice(&data[1..33]); + Ok(Instruction::Deposit { commitment }) + } + Tag::SettleEpoch => { + if data.len() != SETTLE_EPOCH_LEN { + return Err(MirrorProgramError::MalformedInstruction); + } + Ok(Instruction::SettleEpoch { count: data[1] }) + } + Tag::SubmitSpend => { + if data.len() < SUBMIT_SPEND_BASE_LEN { + return Err(MirrorProgramError::MalformedInstruction); + } + let mut proof_a = [0u8; 64]; + let mut proof_b = [0u8; 128]; + let mut proof_c = [0u8; 64]; + let mut root = [0u8; 32]; + let mut nullifier = [0u8; 32]; + let mut target_program = [0u8; 32]; + let mut beneficiary = [0u8; 32]; + proof_a.copy_from_slice(&data[1..65]); + proof_b.copy_from_slice(&data[65..193]); + proof_c.copy_from_slice(&data[193..257]); + root.copy_from_slice(&data[257..289]); + nullifier.copy_from_slice(&data[289..321]); + let selector = read_u64(data, 321); + target_program.copy_from_slice(&data[329..361]); + beneficiary.copy_from_slice(&data[361..393]); + let relay_fee = read_u64(data, 393); + let action_accounts = data[401]; + let mut len_bytes = [0u8; 2]; + len_bytes.copy_from_slice(&data[402..404]); + let payload_len = u16::from_le_bytes(len_bytes) as usize; + // The declared length must account for every remaining byte, so + // trailing data cannot ride along unread. + if data.len() != SUBMIT_SPEND_BASE_LEN + payload_len { + return Err(MirrorProgramError::MalformedInstruction); + } + Ok(Instruction::SubmitSpend { + proof_a, + proof_b, + proof_c, + root, + nullifier, + selector, + target_program, + beneficiary, + relay_fee, + action_accounts, + payload: data[SUBMIT_SPEND_BASE_LEN..].to_vec(), + }) + } + } + } + + /// Serialises for a client. Kept beside the decoder so the two cannot drift. + pub fn pack(&self) -> Vec { + match self { + Instruction::InitPool { + denomination, + entry_fee, + k_floor, + } => { + let mut out = Vec::with_capacity(INIT_POOL_LEN); + out.push(Tag::InitPool as u8); + out.extend_from_slice(&denomination.to_le_bytes()); + out.extend_from_slice(&entry_fee.to_le_bytes()); + out.extend_from_slice(&k_floor.to_le_bytes()); + out + } + Instruction::Deposit { commitment } => { + let mut out = Vec::with_capacity(DEPOSIT_LEN); + out.push(Tag::Deposit as u8); + out.extend_from_slice(commitment); + out + } + Instruction::SubmitSpend { + proof_a, + proof_b, + proof_c, + root, + nullifier, + selector, + target_program, + beneficiary, + relay_fee, + action_accounts, + payload, + } => { + let mut out = Vec::with_capacity(SUBMIT_SPEND_BASE_LEN + payload.len()); + out.push(Tag::SubmitSpend as u8); + out.extend_from_slice(proof_a); + out.extend_from_slice(proof_b); + out.extend_from_slice(proof_c); + out.extend_from_slice(root); + out.extend_from_slice(nullifier); + out.extend_from_slice(&selector.to_le_bytes()); + out.extend_from_slice(target_program); + out.extend_from_slice(beneficiary); + out.extend_from_slice(&relay_fee.to_le_bytes()); + out.push(*action_accounts); + out.extend_from_slice(&(payload.len() as u16).to_le_bytes()); + out.extend_from_slice(payload); + out + } + Instruction::SettleEpoch { count } => { + vec![Tag::SettleEpoch as u8, *count] + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn init() -> Instruction { + Instruction::InitPool { + denomination: 100_000_000, + entry_fee: 5_000, + k_floor: 8, + } + } + + fn deposit() -> Instruction { + Instruction::Deposit { + commitment: [3u8; 32], + } + } + + fn settle() -> Instruction { + Instruction::SettleEpoch { count: 7 } + } + + fn submit_spend() -> Instruction { + // Distinct byte patterns per field so a swapped offset cannot pass. + Instruction::SubmitSpend { + proof_a: [0xA1; 64], + proof_b: [0xB2; 128], + proof_c: [0xC3; 64], + root: [0xD4; 32], + nullifier: [0xE5; 32], + selector: 0x0102_0304_0506_0708, + target_program: [0x7A; 32], + beneficiary: [0xF6; 32], + relay_fee: 0x1112_1314_1516_1718, + action_accounts: 3, + payload: vec![1, 2, 3, 4, 5], + } + } + + #[test] + fn packing_then_unpacking_is_the_identity() { + for ix in [init(), deposit(), submit_spend(), settle()] { + assert_eq!(Instruction::unpack(&ix.pack()).unwrap(), ix); + } + } + + #[test] + fn the_encoded_lengths_are_pinned() { + // These are the on-chain ABI. A change here breaks every deployed client. + assert_eq!(init().pack().len(), INIT_POOL_LEN); + assert_eq!(deposit().pack().len(), DEPOSIT_LEN); + assert_eq!(submit_spend().pack().len(), SUBMIT_SPEND_BASE_LEN + 5); + assert_eq!(INIT_POOL_LEN, 21); + assert_eq!(DEPOSIT_LEN, 33); + assert_eq!(SUBMIT_SPEND_BASE_LEN, 404); + assert_eq!(settle().pack().len(), SETTLE_EPOCH_LEN); + } + + #[test] + fn empty_data_is_refused() { + assert!(matches!( + Instruction::unpack(&[]), + Err(MirrorProgramError::MalformedInstruction) + )); + } + + #[test] + fn an_unknown_tag_is_refused() { + for tag in [4u8, 5, 99, 255] { + assert!( + matches!( + Instruction::unpack(&[tag]), + Err(MirrorProgramError::MalformedInstruction) + ), + "tag {tag} was accepted" + ); + } + } + + /// Fail-closed on shape, checked rather than asserted in a README. A short + /// buffer must not be zero-extended and a long one must not be truncated. + #[test] + fn every_wrong_length_is_refused() { + for ix in [init(), deposit(), submit_spend(), settle()] { + let good = ix.pack(); + for len in 0..good.len() { + assert!( + Instruction::unpack(&good[..len]).is_err(), + "a {len}-byte prefix was accepted for {ix:?}" + ); + } + let mut long = good.clone(); + long.push(0); + assert!( + Instruction::unpack(&long).is_err(), + "a trailing byte was tolerated for {ix:?}" + ); + } + } + + #[test] + fn fields_decode_at_the_right_offsets() { + // Distinct values so a swapped offset cannot pass by coincidence. + let ix = Instruction::InitPool { + denomination: 0x1122_3344_5566_7788, + entry_fee: 0x99aa_bbcc_ddee_ff00, + k_floor: 0xdead_beef, + }; + assert_eq!(Instruction::unpack(&ix.pack()).unwrap(), ix); + } + + #[test] + fn a_deposit_commitment_survives_verbatim() { + let mut commitment = [0u8; 32]; + for (i, b) in commitment.iter_mut().enumerate() { + *b = i as u8; + } + let ix = Instruction::Deposit { commitment }; + match Instruction::unpack(&ix.pack()).unwrap() { + Instruction::Deposit { commitment: got } => assert_eq!(got, commitment), + other => panic!("decoded as {other:?}"), + } + } +} diff --git a/programs/mirror-pool/src/lib.rs b/programs/mirror-pool/src/lib.rs new file mode 100644 index 00000000..e4815bb4 --- /dev/null +++ b/programs/mirror-pool/src/lib.rs @@ -0,0 +1,29 @@ +//! mirror-pool: a behavioral anonymity set. A member's protocol action is +//! executed by the pool PDA, gated by a Groth16 membership proof verified +//! on-chain, so an observer sees that an action happened but cannot attribute it +//! to a member. +#![forbid(unsafe_code)] + +pub mod error; +pub mod instruction; +pub mod pda; +pub mod processor; +pub mod spend; +pub mod state; +pub mod vk; + +pub use error::MirrorProgramError; +pub use instruction::Instruction; +pub use state::{Pool, POOL_LEN, POOL_VERSION, ROOT_HISTORY}; + +#[cfg(not(feature = "no-entrypoint"))] +solana_program::entrypoint!(entry); + +#[cfg(not(feature = "no-entrypoint"))] +fn entry( + program_id: &solana_program::pubkey::Pubkey, + accounts: &[solana_program::account_info::AccountInfo], + data: &[u8], +) -> solana_program::entrypoint::ProgramResult { + processor::process(program_id, accounts, data) +} diff --git a/programs/mirror-pool/src/pda.rs b/programs/mirror-pool/src/pda.rs new file mode 100644 index 00000000..7339e9b1 --- /dev/null +++ b/programs/mirror-pool/src/pda.rs @@ -0,0 +1,99 @@ +//! Program-derived addresses. +//! +//! One pool per denomination, globally. That is a privacy decision rather than a +//! convenience one: fragmenting deposits of the same size across several pools +//! splits the anonymity set, and a split set is strictly worse for every member +//! in it. Making the denomination the only seed means two users choosing "0.1 +//! SOL" cannot accidentally end up in different crowds. + +use solana_program::pubkey::Pubkey; + +pub const POOL_SEED: &[u8] = b"pool"; +pub const VAULT_SEED: &[u8] = b"vault"; +pub const SPEND_SEED: &[u8] = b"spend"; + +/// The pool account for a denomination. +pub fn pool_address(program_id: &Pubkey, denomination: u64) -> (Pubkey, u8) { + Pubkey::find_program_address(&[POOL_SEED, &denomination.to_le_bytes()], program_id) +} + +/// The vault that escrows a pool's notes. +/// +/// Kept separate from the pool account so that the accounting invariant reads +/// against a balance holding nothing but escrow and its own rent. Entry fees +/// accrue on the pool account instead, so reward lamports can never be mistaken +/// for lamports backing an unspent note. +pub fn vault_address(program_id: &Pubkey, pool: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(&[VAULT_SEED, pool.as_ref()], program_id) +} + +/// The spend record for a nullifier. +/// +/// Seeded by the nullifier itself, so the account's existence *is* the replay +/// guard: a second spend of the same note fails at account creation, before the +/// verifier is even reached. +pub fn spend_address(program_id: &Pubkey, pool: &Pubkey, nullifier: &[u8; 32]) -> (Pubkey, u8) { + Pubkey::find_program_address(&[SPEND_SEED, pool.as_ref(), nullifier], program_id) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn addresses_are_deterministic() { + let program = Pubkey::new_unique(); + let (a, bump_a) = pool_address(&program, 100_000); + let (b, bump_b) = pool_address(&program, 100_000); + assert_eq!(a, b); + assert_eq!(bump_a, bump_b); + } + + #[test] + fn each_denomination_gets_its_own_pool() { + let program = Pubkey::new_unique(); + assert_ne!( + pool_address(&program, 100_000).0, + pool_address(&program, 200_000).0 + ); + } + + #[test] + fn the_vault_is_derived_from_the_pool_not_the_denomination() { + let program = Pubkey::new_unique(); + let (pool, _) = pool_address(&program, 100_000); + let (vault, _) = vault_address(&program, &pool); + assert_ne!(vault, pool); + assert_eq!(vault, vault_address(&program, &pool).0); + } + + #[test] + fn each_nullifier_gets_its_own_spend_record() { + let program = Pubkey::new_unique(); + let (pool, _) = pool_address(&program, 1); + let a = spend_address(&program, &pool, &[1u8; 32]).0; + let b = spend_address(&program, &pool, &[2u8; 32]).0; + assert_ne!(a, b); + assert_eq!(a, spend_address(&program, &pool, &[1u8; 32]).0); + } + + #[test] + fn one_nullifier_in_two_pools_is_two_records() { + // Pool-scoped, so a nullifier burned in one denomination does not block + // an unrelated note in another. + let program = Pubkey::new_unique(); + let (pool_a, _) = pool_address(&program, 1); + let (pool_b, _) = pool_address(&program, 2); + assert_ne!( + spend_address(&program, &pool_a, &[7u8; 32]).0, + spend_address(&program, &pool_b, &[7u8; 32]).0 + ); + } + + #[test] + fn a_different_program_yields_different_addresses() { + let (a, _) = pool_address(&Pubkey::new_unique(), 1); + let (b, _) = pool_address(&Pubkey::new_unique(), 1); + assert_ne!(a, b); + } +} diff --git a/programs/mirror-pool/src/processor.rs b/programs/mirror-pool/src/processor.rs new file mode 100644 index 00000000..4135455f --- /dev/null +++ b/programs/mirror-pool/src/processor.rs @@ -0,0 +1,987 @@ +//! Instruction handlers. + +use crate::{ + error::MirrorProgramError, + instruction::Instruction, + pda::{pool_address, spend_address, vault_address, POOL_SEED, SPEND_SEED, VAULT_SEED}, + spend::{spend_len, Spend, MAX_PAYLOAD}, + state::{Pool, POOL_LEN}, +}; +use mirror_core::{hash_node, Field, TREE_DEPTH}; +use solana_program::{ + account_info::{next_account_info, AccountInfo}, + entrypoint::ProgramResult, + program::invoke_signed, + pubkey::Pubkey, + rent::Rent, + sysvar::Sysvar, +}; +use solana_system_interface::{instruction as system_instruction, program as system_program}; + +pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult { + match Instruction::unpack(data)? { + Instruction::InitPool { + denomination, + entry_fee, + k_floor, + } => init_pool(program_id, accounts, denomination, entry_fee, k_floor), + Instruction::Deposit { commitment } => deposit(program_id, accounts, commitment), + Instruction::SubmitSpend { + proof_a, + proof_b, + proof_c, + root, + nullifier, + selector, + target_program, + beneficiary, + relay_fee, + action_accounts, + payload, + } => submit_spend( + program_id, + accounts, + SpendRequest { + proof_a, + proof_b, + proof_c, + root, + nullifier, + selector, + target_program, + beneficiary, + relay_fee, + action_accounts, + payload, + }, + ), + Instruction::SettleEpoch { count } => settle_epoch(program_id, accounts, count), + } +} + +/// One validated spend, held until the whole batch has been read. +/// +/// Settlement cannot execute a batch in a single pass. A call carrying the +/// pool's vault as a signer is refused by the runtime if this program has +/// already moved the vault's lamports in the same instruction, and "the same +/// instruction" spans the whole batch — so those calls have to happen before +/// every payout, including payouts owed to other members. +struct Pending<'a> { + spend: AccountInfo<'a>, + beneficiary: AccountInfo<'a>, + relay: AccountInfo<'a>, + /// The callee's own account, for the two selectors that make a call. + target: Option>, + action_infos: Vec>, + selector: u64, + relay_fee: u64, + payout: u64, +} + +/// The fields of a spend, grouped so the handler takes one argument. +struct SpendRequest { + proof_a: [u8; 64], + proof_b: [u8; 128], + proof_c: [u8; 64], + root: [u8; 32], + nullifier: [u8; 32], + selector: u64, + target_program: [u8; 32], + beneficiary: [u8; 32], + relay_fee: u64, + action_accounts: u8, + payload: Vec, +} + +/// Creates a program-owned account at a PDA, tolerating lamports already sent to +/// it. +/// +/// `system_instruction::create_account` fails outright when the destination +/// holds any lamports, and that is a griefing vector rather than a safeguard: +/// every PDA this program creates is derived from public data. A nullifier is +/// visible in the `submit_spend` instruction, so anyone who sees the transaction +/// — most obviously the relay it was handed to — can send the rent-exempt +/// minimum to that spend PDA first and make the note permanently unspendable for +/// about 0.00089 SOL. The same trick on a pool or vault address prevents that +/// denomination's pool from ever being created. +/// +/// The three-step form is immune: top the account up to rent exemption, then +/// allocate and assign under the PDA's own seeds. A squatter can send lamports +/// but cannot allocate or assign without those seeds, so their deposit only +/// reduces what the legitimate payer owes. +fn create_pda_account<'a>( + payer: &AccountInfo<'a>, + account: &AccountInfo<'a>, + system: &AccountInfo<'a>, + space: usize, + owner: &Pubkey, + seeds: &[&[u8]], +) -> ProgramResult { + let rent = Rent::get()?; + let required = rent.minimum_balance(space); + let held = account.lamports(); + + if held < required { + solana_program::program::invoke( + &system_instruction::transfer(payer.key, account.key, required - held), + &[payer.clone(), account.clone(), system.clone()], + )?; + } + invoke_signed( + &system_instruction::allocate(account.key, space as u64), + &[account.clone(), system.clone()], + &[seeds], + )?; + invoke_signed( + &system_instruction::assign(account.key, owner), + &[account.clone(), system.clone()], + &[seeds], + ) +} + +/// Creates the pool and its vault and seeds the accumulator to an empty tree. +/// +/// Permissionless: the first caller for a denomination creates the crowd +/// everyone else joins. There is no privileged authority, so there is no key +/// whose loss freezes the pool. Baking an authority into the pool's PDA seeds is +/// the tempting alternative and it is a one-way door: seeds cannot change, so +/// without a rotation instruction that authority is permanent, a rotating relay +/// becomes undeployable, and the escrow is hostage to a single key forever. +fn init_pool( + program_id: &Pubkey, + accounts: &[AccountInfo], + denomination: u64, + entry_fee: u64, + k_floor: u32, +) -> ProgramResult { + let iter = &mut accounts.iter(); + let payer = next_account_info(iter)?; + let pool_account = next_account_info(iter)?; + let vault_account = next_account_info(iter)?; + let system = next_account_info(iter)?; + + if !payer.is_signer { + return Err(MirrorProgramError::MissingSignature.into()); + } + if !system_program::check_id(system.key) { + return Err(MirrorProgramError::InvalidOwner.into()); + } + + let (expected_pool, pool_bump) = pool_address(program_id, denomination); + if *pool_account.key != expected_pool { + return Err(MirrorProgramError::InvalidPda.into()); + } + let (expected_vault, vault_bump) = vault_address(program_id, &expected_pool); + if *vault_account.key != expected_vault { + return Err(MirrorProgramError::InvalidPda.into()); + } + + let denom_le = denomination.to_le_bytes(); + + // The pool account carries the accumulator and its own rent, and nothing + // else: entry fees are refused at initialisation, so nothing accrues here. + create_pda_account( + payer, + pool_account, + system, + POOL_LEN, + program_id, + &[POOL_SEED, &denom_le, &[pool_bump]], + )?; + + // The vault holds escrow only, and carries no data of its own: the + // accounting invariant is a statement about its lamports, so anything else + // living there would muddy it. + create_pda_account( + payer, + vault_account, + system, + 0, + program_id, + &[VAULT_SEED, expected_pool.as_ref(), &[vault_bump]], + )?; + + let mut data = pool_account.try_borrow_mut_data()?; + let mut pool = Pool::load_uninitialised(&mut data)?; + pool.initialise(pool_bump, vault_bump, denomination, entry_fee, k_floor)?; + Ok(()) +} + +/// Escrows exactly one denomination and appends a note commitment. +/// +/// The escrowed amount is read from the pool, never from the instruction, so a +/// deposit cannot claim a size the pool did not set. This is the ingress half of +/// the accounting invariant, and it is the half most easily left out: take the +/// escrowed lamports as a caller-supplied parameter without binding them to the +/// hidden commitment, and a depositor of one lamport can later withdraw the +/// whole pool with an entirely valid proof. +/// +/// Duplicate commitments are not rejected. Doing so would cost a marker account +/// per deposit, and the only party a duplicate harms is whoever submitted it: +/// they cannot know the original's secret, so they can never spend the note they +/// paid for. It burns their own money and leaves every other member unaffected. +fn deposit(program_id: &Pubkey, accounts: &[AccountInfo], commitment: [u8; 32]) -> ProgramResult { + let iter = &mut accounts.iter(); + let depositor = next_account_info(iter)?; + let pool_account = next_account_info(iter)?; + let vault_account = next_account_info(iter)?; + let system = next_account_info(iter)?; + + if !depositor.is_signer { + return Err(MirrorProgramError::MissingSignature.into()); + } + if !system_program::check_id(system.key) { + return Err(MirrorProgramError::InvalidOwner.into()); + } + if pool_account.owner != program_id || vault_account.owner != program_id { + return Err(MirrorProgramError::InvalidOwner.into()); + } + + // A canonical scalar, checked here rather than at first use. A commitment + // at or above the modulus would be rejected by the Poseidon syscall deep in + // the insert, after lamports had already moved. + let leaf = Field::from_bytes(commitment).map_err(MirrorProgramError::from)?; + + let denomination = { + let mut data = pool_account.try_borrow_mut_data()?; + let pool = Pool::load(&mut data)?; + if *vault_account.key != vault_address(program_id, pool_account.key).0 { + return Err(MirrorProgramError::InvalidPda.into()); + } + pool.denomination() + }; + + // A depositor pays the denomination and nothing else. There is no fee + // transfer here because `Pool::initialise` refuses a nonzero entry fee — + // fees would accrue on the pool account with no instruction able to pay + // them out, and no authority that could be given one. Should a future + // version add a real payout path, the collection belongs here. + solana_program::program::invoke( + &system_instruction::transfer(depositor.key, vault_account.key, denomination), + &[depositor.clone(), vault_account.clone(), system.clone()], + )?; + + let mut data = pool_account.try_borrow_mut_data()?; + let mut pool = Pool::load(&mut data)?; + let index = insert_leaf(&mut pool, leaf)?; + pool.record_deposit(index + 1)?; + + // Re-read the invariant from the account after the transfers landed, rather + // than trusting that they did. + let rent = Rent::get()?; + let required = pool + .required_vault_lamports()? + .checked_add(rent.minimum_balance(0)) + .ok_or(MirrorProgramError::ArithmeticOverflow)?; + if vault_account.lamports() < required { + return Err(MirrorProgramError::InsolventVault.into()); + } + Ok(()) +} + +/// Proves membership, burns the nullifier, and records the authorised action. +/// +/// Nothing is paid out here. Settlement executes the batch, so every action in +/// an epoch lands on one timestamp and in one ordering — which is the point of a +/// synchronised crowd, and the reason a per-spend payout would leak exactly what +/// the pool exists to hide. +/// +/// The relay signs, not the member. A member who pays their own fee signs with +/// their own wallet and destroys their own anonymity, so no member key appears +/// on chain at any point in this path. Relaying stays permissionless — there is +/// no allowlist and no authority whose absence freezes the pool — but a given +/// proof names the relay it was made for, so the choice is the member's rather +/// than the winner of a race. +/// +/// Note the ordering. The proof is verified *before* the spend account is +/// created, but the account's existence is what makes replay impossible, and +/// account creation fails if it already exists. So a replayed proof — however +/// valid — cannot produce a second record. +fn submit_spend(program_id: &Pubkey, accounts: &[AccountInfo], req: SpendRequest) -> ProgramResult { + let iter = &mut accounts.iter(); + let relay = next_account_info(iter)?; + let pool_account = next_account_info(iter)?; + let spend_account = next_account_info(iter)?; + let system = next_account_info(iter)?; + + if !relay.is_signer { + return Err(MirrorProgramError::MissingSignature.into()); + } + if !system_program::check_id(system.key) { + return Err(MirrorProgramError::InvalidOwner.into()); + } + if pool_account.owner != program_id { + return Err(MirrorProgramError::InvalidOwner.into()); + } + + // Canonical scalars, checked before anything else touches them. The Groth16 + // verifier rejects public inputs at or above the modulus, and the Poseidon + // syscall rejects non-canonical preimages; doing it here turns both into one + // named error instead of an opaque failure deeper in. + let root = Field::from_bytes(req.root).map_err(MirrorProgramError::from)?; + let nullifier_field = Field::from_bytes(req.nullifier).map_err(MirrorProgramError::from)?; + + let (denomination, k_floor, deposit_count) = { + let mut data = pool_account.try_borrow_mut_data()?; + let pool = Pool::load(&mut data)?; + (pool.denomination(), pool.k_floor(), pool.deposit_count()) + }; + + // The relay is paid out of the denomination, so a fee at or above it would + // leave the member nothing and, at exactly the denomination, would let a + // relay take the whole note. + if req.relay_fee >= denomination { + return Err(MirrorProgramError::RelayFeeTooLarge.into()); + } + + // The anonymity floor. This bounds *program-visible* membership: how many + // notes the tree holds. It is not the effective anonymity set, which is + // smaller because an observer can partition members by funding provenance — + // that is measured off-chain and reported honestly rather than asserted away + // here. + if deposit_count < k_floor as u64 { + return Err(MirrorProgramError::BelowAnonymityFloor.into()); + } + + { + let mut data = pool_account.try_borrow_mut_data()?; + let pool = Pool::load(&mut data)?; + if !pool.knows_root(root) { + return Err(MirrorProgramError::UnknownRoot.into()); + } + } + + // The replay guard, and it runs before the pairing rather than after. + // + // A spent nullifier is knowable from one account read; verifying a proof + // costs about 95k compute units. Checking the cheap thing first means a + // replay is rejected at roughly 11k CU instead of 95k, which matters because + // replays are exactly what an attacker submits in bulk. + // + // It is also an explicit check rather than a reliance on account creation + // failing: a failed CPI terminates the instruction with the *system + // program's* error, so a replay would report a bare "already in use" that + // proves nothing about this program. Devnet evidence records error codes, + // and a code that could have come from anywhere is not evidence. + let (expected_spend, spend_bump) = spend_address(program_id, pool_account.key, &req.nullifier); + if *spend_account.key != expected_spend { + return Err(MirrorProgramError::InvalidPda.into()); + } + // Keyed on allocated data, not on lamports. Anyone can send lamports to a + // PDA derived from a public nullifier; only this program can allocate it. + // Treating a balance as "already spent" would let a bystander brick a note + // for the price of rent exemption. + if !spend_account.data_is_empty() { + return Err(MirrorProgramError::NullifierAlreadySpent.into()); + } + + // Recomputed, never transmitted. If the relay altered the selector, the + // beneficiary or its own fee, this binding differs from the one the prover + // committed to and the pairing fails. There is no separate field that could + // be checked incorrectly or forgotten. + // + // The relay's own key goes in too, taken from the account that signed rather + // than from anything the caller could state. That is what stops a bystander + // from lifting a proof out of an unlanded transaction, naming themselves as + // relay, and landing it first to collect the fee: the binding they would + // need is the member's, and the member never signed one naming them. + if req.payload.len() > MAX_PAYLOAD { + return Err(MirrorProgramError::PayloadTooLarge.into()); + } + // Refuse a shape settlement could never satisfy, here rather than at + // settlement. Reaching settlement means the nullifier has already burned, + // and there is no instruction that can amend or refund a spend — so a + // record that cannot settle is a note destroyed. The binding covers these + // fields too; this check turns a griefing attempt into a failed transaction + // instead of a failed transaction plus a dead note. + match req.selector { + SELECTOR_TRANSFER if req.action_accounts != 0 => { + return Err(MirrorProgramError::MalformedInstruction.into()); + } + SELECTOR_TRANSFER | SELECTOR_INVOKE | SELECTOR_INVOKE_SIGNED => {} + _ => return Err(MirrorProgramError::UnknownSelector.into()), + } + let binding = mirror_core::action_binding( + req.selector, + &req.target_program, + &req.beneficiary, + &relay.key.to_bytes(), + req.relay_fee, + req.action_accounts, + &req.payload, + ); + + let public_inputs: [[u8; 32]; 3] = [ + root.to_bytes(), + nullifier_field.to_bytes(), + binding.to_bytes(), + ]; + let mut verifier = groth16_solana::groth16::Groth16Verifier::<3>::new( + &req.proof_a, + &req.proof_b, + &req.proof_c, + &public_inputs, + &crate::vk::VERIFYING_KEY, + ) + .map_err(|_| MirrorProgramError::ProofVerificationFailed)?; + verifier + .verify() + .map_err(|_| MirrorProgramError::ProofVerificationFailed)?; + + create_pda_account( + relay, + spend_account, + system, + spend_len(req.payload.len()), + program_id, + &[ + SPEND_SEED, + pool_account.key.as_ref(), + &req.nullifier, + &[spend_bump], + ], + )?; + + let now = solana_program::clock::Clock::get()?.unix_timestamp; + let mut spend_data = spend_account.try_borrow_mut_data()?; + let mut record = Spend::load_uninitialised(&mut spend_data)?; + record.initialise( + spend_bump, + req.selector, + req.relay_fee, + now, + &req.beneficiary, + &relay.key.to_bytes(), + &pool_account.key.to_bytes(), + &req.target_program, + req.action_accounts, + &req.payload, + )?; + + // The spend counter is deliberately *not* advanced here. The note is + // committed to be paid but has not been paid, so the vault must still cover + // it; leaving the counter alone keeps `required_vault_lamports` an upper + // bound on what is owed until settlement actually disburses. + Ok(()) +} + +/// The plain-transfer action: pay the beneficiary, no CPI. +/// +/// Kept as selector zero because a transfer is the degenerate action and the +/// protocol should not need a target program to express it. +pub const SELECTOR_TRANSFER: u64 = 0; + +/// Invoke `target_program` with the stored payload, signed by the pool. +/// +/// This is what makes the pool a behavioural anonymity set rather than a value +/// mixer. The brief asks for "Tornado Cash for behavioural patterns and +/// withdrawals — not for funds": an observer should see that a stake, a swap or +/// a vote happened and be unable to say which member asked for it. A pool that +/// only moves lamports answers the wrong question. +pub const SELECTOR_INVOKE: u64 = 1; + +/// Invoke `target_program` with the pool's vault as a **signer** of the call. +/// +/// Selector one funds the beneficiary and then invokes, which is what an action +/// wants when the target must see the value before it acts. The cost is that the +/// vault cannot be one of the callee's accounts: this program has already moved +/// its lamports by direct mutation, and the runtime rejects the whole +/// instruction as `UnbalancedInstruction` when that account then crosses a CPI +/// boundary. +/// +/// This selector pays *after* the invoke instead, which leaves the vault's +/// balance untouched at the moment of the call and lets it be handed to the +/// callee as a signer. That is what a delegated authority needs — a stake +/// account's authority, a governance vote's authority — and it is the difference +/// between a pool that can move lamports on your behalf and one that can *act* +/// on your behalf. +/// +/// The two orderings cannot be combined, so the member picks. The selector is +/// inside the action binding, so the choice is the member's and a settler cannot +/// change it. +pub const SELECTOR_INVOKE_SIGNED: u64 = 2; + +/// How long a spend may wait before it can settle alone. +/// +/// Below the crowd size, a batch must wait this out. It is the escape valve that +/// makes the crowd requirement safe: without it, a quiet pool could hold a +/// member's funds indefinitely because the crowd never arrives, and a privacy +/// tool that can strand your money is not one anybody should use. +pub const SETTLE_TIMEOUT_SECONDS: i64 = 3_600; + +/// Executes a batch of pending spends in one transaction. +/// +/// Every payout in the batch shares a timestamp and an ordering, which is what +/// makes the crowd synchronised: an observer watching beneficiaries receive +/// funds cannot use arrival time to tell them apart. +/// +/// Permissionless. Anyone may settle, so no operator's absence can strand a +/// member — and a member can always settle their own batch once the timeout has +/// passed. +/// +/// The crowd rule: a batch must carry at least `k_floor` spends, **or** every +/// spend in it must have waited out `SETTLE_TIMEOUT_SECONDS`. Requiring the crowd +/// unconditionally would be a liveness hazard on a quiet pool; dropping the +/// requirement would make "synchronised" a word rather than a property. This is +/// the honest middle: synchronised when there is traffic, still liquid when +/// there is not. +/// +/// **The timeout side has no floor, and a batch of one settles.** Settlement is +/// permissionless, so an adversary may be the settler and may compose the batch; +/// a spend becomes settleable alone an hour after it was submitted, whatever +/// else is pending. `k_floor` bounds a batch that settles by crowd and bounds +/// nothing about one that settles by clock. That is a deliberate trade of +/// anonymity for solvency — the alternative freezes a quiet pool's escrow with +/// no authority able to release it — and `docs/THREAT_MODEL.md` argues it rather +/// than leaving it to be discovered. +fn settle_epoch(program_id: &Pubkey, accounts: &[AccountInfo], count: u8) -> ProgramResult { + if count == 0 { + return Err(MirrorProgramError::MalformedInstruction.into()); + } + + let iter = &mut accounts.iter(); + let settler = next_account_info(iter)?; + let pool_account = next_account_info(iter)?; + let vault_account = next_account_info(iter)?; + + if !settler.is_signer { + return Err(MirrorProgramError::MissingSignature.into()); + } + if pool_account.owner != program_id || vault_account.owner != program_id { + return Err(MirrorProgramError::InvalidOwner.into()); + } + if *vault_account.key != vault_address(program_id, pool_account.key).0 { + return Err(MirrorProgramError::InvalidPda.into()); + } + + let (denomination, k_floor) = { + let mut data = pool_account.try_borrow_mut_data()?; + let pool = Pool::load(&mut data)?; + (pool.denomination(), pool.k_floor()) + }; + + let now = solana_program::clock::Clock::get()?.unix_timestamp; + let crowd_satisfied = count as u32 >= k_floor; + + // Every member in a batch must be paid the same amount, and the fee is the + // only thing that can make them differ. + // + // A member receives `denomination - relay_fee`, and that lamport figure is + // public the moment settlement lands. A batch whose members paid different + // fees therefore settles into visibly different payouts, and an observer + // partitions it by value — without breaking a proof, without knowing a + // secret, by reading the balances. The crowd rule, the shared timestamp and + // the single settling signature all exist to stop exactly that partition, + // and a fee that varies hands it back. + // + // Enforced here rather than at submission because it is a property of the + // *batch*, not of any one record: a member is free to pay whatever fee they + // agreed with their relay, and they settle with the members who agreed the + // same. Nothing stops a settler grouping by fee; this stops them mixing. + let mut batch_fee: Option = None; + + // Each spend brings its record, its beneficiary and its relay. + let mut pending: Vec = Vec::with_capacity(count as usize); + for _ in 0..count { + let spend_account = next_account_info(iter)?; + let beneficiary = next_account_info(iter)?; + let relay = next_account_info(iter)?; + + if spend_account.owner != program_id { + return Err(MirrorProgramError::InvalidOwner.into()); + } + + let (relay_fee, payout, selector, action_accounts) = { + let mut data = spend_account.try_borrow_mut_data()?; + let mut record = Spend::load(&mut data)?; + + // A record from another pool must not reach this vault. + if record.pool() != pool_account.key.to_bytes() { + return Err(MirrorProgramError::InvalidPda.into()); + } + // The accounts must be the ones the proof bound. + if record.beneficiary() != beneficiary.key.to_bytes() + || record.relay() != relay.key.to_bytes() + { + return Err(MirrorProgramError::InvalidPda.into()); + } + if !crowd_satisfied + && now.saturating_sub(record.submitted_at()) < SETTLE_TIMEOUT_SECONDS + { + return Err(MirrorProgramError::CrowdTooSmall.into()); + } + + // Refuses a second settlement of the same record, which is the + // double-spend an attacker would reach for: pass one pending spend + // twice in a single batch and be paid twice. + record.mark_settled()?; + + let relay_fee = record.relay_fee(); + let payout = denomination + .checked_sub(relay_fee) + .ok_or(MirrorProgramError::ArithmeticOverflow)?; + ( + relay_fee, + payout, + record.selector(), + record.action_accounts(), + ) + }; + + match batch_fee { + None => batch_fee = Some(relay_fee), + Some(first) if first != relay_fee => { + return Err(MirrorProgramError::FeeNotUniform.into()) + } + Some(_) => {} + } + + let (target, action_infos) = match selector { + SELECTOR_TRANSFER => { + if action_accounts != 0 { + return Err(MirrorProgramError::MalformedInstruction.into()); + } + (None, Vec::new()) + } + SELECTOR_INVOKE | SELECTOR_INVOKE_SIGNED => { + // The target program's own account comes first, because a CPI + // requires the callee to be present in the caller's account + // list. Its key is checked against the record, so a settler + // supplying a different program is refused before any value + // moves rather than discovered by the runtime. + let target_info = next_account_info(iter)?.clone(); + + // Then the action's own accounts. + let mut action_infos = Vec::with_capacity(action_accounts as usize); + for _ in 0..action_accounts { + action_infos.push(next_account_info(iter)?.clone()); + } + (Some(target_info), action_infos) + } + _ => return Err(MirrorProgramError::UnknownSelector.into()), + }; + + pending.push(Pending { + spend: spend_account.clone(), + beneficiary: beneficiary.clone(), + relay: relay.clone(), + target, + action_infos, + selector, + relay_fee, + payout, + }); + } + + // Pass one: every call the pool signs, before a single lamport in this + // instruction has moved. + // + // This is the constraint that forces two passes rather than one, and it is + // about the *batch* and not about the spend. A CPI carrying the vault is + // refused by the runtime if this program has already mutated the vault's + // lamports anywhere in the same instruction — including on behalf of a + // different member earlier in the batch. Settling one signed action after + // three transfers is the case that finds this, and it is the ordinary case: + // a crowd is mixed by definition, and a signed action that could only settle + // alone would have to wait out the timeout, which is precisely the + // synchronised batch it exists to join. + for p in &pending { + if p.selector == SELECTOR_INVOKE_SIGNED { + let target_info = p + .target + .as_ref() + .ok_or(MirrorProgramError::MalformedInstruction)?; + invoke_action( + program_id, + pool_account, + vault_account, + &p.spend, + &p.beneficiary, + target_info, + p.payout, + &p.action_infos, + true, + )?; + } + } + + // Pass two: the money, and the calls that need to be funded before they run. + for p in &pending { + match p.selector { + // The vault is owned by this program, so lamports move by direct + // mutation rather than a system CPI: no signer seeds and no nested + // invoke on the hot path. + SELECTOR_TRANSFER | SELECTOR_INVOKE_SIGNED => { + move_lamports(vault_account, &p.beneficiary, p.payout)?; + } + SELECTOR_INVOKE => { + let target_info = p + .target + .as_ref() + .ok_or(MirrorProgramError::MalformedInstruction)?; + invoke_action( + program_id, + pool_account, + vault_account, + &p.spend, + &p.beneficiary, + target_info, + p.payout, + &p.action_infos, + false, + )?; + } + _ => return Err(MirrorProgramError::UnknownSelector.into()), + } + if p.relay_fee > 0 { + move_lamports(vault_account, &p.relay, p.relay_fee)?; + } + } + + let settled = pending.len() as u64; + let mut data = pool_account.try_borrow_mut_data()?; + let mut pool = Pool::load(&mut data)?; + for _ in 0..settled { + pool.record_spend()?; + } + + // The accounting invariant, re-read from the account after the lamports + // actually moved rather than assumed from the arithmetic above. + let rent = Rent::get()?; + let required = pool + .required_vault_lamports()? + .checked_add(rent.minimum_balance(0)) + .ok_or(MirrorProgramError::ArithmeticOverflow)?; + if vault_account.lamports() < required { + return Err(MirrorProgramError::InsolventVault.into()); + } + Ok(()) +} + +/// Invokes the member's chosen program on their behalf. +/// +/// The call is made by this program and the value comes out of the pool's vault, +/// so from the chain's point of view the action was taken by the pool. Every +/// member's action looks the same from outside, which is what makes it +/// unattributable: the on-chain trace of a stake made through this pool is +/// identical whoever asked for it. +/// +/// Under `SELECTOR_INVOKE_SIGNED` the vault is additionally a *signer* of the +/// call, so the pool can act as a delegated authority rather than only as a +/// source of funds. +/// +/// The payload and the target were both fixed at submit time and bound into the +/// proof, so a settler chooses neither, and the declared account count is bound +/// too. What a settler still supplies is *which* accounts fill those slots, and +/// those are the target program's problem to validate — exactly as they would be +/// for any caller. For a target whose destination is an account rather than +/// instruction data, that is a real limit, and the threat model says so. +/// +/// Whether the vault may be one of the callee's own accounts depends on +/// `pool_signs`, and the reason is lamport ordering rather than taste — see +/// `SELECTOR_INVOKE_SIGNED`. +#[allow(clippy::too_many_arguments)] +fn invoke_action<'a>( + program_id: &Pubkey, + pool_account: &AccountInfo<'a>, + vault_account: &AccountInfo<'a>, + spend_account: &AccountInfo<'a>, + beneficiary: &AccountInfo<'a>, + target_info: &AccountInfo<'a>, + payout: u64, + action_infos: &[AccountInfo<'a>], + pool_signs: bool, +) -> ProgramResult { + let (target, payload) = { + let mut data = spend_account.try_borrow_mut_data()?; + let record = Spend::load(&mut data)?; + (record.target_program(), record.payload().to_vec()) + }; + let vault_bump = { + let pool_data = pool_account.try_borrow_data()?; + Pool::vault_bump_of(&pool_data)? + }; + + // The pool never invokes itself. Doing so would let a member craft a payload + // that re-enters settlement, and re-entrancy around a lamport-moving loop is + // not something to leave to careful reading. + let target_key = Pubkey::new_from_array(target); + if target_key == *program_id { + return Err(MirrorProgramError::SelfInvocationRefused.into()); + } + // The account supplied must be the program the member proved. + if *target_info.key != target_key { + return Err(MirrorProgramError::InvalidPda.into()); + } + + // Under `SELECTOR_INVOKE` the vault must not be one of the callee's + // accounts, and this is a runtime constraint rather than a policy: the + // payout below moves the vault's lamports by direct mutation, and an account + // mutated that way then handed across a CPI boundary makes the runtime + // reject the whole instruction as `UnbalancedInstruction`. Refusing it here + // turns that into a named error instead of an opaque runtime failure. + if !pool_signs { + if action_infos.iter().any(|a| a.key == vault_account.key) { + return Err(MirrorProgramError::MalformedInstruction.into()); + } + // Fund the action before invoking, so the target sees the value it is + // meant to act on. Under `SELECTOR_INVOKE_SIGNED` the caller pays after + // every signed call in the batch has run instead. + move_lamports(vault_account, beneficiary, payout)?; + } + + // The vault's signature is granted by `invoke_signed` below, but only for + // accounts that appear in the instruction's own list — an account passed in + // the infos and absent from the metas is ignored by the callee, signer seeds + // or not. So under `SELECTOR_INVOKE_SIGNED` the flag has to be set here, on + // the meta, for the callee to see the pool as a signer at all. + let metas: Vec = action_infos + .iter() + .map(|a| solana_program::instruction::AccountMeta { + pubkey: *a.key, + is_signer: a.is_signer || (pool_signs && a.key == vault_account.key), + is_writable: a.is_writable, + }) + .collect(); + + let ix = solana_program::instruction::Instruction { + program_id: target_key, + accounts: metas, + data: payload, + }; + + // The vault and the target may already be among the action's accounts — the + // vault whenever the action needs the pool to sign for it, which is the + // normal case. Appending them unconditionally puts the same account in the + // list twice, and the runtime then reconciles its lamports against itself + // and fails the whole instruction as unbalanced. + let mut infos = action_infos.to_vec(); + if !infos.iter().any(|a| a.key == vault_account.key) { + infos.push(vault_account.clone()); + } + if !infos.iter().any(|a| a.key == target_info.key) { + infos.push(target_info.clone()); + } + + invoke_signed( + &ix, + &infos, + &[&[VAULT_SEED, pool_account.key.as_ref(), &[vault_bump]]], + ) +} + +/// Moves lamports between two accounts this program owns or may credit. +fn move_lamports( + from: &AccountInfo, + to: &AccountInfo, + amount: u64, +) -> Result<(), MirrorProgramError> { + let mut from_lamports = from + .try_borrow_mut_lamports() + .map_err(|_| MirrorProgramError::InsolventVault)?; + let mut to_lamports = to + .try_borrow_mut_lamports() + .map_err(|_| MirrorProgramError::InsolventVault)?; + **from_lamports = from_lamports + .checked_sub(amount) + .ok_or(MirrorProgramError::InsolventVault)?; + **to_lamports = to_lamports + .checked_add(amount) + .ok_or(MirrorProgramError::ArithmeticOverflow)?; + Ok(()) +} + +/// Appends `leaf` to the pool's frontier, returning its index. +/// +/// The same walk as `mirror_core::Frontier::insert`, over account bytes. The +/// two are asserted to agree in the program's test suite, because a divergence +/// here means the host builds proofs against a root the chain will never hold. +fn insert_leaf(pool: &mut Pool<'_>, leaf: Field) -> Result { + let index = pool.next_index(); + if index >= 1u64 << TREE_DEPTH { + return Err(MirrorProgramError::TreeFull); + } + + let ladder = mirror_core::baked_ladder().map_err(MirrorProgramError::from)?; + let mut current = leaf; + let mut path = index; + + for (level, zero) in ladder.iter().take(TREE_DEPTH).enumerate() { + if path & 1 == 0 { + pool.set_filled(level, current)?; + current = hash_node(current, *zero).map_err(MirrorProgramError::from)?; + } else { + let left = pool.filled(level)?; + current = hash_node(left, current).map_err(MirrorProgramError::from)?; + } + path >>= 1; + } + + pool.push_root(current); + Ok(index) +} + +#[cfg(test)] +mod tests { + use super::*; + use mirror_core::Frontier; + + /// The program's accumulator and the host's must produce identical roots + /// over the same insertion sequence. If they ever diverge, every proof the + /// host builds targets a root the chain does not have. + #[test] + fn the_program_insert_matches_the_host_accumulator() { + let mut data = vec![0u8; POOL_LEN]; + { + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + pool.initialise(255, 254, 1_000_000, 0, 2).unwrap(); + } + let mut host = Frontier::new().unwrap(); + let mut pool_data = data; + + for i in 1..=17u64 { + let leaf = Field::from_u64(i * 1_000 + 7); + let host_index = host.insert(leaf).unwrap(); + + let mut pool = Pool::load(&mut pool_data).unwrap(); + let program_index = insert_leaf(&mut pool, leaf).unwrap(); + pool.record_deposit(program_index + 1).unwrap(); + + assert_eq!(program_index, host_index, "leaf index diverged at {i}"); + assert_eq!( + pool.current_root().unwrap(), + host.root(), + "root diverged after {i} insertions" + ); + } + } + + #[test] + fn every_intermediate_root_stays_known() { + let mut data = vec![0u8; POOL_LEN]; + { + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + pool.initialise(255, 254, 1, 0, 2).unwrap(); + } + let mut roots = Vec::new(); + for i in 1..=20u64 { + let mut pool = Pool::load(&mut data).unwrap(); + insert_leaf(&mut pool, Field::from_u64(i)).unwrap(); + roots.push(pool.current_root().unwrap()); + } + let pool = Pool::load(&mut data).unwrap(); + for (i, root) in roots.iter().enumerate() { + assert!( + pool.knows_root(*root), + "root after deposit {i} was forgotten while still inside the ring" + ); + } + } + + #[test] + fn a_non_canonical_commitment_is_refused_before_anything_moves() { + // The value the Poseidon syscall would reject much later, after + // lamports had already been transferred. + assert!(Field::from_bytes([0xff; 32]).is_err()); + } +} diff --git a/programs/mirror-pool/src/spend.rs b/programs/mirror-pool/src/spend.rs new file mode 100644 index 00000000..82aef1a0 --- /dev/null +++ b/programs/mirror-pool/src/spend.rs @@ -0,0 +1,402 @@ +//! The spend record. +//! +//! One account per nullifier, seeded by it. Its *existence* is the replay +//! guard — `submit_spend` refuses outright if it is already there — and its +//! contents are the action the proof authorised, held until settlement. +//! +//! Folding the nullifier marker and the pending action into one account is +//! deliberate: two accounts keyed by the same value can disagree, and an account +//! that exists to be checked but never read is easy to forget to check. + +use crate::error::MirrorProgramError; + +/// Not yet executed. +pub const STATUS_PENDING: u8 = 1; +/// Executed at settlement. +pub const STATUS_SETTLED: u8 = 2; + +mod offset { + pub const VERSION: usize = 0; + pub const STATUS: usize = 1; + pub const BUMP: usize = 2; + pub const ACTION_ACCOUNTS: usize = 3; + pub const PAYLOAD_LEN: usize = 4; + pub const SELECTOR: usize = 8; + pub const RELAY_FEE: usize = 16; + pub const SUBMITTED_AT: usize = 24; + pub const BENEFICIARY: usize = 32; + pub const RELAY: usize = 64; + pub const POOL: usize = 96; + pub const TARGET_PROGRAM: usize = 128; + pub const PAYLOAD: usize = 160; +} + +/// Fixed part of the record. The payload follows it. +pub const SPEND_BASE_LEN: usize = offset::PAYLOAD; + +/// Largest action payload a spend may carry. +/// +/// Bounded because the payload lives in the record, which is what lets +/// settlement batch several actions into one transaction: the instruction data +/// is already on chain, so a settle transaction carries only account references. +/// An unbounded payload would trade the synchronised crowd for expressiveness. +pub const MAX_PAYLOAD: usize = 256; + +pub const SPEND_VERSION: u8 = 1; + +const _: () = assert!(SPEND_BASE_LEN == 160); + +/// Account size for a record carrying `payload_len` bytes. +pub fn spend_len(payload_len: usize) -> usize { + SPEND_BASE_LEN + payload_len +} + +pub struct Spend<'a> { + data: &'a mut [u8], +} + +impl<'a> Spend<'a> { + pub fn load(data: &'a mut [u8]) -> Result { + // The upper bound is what stops this from being a type confusion. + // + // `POOL_VERSION` and `SPEND_VERSION` are both 1 and both live at offset + // zero, so the version byte distinguishes *layout revisions* and not + // account *kinds*: a pool account passed where a spend record is + // expected clears the version check. Settlement's other checks — + // `record.pool()` against the pool key — would then have to be read out + // of Merkle frontier bytes and are what actually refuse it, which is a + // coincidence to depend on rather than a rule. No spend record is ever + // larger than this, and every other account this program owns is, so + // one comparison makes the confusion unrepresentable. + if data.len() < SPEND_BASE_LEN + || data.len() > spend_len(MAX_PAYLOAD) + || data[offset::VERSION] != SPEND_VERSION + { + return Err(MirrorProgramError::InvalidSpendAccount); + } + let spend = Spend { data }; + // The declared payload length must match the account, or a reader could + // be pointed past the end of the data it was given. + if spend.data.len() != spend_len(spend.payload_len()) { + return Err(MirrorProgramError::InvalidSpendAccount); + } + Ok(spend) + } + + pub fn load_uninitialised(data: &'a mut [u8]) -> Result { + if data.len() < SPEND_BASE_LEN || data.len() > spend_len(MAX_PAYLOAD) { + return Err(MirrorProgramError::InvalidSpendAccount); + } + if data[offset::VERSION] != 0 { + return Err(MirrorProgramError::NullifierAlreadySpent); + } + Ok(Spend { data }) + } + + #[allow(clippy::too_many_arguments)] + pub fn initialise( + &mut self, + bump: u8, + selector: u64, + relay_fee: u64, + submitted_at: i64, + beneficiary: &[u8; 32], + relay: &[u8; 32], + pool: &[u8; 32], + target_program: &[u8; 32], + action_accounts: u8, + payload: &[u8], + ) -> Result<(), MirrorProgramError> { + if payload.len() > MAX_PAYLOAD || self.data.len() != spend_len(payload.len()) { + return Err(MirrorProgramError::InvalidSpendAccount); + } + self.data[offset::VERSION] = SPEND_VERSION; + self.data[offset::STATUS] = STATUS_PENDING; + self.data[offset::BUMP] = bump; + self.data[offset::ACTION_ACCOUNTS] = action_accounts; + self.data[offset::PAYLOAD_LEN..offset::PAYLOAD_LEN + 2] + .copy_from_slice(&(payload.len() as u16).to_le_bytes()); + self.data[offset::TARGET_PROGRAM..offset::TARGET_PROGRAM + 32] + .copy_from_slice(target_program); + self.data[offset::PAYLOAD..offset::PAYLOAD + payload.len()].copy_from_slice(payload); + self.data[offset::SELECTOR..offset::SELECTOR + 8].copy_from_slice(&selector.to_le_bytes()); + self.data[offset::RELAY_FEE..offset::RELAY_FEE + 8] + .copy_from_slice(&relay_fee.to_le_bytes()); + self.data[offset::SUBMITTED_AT..offset::SUBMITTED_AT + 8] + .copy_from_slice(&submitted_at.to_le_bytes()); + self.data[offset::BENEFICIARY..offset::BENEFICIARY + 32].copy_from_slice(beneficiary); + self.data[offset::RELAY..offset::RELAY + 32].copy_from_slice(relay); + self.data[offset::POOL..offset::POOL + 32].copy_from_slice(pool); + Ok(()) + } + + /// How many accounts the action's CPI expects. + pub fn action_accounts(&self) -> u8 { + self.data[offset::ACTION_ACCOUNTS] + } + + pub fn payload_len(&self) -> usize { + let mut b = [0u8; 2]; + b.copy_from_slice(&self.data[offset::PAYLOAD_LEN..offset::PAYLOAD_LEN + 2]); + u16::from_le_bytes(b) as usize + } + + /// The program the pool will invoke on this member's behalf. + pub fn target_program(&self) -> [u8; 32] { + let mut b = [0u8; 32]; + b.copy_from_slice(&self.data[offset::TARGET_PROGRAM..offset::TARGET_PROGRAM + 32]); + b + } + + /// The instruction data for that invocation, stored at submit time so a + /// settle transaction carries only account references. + pub fn payload(&self) -> &[u8] { + &self.data[offset::PAYLOAD..offset::PAYLOAD + self.payload_len()] + } + + pub fn status(&self) -> u8 { + self.data[offset::STATUS] + } + pub fn bump(&self) -> u8 { + self.data[offset::BUMP] + } + pub fn selector(&self) -> u64 { + let mut b = [0u8; 8]; + b.copy_from_slice(&self.data[offset::SELECTOR..offset::SELECTOR + 8]); + u64::from_le_bytes(b) + } + pub fn relay_fee(&self) -> u64 { + let mut b = [0u8; 8]; + b.copy_from_slice(&self.data[offset::RELAY_FEE..offset::RELAY_FEE + 8]); + u64::from_le_bytes(b) + } + /// Unix time the spend was accepted. Settlement uses it to decide whether a + /// batch may go out below the crowd size. + pub fn submitted_at(&self) -> i64 { + let mut b = [0u8; 8]; + b.copy_from_slice(&self.data[offset::SUBMITTED_AT..offset::SUBMITTED_AT + 8]); + i64::from_le_bytes(b) + } + pub fn beneficiary(&self) -> [u8; 32] { + let mut b = [0u8; 32]; + b.copy_from_slice(&self.data[offset::BENEFICIARY..offset::BENEFICIARY + 32]); + b + } + pub fn relay(&self) -> [u8; 32] { + let mut b = [0u8; 32]; + b.copy_from_slice(&self.data[offset::RELAY..offset::RELAY + 32]); + b + } + /// The pool this spend belongs to. + /// + /// Settlement checks it, so a record from one denomination cannot be + /// presented to another pool's vault. + pub fn pool(&self) -> [u8; 32] { + let mut b = [0u8; 32]; + b.copy_from_slice(&self.data[offset::POOL..offset::POOL + 32]); + b + } + + /// Marks the spend executed, refusing to do so twice. + pub fn mark_settled(&mut self) -> Result<(), MirrorProgramError> { + if self.status() != STATUS_PENDING { + return Err(MirrorProgramError::AlreadySettled); + } + self.data[offset::STATUS] = STATUS_SETTLED; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const PAYLOAD: &[u8] = b"delegate stake"; + + fn fresh() -> Vec { + vec![0u8; spend_len(PAYLOAD.len())] + } + + fn init(data: &mut [u8]) { + let mut s = Spend::load_uninitialised(data).unwrap(); + s.initialise( + 251, + 7, + 12_345, + 1_700_000_000, + &[9u8; 32], + &[4u8; 32], + &[5u8; 32], + &[6u8; 32], + 4, + PAYLOAD, + ) + .unwrap(); + } + + #[test] + fn a_spend_reads_back_what_was_written() { + let mut data = fresh(); + init(&mut data); + let s = Spend::load(&mut data).unwrap(); + assert_eq!(s.status(), STATUS_PENDING); + assert_eq!(s.bump(), 251); + assert_eq!(s.selector(), 7); + assert_eq!(s.relay_fee(), 12_345); + assert_eq!(s.submitted_at(), 1_700_000_000); + assert_eq!(s.beneficiary(), [9u8; 32]); + assert_eq!(s.relay(), [4u8; 32]); + assert_eq!(s.pool(), [5u8; 32]); + assert_eq!(s.target_program(), [6u8; 32]); + assert_eq!(s.action_accounts(), 4); + assert_eq!(s.payload(), PAYLOAD); + } + + /// The action a member proved must survive settlement byte for byte: a + /// truncated or padded payload would invoke the target with parameters + /// nobody authorised. + #[test] + fn a_payload_round_trips_at_every_length() { + for len in [0usize, 1, 31, 32, 33, MAX_PAYLOAD] { + let payload: Vec = (0..len).map(|i| (i % 251) as u8).collect(); + let mut data = vec![0u8; spend_len(len)]; + { + let mut s = Spend::load_uninitialised(&mut data).unwrap(); + s.initialise( + 1, 0, 0, 0, &[0u8; 32], &[0u8; 32], &[0u8; 32], &[0u8; 32], 0, &payload, + ) + .unwrap(); + } + let s = Spend::load(&mut data).unwrap(); + assert_eq!(s.payload(), &payload[..], "length {len} did not round trip"); + assert_eq!(s.payload_len(), len); + } + } + + #[test] + fn a_payload_beyond_the_maximum_is_refused() { + let payload = vec![0u8; MAX_PAYLOAD + 1]; + let mut data = vec![0u8; spend_len(payload.len())]; + assert!(Spend::load_uninitialised(&mut data).is_err()); + } + + /// An account whose length disagrees with its declared payload length would + /// let a reader run past the end of what it was given. + #[test] + fn a_record_whose_length_contradicts_its_header_is_refused() { + let mut data = fresh(); + init(&mut data); + data.push(0); + assert!(matches!( + Spend::load(&mut data), + Err(MirrorProgramError::InvalidSpendAccount) + )); + } + + #[test] + fn an_existing_record_refuses_reinitialisation() { + let mut data = fresh(); + init(&mut data); + assert!(matches!( + Spend::load_uninitialised(&mut data), + Err(MirrorProgramError::NullifierAlreadySpent) + )); + } + + #[test] + fn a_spend_settles_exactly_once() { + let mut data = fresh(); + init(&mut data); + let mut s = Spend::load(&mut data).unwrap(); + s.mark_settled().unwrap(); + assert_eq!(s.status(), STATUS_SETTLED); + assert!(matches!( + s.mark_settled(), + Err(MirrorProgramError::AlreadySettled) + )); + } + + #[test] + fn a_wrong_length_account_is_refused() { + let mut short = vec![0u8; SPEND_BASE_LEN - 1]; + assert!(Spend::load(&mut short).is_err()); + assert!(Spend::load_uninitialised(&mut short).is_err()); + } + + #[test] + fn fields_do_not_overlap() { + // Distinct values in every field; if two overlapped, one would clobber + // the other and this would fail. + let mut data = fresh(); + { + let mut s = Spend::load_uninitialised(&mut data).unwrap(); + s.initialise( + 0xEE, + 0x1122_3344_5566_7788, + 0x99AA_BBCC_DDEE_FF00, + -0x0102_0304_0506_0708, + &[0xAB; 32], + &[0xCD; 32], + &[0xEF; 32], + &[0x12; 32], + 7, + PAYLOAD, + ) + .unwrap(); + } + let s = Spend::load(&mut data).unwrap(); + assert_eq!(s.bump(), 0xEE); + assert_eq!(s.selector(), 0x1122_3344_5566_7788); + assert_eq!(s.relay_fee(), 0x99AA_BBCC_DDEE_FF00); + assert_eq!(s.submitted_at(), -0x0102_0304_0506_0708); + assert_eq!(s.beneficiary(), [0xAB; 32]); + assert_eq!(s.relay(), [0xCD; 32]); + assert_eq!(s.pool(), [0xEF; 32]); + assert_eq!(s.target_program(), [0x12; 32]); + assert_eq!(s.action_accounts(), 7); + } + + /// A pool account must never load as a spend record. + /// + /// Both carry version 1 at offset zero, so the version byte cannot tell them + /// apart. This pins the size bound that does. The value is not + /// `POOL_LEN` by import but by construction: any account bigger than the + /// largest possible record is refused, whatever it happens to be. + #[test] + fn an_account_too_large_to_be_a_record_is_refused() { + let mut pool_sized = vec![0u8; 4792]; + pool_sized[offset::VERSION] = SPEND_VERSION; + // Declare exactly the payload length that makes the arithmetic close, + // which is what a colliding account would have to do. + let declared = (4792 - SPEND_BASE_LEN) as u16; + pool_sized[offset::PAYLOAD_LEN..offset::PAYLOAD_LEN + 2] + .copy_from_slice(&declared.to_le_bytes()); + assert!( + Spend::load(&mut pool_sized).is_err(), + "an account far larger than any record loaded as one" + ); + } + + #[test] + fn the_largest_legal_record_still_loads() { + let mut data = vec![0u8; spend_len(MAX_PAYLOAD)]; + { + let mut spend = Spend::load_uninitialised(&mut data).unwrap(); + spend + .initialise( + 1, + 0, + 0, + 0, + &[0; 32], + &[0; 32], + &[0; 32], + &[0; 32], + 0, + &[7u8; MAX_PAYLOAD], + ) + .unwrap(); + } + assert_eq!(Spend::load(&mut data).unwrap().payload().len(), MAX_PAYLOAD); + } +} diff --git a/programs/mirror-pool/src/state.rs b/programs/mirror-pool/src/state.rs new file mode 100644 index 00000000..878d5d6f --- /dev/null +++ b/programs/mirror-pool/src/state.rs @@ -0,0 +1,589 @@ +//! The pool account. +//! +//! Laid out explicitly at fixed offsets rather than through a serialisation +//! framework. The layout is the on-chain ABI, so it is worth being able to read +//! it in one place, and every accessor is bounds-checked — the crate forbids +//! unsafe, so there are no transmutes over account data. +//! +//! Integers are little-endian, matching Solana convention. Field elements are +//! canonical big-endian 32-byte scalars, matching the Poseidon syscall and the +//! Groth16 verifier, so no value is ever byte-swapped in flight. + +use crate::error::MirrorProgramError; +use mirror_core::{Field, TREE_DEPTH, ZERO_LADDER}; + +/// How many past roots stay acceptable. +/// +/// A prover builds a proof against whatever root was current when they read the +/// chain; by the time a relay lands the transaction, later deposits may have +/// advanced it. The ring is how long a proof stays valid. +/// +/// 128 is deliberate, and the sizing interacts with how many leaves an +/// operation appends. A 32-entry ring against a design that appends two leaves +/// per spend gives a proof a useful life of about sixteen operations, which +/// holds in a test and collapses under any real load. +pub const ROOT_HISTORY: usize = 128; + +/// Byte offsets. Kept together so the layout can be audited as a unit. +mod offset { + use super::*; + pub const VERSION: usize = 0; + pub const BUMP: usize = 1; + pub const VAULT_BUMP: usize = 2; + pub const DEPTH: usize = 3; + pub const DENOMINATION: usize = 4; + pub const ENTRY_FEE: usize = 12; + pub const K_FLOOR: usize = 20; + pub const DEPOSIT_COUNT: usize = 24; + pub const SPEND_COUNT: usize = 32; + pub const NEXT_INDEX: usize = 40; + pub const ROOT_POS: usize = 48; + pub const _RESERVED: usize = 52; + pub const FILLED: usize = 56; + pub const ROOTS: usize = FILLED + 32 * TREE_DEPTH; + pub const END: usize = ROOTS + 32 * ROOT_HISTORY; +} + +/// Total size of the pool account. +pub const POOL_LEN: usize = offset::END; + +/// The current layout version. Bumping it invalidates old accounts rather than +/// reinterpreting their bytes. +pub const POOL_VERSION: u8 = 1; + +/// Smallest permitted anonymity floor. One is not a crowd. +pub const MIN_K_FLOOR: u32 = 2; + +/// Largest permitted anonymity floor: the tree's capacity. +/// +/// A floor above this can never be met, and since a pool is unique per +/// denomination and creation is permissionless, that would permanently deny the +/// protocol that denomination. +pub const MAX_K_FLOOR: u32 = 1 << TREE_DEPTH; + +// Pin the layout. A field inserted in the middle would otherwise silently +// reinterpret every deployed account. +const _: () = assert!(offset::FILLED == 56); +const _: () = assert!(offset::ROOTS == 696); +const _: () = assert!(POOL_LEN == 4792); + +/// A borrowed, bounds-checked view over the pool account's bytes. +pub struct Pool<'a> { + data: &'a mut [u8], +} + +macro_rules! read_u64 { + ($self:ident, $off:expr) => {{ + let mut b = [0u8; 8]; + b.copy_from_slice(&$self.data[$off..$off + 8]); + u64::from_le_bytes(b) + }}; +} + +macro_rules! write_u64 { + ($self:ident, $off:expr, $v:expr) => { + $self.data[$off..$off + 8].copy_from_slice(&$v.to_le_bytes()) + }; +} + +impl<'a> Pool<'a> { + /// Wraps account data, rejecting a wrong length or an unknown version. + pub fn load(data: &'a mut [u8]) -> Result { + if data.len() != POOL_LEN { + return Err(MirrorProgramError::InvalidPoolAccount); + } + if data[offset::VERSION] != POOL_VERSION { + return Err(MirrorProgramError::InvalidPoolAccount); + } + if data[offset::DEPTH] as usize != TREE_DEPTH { + return Err(MirrorProgramError::InvalidPoolAccount); + } + Ok(Pool { data }) + } + + /// Wraps a freshly allocated, all-zero account for initialisation. + pub fn load_uninitialised(data: &'a mut [u8]) -> Result { + if data.len() != POOL_LEN { + return Err(MirrorProgramError::InvalidPoolAccount); + } + if data[offset::VERSION] != 0 { + return Err(MirrorProgramError::AlreadyInitialised); + } + Ok(Pool { data }) + } + + pub fn bump(&self) -> u8 { + self.data[offset::BUMP] + } + pub fn vault_bump(&self) -> u8 { + self.data[offset::VAULT_BUMP] + } + + /// The vault bump, read from an account still under an immutable borrow. + /// + /// [`Pool::load`] needs `&mut [u8]` because one wrapper serves every + /// accessor, but settlement wants the bump while it holds the pool + /// immutably. Reading the byte through its named offset — behind the same + /// length and version checks `load` applies — keeps the layout owned by + /// this module. Reaching into the account with a literal index would put a + /// second, silent copy of the layout in the processor, and it would not + /// notice a pool account of the wrong version at all. + pub fn vault_bump_of(data: &[u8]) -> Result { + if data.len() != POOL_LEN || data[offset::VERSION] != POOL_VERSION { + return Err(MirrorProgramError::InvalidPoolAccount); + } + Ok(data[offset::VAULT_BUMP]) + } + pub fn denomination(&self) -> u64 { + read_u64!(self, offset::DENOMINATION) + } + pub fn entry_fee(&self) -> u64 { + read_u64!(self, offset::ENTRY_FEE) + } + pub fn k_floor(&self) -> u32 { + let mut b = [0u8; 4]; + b.copy_from_slice(&self.data[offset::K_FLOOR..offset::K_FLOOR + 4]); + u32::from_le_bytes(b) + } + pub fn deposit_count(&self) -> u64 { + read_u64!(self, offset::DEPOSIT_COUNT) + } + pub fn spend_count(&self) -> u64 { + read_u64!(self, offset::SPEND_COUNT) + } + pub fn next_index(&self) -> u64 { + read_u64!(self, offset::NEXT_INDEX) + } + fn root_pos(&self) -> u32 { + let mut b = [0u8; 4]; + b.copy_from_slice(&self.data[offset::ROOT_POS..offset::ROOT_POS + 4]); + u32::from_le_bytes(b) + } + + /// Writes the immutable parameters and seeds the accumulator to an empty + /// tree of the configured depth. + #[allow(clippy::too_many_arguments)] + pub fn initialise( + &mut self, + bump: u8, + vault_bump: u8, + denomination: u64, + entry_fee: u64, + k_floor: u32, + ) -> Result<(), MirrorProgramError> { + if denomination == 0 { + return Err(MirrorProgramError::InvalidParameter); + } + // The floor must be reachable, and it must actually be a crowd. + // + // Pool creation is permissionless and a pool is unique per denomination + // forever, so an unbounded floor is a griefing vector rather than a + // configuration mistake: a floor above the tree's capacity makes every + // spend fail permanently, and because no second pool for that + // denomination can ever exist, every later depositor loses their deposit + // with no recovery. Costing a fraction of a SOL, that would deny the + // protocol one denomination at a time. + // + // MIN_K_FLOOR is 2 because a floor of one is the anonymity set of one + // this check exists to prevent — it advertises that a privacy tool was + // used while providing no cover. + if !(MIN_K_FLOOR..=MAX_K_FLOOR).contains(&k_floor) { + return Err(MirrorProgramError::InvalidParameter); + } + // The entry fee must be zero, and this is a deliberate refusal rather + // than an unfinished feature. + // + // Fees accrue on the pool account. The dwell-reward mechanism that was + // meant to pay them out was cut, and it cannot simply be added back: + // paying them to anyone requires an authority, and this program has + // none by design — there is deliberately no key whose loss freezes the + // pool. So a nonzero fee here would be lamports that every depositor + // pays and that no instruction, and no person, can ever recover. + // + // Permitting that and documenting it as a known gap would be leaving a + // fund trap armed behind a paragraph. The field stays in the layout + // because the accessor and the offsets are already load-bearing and a + // future version with a real payout path will want it; until that path + // exists, the only permitted value is zero. + if entry_fee != 0 { + return Err(MirrorProgramError::InvalidParameter); + } + + self.data[offset::VERSION] = POOL_VERSION; + self.data[offset::BUMP] = bump; + self.data[offset::VAULT_BUMP] = vault_bump; + self.data[offset::DEPTH] = TREE_DEPTH as u8; + write_u64!(self, offset::DENOMINATION, denomination); + write_u64!(self, offset::ENTRY_FEE, entry_fee); + self.data[offset::K_FLOOR..offset::K_FLOOR + 4].copy_from_slice(&k_floor.to_le_bytes()); + + // An empty tree's frontier is the zero ladder, and its root is the top + // of that ladder. Seeding from the shared constant is what keeps the + // program and the host prover on one accumulator. + for (level, zero) in ZERO_LADDER.iter().take(TREE_DEPTH).enumerate() { + let at = offset::FILLED + level * 32; + self.data[at..at + 32].copy_from_slice(zero); + } + self.push_root(Field::from_bytes(ZERO_LADDER[TREE_DEPTH])?); + Ok(()) + } + + pub fn filled(&self, level: usize) -> Result { + if level >= TREE_DEPTH { + return Err(MirrorProgramError::MalformedInstruction); + } + let at = offset::FILLED + level * 32; + let mut b = [0u8; 32]; + b.copy_from_slice(&self.data[at..at + 32]); + Ok(Field::from_bytes(b)?) + } + + pub fn set_filled(&mut self, level: usize, value: Field) -> Result<(), MirrorProgramError> { + if level >= TREE_DEPTH { + return Err(MirrorProgramError::MalformedInstruction); + } + let at = offset::FILLED + level * 32; + self.data[at..at + 32].copy_from_slice(value.as_bytes()); + Ok(()) + } + + /// Appends a root to the ring and makes it current. + pub fn push_root(&mut self, root: Field) { + let pos = (self.root_pos() as usize + 1) % ROOT_HISTORY; + let at = offset::ROOTS + pos * 32; + self.data[at..at + 32].copy_from_slice(root.as_bytes()); + self.data[offset::ROOT_POS..offset::ROOT_POS + 4] + .copy_from_slice(&(pos as u32).to_le_bytes()); + } + + pub fn current_root(&self) -> Result { + let at = offset::ROOTS + self.root_pos() as usize * 32; + let mut b = [0u8; 32]; + b.copy_from_slice(&self.data[at..at + 32]); + Ok(Field::from_bytes(b)?) + } + + /// Whether `root` appears anywhere in the retained history. + /// + /// The all-zero slots of a young ring are skipped, so a proof against a + /// literal zero root can never be accepted by accident. + pub fn knows_root(&self, root: Field) -> bool { + if root.is_zero() { + return false; + } + (0..ROOT_HISTORY).any(|i| { + let at = offset::ROOTS + i * 32; + self.data[at..at + 32] == root.to_bytes() + }) + } + + pub fn record_deposit(&mut self, new_index: u64) -> Result<(), MirrorProgramError> { + let count = self + .deposit_count() + .checked_add(1) + .ok_or(MirrorProgramError::ArithmeticOverflow)?; + write_u64!(self, offset::DEPOSIT_COUNT, count); + write_u64!(self, offset::NEXT_INDEX, new_index); + Ok(()) + } + + pub fn record_spend(&mut self) -> Result<(), MirrorProgramError> { + let count = self + .spend_count() + .checked_add(1) + .ok_or(MirrorProgramError::ArithmeticOverflow)?; + // A spend without a matching deposit would mean the nullifier set and + // the accumulator disagree, so refuse rather than record it. + if count > self.deposit_count() { + return Err(MirrorProgramError::InsolventVault); + } + write_u64!(self, offset::SPEND_COUNT, count); + Ok(()) + } + + /// Notes that have been deposited and not yet spent. + pub fn outstanding_notes(&self) -> Result { + self.deposit_count() + .checked_sub(self.spend_count()) + .ok_or(MirrorProgramError::ArithmeticOverflow) + } + + /// Lamports the vault must still hold to cover every unspent note. + /// + /// The accounting invariant of the whole protocol. Because the denomination + /// is a pool constant rather than a hidden field, the amount owed is a + /// function of two counters and cannot be influenced by anything a prover + /// supplies. Without an invariant of this shape a shielded pool is drainable + /// in one of two standard ways: an escrowed amount never bound to its + /// commitment, or an epoch-scoped nullifier that lets one deposit pay out + /// once per epoch forever. + pub fn required_vault_lamports(&self) -> Result { + self.outstanding_notes()? + .checked_mul(self.denomination()) + .ok_or(MirrorProgramError::ArithmeticOverflow) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn blank() -> Vec { + vec![0u8; POOL_LEN] + } + + fn initialised(denomination: u64) -> Vec { + let mut data = blank(); + { + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + pool.initialise(254, 253, denomination, 0, 4).unwrap(); + } + data + } + + #[test] + fn a_fresh_pool_reads_back_its_parameters() { + let mut data = initialised(100_000); + let pool = Pool::load(&mut data).unwrap(); + assert_eq!(pool.bump(), 254); + assert_eq!(pool.vault_bump(), 253); + assert_eq!(pool.denomination(), 100_000); + assert_eq!(pool.entry_fee(), 0); + assert_eq!(pool.k_floor(), 4); + assert_eq!(pool.deposit_count(), 0); + assert_eq!(pool.spend_count(), 0); + assert_eq!(pool.next_index(), 0); + } + + /// The immutable reader must agree with the borrowing accessor, and must + /// refuse what `load` refuses. Settlement signs the vault with whatever + /// this returns, so a reader that answered from a wrong-sized or + /// wrong-version account would produce a bump for a PDA nobody controls. + #[test] + fn the_immutable_vault_bump_reader_agrees_and_validates() { + let mut data = initialised(1_000); + assert_eq!( + Pool::vault_bump_of(&data).unwrap(), + Pool::load(&mut data).unwrap().vault_bump() + ); + + let short = vec![0u8; POOL_LEN - 1]; + assert!(matches!( + Pool::vault_bump_of(&short), + Err(MirrorProgramError::InvalidPoolAccount) + )); + + let mut wrong_version = initialised(1_000); + wrong_version[offset::VERSION] = POOL_VERSION.wrapping_add(1); + assert!(matches!( + Pool::vault_bump_of(&wrong_version), + Err(MirrorProgramError::InvalidPoolAccount) + )); + } + + #[test] + fn a_fresh_pool_starts_at_the_empty_tree_root() { + let mut data = initialised(1); + let pool = Pool::load(&mut data).unwrap(); + let empty = mirror_core::Frontier::new().unwrap(); + assert_eq!( + pool.current_root().unwrap(), + empty.root(), + "the program and the host must start from one accumulator" + ); + } + + #[test] + fn the_frontier_is_seeded_from_the_zero_ladder() { + let mut data = initialised(1); + let pool = Pool::load(&mut data).unwrap(); + let ladder = mirror_core::baked_ladder().unwrap(); + for (level, expected) in ladder.iter().take(TREE_DEPTH).enumerate() { + assert_eq!(pool.filled(level).unwrap(), *expected); + } + } + + #[test] + fn a_wrong_length_account_is_refused() { + let mut short = vec![0u8; POOL_LEN - 1]; + assert!(matches!( + Pool::load(&mut short), + Err(MirrorProgramError::InvalidPoolAccount) + )); + let mut long = vec![0u8; POOL_LEN + 1]; + assert!(matches!( + Pool::load(&mut long), + Err(MirrorProgramError::InvalidPoolAccount) + )); + } + + #[test] + fn an_uninitialised_account_is_not_loadable_as_a_pool() { + let mut data = blank(); + assert!(matches!( + Pool::load(&mut data), + Err(MirrorProgramError::InvalidPoolAccount) + )); + } + + #[test] + fn initialising_twice_is_refused() { + let mut data = initialised(1); + assert!(matches!( + Pool::load_uninitialised(&mut data), + Err(MirrorProgramError::AlreadyInitialised) + )); + } + + #[test] + fn a_zero_denomination_or_zero_floor_is_refused() { + let mut data = blank(); + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + assert!(matches!( + pool.initialise(1, 1, 0, 0, 4), + Err(MirrorProgramError::InvalidParameter) + )); + assert!(matches!( + pool.initialise(1, 1, 100, 0, 0), + Err(MirrorProgramError::InvalidParameter) + )); + } + + /// A floor nobody can reach is a permanent denial of that denomination, + /// because pools are unique per denomination and creation is permissionless. + /// A griefer paying one pool's rent would otherwise lock out every honest + /// depositor for that size, forever, and take their deposits with it. + #[test] + fn an_unreachable_anonymity_floor_is_refused() { + let mut data = blank(); + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + assert!(matches!( + pool.initialise(1, 1, 1_000_000, 0, u32::MAX), + Err(MirrorProgramError::InvalidParameter) + )); + assert!(matches!( + pool.initialise(1, 1, 1_000_000, 0, MAX_K_FLOOR + 1), + Err(MirrorProgramError::InvalidParameter) + )); + assert!(pool.initialise(1, 1, 1_000_000, 0, MAX_K_FLOOR).is_ok()); + } + + #[test] + fn a_floor_of_one_is_refused_because_one_is_not_a_crowd() { + let mut data = blank(); + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + assert!(matches!( + pool.initialise(1, 1, 1_000_000, 0, 1), + Err(MirrorProgramError::InvalidParameter) + )); + assert!(pool.initialise(1, 1, 1_000_000, 0, MIN_K_FLOOR).is_ok()); + } + + /// A nonzero entry fee is unrecoverable, so it is refused at creation + /// rather than documented as a caveat. + /// + /// Fees land on the pool account and no instruction pays them out; adding + /// one would require an authority this program deliberately does not have. + /// Any nonzero value is therefore lamports that depositors pay and nobody + /// can ever retrieve — including a value well below the denomination, which + /// is the case an "is the fee affordable" check would happily wave through. + #[test] + fn a_nonzero_entry_fee_is_refused() { + let mut data = blank(); + let mut pool = Pool::load_uninitialised(&mut data).unwrap(); + for fee in [1, 999, 1_000, u64::MAX] { + assert!( + matches!( + pool.initialise(1, 1, 1_000, fee, 4), + Err(MirrorProgramError::InvalidParameter) + ), + "entry fee {fee} must be refused: nothing can pay it out" + ); + } + assert!(pool.initialise(1, 1, 1_000, 0, 4).is_ok()); + } + + #[test] + fn the_root_ring_remembers_and_then_forgets() { + let mut data = initialised(1); + let mut pool = Pool::load(&mut data).unwrap(); + + let first = Field::from_u64(1_000); + pool.push_root(first); + assert!(pool.knows_root(first)); + assert_eq!(pool.current_root().unwrap(), first); + + // Fill the ring exactly once more; the first root should still be the + // oldest survivor. + for i in 1..ROOT_HISTORY { + pool.push_root(Field::from_u64(1_000 + i as u64)); + } + assert!(pool.knows_root(first), "evicted one push too early"); + + pool.push_root(Field::from_u64(9_999)); + assert!(!pool.knows_root(first), "should have aged out by now"); + } + + #[test] + fn an_unknown_root_is_not_accepted() { + let mut data = initialised(1); + let pool = Pool::load(&mut data).unwrap(); + assert!(!pool.knows_root(Field::from_u64(12345))); + } + + #[test] + fn a_zero_root_is_never_accepted() { + // A young ring is mostly zeroes. Treating zero as a known root would let + // a proof against an all-zero root pass while the ring is still filling. + let mut data = initialised(1); + let pool = Pool::load(&mut data).unwrap(); + assert!(!pool.knows_root(Field::ZERO)); + } + + #[test] + fn the_vault_requirement_tracks_outstanding_notes() { + let mut data = initialised(1_000_000); + let mut pool = Pool::load(&mut data).unwrap(); + assert_eq!(pool.required_vault_lamports().unwrap(), 0); + + for i in 1..=5u64 { + pool.record_deposit(i).unwrap(); + } + assert_eq!(pool.outstanding_notes().unwrap(), 5); + assert_eq!(pool.required_vault_lamports().unwrap(), 5_000_000); + + pool.record_spend().unwrap(); + pool.record_spend().unwrap(); + assert_eq!(pool.outstanding_notes().unwrap(), 3); + assert_eq!(pool.required_vault_lamports().unwrap(), 3_000_000); + } + + /// The shape both standard drains converge on: more payouts than deposits. + /// Here it is not a matter of catching it late in the spend path — the + /// counter itself refuses. + #[test] + fn spending_more_notes_than_were_deposited_is_refused() { + let mut data = initialised(1_000); + let mut pool = Pool::load(&mut data).unwrap(); + pool.record_deposit(1).unwrap(); + pool.record_spend().unwrap(); + assert!(matches!( + pool.record_spend(), + Err(MirrorProgramError::InsolventVault) + )); + assert_eq!( + pool.spend_count(), + 1, + "the refused spend must not be recorded" + ); + } + + #[test] + fn a_level_outside_the_tree_is_refused_rather_than_wrapping() { + let mut data = initialised(1); + let mut pool = Pool::load(&mut data).unwrap(); + assert!(pool.filled(TREE_DEPTH).is_err()); + assert!(pool.set_filled(TREE_DEPTH, Field::ZERO).is_err()); + assert!(pool.filled(TREE_DEPTH - 1).is_ok()); + } +} diff --git a/programs/mirror-pool/src/vk.rs b/programs/mirror-pool/src/vk.rs new file mode 100644 index 00000000..391d7b26 --- /dev/null +++ b/programs/mirror-pool/src/vk.rs @@ -0,0 +1,78 @@ +//! Generated by `mirror setup`. Do not edit. +//! +//! Verifies 3 public inputs: root, nullifier, action_binding. + +use groth16_solana::groth16::Groth16Verifyingkey; + +pub const VK_ALPHA_G1: [u8; 64] = [ + 21, 82, 151, 215, 133, 209, 133, 55, 176, 54, 67, 95, 195, 62, 157, 215, 31, 7, 105, 216, 244, + 250, 149, 193, 71, 181, 36, 43, 228, 229, 195, 13, 21, 9, 158, 45, 229, 19, 240, 147, 210, 141, + 128, 164, 248, 125, 69, 35, 90, 111, 251, 90, 119, 54, 197, 89, 7, 143, 146, 56, 97, 14, 139, + 7, +]; + +pub const VK_BETA_G2: [u8; 128] = [ + 9, 82, 221, 5, 233, 247, 2, 96, 83, 253, 67, 2, 10, 138, 173, 130, 70, 142, 123, 171, 205, 241, + 190, 121, 108, 236, 13, 236, 114, 47, 161, 87, 39, 45, 103, 187, 196, 122, 67, 169, 78, 44, + 144, 72, 14, 131, 168, 237, 35, 124, 214, 42, 60, 168, 187, 13, 246, 188, 146, 214, 246, 123, + 218, 55, 10, 196, 101, 47, 197, 232, 124, 214, 127, 68, 155, 25, 28, 49, 136, 220, 218, 223, + 252, 132, 8, 133, 79, 203, 16, 6, 230, 6, 166, 30, 66, 71, 36, 47, 248, 181, 201, 98, 233, 199, + 176, 245, 112, 192, 147, 101, 159, 91, 202, 110, 10, 185, 241, 90, 68, 47, 247, 200, 37, 106, + 253, 129, 167, 147, +]; + +pub const VK_GAMMA_G2: [u8; 128] = [ + 35, 75, 106, 178, 55, 49, 73, 97, 91, 224, 163, 227, 199, 118, 23, 111, 151, 210, 181, 65, 227, + 60, 114, 66, 8, 157, 245, 33, 107, 30, 38, 64, 32, 161, 157, 224, 170, 224, 15, 121, 239, 203, + 177, 82, 175, 166, 6, 236, 178, 169, 161, 16, 159, 115, 122, 235, 37, 226, 113, 43, 181, 164, + 54, 0, 33, 207, 158, 226, 182, 57, 223, 100, 252, 249, 45, 246, 200, 14, 108, 229, 219, 29, + 240, 134, 235, 80, 148, 207, 107, 80, 234, 241, 121, 163, 7, 84, 4, 109, 157, 126, 104, 68, 96, + 189, 78, 189, 208, 76, 46, 20, 233, 68, 162, 127, 16, 58, 251, 140, 15, 90, 2, 34, 21, 14, 32, + 169, 251, 211, +]; + +pub const VK_DELTA_G2: [u8; 128] = [ + 40, 20, 18, 97, 68, 157, 250, 8, 221, 119, 154, 73, 222, 28, 100, 106, 253, 91, 198, 171, 86, + 72, 160, 111, 38, 32, 187, 208, 130, 25, 223, 122, 36, 59, 96, 41, 163, 186, 118, 220, 146, + 105, 183, 85, 90, 72, 94, 14, 104, 189, 238, 53, 195, 49, 5, 231, 89, 213, 229, 203, 101, 54, + 50, 36, 5, 175, 247, 82, 89, 10, 182, 243, 105, 5, 71, 34, 143, 218, 179, 1, 245, 101, 147, 8, + 208, 213, 161, 118, 84, 17, 184, 242, 92, 184, 143, 63, 7, 4, 188, 135, 100, 220, 94, 140, 210, + 151, 158, 172, 69, 225, 61, 55, 105, 28, 142, 150, 15, 189, 49, 16, 42, 204, 189, 160, 87, 127, + 3, 201, +]; + +pub const VK_IC: [[u8; 64]; 4] = [ + [ + 20, 219, 151, 102, 164, 174, 178, 55, 2, 228, 221, 187, 172, 199, 119, 6, 177, 227, 172, + 212, 219, 233, 72, 136, 13, 45, 165, 160, 150, 67, 122, 225, 14, 157, 212, 232, 42, 17, 86, + 110, 221, 71, 23, 92, 193, 113, 72, 153, 111, 57, 140, 234, 65, 62, 248, 8, 146, 125, 169, + 106, 66, 172, 201, 244, + ], + [ + 17, 241, 112, 76, 90, 220, 39, 228, 16, 33, 184, 185, 105, 35, 155, 123, 64, 105, 83, 149, + 108, 219, 185, 187, 76, 123, 90, 255, 7, 65, 88, 6, 41, 238, 235, 201, 21, 15, 93, 181, + 195, 85, 111, 200, 6, 180, 177, 182, 31, 99, 47, 17, 253, 15, 2, 69, 108, 5, 232, 237, 1, + 161, 0, 198, + ], + [ + 13, 120, 152, 134, 145, 252, 68, 46, 75, 136, 106, 72, 177, 67, 152, 46, 47, 68, 177, 210, + 98, 124, 230, 61, 238, 66, 104, 236, 191, 70, 46, 218, 26, 46, 194, 255, 215, 146, 70, 137, + 183, 164, 104, 10, 60, 100, 190, 150, 16, 223, 113, 213, 73, 121, 245, 61, 200, 123, 183, + 120, 158, 245, 88, 44, + ], + [ + 34, 22, 145, 135, 219, 16, 59, 168, 253, 71, 187, 213, 93, 117, 79, 0, 211, 18, 38, 69, 58, + 50, 106, 125, 41, 23, 119, 36, 26, 142, 79, 249, 18, 170, 34, 68, 137, 114, 130, 7, 23, 50, + 131, 197, 43, 227, 170, 73, 126, 44, 12, 252, 195, 181, 113, 202, 228, 32, 144, 164, 122, + 227, 146, 198, + ], +]; + +pub const VERIFYING_KEY: Groth16Verifyingkey<'static> = Groth16Verifyingkey { + nr_pubinputs: 3, + vk_alpha_g1: VK_ALPHA_G1, + vk_beta_g2: VK_BETA_G2, + vk_gamme_g2: VK_GAMMA_G2, + vk_delta_g2: VK_DELTA_G2, + vk_ic: &VK_IC, +}; diff --git a/programs/mirror-pool/tests/action_ceiling.rs b/programs/mirror-pool/tests/action_ceiling.rs new file mode 100644 index 00000000..85afbe52 --- /dev/null +++ b/programs/mirror-pool/tests/action_ceiling.rs @@ -0,0 +1,1045 @@ +//! What an action costs the crowd, measured against the compiled program. +//! +//! `batch_ceiling.rs` establishes that ten spends fit in one settlement and that +//! the 1232-byte packet, not compute, is what stops the eleventh. That number is +//! for plain transfers, where a spend brings exactly three accounts nobody else +//! shares: its record, its beneficiary and its relay. A spend whose action is a +//! CPI brings more — the callee's own program account, plus one slot per account +//! the action needs — so the ceiling for an action batch is lower, and until this +//! file nobody had taken it. +//! +//! The ceiling is not one number, because it is not a property of the action's +//! *shape* alone. Transaction size is driven by how many **distinct** keys the +//! message names, and two members delegating to the same validator name one vote +//! account between them while two members delegating to different validators name +//! two. So a batch whose members agree carries more members than a batch whose +//! members diverge: divergence in the content of an action is paid for in +//! anonymity-set size. That is the result this file is named for, and the two +//! stake batches below are settled for real rather than argued. +//! +//! Real means real. litesvm carries the Core BPF stake program, so a member's +//! `DelegateStake` here is executed by the actual stake program against a vote +//! account the actual vote program initialised, with the pool's vault signing as +//! the stake authority through `invoke_signed`. The batches settle, the stake +//! accounts end up delegated, and the compute the settlement consumed is +//! reported next to the bytes — because a size-only claim cannot say whether +//! compute also binds. +//! +//! Not every row is executed, and the table says which are. The two +//! stake-delegation rows — the result — are settled at their ceiling. The generic +//! curve around them (a call with k action accounts, shared between the members +//! or one each) is a size measurement and nothing more: it is taken from the +//! program's real instruction encoding rather than from arithmetic, but no batch +//! of that shape was run, so it is labelled `size only` and carries no compute +//! figure. The transfer row is the control: `batch_ceiling.rs` already settles it +//! against the same `.so`, so this file recomputing 10 spends / 1228 bytes is a +//! check on the encoder rather than a new claim. If that row ever moves, the +//! model of the wire here is wrong and every other number it prints is suspect. +//! +//! Requires `make build-sbf` first, like the rest of the on-chain suite. + +use litesvm::LiteSVM; +use mirror_circuit::{generate_reproducible, prove, Keys, SolanaProof, Witness}; +use mirror_core::{Field, MerkleTree, Note}; +use mirror_pool_program::{ + instruction::Instruction as MirrorIx, + pda::{pool_address, spend_address, vault_address}, + Pool, +}; +use solana_keypair::Keypair; +use solana_message::Message; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; +use solana_signer::Signer; +use solana_transaction::Transaction; + +const SEED: &[u8] = b"mirror-pool-reproducible-dev-setup-v1"; +const DENOMINATION: u64 = 100_000_000; // 0.1 SOL +const ENTRY_FEE: u64 = 0; +const K_FLOOR: u32 = 4; +const RELAY_FEE: u64 = 1_000_000; +const INVOKE_SIGNED: u64 = mirror_pool_program::processor::SELECTOR_INVOKE_SIGNED; + +/// The 1280-byte IPv6 minimum MTU, less a 40-byte IPv6 header and an 8-byte +/// fragment header. Restated here for the same reason `batch_ceiling.rs` restates +/// it: no crate this test already depends on re-exports +/// `solana_packet::PACKET_DATA_SIZE`, and a derivation a reader can check is +/// worth more than a constant they have to trust. +const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; + +/// What a transaction carrying a single non-budget instruction gets unless it +/// asks for more. Asking costs a second instruction, and at these batch sizes +/// there are no bytes to spare for one. +const DEFAULT_COMPUTE_BUDGET: u64 = 200_000; + +// The addresses of the programs and sysvars a stake delegation names. Written as +// strings because these are cluster constants rather than anything this +// repository derives, and because `solana-program` 4.0 no longer re-exports the +// stake and vote ids at all. +const STAKE_PROGRAM: &str = "Stake11111111111111111111111111111111111111"; +const VOTE_PROGRAM: &str = "Vote111111111111111111111111111111111111111"; +/// Unused by the current stake program and still required in the account list at +/// the position `DelegateStake` has always put it. It costs a slot either way, +/// which is the only reason this measurement cares. +const STAKE_CONFIG: &str = "StakeConfig11111111111111111111111111111111"; +const CLOCK_SYSVAR: &str = "SysvarC1ock11111111111111111111111111111111"; +const STAKE_HISTORY_SYSVAR: &str = "SysvarStakeHistory1111111111111111111111111"; +const RENT_SYSVAR: &str = "SysvarRent111111111111111111111111111111111"; + +/// `VoteStateV3::size_of()`, and `VoteStateV4` deliberately matches it. +const VOTE_STATE_LEN: usize = 3762; +/// `StakeStateV2::size_of()`. +const STAKE_STATE_LEN: usize = 200; + +/// `StakeInstruction::DelegateStake`, bincode-encoded: a unit variant at index +/// two of the enum, which is a four-byte little-endian discriminant and nothing +/// else. This is the entire payload a member commits to when they delegate — the +/// validator is chosen by an *account*, not by the instruction data, which is +/// exactly why divergent validators cost keys rather than bytes. +const DELEGATE_STAKE: [u8; 4] = [2, 0, 0, 0]; + +/// What each stake account holds before the pool delegates it. +/// +/// It has to be pre-funded, and the reason is the selector rather than the test +/// rig: `SELECTOR_INVOKE_SIGNED` pays the beneficiary *after* the call so that +/// the vault's lamports are untouched at the moment it signs, so the amount the +/// stake program sees is whatever the account already held. The member's payout +/// lands on top of the delegation afterwards. One SOL clears the stake program's +/// minimum delegation with room to spare. +const PRE_STAKED: u64 = 1_000_000_000; + +// --------------------------------------------------------------------------- +// The answers, pinned +// +// Produced by the tests below and written back here. A fourth account per spend, +// or a stake delegation that grows a slot, must fail a test rather than quietly +// shrink the crowd a single settlement can carry. +// --------------------------------------------------------------------------- + +/// The plain-transfer ceiling, recomputed here from the encoder and cross-checked +/// against the executed measurement in `batch_ceiling.rs`. +const TRANSFER_CEILING: usize = 10; +const TRANSFER_BYTES: usize = 1228; + +/// A batch of members all delegating to the **same** validator. Per spend the +/// distinct keys are the record, the stake account and the relay; the vote +/// account, the two sysvars, the config account, the stake program and the pool's +/// vault are named once for the whole batch. +const SAME_VALIDATOR_CEILING: usize = 7; +const SAME_VALIDATOR_BYTES: usize = 1140; + +/// The same delegation where every member picked their own validator. One more +/// distinct key per spend, and the crowd loses a member. +const DIFFERENT_VALIDATOR_CEILING: usize = 6; +const DIFFERENT_VALIDATOR_BYTES: usize = 1194; + +fn key(s: &str) -> Pubkey { + s.parse().expect("a valid base58 address") +} + +fn program_bytes() -> Vec { + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../target/sbf/deploy/mirror_pool_program.so" + ); + std::fs::read(path).unwrap_or_else(|e| { + panic!("could not read {path}: {e}\n\nRun `make build-sbf` first."); + }) +} + +// --------------------------------------------------------------------------- +// The wire +// --------------------------------------------------------------------------- + +/// The three accounts every settlement names before the batch begins. +/// +/// Split out from the SVM because transaction size is a pure function of the +/// message, so the sweeps below cost nothing to run and the real settlements can +/// be checked against them. +#[derive(Clone, Copy)] +struct Wire { + program_id: Pubkey, + pool: Pubkey, + vault: Pubkey, +} + +impl Wire { + fn new(program_id: Pubkey) -> Self { + let (pool, _) = pool_address(&program_id, DENOMINATION); + let (vault, _) = vault_address(&program_id, &pool); + Wire { + program_id, + pool, + vault, + } + } +} + +/// One spend in the order `settle_epoch` walks it: the record, the beneficiary +/// the proof bound, the relay that submitted it, then — for a CPI selector — the +/// callee's own program account followed by exactly the accounts the action +/// declared. The target precedes the action accounts because the handler reads it +/// first; getting that order wrong would measure a transaction the program cannot +/// execute. +struct Spend { + record: Pubkey, + beneficiary: Pubkey, + relay: Pubkey, + target: Option, + action: Vec, +} + +fn settle_ix(wire: &Wire, batch: &[Spend], settler: &Pubkey) -> Instruction { + let mut metas = vec![ + AccountMeta::new(*settler, true), + AccountMeta::new(wire.pool, false), + AccountMeta::new(wire.vault, false), + ]; + for spend in batch { + metas.push(AccountMeta::new(spend.record, false)); + metas.push(AccountMeta::new(spend.beneficiary, false)); + metas.push(AccountMeta::new(spend.relay, false)); + if let Some(target) = spend.target { + metas.push(AccountMeta::new_readonly(target, false)); + } + metas.extend(spend.action.iter().cloned()); + } + Instruction::new_with_bytes( + wire.program_id, + &MirrorIx::SettleEpoch { + count: batch.len() as u8, + } + .pack(), + metas, + ) +} + +fn settle_tx(svm: &LiteSVM, wire: &Wire, batch: &[Spend], settler: &Keypair) -> Transaction { + let ix = settle_ix(wire, batch, &settler.pubkey()); + let msg = Message::new(&[ix], Some(&settler.pubkey())); + Transaction::new(&[settler], msg, svm.latest_blockhash()) +} + +/// What this transaction weighs on the wire. +/// +/// A legacy transaction is a compact array of 64-byte signatures followed by the +/// serialized message, and `Message::serialize` is what a validator receives +/// rather than an approximation of it. The single-byte length prefix is asserted +/// rather than assumed: a second signer would move every number in this file by +/// 65 bytes without changing anything visible at the call site. +fn wire_len(tx: &Transaction) -> usize { + assert_eq!( + tx.signatures.len(), + 1, + "the framing here holds for a single signature" + ); + 1 + 64 * tx.signatures.len() + tx.message.serialize().len() +} + +// --------------------------------------------------------------------------- +// Shapes +// --------------------------------------------------------------------------- + +/// Where the key in an action's account slot comes from, which is the only thing +/// about that slot the encoding cares about. +/// +/// A slot always costs one byte in the instruction's account-index list. Whether +/// it also costs 32 bytes of key depends entirely on whether the batch has named +/// that account already — which is why `Shared`, `Vault` and `Beneficiary` are +/// distinguished from `Unique` at all. +#[derive(Clone, Copy)] +enum Slot { + /// A key belonging to this spend alone: a second member's identical action + /// would name a different one. Every member's own vote account, under + /// divergent delegation. + Unique, + /// A key the whole batch shares. The index picks *which* shared key, so two + /// shared slots are two accounts, not one. + Shared(usize), + /// The pool's vault, which the settlement has already named as its third + /// account. Free in keys, one byte in indices. + Vault, + /// This spend's own beneficiary, already named. A stake delegation puts the + /// stake account here, and it is the same account the payout goes to. + Beneficiary, +} + +/// A settlement shape: what each spend in the batch brings. +struct Shape { + name: String, + /// Whether the selector makes a call, and so whether each spend also names + /// the callee's program account. Shared across a batch whose members all + /// invoke the same program, which is the interesting case. + calls: bool, + action: Vec, +} + +impl Shape { + fn transfer() -> Self { + Shape { + name: "transfer".into(), + calls: false, + action: Vec::new(), + } + } + + fn cpi(name: &str, action: Vec) -> Self { + Shape { + name: name.into(), + calls: true, + action, + } + } + + /// The stake delegation both experiments below settle for real, in the order + /// `DelegateStake` requires: stake account, vote account, clock, stake + /// history, the unused config account, and the stake authority — which for a + /// member who must never appear on chain can only be the pool's vault. + fn delegation(name: &str, vote: Slot) -> Self { + Shape::cpi( + name, + vec![ + Slot::Beneficiary, + vote, + Slot::Shared(1), + Slot::Shared(2), + Slot::Shared(3), + Slot::Vault, + ], + ) + } + + /// How many keys a spend of this shape adds that no other spend shares: the + /// record, the beneficiary and the relay, plus its unique action accounts. + /// This is the number the ceiling actually turns on. + fn distinct_keys_per_spend(&self) -> usize { + 3 + self + .action + .iter() + .filter(|s| matches!(s, Slot::Unique)) + .count() + } + + fn slots_per_spend(&self) -> usize { + 3 + usize::from(self.calls) + self.action.len() + } +} + +/// A batch of `n` spends of this shape, filled with placeholder keys. +/// +/// Placeholders are legitimate here for the reason `batch_ceiling.rs` sets out: +/// transaction size depends on how many distinct accounts a message names, not on +/// which. What placeholders cannot check is that the shape is the one the program +/// walks — so the real settlements below assert their own wire size against the +/// prediction this makes, and a mistake in the model fails a test instead of +/// quietly biasing the answer. +fn placeholder_batch(wire: &Wire, shape: &Shape, n: usize) -> Vec { + let target = Pubkey::new_unique(); + let shared: Vec = (0..shape.action.len().max(1)) + .map(|_| Pubkey::new_unique()) + .collect(); + (0..n) + .map(|_| { + let beneficiary = Pubkey::new_unique(); + let action = shape + .action + .iter() + .map(|slot| match slot { + Slot::Unique => AccountMeta::new_readonly(Pubkey::new_unique(), false), + Slot::Shared(i) => AccountMeta::new_readonly(shared[*i], false), + Slot::Vault => AccountMeta::new_readonly(wire.vault, false), + Slot::Beneficiary => AccountMeta::new(beneficiary, false), + }) + .collect(); + Spend { + record: Pubkey::new_unique(), + beneficiary, + relay: Pubkey::new_unique(), + target: shape.calls.then_some(target), + action, + } + }) + .collect() +} + +/// The largest batch of this shape that still fits in a packet, and its size, +/// found by serializing rather than by arithmetic. +/// +/// The sweep stops at the first batch that does not fit, which is sound because +/// size is monotonic in the batch length — every extra spend adds slots and can +/// only add keys. It is also necessary: a message can name at most 256 accounts, +/// and a shape with four unique action accounts reaches that ceiling long before +/// the loop would otherwise end, which is a panic rather than a measurement. +fn ceiling_of(svm: &LiteSVM, wire: &Wire, settler: &Keypair, shape: &Shape) -> (usize, usize) { + let mut answer = (0, 0); + for n in 1..=64 { + let batch = placeholder_batch(wire, shape, n); + let bytes = wire_len(&settle_tx(svm, wire, &batch, settler)); + if bytes > PACKET_DATA_SIZE { + break; + } + answer = (n, bytes); + } + answer +} + +// --------------------------------------------------------------------------- +// The pool +// --------------------------------------------------------------------------- + +struct Env { + svm: LiteSVM, + wire: Wire, + payer: Keypair, +} + +fn setup() -> Env { + let mut svm = LiteSVM::new(); + let program_id = Pubkey::new_unique(); + svm.add_program(program_id, &program_bytes()) + .expect("loading the built program"); + + let payer = Keypair::new(); + svm.airdrop(&payer.pubkey(), 1_000_000_000_000).unwrap(); + + Env { + svm, + wire: Wire::new(program_id), + payer, + } +} + +impl Env { + fn send(&mut self, ixs: &[Instruction], signers: &[&Keypair]) -> Result { + let msg = Message::new(ixs, Some(&signers[0].pubkey())); + let tx = Transaction::new(signers, msg, self.svm.latest_blockhash()); + self.svm + .send_transaction(tx) + .map(|m| m.compute_units_consumed) + .map_err(|e| format!("{:?} | logs: {:#?}", e.err, e.meta.logs)) + } + + fn init_pool(&mut self) { + let ix = Instruction::new_with_bytes( + self.wire.program_id, + &MirrorIx::InitPool { + denomination: DENOMINATION, + entry_fee: ENTRY_FEE, + k_floor: K_FLOOR, + } + .pack(), + vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.wire.pool, false), + AccountMeta::new(self.wire.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let payer = self.payer.insecure_clone(); + self.send(&[ix], &[&payer]).expect("init_pool"); + } + + fn deposit(&mut self, commitment: Field) { + let depositor = Keypair::new(); + self.svm + .airdrop(&depositor.pubkey(), DENOMINATION + 10_000_000) + .unwrap(); + let ix = Instruction::new_with_bytes( + self.wire.program_id, + &MirrorIx::Deposit { + commitment: commitment.to_bytes(), + } + .pack(), + vec![ + AccountMeta::new(depositor.pubkey(), true), + AccountMeta::new(self.wire.pool, false), + AccountMeta::new(self.wire.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + self.send(&[ix], &[&depositor]).expect("deposit"); + } + + fn spend_count(&self) -> u64 { + let mut data = self + .svm + .get_account(&self.wire.pool) + .expect("pool exists") + .data; + Pool::load(&mut data).unwrap().spend_count() + } + + /// A vote account made by the real vote program, so the stake program is + /// handed genuine state rather than bytes this test guessed at. + fn make_vote_account(&mut self) -> Pubkey { + let vote = Keypair::new(); + let node = Keypair::new(); + let lamports = self.svm.minimum_balance_for_rent_exemption(VOTE_STATE_LEN); + let create = solana_system_interface::instruction::create_account( + &self.payer.pubkey(), + &vote.pubkey(), + lamports, + VOTE_STATE_LEN as u64, + &key(VOTE_PROGRAM), + ); + // `VoteInstruction::InitializeAccount(VoteInit)`: a four-byte variant + // index of zero, then the node identity, the authorized voter, the + // authorized withdrawer and a one-byte commission. Hand-encoded because + // the vote interface crate is not a dependency of this program and the + // encoding is four fields long. + let mut data = Vec::with_capacity(101); + data.extend_from_slice(&0u32.to_le_bytes()); + data.extend_from_slice(&node.pubkey().to_bytes()); + data.extend_from_slice(&node.pubkey().to_bytes()); + data.extend_from_slice(&node.pubkey().to_bytes()); + data.push(0); + let init = Instruction::new_with_bytes( + key(VOTE_PROGRAM), + &data, + vec![ + AccountMeta::new(vote.pubkey(), false), + AccountMeta::new_readonly(key(RENT_SYSVAR), false), + AccountMeta::new_readonly(key(CLOCK_SYSVAR), false), + AccountMeta::new_readonly(node.pubkey(), true), + ], + ); + let payer = self.payer.insecure_clone(); + self.send(&[create, init], &[&payer, &vote, &node]) + .expect("initialising a vote account"); + vote.pubkey() + } + + /// A stake account whose authority is the pool's vault, created and + /// initialised by the real stake program. + /// + /// The keypair is supplied by the caller because the stake account is the + /// spend's beneficiary and therefore inside the member's proof: the same + /// address has to exist in every pool a given proof is replayed into. + fn make_stake_account(&mut self, stake: &Keypair) { + let lamports = self.svm.minimum_balance_for_rent_exemption(STAKE_STATE_LEN) + PRE_STAKED; + let create = solana_system_interface::instruction::create_account( + &self.payer.pubkey(), + &stake.pubkey(), + lamports, + STAKE_STATE_LEN as u64, + &key(STAKE_PROGRAM), + ); + // `StakeInstruction::Initialize(Authorized, Lockup)`: variant index zero, + // then staker and withdrawer, then a lockup of no timestamp, no epoch and + // no custodian. Both authorities are the vault, because the member never + // appears on chain and nobody else may move this stake. + let mut data = Vec::with_capacity(116); + data.extend_from_slice(&0u32.to_le_bytes()); + data.extend_from_slice(&self.wire.vault.to_bytes()); + data.extend_from_slice(&self.wire.vault.to_bytes()); + data.extend_from_slice(&0i64.to_le_bytes()); + data.extend_from_slice(&0u64.to_le_bytes()); + data.extend_from_slice(&[0u8; 32]); + let init = Instruction::new_with_bytes( + key(STAKE_PROGRAM), + &data, + vec![ + AccountMeta::new(stake.pubkey(), false), + AccountMeta::new_readonly(key(RENT_SYSVAR), false), + ], + ); + let payer = self.payer.insecure_clone(); + self.send(&[create, init], &[&payer, stake]) + .expect("initialising a stake account"); + } + + /// True once the stake program has written a delegation into the account. + /// + /// `StakeStateV2` is a bincode enum and variant two is `Stake`, so the first + /// four bytes are the whole test. Reading the discriminant rather than + /// trusting the transaction's success means a settlement that returned Ok + /// without the CPI actually landing cannot pass. + fn is_delegated(&self, stake: &Pubkey) -> bool { + self.svm + .get_account(stake) + .map(|a| a.data[..4] == [2, 0, 0, 0]) + .unwrap_or(false) + } +} + +/// A member's proof and the stake account it was bound to. +/// +/// The binding covers the selector, the target program, the beneficiary, the +/// relay fee, the declared account count and the payload — and nothing else. The +/// vote account is a settler-supplied slot, so the *same* proof serves both +/// experiments below: agreeing on a validator and diverging over one are the same +/// spend as far as the member's commitment is concerned, which is precisely why +/// the cost of diverging is measured in keys rather than in proofs. +struct Ticket { + proof: SolanaProof, + stake: Keypair, + relay: Keypair, +} + +fn host_tree(count: usize) -> (MerkleTree, Vec) { + let denom_tag = Field::from_u64(DENOMINATION); + let mut tree = MerkleTree::new().unwrap(); + let mut notes = Vec::new(); + for i in 1..=count as u64 { + let note = Note::new( + Field::from_u64(i * 1_000_003), + Field::from_u64(i * 7_919), + denom_tag, + ); + tree.insert(note.commitment().unwrap()).unwrap(); + notes.push(note); + } + (tree, notes) +} + +fn prove_delegations(keys: &Keys, tree: &MerkleTree, notes: &[Note]) -> Vec { + use ark_std::rand::SeedableRng; + notes + .iter() + .enumerate() + .map(|(index, note)| { + let stake = Keypair::new(); + // Minted before the binding, not after: the relay is part of the + // preimage now, so the proof has to know which key will carry it. + let relay = Keypair::new(); + let merkle_proof = tree.proof(index as u64).unwrap(); + let binding = mirror_core::action_binding( + INVOKE_SIGNED, + &key(STAKE_PROGRAM).to_bytes(), + &stake.pubkey().to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + 6, + &DELEGATE_STAKE, + ); + let witness = Witness { + note: *note, + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8; 32]); + Ticket { + proof: prove(keys, &witness, &mut rng).expect("proving"), + stake, + relay, + } + }) + .collect() +} + +/// One spend of the delegation shape, ready for settlement. +fn delegation_spend(wire: &Wire, ticket: &Ticket, vote: &Pubkey) -> Spend { + let nullifier = ticket.proof.public_inputs[1]; + let (record, _) = spend_address(&wire.program_id, &wire.pool, &nullifier); + Spend { + record, + beneficiary: ticket.stake.pubkey(), + relay: ticket.relay.pubkey(), + target: Some(key(STAKE_PROGRAM)), + action: vec![ + AccountMeta::new(ticket.stake.pubkey(), false), + AccountMeta::new_readonly(*vote, false), + AccountMeta::new_readonly(key(CLOCK_SYSVAR), false), + AccountMeta::new_readonly(key(STAKE_HISTORY_SYSVAR), false), + AccountMeta::new_readonly(key(STAKE_CONFIG), false), + // Not marked a signer here, and it cannot be: a PDA has no key. The + // signature comes from `invoke_signed` inside the program, from seeds + // only the program holds. + AccountMeta::new_readonly(wire.vault, false), + ], + } +} + +/// A fresh pool holding `notes`, with every delegation submitted and pending, and +/// with the stake accounts the proofs named already initialised. +/// +/// `distinct_votes` is the entire difference between the two experiments: with it +/// false the crowd agrees on one validator, with it true every member brings their +/// own. Everything else — the notes, the proofs, the payload, the stake accounts — +/// is identical, which is what makes the two ceilings comparable at all. +fn pending_pool(notes: &[Note], tickets: &[Ticket], distinct_votes: bool) -> (Env, Vec) { + let mut env = setup(); + env.init_pool(); + for note in notes { + env.deposit(note.commitment().unwrap()); + } + + let shared_vote = (!distinct_votes).then(|| env.make_vote_account()); + let mut spends = Vec::new(); + for (i, ticket) in tickets.iter().enumerate() { + env.make_stake_account(&ticket.stake); + env.svm + .airdrop(&ticket.relay.pubkey(), 10_000_000_000) + .unwrap(); + + let nullifier = ticket.proof.public_inputs[1]; + let (record, _) = spend_address(&env.wire.program_id, &env.wire.pool, &nullifier); + let ix = Instruction::new_with_bytes( + env.wire.program_id, + &MirrorIx::SubmitSpend { + proof_a: ticket.proof.proof_a, + proof_b: ticket.proof.proof_b, + proof_c: ticket.proof.proof_c, + root: ticket.proof.public_inputs[0], + nullifier, + selector: INVOKE_SIGNED, + target_program: key(STAKE_PROGRAM).to_bytes(), + beneficiary: ticket.stake.pubkey().to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 6, + payload: DELEGATE_STAKE.to_vec(), + } + .pack(), + vec![ + AccountMeta::new(ticket.relay.pubkey(), true), + AccountMeta::new(env.wire.pool, false), + AccountMeta::new(record, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let relay = ticket.relay.insecure_clone(); + env.send(&[ix], &[&relay]) + .unwrap_or_else(|e| panic!("submit {i} failed: {e}")); + + let vote = match shared_vote { + Some(vote) => vote, + None => env.make_vote_account(), + }; + spends.push(delegation_spend(&env.wire, ticket, &vote)); + } + (env, spends) +} + +// --------------------------------------------------------------------------- +// The measurements +// --------------------------------------------------------------------------- + +/// The curve, as a table, before anything is settled. +/// +/// Nothing in *this* test executes: it is the encoding alone, which is free, and +/// that is what makes it worth printing across the whole range rather than at the +/// two points the executed test can afford. Every row says where its number comes +/// from, because "size only" and "settled" are not the same claim and a table +/// that blurs them is the kind of thing this repository does not publish. +/// +/// The transfer row is the control. It has to reproduce the ceiling +/// `batch_ceiling.rs` reached by settling real spends; if it does not, this +/// file's model of the wire is wrong and nothing else it prints can be trusted. +#[test] +fn every_account_an_action_names_costs_the_batch_a_member() { + let svm = LiteSVM::new(); + let wire = Wire::new(Pubkey::new_unique()); + let settler = Keypair::new(); + + let row = |shape: &Shape, taken: &str| { + let (ceiling, bytes) = ceiling_of(&svm, &wire, &settler, shape); + assert!(ceiling > 0, "{} does not fit at all", shape.name); + println!( + " {:<28} {:>5} {:>5} {:>8} {:>6} {taken}", + shape.name, + shape.slots_per_spend(), + shape.distinct_keys_per_spend(), + ceiling, + bytes + ); + (ceiling, bytes) + }; + + println!("\n shape slots keys ceiling bytes taken by"); + let transfer = row(&Shape::transfer(), "size; settled in batch_ceiling.rs"); + let bare_call = row(&Shape::cpi("call, no accounts", Vec::new()), "size only"); + + // The two curves the table exists to separate: the same action account + // *count* costing shared keys, and costing a key per member. Only the second + // curve is a statement about anonymity — the first is what a batch pays for + // making a call at all. + let mut shared_curve = vec![(0usize, bare_call)]; + let mut unique_curve = Vec::new(); + for k in [1usize, 2, 4, 6, 8] { + let shared = row( + &Shape::cpi( + &format!("call, {k} shared"), + (0..k).map(Slot::Shared).collect(), + ), + "size only", + ); + let unique = row( + &Shape::cpi( + &format!("call, {k} per member"), + (0..k).map(|_| Slot::Unique).collect(), + ), + "size only", + ); + assert!( + unique.0 < shared.0, + "with {k} action accounts, a batch whose members name their own \ + accounts carried {} members and a batch that shares them carried \ + {}: naming a distinct account has stopped costing anything, which \ + the encoding cannot do", + unique.0, + shared.0 + ); + shared_curve.push((k, shared)); + unique_curve.push((k, unique)); + } + + let same = row( + &Shape::delegation("delegate, one validator", Slot::Shared(0)), + "size; settled below", + ); + let diverging = row( + &Shape::delegation("delegate, a validator each", Slot::Unique), + "size; settled below", + ); + println!(); + + assert_eq!( + transfer, + (TRANSFER_CEILING, TRANSFER_BYTES), + "the transfer row no longer reproduces the executed measurement in \ + batch_ceiling.rs, so this file's encoding of a settlement is wrong and \ + every other number it prints is unsafe" + ); + assert_eq!( + same, + (SAME_VALIDATOR_CEILING, SAME_VALIDATOR_BYTES), + "the ceiling for a batch delegating to one validator moved" + ); + assert_eq!( + diverging, + (DIFFERENT_VALIDATOR_CEILING, DIFFERENT_VALIDATOR_BYTES), + "the ceiling for a batch delegating to a validator each moved" + ); + + // Both curves have to fall. An action that needs more accounts can never + // carry more members than one that needs fewer, whoever the accounts belong + // to; if that ever stops holding, the model of the wire above is wrong. + for curve in [&shared_curve, &unique_curve] { + for pair in curve.windows(2) { + let [(smaller, (more, _)), (larger, (fewer, _))] = pair else { + unreachable!("windows(2) yields pairs") + }; + assert!( + fewer <= more, + "{larger} action accounts carried {fewer} members and {smaller} \ + carried {more}, so a larger action bought a larger crowd" + ); + } + } +} + +/// The result, settled rather than serialized. +/// +/// Two crowds of members ask the pool to delegate stake on their behalf. In the +/// first every member picked the same validator; in the second every member +/// picked their own. Nothing else differs — not the selector, not the payload, +/// not the proofs, which are literally the same proofs replayed into a second +/// pool, because the vote account is a settlement slot rather than something the +/// member committed to. +/// +/// The agreeing crowd fits one more member. That is the whole finding: an +/// anonymity set is bounded by how much its members' actions have in common, and +/// on Solana the bound is mechanical rather than statistical — a batch that names +/// more distinct accounts does not fit in a packet, whatever the members wanted. +/// +/// Both ceilings are executed against the real `.so` and the real stake program, +/// and both are checked against the byte count the placeholder sweep predicted, +/// so a mistake in the model above fails here rather than passing quietly. The +/// batch one larger than each ceiling is then settled in a fresh pool to show +/// what actually stops it: the SVM takes it, so the packet is the constraint and +/// compute is not close. +#[test] +fn a_crowd_that_agrees_on_its_validator_carries_one_more_member() { + let probe_svm = LiteSVM::new(); + let probe_wire = Wire::new(Pubkey::new_unique()); + let prober = Keypair::new(); + let same_shape = Shape::delegation("same", Slot::Shared(0)); + let diverging_shape = Shape::delegation("diverging", Slot::Unique); + let (same_bracket, _) = ceiling_of(&probe_svm, &probe_wire, &prober, &same_shape); + let (diverging_bracket, _) = ceiling_of(&probe_svm, &probe_wire, &prober, &diverging_shape); + println!( + "the encoding admits {same_bracket} delegations to one validator and \ + {diverging_bracket} to a validator each; proving one more than the larger" + ); + + let keys = generate_reproducible(SEED).expect("setup"); + let (tree, notes) = host_tree(same_bracket.max(diverging_bracket) + 1); + let tickets = prove_delegations(&keys, &tree, ¬es); + + let same = settle_at_ceiling(¬es, &tickets, false, "one validator"); + let diverging = settle_at_ceiling(¬es, &tickets, true, "a validator each"); + + assert_eq!( + (same.0, same.1), + (SAME_VALIDATOR_CEILING, SAME_VALIDATOR_BYTES), + "the executed ceiling for a batch delegating to one validator moved" + ); + assert_eq!( + (diverging.0, diverging.1), + (DIFFERENT_VALIDATOR_CEILING, DIFFERENT_VALIDATOR_BYTES), + "the executed ceiling for a batch delegating to a validator each moved" + ); + assert!( + same.0 > diverging.0, + "agreeing on a validator no longer buys the crowd a member: {} against {}", + same.0, + diverging.0 + ); + println!( + "\n a crowd that agrees on its validator settles {} members; a crowd that \ + diverges settles {}. The divergent batch names {} distinct keys per spend \ + instead of {}, and the extra key is the whole difference.\n", + same.0, + diverging.0, + diverging_shape.distinct_keys_per_spend(), + same_shape.distinct_keys_per_spend() + ); +} + +/// Settles the largest batch that fits, and then demonstrates what stops the next +/// one. Returns the ceiling and its wire size. +/// +/// The shape is derived from `distinct_votes` rather than passed alongside it, so +/// the batch this settles and the batch the placeholder sweep models cannot drift +/// apart. Every real batch is weighed against its placeholder twin at the same +/// length: that is what turns the free sweep from an assumption into a checked +/// prediction, and it is the only thing standing between this file and a table of +/// numbers about a transaction the program could not execute. +/// +/// The sweep runs *downward* from the bracket for the same reason +/// `batch_ceiling.rs` does: a rejected settlement leaves its records pending, so +/// one pool can be asked many times, but an accepted one consumes them, so the +/// first acceptance has to be the answer. +fn settle_at_ceiling( + notes: &[Note], + tickets: &[Ticket], + distinct_votes: bool, + label: &str, +) -> (usize, usize) { + let shape = Shape::delegation( + label, + if distinct_votes { + Slot::Unique + } else { + Slot::Shared(0) + }, + ); + let (mut env, pending) = pending_pool(notes, tickets, distinct_votes); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let (bracket, _) = ceiling_of(&env.svm, &env.wire, &settler, &shape); + + let mut ceiling = 0usize; + let mut bytes_at_ceiling = 0usize; + let mut cu_at_ceiling = 0u64; + for n in (1..=bracket).rev() { + let tx = settle_tx(&env.svm, &env.wire, &pending[..n], &settler); + let bytes = wire_len(&tx); + let predicted = wire_len(&settle_tx( + &env.svm, + &env.wire, + &placeholder_batch(&env.wire, &shape, n), + &settler, + )); + assert_eq!( + bytes, predicted, + "the placeholder model of {label} weighs a batch of {n} differently \ + from the real one, so the table this file prints describes a \ + settlement that does not exist" + ); + assert!( + bytes <= PACKET_DATA_SIZE, + "the placeholder bracket disagreed with a real batch of {n}: {bytes} bytes" + ); + match env.svm.send_transaction(tx) { + Ok(meta) => { + ceiling = n; + bytes_at_ceiling = bytes; + cu_at_ceiling = meta.compute_units_consumed; + break; + } + Err(e) => println!( + "{n} delegations fit in {bytes} bytes but failed: {:?}", + e.err + ), + } + } + assert!(ceiling > 0, "no batch of delegations settled at all"); + assert_eq!( + env.spend_count(), + ceiling as u64, + "the settlement that succeeded did not settle the whole batch" + ); + // The transaction succeeding is not evidence that the delegations happened; + // the stake accounts saying so is. + for spend in &pending[..ceiling] { + assert!( + env.is_delegated(&spend.beneficiary), + "settlement returned Ok but {} was never delegated", + spend.beneficiary + ); + } + println!( + "settled {ceiling} real stake delegations ({label}) in one transaction: \ + {bytes_at_ceiling} bytes ({} to spare), {cu_at_ceiling} CU of \ + {DEFAULT_COMPUTE_BUDGET}", + PACKET_DATA_SIZE - bytes_at_ceiling + ); + assert!( + cu_at_ceiling < DEFAULT_COMPUTE_BUDGET, + "a full settlement used {cu_at_ceiling} CU, over the default budget" + ); + + // Why one more fails, and it takes two judges. litesvm never sees a packet, + // so it will happily execute a batch no validator would accept; the wire + // format never sees a compute meter. The same batch of `ceiling + 1` is + // measured on the wire and replayed into a second, identical pool where the + // SVM rules on it. + let over = ceiling + 1; + let (mut second, again) = pending_pool(notes, tickets, distinct_votes); + let other = Keypair::new(); + second.svm.airdrop(&other.pubkey(), 10_000_000_000).unwrap(); + let tx = settle_tx(&second.svm, &second.wire, &again[..over], &other); + let bytes_over = wire_len(&tx); + assert_eq!( + bytes_over, + wire_len(&settle_tx( + &second.svm, + &second.wire, + &placeholder_batch(&second.wire, &shape, over), + &other, + )), + "the placeholder model and the real batch disagree at {over} spends" + ); + let verdict = second.svm.send_transaction(tx); + + assert!( + bytes_over > PACKET_DATA_SIZE, + "{over} delegations fit in {bytes_over} bytes, so the packet is not what \ + stops them and the sweep above stopped one short" + ); + let Ok(over_meta) = &verdict else { + panic!( + "the SVM refused {over} delegations, so the packet limit is not the \ + only thing in the way and this ceiling reports the wrong constraint" + ) + }; + assert!( + over_meta.compute_units_consumed < DEFAULT_COMPUTE_BUDGET, + "settling {over} delegations cost {} CU, at or over the default budget, so \ + compute now binds alongside the packet", + over_meta.compute_units_consumed + ); + println!( + "{over} delegations ({label}): rejected by the wire at {bytes_over} bytes, \ + {} over the {PACKET_DATA_SIZE}-byte limit — while the SVM settled the same \ + batch in {} CU, so compute is not the constraint", + bytes_over - PACKET_DATA_SIZE, + over_meta.compute_units_consumed + ); + + (ceiling, bytes_at_ceiling) +} diff --git a/programs/mirror-pool/tests/batch_ceiling.rs b/programs/mirror-pool/tests/batch_ceiling.rs new file mode 100644 index 00000000..ce566296 --- /dev/null +++ b/programs/mirror-pool/tests/batch_ceiling.rs @@ -0,0 +1,514 @@ +//! How many spends actually fit in one settlement, measured against the compiled +//! program. +//! +//! `settle_epoch` takes a count and reads three accounts per spend, and every +//! sentence in this repository that says "batch" is quietly assuming that count +//! can be large. Two unrelated things bound it: the 1232-byte packet a +//! transaction has to fit inside, and the compute budget the instruction runs +//! under. Only one of them binds, and which one it is changes what a settler +//! should do about it — ask for more compute, or send more transactions. +//! +//! So the number is taken rather than argued. Nothing below is extrapolated from +//! a smaller batch: the ceiling is found by settling real spends against the real +//! `.so` in litesvm, and both limits are reported at the answer. +//! +//! **This measures a *legacy* transaction, and that scoping is the whole +//! meaning of the number.** A legacy message names every account by its full 32 +//! bytes, which is what makes a member cost ~99 bytes and what puts the wall at +//! ten. A v0 message may instead resolve accounts through an address lookup +//! table published on chain, at one byte per account — the packet then stops +//! binding entirely, and something else takes over. `crates/mirror-cli/src/ +//! lookup.rs` is that path, and `mirror settle` takes it automatically for any +//! batch this test would refuse. Ten is the floor a settler gets with no setup +//! at all, not the most the program can do. +//! +//! Requires `make build-sbf` first, like the end-to-end suite. This is a +//! measurement of the deployed artefact, not of the host crate, so a missing +//! artefact says so rather than quietly measuring nothing. + +use litesvm::LiteSVM; +use mirror_circuit::{generate_reproducible, prove, Keys, SolanaProof, Witness}; +use mirror_core::{Field, MerkleTree, Note}; +use mirror_pool_program::{ + instruction::Instruction as MirrorIx, + pda::{pool_address, spend_address, vault_address}, + Pool, +}; +use solana_keypair::Keypair; +use solana_message::Message; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; +use solana_signer::Signer; +use solana_transaction::Transaction; + +const SEED: &[u8] = b"mirror-pool-reproducible-dev-setup-v1"; +const DENOMINATION: u64 = 100_000_000; // 0.1 SOL +const ENTRY_FEE: u64 = 0; +const K_FLOOR: u32 = 4; +const RELAY_FEE: u64 = 1_000_000; +const SELECTOR: u64 = mirror_pool_program::processor::SELECTOR_TRANSFER; + +/// The 1280-byte IPv6 minimum MTU, less a 40-byte IPv6 header and an 8-byte +/// fragment header. Restated here because no crate this test already depends on +/// re-exports it; `solana_packet::PACKET_DATA_SIZE` is the original, and the +/// derivation is written out so a reader can check the number rather than trust +/// it. +const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; + +/// What a transaction carrying a single non-budget instruction is given unless it +/// asks for more. Asking costs a second instruction, and a second instruction +/// costs bytes this measurement has none to spare — which is the whole reason the +/// two limits have to be reported together rather than one at a time. +const DEFAULT_COMPUTE_BUDGET: u64 = 200_000; + +// --------------------------------------------------------------------------- +// The answers, pinned +// +// Produced by the test at the bottom of this file and written back here, so that +// a change to the account shape of `settle_epoch` — a fourth account per spend, +// a signer added to the batch — fails a test instead of silently halving what a +// settler can carry. +// --------------------------------------------------------------------------- + +/// The largest batch that both fits in a packet and executes. +const MAX_SPENDS_PER_SETTLEMENT: usize = 10; +/// The wire size of that settlement. There is no room for an eleventh spend and +/// not much room for anything else either. +const BYTES_AT_MAX: usize = 1228; + +fn program_bytes() -> Vec { + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../target/sbf/deploy/mirror_pool_program.so" + ); + std::fs::read(path).unwrap_or_else(|e| { + panic!("could not read {path}: {e}\n\nRun `make build-sbf` first."); + }) +} + +struct Env { + svm: LiteSVM, + program_id: Pubkey, + payer: Keypair, + pool: Pubkey, + vault: Pubkey, +} + +fn setup() -> Env { + let mut svm = LiteSVM::new(); + let program_id = Pubkey::new_unique(); + svm.add_program(program_id, &program_bytes()) + .expect("loading the built program"); + + let payer = Keypair::new(); + svm.airdrop(&payer.pubkey(), 100_000_000_000).unwrap(); + + let (pool, _) = pool_address(&program_id, DENOMINATION); + let (vault, _) = vault_address(&program_id, &pool); + + Env { + svm, + program_id, + payer, + pool, + vault, + } +} + +impl Env { + fn send(&mut self, ix: Instruction, signer: &Keypair) -> Result<(), String> { + let msg = Message::new(&[ix], Some(&signer.pubkey())); + let tx = Transaction::new(&[signer], msg, self.svm.latest_blockhash()); + self.svm + .send_transaction(tx) + .map(|_| ()) + .map_err(|e| format!("{:?}", e.err)) + } + + fn init_pool(&mut self) { + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::InitPool { + denomination: DENOMINATION, + entry_fee: ENTRY_FEE, + k_floor: K_FLOOR, + } + .pack(), + vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let payer = self.payer.insecure_clone(); + self.send(ix, &payer).expect("init_pool"); + } + + fn deposit(&mut self, commitment: Field, depositor: &Keypair) -> Result<(), String> { + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::Deposit { + commitment: commitment.to_bytes(), + } + .pack(), + vec![ + AccountMeta::new(depositor.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + self.send(ix, depositor) + } + + fn spend_count(&self) -> u64 { + let mut data = self.svm.get_account(&self.pool).expect("pool exists").data; + Pool::load(&mut data).unwrap().spend_count() + } +} + +/// One spend as settlement sees it: the record, the beneficiary the proof bound, +/// and the relay that submitted it. Three accounts, which is the unit this whole +/// measurement is denominated in. +type Party = (Pubkey, Pubkey, Pubkey); + +fn spend_ix( + env: &Env, + proof: &SolanaProof, + nullifier: [u8; 32], + beneficiary: &Pubkey, + relay: &Pubkey, +) -> Instruction { + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(*relay, true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ) +} + +fn settle_ix(env: &Env, batch: &[Party], settler: &Pubkey) -> Instruction { + let mut metas = vec![ + AccountMeta::new(*settler, true), + AccountMeta::new(env.pool, false), + AccountMeta::new(env.vault, false), + ]; + for (spend, beneficiary, relay) in batch { + metas.push(AccountMeta::new(*spend, false)); + metas.push(AccountMeta::new(*beneficiary, false)); + metas.push(AccountMeta::new(*relay, false)); + } + Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SettleEpoch { + count: batch.len() as u8, + } + .pack(), + metas, + ) +} + +fn settle_tx(env: &Env, batch: &[Party], settler: &Keypair) -> Transaction { + let ix = settle_ix(env, batch, &settler.pubkey()); + let msg = Message::new(&[ix], Some(&settler.pubkey())); + Transaction::new(&[settler], msg, env.svm.latest_blockhash()) +} + +/// What this transaction weighs on the wire. +/// +/// A legacy transaction is a compact array of 64-byte signatures followed by the +/// serialized message, and `Message::serialize` is the encoding a validator +/// receives, not an approximation of it. The one-byte length prefix is asserted +/// rather than assumed: a second signer would move the answer by 65 bytes without +/// changing anything visible at the call site. +fn wire_len(tx: &Transaction) -> usize { + assert_eq!( + tx.signatures.len(), + 1, + "the framing here holds for a single signature" + ); + 1 + 64 * tx.signatures.len() + tx.message.serialize().len() +} + +/// The largest batch whose transaction still fits in a packet, found by +/// serializing rather than by arithmetic. +/// +/// Placeholder keys are legitimate here and only here: transaction size depends +/// on how many distinct accounts the message names, not on which. The real batch +/// is checked against this bracket below, so an error in that reasoning fails the +/// test rather than biasing it. +fn largest_batch_that_fits(env: &Env, settler: &Keypair) -> usize { + let mut fits = 0; + for n in 1..=64 { + let placeholders: Vec = (0..n) + .map(|_| { + ( + Pubkey::new_unique(), + Pubkey::new_unique(), + Pubkey::new_unique(), + ) + }) + .collect(); + if wire_len(&settle_tx(env, &placeholders, settler)) <= PACKET_DATA_SIZE { + fits = n; + } + } + fits +} + +/// A member's proof and the two addresses it was bound to. +/// +/// The binding covers the selector, the target, the beneficiary, the relay, the +/// relay fee and the payload — but *not* the pool. So one round of proving can be +/// replayed into a second, identical pool, which is what lets this file run two +/// independent settlement experiments for the price of one. +/// +/// That the relay is bound is why it is carried here rather than minted at +/// submission time: both runs must present the same relay, because a second +/// relay would need a second proof. +struct Ticket { + proof: SolanaProof, + beneficiary: Pubkey, + relay: Keypair, +} + +fn host_tree(count: usize) -> (MerkleTree, Vec) { + let denom_tag = Field::from_u64(DENOMINATION); + let mut tree = MerkleTree::new().unwrap(); + let mut notes = Vec::new(); + for i in 1..=count as u64 { + let note = Note::new( + Field::from_u64(i * 1_000_003), + Field::from_u64(i * 7_919), + denom_tag, + ); + tree.insert(note.commitment().unwrap()).unwrap(); + notes.push(note); + } + (tree, notes) +} + +fn prove_tickets(keys: &Keys, tree: &MerkleTree, notes: &[Note]) -> Vec { + use ark_std::rand::SeedableRng; + notes + .iter() + .enumerate() + .map(|(index, note)| { + let beneficiary = Pubkey::new_unique(); + // Minted before the binding, not after: the relay is part of the + // preimage now, so the proof has to know which key will carry it. + let relay = Keypair::new(); + let merkle_proof = tree.proof(index as u64).unwrap(); + let binding = mirror_core::action_binding( + SELECTOR, + &[0u8; 32], + &beneficiary.to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + 0, + &[], + ); + let witness = Witness { + note: *note, + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8; 32]); + Ticket { + proof: prove(keys, &witness, &mut rng).expect("proving"), + beneficiary, + relay, + } + }) + .collect() +} + +/// A fresh pool holding `notes`, with every ticket submitted and pending. +fn pending_pool(notes: &[Note], tickets: &[Ticket]) -> (Env, Vec) { + let mut env = setup(); + env.init_pool(); + + for (i, note) in notes.iter().enumerate() { + let depositor = Keypair::new(); + env.svm + .airdrop(&depositor.pubkey(), DENOMINATION + 10_000_000) + .unwrap(); + env.deposit(note.commitment().unwrap(), &depositor) + .unwrap_or_else(|e| panic!("deposit {i} failed: {e}")); + } + + let mut pending = Vec::new(); + for (i, ticket) in tickets.iter().enumerate() { + env.svm + .airdrop(&ticket.relay.pubkey(), 10_000_000_000) + .unwrap(); + let nullifier = ticket.proof.public_inputs[1]; + let ix = spend_ix( + &env, + &ticket.proof, + nullifier, + &ticket.beneficiary, + &ticket.relay.pubkey(), + ); + let relay = ticket.relay.insecure_clone(); + env.send(ix, &relay) + .unwrap_or_else(|e| panic!("submit {i} failed: {e}")); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + pending.push((spend_pda, ticket.beneficiary, ticket.relay.pubkey())); + } + (env, pending) +} + +/// The measurement. +/// +/// Bracketing, because a Groth16 proof takes about four seconds and sweeping +/// upward from one spend would spend a minute rediscovering that small batches +/// are small. Transaction size is a pure function of the account count, so the +/// region worth proving for is found first by serializing placeholder batches — +/// free, and cross-checked against the real batch inside the sweep. Only then are +/// proofs made, one more than the bracket admits, and the real sweep runs +/// *downward* from the bracket: a settlement that is rejected leaves its records +/// pending, so one pool can be asked many times, but a settlement that succeeds +/// consumes them, so the first success has to be the answer. +/// +/// Every spend here brings three accounts no other spend shares. That is the +/// worst case for the encoding and it is the case a settler has to plan against; +/// a batch whose members happened to share a relay would name fewer distinct keys +/// and is a different measurement. +#[test] +fn ten_spends_fit_in_one_settlement_and_the_packet_is_what_stops_the_eleventh() { + let probe = setup(); + let prober = Keypair::new(); + let bracket = largest_batch_that_fits(&probe, &prober); + println!("the encoding admits {bracket} spends; proving one more than that"); + + let keys = generate_reproducible(SEED).expect("setup"); + let (tree, notes) = host_tree(bracket + 1); + let tickets = prove_tickets(&keys, &tree, ¬es); + + let (mut env, pending) = pending_pool(¬es, &tickets); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + + let mut ceiling = 0usize; + let mut bytes_at_ceiling = 0usize; + let mut cu_at_ceiling = 0u64; + for n in (1..=bracket).rev() { + let tx = settle_tx(&env, &pending[..n], &settler); + let bytes = wire_len(&tx); + assert!( + bytes <= PACKET_DATA_SIZE, + "the placeholder bracket disagreed with a real batch of {n}: {bytes} bytes" + ); + match env.svm.send_transaction(tx) { + Ok(meta) => { + ceiling = n; + bytes_at_ceiling = bytes; + cu_at_ceiling = meta.compute_units_consumed; + break; + } + Err(e) => println!("{n} spends fit in {bytes} bytes but failed: {:?}", e.err), + } + } + assert!(ceiling > 0, "no batch settled at all"); + assert_eq!( + env.spend_count(), + ceiling as u64, + "the settlement that succeeded did not settle the whole batch" + ); + println!( + "settled {ceiling} spends in one transaction: {bytes_at_ceiling} bytes \ + ({} to spare), {cu_at_ceiling} CU of {DEFAULT_COMPUTE_BUDGET}", + PACKET_DATA_SIZE - bytes_at_ceiling + ); + + // Why one more fails, demonstrated rather than asserted — and it needs two + // judges, because neither can answer alone. litesvm never sees a packet, so + // it will happily execute a batch no validator would accept; the wire format + // never sees a compute meter. So the same batch of `ceiling + 1` is measured + // on the wire and replayed into a second, identical pool where the SVM gets + // to rule on it. If the SVM settles it while the bytes are over the limit, + // the packet is what binds and compute is not close. + let over = ceiling + 1; + let (mut second, again) = pending_pool(¬es, &tickets); + let other = Keypair::new(); + second.svm.airdrop(&other.pubkey(), 10_000_000_000).unwrap(); + let tx = settle_tx(&second, &again[..over], &other); + let bytes_over = wire_len(&tx); + let verdict = second.svm.send_transaction(tx); + + match (&verdict, bytes_over > PACKET_DATA_SIZE) { + (Ok(meta), true) => println!( + "{over} spends: rejected by the wire at {bytes_over} bytes, \ + {} over the {PACKET_DATA_SIZE}-byte limit — while the SVM settled the \ + same batch in {} CU, so compute is not the constraint", + bytes_over - PACKET_DATA_SIZE, + meta.compute_units_consumed + ), + (Err(e), _) => println!( + "{over} spends: rejected by the runtime at {bytes_over} bytes: {:?}", + e.err + ), + (Ok(_), false) => panic!( + "a batch of {over} both fits in {bytes_over} bytes and executes, so the \ + sweep above stopped one short of the real ceiling" + ), + } + + assert!( + bytes_over > PACKET_DATA_SIZE, + "{over} spends fit in {bytes_over} bytes, so the packet is not what stops them" + ); + // Both halves of the claim are load-bearing. If the SVM ever refuses this + // batch, the packet stops being the only thing in the way and the name of + // this test is no longer true, whatever the ceiling turns out to be. + let Ok(over_meta) = &verdict else { + panic!( + "the SVM refused {over} spends, so the packet limit is not what binds \ + and this test reports the wrong constraint" + ) + }; + assert!( + over_meta.compute_units_consumed < DEFAULT_COMPUTE_BUDGET, + "settling {over} spends cost {} CU, at or over the default budget, so \ + compute now binds alongside the packet", + over_meta.compute_units_consumed + ); + + assert_eq!( + ceiling, MAX_SPENDS_PER_SETTLEMENT, + "the settlement ceiling moved: {ceiling} spends per transaction, not \ + {MAX_SPENDS_PER_SETTLEMENT}" + ); + assert_eq!( + bytes_at_ceiling, BYTES_AT_MAX, + "the wire size of a full settlement moved: {bytes_at_ceiling} bytes, not \ + {BYTES_AT_MAX}" + ); + assert!( + cu_at_ceiling < DEFAULT_COMPUTE_BUDGET, + "a full settlement used {cu_at_ceiling} CU, over the default budget" + ); +} diff --git a/programs/mirror-pool/tests/end_to_end.rs b/programs/mirror-pool/tests/end_to_end.rs new file mode 100644 index 00000000..6a7fd32a --- /dev/null +++ b/programs/mirror-pool/tests/end_to_end.rs @@ -0,0 +1,2166 @@ +//! The whole protocol against the real compiled program. +//! +//! Every other test in this repository calls functions directly. This one loads +//! the `.so` that `make build-sbf` produces into a real SVM, sends real +//! transactions, and verifies a real Groth16 proof through the actual syscall. +//! It is the only test that can catch a divergence between what the host +//! believes and what the chain does. +//! +//! Requires `make build-sbf` first. If the artifact is missing the test says so +//! rather than silently passing, because a privacy test that quietly does +//! nothing is worse than no test. + +use litesvm::LiteSVM; +use mirror_circuit::{generate_reproducible, prove, Keys, Witness}; +use mirror_core::{Field, MerkleTree, Note}; +#[allow(unused_imports)] +use mirror_pool_program::{ + instruction::Instruction as MirrorIx, + pda::{pool_address, spend_address, vault_address}, + spend::{spend_len, Spend, SPEND_BASE_LEN, STATUS_PENDING, STATUS_SETTLED}, + Pool, POOL_LEN, +}; +use solana_keypair::Keypair; +use solana_message::Message; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; +use solana_signer::Signer; +use solana_transaction::Transaction; + +const SEED: &[u8] = b"mirror-pool-reproducible-dev-setup-v1"; +const DENOMINATION: u64 = 100_000_000; // 0.1 SOL +const ENTRY_FEE: u64 = 0; +const K_FLOOR: u32 = 4; +const RELAY_FEE: u64 = 1_000_000; +const SELECTOR: u64 = mirror_pool_program::processor::SELECTOR_TRANSFER; + +/// The real SPL Memo program, fetched from mainnet, used as a CPI target so the +/// action path is exercised against a program that exists rather than a stub. +const MEMO_PROGRAM: &str = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"; + +fn memo_bytes() -> Vec { + let path = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/spl_memo.so"); + std::fs::read(path).expect("spl_memo.so fixture") +} + +fn program_bytes() -> Vec { + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../target/sbf/deploy/mirror_pool_program.so" + ); + std::fs::read(path).unwrap_or_else(|e| { + panic!("could not read {path}: {e}\n\nRun `make build-sbf` first."); + }) +} + +struct Env { + svm: LiteSVM, + program_id: Pubkey, + payer: Keypair, + pool: Pubkey, + vault: Pubkey, +} + +fn setup() -> Env { + let mut svm = LiteSVM::new(); + let program_id = Pubkey::new_unique(); + svm.add_program(program_id, &program_bytes()) + .expect("loading the built program"); + + let payer = Keypair::new(); + svm.airdrop(&payer.pubkey(), 100_000_000_000).unwrap(); + + let (pool, _) = pool_address(&program_id, DENOMINATION); + let (vault, _) = vault_address(&program_id, &pool); + + Env { + svm, + program_id, + payer, + pool, + vault, + } +} + +impl Env { + /// Sends a transaction, treating runtime deduplication as a test bug. + /// + /// A resubmitted byte-identical transaction is rejected as AlreadyProcessed + /// *before the program runs*, so any negative test that reaches that state is + /// asserting nothing about this program. Two tests in this file passed that + /// way before this guard existed. Vary the fee payer to make a genuine + /// retry. + fn send(&mut self, ix: Instruction, signer: &Keypair) -> Result<(), String> { + let msg = Message::new(&[ix], Some(&signer.pubkey())); + let tx = Transaction::new(&[signer], msg, self.svm.latest_blockhash()); + self.svm.send_transaction(tx).map(|_| ()).map_err(|e| { + let rendered = format!( + "{:?} | logs: {:?}", + e.err, + e.meta.logs.iter().rev().take(4).collect::>() + ); + assert!( + !rendered.contains("AlreadyProcessed"), + "the runtime deduplicated this transaction, so the program never \ + ran and the test proves nothing. Vary the fee payer: {rendered}" + ); + rendered + }) + } + + fn send_expect_cu(&mut self, ix: Instruction, signer: &Keypair) -> u64 { + let msg = Message::new(&[ix], Some(&signer.pubkey())); + let tx = Transaction::new(&[signer], msg, self.svm.latest_blockhash()); + let meta = self.svm.send_transaction(tx).unwrap_or_else(|e| { + panic!("transaction failed: {:?}\nlogs: {:#?}", e.err, e.meta.logs) + }); + meta.compute_units_consumed + } + + fn init_pool(&mut self) { + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::InitPool { + denomination: DENOMINATION, + entry_fee: ENTRY_FEE, + k_floor: K_FLOOR, + } + .pack(), + vec![ + AccountMeta::new(self.payer.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let payer = self.payer.insecure_clone(); + self.send(ix, &payer).expect("init_pool"); + } + + fn deposit(&mut self, commitment: Field, depositor: &Keypair) -> Result<(), String> { + let ix = Instruction::new_with_bytes( + self.program_id, + &MirrorIx::Deposit { + commitment: commitment.to_bytes(), + } + .pack(), + vec![ + AccountMeta::new(depositor.pubkey(), true), + AccountMeta::new(self.pool, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + self.send(ix, depositor) + } + + fn pool_state(&self) -> Vec { + self.svm.get_account(&self.pool).expect("pool exists").data + } + + fn vault_lamports(&self) -> u64 { + self.svm + .get_account(&self.vault) + .map(|a| a.lamports) + .unwrap_or(0) + } +} + +/// Builds a pool with `count` deposits and returns the host-side tree plus the +/// notes, so a proof can be produced for any of them. +fn seeded_pool(count: u64) -> (Env, MerkleTree, Vec, Keys) { + let mut env = setup(); + env.init_pool(); + + let denom_tag = Field::from_u64(DENOMINATION); + let mut tree = MerkleTree::new().unwrap(); + let mut notes = Vec::new(); + + for i in 1..=count { + let note = Note::new( + Field::from_u64(i * 1_000_003), + Field::from_u64(i * 7_919), + denom_tag, + ); + let depositor = Keypair::new(); + env.svm + .airdrop(&depositor.pubkey(), DENOMINATION + 10_000_000) + .unwrap(); + env.deposit(note.commitment().unwrap(), &depositor) + .unwrap_or_else(|e| panic!("deposit {i} failed: {e}")); + tree.insert(note.commitment().unwrap()).unwrap(); + notes.push(note); + } + + let keys = generate_reproducible(SEED).expect("setup"); + (env, tree, notes, keys) +} + +fn spend_ix( + env: &Env, + proof: &mirror_circuit::SolanaProof, + nullifier: [u8; 32], + beneficiary: &Pubkey, + relay: &Pubkey, +) -> Instruction { + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(*relay, true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ) +} + +/// Produces a proof for note `index`, bound to `beneficiary`. +/// A proof and a `submit_spend` for note `index` at an arbitrary relay fee. +/// +/// The fee is bound into the proof, so a differing fee is a differing statement +/// rather than a field a test can edit afterwards — which is why this exists +/// separately from the fixed-fee helpers. +#[allow(clippy::too_many_arguments)] +fn spend_ix_at_fee( + env: &Env, + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + beneficiary: &Pubkey, + relay: &Pubkey, + relay_fee: u64, +) -> ([u8; 32], Instruction) { + use ark_std::rand::SeedableRng; + let merkle_proof = tree.proof(index as u64).unwrap(); + let binding = mirror_core::action_binding( + SELECTOR, + &[0u8; 32], + &beneficiary.to_bytes(), + &relay.to_bytes(), + relay_fee, + 0, + &[], + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8; 32]); + let proof = prove(keys, &witness, &mut rng).expect("proving"); + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let ix = Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(*relay, true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + (nullifier, ix) +} + +fn proof_for( + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + beneficiary: &Pubkey, + relay: &Pubkey, +) -> mirror_circuit::SolanaProof { + use ark_std::rand::SeedableRng; + let merkle_proof = tree.proof(index as u64).unwrap(); + let binding = mirror_core::action_binding( + SELECTOR, + &[0u8; 32], + &beneficiary.to_bytes(), + &relay.to_bytes(), + RELAY_FEE, + 0, + &[], + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([index as u8; 32]); + prove(keys, &witness, &mut rng).expect("proving") +} + +#[test] +fn a_pool_initialises_with_an_empty_accumulator() { + let mut env = setup(); + env.init_pool(); + + let mut data = env.pool_state(); + assert_eq!(data.len(), POOL_LEN); + let pool = Pool::load(&mut data).unwrap(); + assert_eq!(pool.denomination(), DENOMINATION); + assert_eq!(pool.k_floor(), K_FLOOR); + assert_eq!(pool.deposit_count(), 0); + assert_eq!( + pool.current_root().unwrap(), + mirror_core::Frontier::new().unwrap().root(), + "the deployed program and the host must start from one accumulator" + ); +} + +#[test] +fn deposits_escrow_exactly_the_denomination_and_advance_the_root() { + let (env, tree, _notes, _keys) = seeded_pool(4); + + let mut data = env.pool_state(); + let pool = Pool::load(&mut data).unwrap(); + assert_eq!(pool.deposit_count(), 4); + assert_eq!( + pool.current_root().unwrap(), + tree.root().unwrap(), + "the on-chain root diverged from the host tree" + ); + + // Escrow, plus the vault's own rent exemption. + assert!( + env.vault_lamports() >= 4 * DENOMINATION, + "vault holds {} for 4 notes of {DENOMINATION}", + env.vault_lamports() + ); + assert_eq!(pool.required_vault_lamports().unwrap(), 4 * DENOMINATION); +} + +/// The decisive test: a proof built by the host prover, verified by the real +/// Groth16 syscall inside the deployed program. +#[test] +fn a_real_proof_verifies_on_chain_and_records_the_spend() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let proof = proof_for(&keys, &tree, ¬es, 2, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + + let ix = spend_ix(&env, &proof, nullifier, &beneficiary, &relay.pubkey()); + let cu = env.send_expect_cu(ix, &relay); + println!("submit_spend consumed {cu} compute units"); + // The headline cost of the protocol, and the reason the two phases exist. + // Bounded rather than pinned: the exact figure moves by a few thousand CU + // between runs with the bump search on a freshly generated nullifier. + assert!( + cu < 110_000, + "submit_spend used {cu} CU, above what it has ever measured and close \ + to the 200,000 default per-instruction budget" + ); + + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let mut data = env + .svm + .get_account(&spend_pda) + .expect("spend recorded") + .data; + assert_eq!( + data.len(), + spend_len(0), + "a transfer action carries no payload" + ); + let record = Spend::load(&mut data).unwrap(); + assert_eq!(record.status(), STATUS_PENDING); + assert_eq!(record.selector(), SELECTOR); + assert_eq!(record.relay_fee(), RELAY_FEE); + assert_eq!(record.beneficiary(), beneficiary.to_bytes()); + assert_eq!( + record.relay(), + relay.pubkey().to_bytes(), + "the relay that submitted must be the one paid at settlement" + ); + + // No member key appears anywhere in this path. The spend was submitted by a + // relay and the record names only the relay and the beneficiary, neither of + // which is the depositor: every deposit in this pool came from its own fresh + // keypair inside `seeded_pool`, and none of those signed anything here. + assert_eq!(record.relay(), relay.pubkey().to_bytes()); + assert_ne!(record.relay(), record.beneficiary()); +} + +#[test] +fn the_same_note_cannot_be_spent_twice() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let first_relay = Keypair::new(); + let second_relay = Keypair::new(); + env.svm + .airdrop(&first_relay.pubkey(), 10_000_000_000) + .unwrap(); + env.svm + .airdrop(&second_relay.pubkey(), 10_000_000_000) + .unwrap(); + + let proof = proof_for(&keys, &tree, ¬es, 1, &beneficiary, &first_relay.pubkey()); + let nullifier = proof.public_inputs[1]; + + let ix = spend_ix(&env, &proof, nullifier, &beneficiary, &first_relay.pubkey()); + env.send(ix, &first_relay).expect("first spend"); + + // The replay goes through a *different* relay, so the transaction is not + // byte-identical and the runtime's duplicate-signature check cannot be what + // rejects it. An earlier version of this test reused the first relay and + // passed for the wrong reason: it was rejected as AlreadyProcessed before + // the program ran at all. + // + // Since the relay joined the action binding, this proof would *also* fail + // the pairing under the second relay — which is exactly why the assertion + // below is on `Custom(15)` and not merely on "rejected". The nullifier guard + // is checked before the binding is recomputed, so a spent note costs a + // replayer ~11k CU instead of the ~95k a pairing would. Getting + // ProofVerificationFailed here would mean that ordering had silently + // inverted, and the cheap guard had stopped being the first thing to run. + let replay = spend_ix( + &env, + &proof, + nullifier, + &beneficiary, + &second_relay.pubkey(), + ); + let err = env + .send(replay, &second_relay) + .expect_err("a replayed proof was accepted"); + println!("replay rejected: {err}"); + assert!( + !err.contains("AlreadyProcessed"), + "the runtime deduplicated the transaction; the nullifier guard was never reached: {err}" + ); + assert!( + err.contains("Custom(15)"), + "expected NullifierAlreadySpent (15), got: {err}" + ); +} + +#[test] +fn a_relay_cannot_redirect_the_payout() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let honest_beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let proof = proof_for( + &keys, + &tree, + ¬es, + 0, + &honest_beneficiary, + &relay.pubkey(), + ); + let nullifier = proof.public_inputs[1]; + + // The relay swaps in its own address after the member proved. + let thief = Pubkey::new_unique(); + let ix = spend_ix(&env, &proof, nullifier, &thief, &relay.pubkey()); + let err = env + .send(ix, &relay) + .expect_err("a redirected payout was accepted"); + println!("redirect rejected: {err}"); + assert!( + err.contains("Custom(18)"), + "expected ProofVerificationFailed: {err}" + ); +} + +#[test] +fn a_relay_cannot_inflate_its_own_fee() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let proof = proof_for(&keys, &tree, ¬es, 3, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE * 50, // proved for RELAY_FEE + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let err = env + .send(ix, &relay) + .expect_err("an inflated relay fee was accepted"); + println!("fee inflation rejected: {err}"); + assert!( + err.contains("Custom(18)"), + "expected ProofVerificationFailed: {err}" + ); +} + +#[test] +fn a_proof_against_an_unknown_root_is_rejected() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let mut proof = proof_for(&keys, &tree, ¬es, 4, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + // A root the pool has never held. Flip a low bit so the value stays a + // canonical scalar and the rejection comes from the history check. + proof.public_inputs[0][31] ^= 1; + + let ix = spend_ix(&env, &proof, nullifier, &beneficiary, &relay.pubkey()); + let err = env + .send(ix, &relay) + .expect_err("an unknown root was accepted"); + println!("unknown root rejected: {err}"); + assert!(err.contains("Custom(17)"), "expected UnknownRoot: {err}"); +} + +#[test] +fn a_pool_below_its_anonymity_floor_refuses_to_act() { + // Three deposits against a floor of four: acting here would give the member + // an anonymity set smaller than the pool promises. + let (mut env, tree, notes, keys) = seeded_pool(3); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let proof = proof_for(&keys, &tree, ¬es, 0, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + let ix = spend_ix(&env, &proof, nullifier, &beneficiary, &relay.pubkey()); + let err = env + .send(ix, &relay) + .expect_err("a spend below the anonymity floor was accepted"); + println!("below-floor rejected: {err}"); + assert!( + err.contains("Custom(19)"), + "expected BelowAnonymityFloor: {err}" + ); +} + +#[test] +fn a_forged_proof_is_rejected() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let mut proof = proof_for(&keys, &tree, ¬es, 2, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + // Corrupt the proof itself. + proof.proof_a[63] ^= 1; + + let ix = spend_ix(&env, &proof, nullifier, &beneficiary, &relay.pubkey()); + let err = env + .send(ix, &relay) + .expect_err("a corrupted proof was accepted"); + println!("forged proof rejected: {err}"); + assert!( + err.contains("Custom(18)"), + "expected ProofVerificationFailed: {err}" + ); +} + +// --------------------------------------------------------------------------- +// Settlement +// --------------------------------------------------------------------------- + +/// Submits `n` spends and returns their (spend PDA, beneficiary, relay) triples. +fn submit_batch( + env: &mut Env, + tree: &MerkleTree, + notes: &[Note], + keys: &Keys, + n: usize, +) -> Vec<(Pubkey, Pubkey, Keypair)> { + let mut out = Vec::new(); + for i in 0..n { + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let proof = proof_for(keys, tree, notes, i, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + let ix = spend_ix(env, &proof, nullifier, &beneficiary, &relay.pubkey()); + env.send(ix, &relay) + .unwrap_or_else(|e| panic!("submit {i} failed: {e}")); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + out.push((spend_pda, beneficiary, relay)); + } + out +} + +fn settle_ix(env: &Env, batch: &[(Pubkey, Pubkey, Keypair)], settler: &Pubkey) -> Instruction { + settle_ix_with_targets(env, batch, settler, &[]) +} + +/// Settlement where some spends invoke a program. `targets[i]`, when present, +/// is the program account for `batch[i]`, which a CPI requires to be in the +/// caller's account list. +fn settle_ix_with_targets( + env: &Env, + batch: &[(Pubkey, Pubkey, Keypair)], + settler: &Pubkey, + targets: &[Option], +) -> Instruction { + settle_ix_full(env, batch, settler, targets, &[]) +} + +/// Settlement carrying, per spend, an optional target program and that action's +/// own account list — the shape a real CPI needs. +fn settle_ix_full( + env: &Env, + batch: &[(Pubkey, Pubkey, Keypair)], + settler: &Pubkey, + targets: &[Option], + action_accounts: &[Vec], +) -> Instruction { + let mut metas = vec![ + AccountMeta::new(*settler, true), + AccountMeta::new(env.pool, false), + AccountMeta::new(env.vault, false), + ]; + for (i, (spend, beneficiary, relay)) in batch.iter().enumerate() { + metas.push(AccountMeta::new(*spend, false)); + metas.push(AccountMeta::new(*beneficiary, false)); + metas.push(AccountMeta::new(relay.pubkey(), false)); + if let Some(Some(target)) = targets.get(i) { + metas.push(AccountMeta::new_readonly(*target, false)); + } + if let Some(accounts) = action_accounts.get(i) { + metas.extend(accounts.iter().cloned()); + } + } + Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SettleEpoch { + count: batch.len() as u8, + } + .pack(), + metas, + ) +} + +#[test] +fn a_full_crowd_settles_and_pays_every_beneficiary() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let batch = submit_batch(&mut env, &tree, ¬es, &keys, K_FLOOR as usize); + + let before: Vec = batch + .iter() + .map(|(_, b, _)| env.svm.get_account(b).map(|a| a.lamports).unwrap_or(0)) + .collect(); + let vault_before = env.vault_lamports(); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let ix = settle_ix(&env, &batch, &settler.pubkey()); + let cu = env.send_expect_cu(ix, &settler); + println!( + "settle_epoch of {} spends consumed {cu} compute units", + batch.len() + ); + + let payout = DENOMINATION - RELAY_FEE; + for (i, (spend, beneficiary, _relay)) in batch.iter().enumerate() { + let after = env.svm.get_account(beneficiary).unwrap().lamports; + assert_eq!( + after - before[i], + payout, + "beneficiary {i} received the wrong amount" + ); + let mut data = env.svm.get_account(spend).unwrap().data; + let record = Spend::load(&mut data).unwrap(); + assert_eq!(record.status(), STATUS_SETTLED); + } + + // The vault paid out exactly the batch, nothing more. + assert_eq!( + vault_before - env.vault_lamports(), + batch.len() as u64 * DENOMINATION + ); + + // And the invariant still holds against the notes that remain unspent. + let mut data = env.pool_state(); + let pool = Pool::load(&mut data).unwrap(); + assert_eq!(pool.spend_count(), batch.len() as u64); + assert_eq!(pool.outstanding_notes().unwrap(), 6 - batch.len() as u64); + assert!( + env.vault_lamports() >= pool.required_vault_lamports().unwrap(), + "vault {} cannot cover {} outstanding notes", + env.vault_lamports(), + pool.outstanding_notes().unwrap() + ); +} + +/// The double-spend an attacker reaches for first: present one pending spend +/// twice inside a single batch and be paid twice for one note. +#[test] +fn the_same_spend_cannot_be_settled_twice_within_one_batch() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let batch = submit_batch(&mut env, &tree, ¬es, &keys, K_FLOOR as usize); + + // Replace the last entry with a duplicate of the first. + let mut doubled: Vec<(Pubkey, Pubkey, Keypair)> = batch + .iter() + .map(|(s, b, r)| (*s, *b, r.insecure_clone())) + .collect(); + let last = doubled.len() - 1; + doubled[last] = (batch[0].0, batch[0].1, batch[0].2.insecure_clone()); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let ix = settle_ix(&env, &doubled, &settler.pubkey()); + let err = env + .send(ix, &settler) + .expect_err("a spend was settled twice in one batch"); + println!("in-batch double settle rejected: {err}"); + assert!( + err.contains("Custom(16)"), + "expected AlreadySettled (16), got: {err}" + ); +} + +#[test] +fn a_settled_spend_cannot_be_settled_again_later() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let batch = submit_batch(&mut env, &tree, ¬es, &keys, K_FLOOR as usize); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let ix = settle_ix(&env, &batch, &settler.pubkey()); + env.send(ix, &settler).expect("first settlement"); + + // A different settler, so the transaction is not byte-identical and the + // rejection has to come from the program. + let other = Keypair::new(); + env.svm.airdrop(&other.pubkey(), 10_000_000_000).unwrap(); + let again = settle_ix(&env, &batch, &other.pubkey()); + let err = env + .send(again, &other) + .expect_err("a settled batch was replayed"); + println!("settlement replay rejected: {err}"); + assert!(err.contains("Custom(16)"), "expected AlreadySettled: {err}"); +} + +#[test] +fn a_batch_below_the_crowd_size_must_wait() { + let (mut env, tree, notes, keys) = seeded_pool(6); + // One short of the floor, and freshly submitted. + let batch = submit_batch(&mut env, &tree, ¬es, &keys, K_FLOOR as usize - 1); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let ix = settle_ix(&env, &batch, &settler.pubkey()); + let err = env + .send(ix, &settler) + .expect_err("a batch below the crowd size settled immediately"); + println!("small batch rejected: {err}"); + assert!( + err.contains("Custom(21)"), + "expected CrowdTooSmall (21), got: {err}" + ); +} + +/// The escape valve. A quiet pool must not hold a member's funds forever, so +/// once the timeout has passed a lone spend settles on its own. +#[test] +fn a_lone_spend_settles_once_the_timeout_has_passed() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let batch = submit_batch(&mut env, &tree, ¬es, &keys, 1); + + let early = Keypair::new(); + let late = Keypair::new(); + env.svm.airdrop(&early.pubkey(), 10_000_000_000).unwrap(); + env.svm.airdrop(&late.pubkey(), 10_000_000_000).unwrap(); + + // Before the timeout: refused. + let ix = settle_ix(&env, &batch, &early.pubkey()); + assert!(env.send(ix, &early).is_err(), "settled too early"); + + // Advance the clock past the timeout. + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + let before = env + .svm + .get_account(&batch[0].1) + .map(|a| a.lamports) + .unwrap_or(0); + let ix = settle_ix(&env, &batch, &late.pubkey()); + env.send(ix, &late).expect("lone spend after timeout"); + let after = env.svm.get_account(&batch[0].1).unwrap().lamports; + assert_eq!(after - before, DENOMINATION - RELAY_FEE); +} + +#[test] +fn settlement_refuses_a_beneficiary_the_proof_did_not_bind() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let batch = submit_batch(&mut env, &tree, ¬es, &keys, K_FLOOR as usize); + + // Swap one beneficiary for an address the member never proved. + let mut tampered: Vec<(Pubkey, Pubkey, Keypair)> = batch + .iter() + .map(|(s, b, r)| (*s, *b, r.insecure_clone())) + .collect(); + tampered[1].1 = Pubkey::new_unique(); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let ix = settle_ix(&env, &tampered, &settler.pubkey()); + let err = env + .send(ix, &settler) + .expect_err("settlement paid an unbound beneficiary"); + println!("unbound beneficiary rejected: {err}"); + assert!(err.contains("Custom(2)"), "expected InvalidPda: {err}"); +} + +/// The permissionless exit, demonstrated rather than added. +/// +/// No `self_spend` instruction exists, because none is needed: a member acts as +/// their own relay with a zero fee, and settlement is already permissionless, so +/// they can settle their own batch once the timeout passes. Nothing in the +/// protocol can hold their escrow — no relay has to cooperate and no operator +/// has to be alive. +/// +/// The cost is exactly the one you would expect: their own wallet signs, so this +/// path gives up the anonymity the relay path provides. It is an escape hatch, +/// not a mode of operation, and this test pins that it works rather than leaving +/// it as an assertion in a README. +#[test] +fn a_member_can_always_exit_without_any_relay() { + let (mut env, tree, notes, keys) = seeded_pool(6); + + // The member is their own relay and their own beneficiary, fee zero. + let member = Keypair::new(); + env.svm.airdrop(&member.pubkey(), 10_000_000_000).unwrap(); + let beneficiary = member.pubkey(); + + let merkle_proof = tree.proof(0).unwrap(); + let binding = mirror_core::action_binding( + SELECTOR, + &[0u8; 32], + &beneficiary.to_bytes(), + &member.pubkey().to_bytes(), + 0, + 0, + &[], + ); + let witness = Witness { + note: notes[0], + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = { + use ark_std::rand::SeedableRng; + ark_std::rand::rngs::StdRng::from_seed([42u8; 32]) + }; + let proof = prove(&keys, &witness, &mut rng).expect("proving"); + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: 0, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(member.pubkey(), true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + env.send(ix, &member) + .expect("member submitted their own spend"); + + // Alone, so the crowd rule sends them to the timeout. + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + let before = env.svm.get_account(&member.pubkey()).unwrap().lamports; + let batch = vec![(spend_pda, beneficiary, member.insecure_clone())]; + let settle = settle_ix(&env, &batch, &member.pubkey()); + env.send(settle, &member) + .expect("member settled their own spend"); + + let after = env.svm.get_account(&member.pubkey()).unwrap().lamports; + // The full denomination, minus whatever the transaction itself cost. + assert!( + after > before, + "the member ended up worse off: {before} -> {after}" + ); + assert!( + after - before >= DENOMINATION - 100_000, + "expected roughly the full denomination back, got {}", + after - before + ); +} + +// --------------------------------------------------------------------------- +// Behavioural actions +// +// The brief asks for "Tornado Cash for behavioural patterns and withdrawals — +// not for funds". A pool that only moves lamports answers the wrong question: +// what should be deniable is that *you* staked, swapped or voted, not merely +// where your money went. +// +// These exercise the pool invoking a real third-party program on a member's +// behalf. The target is the actual SPL Memo program, fetched from mainnet, so +// the CPI path runs against something that exists. +// --------------------------------------------------------------------------- + +const INVOKE: u64 = mirror_pool_program::processor::SELECTOR_INVOKE; +const INVOKE_SIGNED: u64 = mirror_pool_program::processor::SELECTOR_INVOKE_SIGNED; + +/// A spend that asks the pool to invoke `target` with `payload`. +fn action_ix( + env: &Env, + proof: &mirror_circuit::SolanaProof, + nullifier: [u8; 32], + target: &Pubkey, + beneficiary: &Pubkey, + relay: &Pubkey, + payload: &[u8], +) -> Instruction { + action_ix_n( + env, + proof, + nullifier, + target, + beneficiary, + relay, + 0, + payload, + ) +} + +#[allow(clippy::too_many_arguments)] +fn action_ix_n( + env: &Env, + proof: &mirror_circuit::SolanaProof, + nullifier: [u8; 32], + target: &Pubkey, + beneficiary: &Pubkey, + relay: &Pubkey, + action_accounts: u8, + payload: &[u8], +) -> Instruction { + action_ix_sel( + env, + proof, + nullifier, + target, + beneficiary, + relay, + action_accounts, + payload, + INVOKE, + ) +} + +#[allow(clippy::too_many_arguments)] +fn action_ix_sel( + env: &Env, + proof: &mirror_circuit::SolanaProof, + nullifier: [u8; 32], + target: &Pubkey, + beneficiary: &Pubkey, + relay: &Pubkey, + action_accounts: u8, + payload: &[u8], + selector: u64, +) -> Instruction { + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector, + target_program: target.to_bytes(), + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts, + payload: payload.to_vec(), + } + .pack(), + vec![ + AccountMeta::new(*relay, true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ) +} + +#[allow(clippy::too_many_arguments)] +fn action_proof( + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + target: &Pubkey, + beneficiary: &Pubkey, + relay: &Pubkey, + payload: &[u8], +) -> mirror_circuit::SolanaProof { + action_proof_n( + keys, + tree, + notes, + index, + target, + beneficiary, + relay, + 0, + payload, + ) +} + +#[allow(clippy::too_many_arguments)] +fn action_proof_n( + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + target: &Pubkey, + beneficiary: &Pubkey, + relay: &Pubkey, + action_accounts: u8, + payload: &[u8], +) -> mirror_circuit::SolanaProof { + action_proof_sel( + keys, + tree, + notes, + index, + target, + beneficiary, + relay, + action_accounts, + payload, + INVOKE, + ) +} + +#[allow(clippy::too_many_arguments)] +fn action_proof_sel( + keys: &Keys, + tree: &MerkleTree, + notes: &[Note], + index: usize, + target: &Pubkey, + beneficiary: &Pubkey, + relay: &Pubkey, + action_accounts: u8, + payload: &[u8], + selector: u64, +) -> mirror_circuit::SolanaProof { + use ark_std::rand::SeedableRng; + let merkle_proof = tree.proof(index as u64).unwrap(); + let binding = mirror_core::action_binding( + selector, + &target.to_bytes(), + &beneficiary.to_bytes(), + &relay.to_bytes(), + RELAY_FEE, + action_accounts, + payload, + ); + let witness = Witness { + note: notes[index], + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = ark_std::rand::rngs::StdRng::from_seed([200 + index as u8; 32]); + prove(keys, &witness, &mut rng).expect("proving") +} + +/// The thesis, end to end: a crowd of members each perform the *same shape* of +/// protocol action, and the pool invokes the target program for every one of +/// them in a single transaction — one timestamp, one signer on the transaction, +/// nothing distinguishing which member asked for which. +/// +/// An observer sees four memos land at one timestamp, signed by one pool, and +/// has nothing in the transaction that distinguishes which member asked for +/// which. +#[test] +fn a_crowd_of_members_perform_a_real_protocol_action_together() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm + .add_program(memo, &memo_bytes()) + .expect("loading the real SPL Memo program"); + + let mut batch = Vec::new(); + for i in 0..K_FLOOR as usize { + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + // Every member sends the identical payload, which is what makes the + // crowd a crowd: the actions are indistinguishable by content. + let payload = b"mirror-pool".as_slice(); + let proof = action_proof( + &keys, + &tree, + ¬es, + i, + &memo, + &beneficiary, + &relay.pubkey(), + payload, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix( + &env, + &proof, + nullifier, + &memo, + &beneficiary, + &relay.pubkey(), + payload, + ); + env.send(ix, &relay) + .unwrap_or_else(|e| panic!("submitting action {i}: {e}")); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + batch.push((spend_pda, beneficiary, relay)); + } + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let targets: Vec> = batch.iter().map(|_| Some(memo)).collect(); + let ix = settle_ix_with_targets(&env, &batch, &settler.pubkey(), &targets); + let cu = env.send_expect_cu(ix, &settler); + println!( + "settled {} real CPI actions in one transaction, {cu} CU", + batch.len() + ); + // A bound, not a fixed figure. Settlement's cost moves by a few thousand CU + // between runs because the accounts are freshly generated each time and + // `find_program_address` searches a different number of bumps to derive each + // record's address. Pinning the exact number would produce a test that fails + // on nothing, so what is asserted is the property the design depends on: + // four CPI actions and their payouts fit in one instruction's default + // budget, with room to spare. + assert!( + cu < 60_000, + "four settled CPI actions cost {cu} CU, well above what this batch has \ + ever measured — settlement got materially more expensive" + ); + + for (spend, beneficiary, _) in &batch { + let mut data = env.svm.get_account(spend).unwrap().data; + let record = Spend::load(&mut data).unwrap(); + assert_eq!(record.status(), STATUS_SETTLED); + assert_eq!(record.target_program(), memo.to_bytes()); + assert_eq!(record.payload(), b"mirror-pool"); + // The action was funded, so the target acted on real value. + assert!(env.svm.get_account(beneficiary).unwrap().lamports > 0); + } +} + +/// The action path with a non-empty account list, which nothing exercised +/// before: every action test passed zero accounts, so the loop that reads them +/// and the metas built from them were dead code. +/// +/// SPL Memo requires every account handed to it to have signed, so passing one +/// makes the CPI's account list load-bearing rather than decorative — if the +/// program dropped an account, mislabelled its signer flag, or miscounted, Memo +/// rejects. +#[test] +fn an_action_runs_with_a_non_empty_account_list() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let payload = b"signed by the pool".as_slice(); + + // One action account, declared in the proof and therefore bound. + let proof = action_proof_n( + &keys, + &tree, + ¬es, + 0, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix_n( + &env, + &proof, + nullifier, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + ); + env.send(ix, &relay).expect("submitting the action"); + + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + // The settler itself is the action's account. It signs the transaction, so + // Memo's requirement that every account has signed is genuinely satisfied + // through the program's metas rather than by Memo having nothing to check. + let batch = vec![(spend_pda, beneficiary, relay.insecure_clone())]; + let ix = settle_ix_full( + &env, + &batch, + &settler.pubkey(), + &[Some(memo)], + &[vec![AccountMeta::new_readonly(settler.pubkey(), true)]], + ); + let cu = env.send_expect_cu(ix, &settler); + println!("settled a signed CPI action, {cu} CU"); + + let mut data = env.svm.get_account(&spend_pda).unwrap().data; + let record = Spend::load(&mut data).unwrap(); + assert_eq!(record.status(), STATUS_SETTLED); + assert_eq!(record.action_accounts(), 1); + assert_eq!(record.payload(), payload); +} + +/// A settler must not be able to hand the action a different account list than +/// the member declared, because the count is now inside the binding. +#[test] +fn a_settler_cannot_change_how_many_accounts_an_action_gets() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let payload = b"one account".as_slice(); + + let proof = action_proof_n( + &keys, + &tree, + ¬es, + 1, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix_n( + &env, + &proof, + nullifier, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + ); + env.send(ix, &relay).expect("submitting"); + + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + // Supply no action accounts where the record declares one. The program reads + // one account past this spend's own, so it consumes something that is not + // there and fails rather than invoking with a truncated list. + let batch = vec![(spend_pda, beneficiary, relay.insecure_clone())]; + let ix = settle_ix_full(&env, &batch, &settler.pubkey(), &[Some(memo)], &[vec![]]); + let err = env + .send(ix, &settler) + .expect_err("settlement invoked with fewer accounts than declared"); + println!("truncated action account list rejected: {err}"); + // The one negative case without a code of ours: the runtime runs out of + // accounts before the program can rule on it. Asserted explicitly so the + // exception stays visible rather than looking like an oversight. + assert!( + err.contains("NotEnoughAccountKeys"), + "expected the runtime to refuse before the program: {err}" + ); +} + +/// The pool's signature is the member's decision and a settler cannot help +/// themselves to it. +/// +/// Under plain `INVOKE` the payout leaves the vault *before* the call, so the +/// vault cannot cross the CPI boundary — the runtime would reject the whole +/// instruction as unbalanced. The program refuses it by name instead, which +/// turns an opaque runtime failure into a stated rule. A member who wants the +/// pool to sign proves `INVOKE_SIGNED`, and the selector is inside the action +/// binding, so this is not something settlement can decide. +#[test] +fn a_settler_cannot_place_the_vault_in_an_action_account_list() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let payload = b"vault please".as_slice(); + + let proof = action_proof_n( + &keys, + &tree, + ¬es, + 2, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix_n( + &env, + &proof, + nullifier, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + ); + env.send(ix, &relay).expect("submitting"); + + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + let batch = vec![(spend_pda, beneficiary, relay.insecure_clone())]; + let ix = settle_ix_full( + &env, + &batch, + &settler.pubkey(), + &[Some(memo)], + &[vec![AccountMeta::new(env.vault, false)]], + ); + let err = env + .send(ix, &settler) + .expect_err("the vault was accepted as an action account"); + println!("vault as action account rejected: {err}"); + assert!( + err.contains("Custom(1)"), + "expected MalformedInstruction: {err}" + ); +} + +/// The pool acting as a delegated **authority**, not merely as a source of funds. +/// +/// This is the capability a stake delegation or a governance vote needs and a +/// plain transfer does not: somebody has to sign as the authority, and for a +/// member who must never appear on chain that somebody can only be the pool. +/// +/// SPL Memo is the witness, and it is a good one because it is a real third-party +/// program that refuses any account handed to it that has not signed, and because +/// it *names* its signers in its logs. So a memo whose only account is the pool's +/// vault cannot pass by accident: either Memo rejects the instruction, or it +/// prints the vault's own pubkey. The assertion below reads that log. +/// +/// Note what the settler supplies: the vault marked **not** a signer, because a +/// PDA has no key and cannot sign a transaction. The signature comes from +/// `invoke_signed` inside the program, from seeds only this program holds. +#[test] +fn the_pool_signs_an_action_as_its_own_authority() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let payload = b"the pool signed this".as_slice(); + + let proof = action_proof_sel( + &keys, + &tree, + ¬es, + 0, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + INVOKE_SIGNED, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix_sel( + &env, + &proof, + nullifier, + &memo, + &beneficiary, + &relay.pubkey(), + 1, + payload, + INVOKE_SIGNED, + ); + env.send(ix, &relay).expect("submitting the signed action"); + + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + let vault_before = env.vault_lamports(); + let batch = vec![(spend_pda, beneficiary, relay.insecure_clone())]; + let ix = settle_ix_full( + &env, + &batch, + &settler.pubkey(), + &[Some(memo)], + &[vec![AccountMeta::new(env.vault, false)]], + ); + let msg = Message::new(&[ix], Some(&settler.pubkey())); + let tx = Transaction::new(&[&settler], msg, env.svm.latest_blockhash()); + let meta = env + .svm + .send_transaction(tx) + .unwrap_or_else(|e| panic!("settling a signed action: {:?}\n{:#?}", e.err, e.meta.logs)); + + let vault = env.vault.to_string(); + assert!( + meta.logs + .iter() + .any(|l| l.contains("Signed by") && l.contains(&vault)), + "SPL Memo did not report the pool's vault as a signer, so the pool did \ + not actually sign: {:#?}", + meta.logs + ); + println!( + "the pool signed a real CPI as authority, {} CU", + meta.compute_units_consumed + ); + assert!( + meta.compute_units_consumed < 50_000, + "a pool-signed action cost {} CU, well above what it has ever measured", + meta.compute_units_consumed + ); + + // The member is still paid in full, and the payout still leaves the vault — + // the reordering changes when the callee sees the value, not who is owed it. + assert_eq!( + env.svm.get_account(&beneficiary).unwrap().lamports, + DENOMINATION - RELAY_FEE + ); + assert_eq!(vault_before - env.vault_lamports(), DENOMINATION); + + let mut data = env.svm.get_account(&spend_pda).unwrap().data; + assert_eq!(Spend::load(&mut data).unwrap().status(), STATUS_SETTLED); +} + +/// A mixed batch: plain transfers and a call the pool signs, settled together. +/// +/// This is the case a live cluster found and a single-spend test could not. The +/// runtime's objection is not to a signed call following a payout *for that +/// member* — it is to a signed call following any lamport this program moved in +/// the same instruction, which in a batch means the three members settled before +/// it. Settlement therefore runs every signed call first and pays everybody +/// afterwards. +/// +/// The shape matters beyond the bug. A crowd is mixed by definition, and a +/// signed action that could only settle by itself would have to wait out the +/// timeout instead of joining a batch — losing the shared timestamp that makes +/// the crowd worth standing in. +#[test] +fn a_signed_action_settles_inside_a_batch_of_plain_transfers() { + let (mut env, tree, notes, keys) = seeded_pool(8); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + // Three ordinary members first, so the vault has already moved by the time + // the signed call runs. + let mut batch = submit_batch(&mut env, &tree, ¬es, &keys, 3); + let mut targets: Vec> = vec![None, None, None]; + let mut action_accounts: Vec> = vec![Vec::new(), Vec::new(), Vec::new()]; + + let signer_beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let payload = b"one of four".as_slice(); + let proof = action_proof_sel( + &keys, + &tree, + ¬es, + 3, + &memo, + &signer_beneficiary, + &relay.pubkey(), + 1, + payload, + INVOKE_SIGNED, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix_sel( + &env, + &proof, + nullifier, + &memo, + &signer_beneficiary, + &relay.pubkey(), + 1, + payload, + INVOKE_SIGNED, + ); + env.send(ix, &relay).expect("submitting the signed action"); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + batch.push((spend_pda, signer_beneficiary, relay.insecure_clone())); + targets.push(Some(memo)); + action_accounts.push(vec![AccountMeta::new(env.vault, false)]); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let vault_before = env.vault_lamports(); + let ix = settle_ix_full(&env, &batch, &settler.pubkey(), &targets, &action_accounts); + let msg = Message::new(&[ix], Some(&settler.pubkey())); + let tx = Transaction::new(&[&settler], msg, env.svm.latest_blockhash()); + let meta = env + .svm + .send_transaction(tx) + .unwrap_or_else(|e| panic!("mixed batch: {:?}\n{:#?}", e.err, e.meta.logs)); + + let vault = env.vault.to_string(); + assert!( + meta.logs + .iter() + .any(|l| l.contains("Signed by") && l.contains(&vault)), + "the pool did not sign inside a mixed batch: {:#?}", + meta.logs + ); + println!( + "mixed batch of 4 settled, one of them pool-signed, {} CU", + meta.compute_units_consumed + ); + + // Everyone in the batch is paid, whatever their action was. + for (_, beneficiary, _) in &batch { + assert_eq!( + env.svm.get_account(beneficiary).unwrap().lamports, + DENOMINATION - RELAY_FEE, + "a member of the mixed batch went unpaid" + ); + } + assert_eq!(vault_before - env.vault_lamports(), 4 * DENOMINATION); +} + +/// The attack the signing selector invites: point the pool's own signature at +/// the System Program and tell it to move the escrow somewhere else. +/// +/// Every ingredient is legitimate. The proof is genuine, the member owns the +/// note, the selector is one the protocol offers, and the payload is a +/// well-formed `SystemInstruction::Transfer` draining the vault to an address +/// the member chose. Nothing in this program inspects the payload — it cannot, +/// the payload is opaque by design — so what refuses this is the ownership rule +/// underneath: the System Program may only debit accounts it owns, and the vault +/// is owned by the pool. +/// +/// That is the reason the pool's signature is safe to hand out. It is worth a +/// test rather than a sentence, because the sentence is the kind that stays true +/// only until somebody gives the vault a second owner or a data layout. +#[test] +fn the_pools_signature_cannot_be_turned_against_its_own_vault() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let system = solana_system_interface::program::ID; + + let attacker = Pubkey::new_unique(); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + // SystemInstruction::Transfer { lamports }: discriminant 2 as u32, then the + // amount. Drain everything the vault is holding for the other members. + let mut payload = 2u32.to_le_bytes().to_vec(); + payload.extend_from_slice(&(DENOMINATION * 5).to_le_bytes()); + + let proof = action_proof_sel( + &keys, + &tree, + ¬es, + 1, + &system, + &beneficiary, + &relay.pubkey(), + 2, + &payload, + INVOKE_SIGNED, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix_sel( + &env, + &proof, + nullifier, + &system, + &beneficiary, + &relay.pubkey(), + 2, + &payload, + INVOKE_SIGNED, + ); + env.send(ix, &relay).expect("submitting the drain attempt"); + + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + let vault_before = env.vault_lamports(); + let batch = vec![(spend_pda, beneficiary, relay.insecure_clone())]; + let ix = settle_ix_full( + &env, + &batch, + &settler.pubkey(), + &[Some(system)], + &[vec![ + AccountMeta::new(env.vault, false), + AccountMeta::new(attacker, false), + ]], + ); + let err = env + .send(ix, &settler) + .expect_err("the pool signed away its own escrow"); + println!("vault drain via the pool's own signature rejected: {err}"); + + // The whole transaction reverted, so nothing moved and the note is unspent. + assert_eq!(env.vault_lamports(), vault_before); + assert_eq!(env.svm.get_account(&attacker).map(|a| a.lamports), None); + let mut data = env.svm.get_account(&spend_pda).unwrap().data; + assert_eq!( + Spend::load(&mut data).unwrap().status(), + mirror_pool_program::spend::STATUS_PENDING, + "the spend was consumed by an attack that failed" + ); +} + +#[test] +fn a_relay_cannot_swap_the_target_program() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let payload = b"hello".as_slice(); + let proof = action_proof( + &keys, + &tree, + ¬es, + 0, + &memo, + &beneficiary, + &relay.pubkey(), + payload, + ); + let nullifier = proof.public_inputs[1]; + + // Proved for the memo program; submitted for something else. + let impostor = Pubkey::new_unique(); + let ix = action_ix( + &env, + &proof, + nullifier, + &impostor, + &beneficiary, + &relay.pubkey(), + payload, + ); + let err = env + .send(ix, &relay) + .expect_err("a swapped target program was accepted"); + println!("target swap rejected: {err}"); + assert!(err.contains("Custom(18)"), "expected proof failure: {err}"); +} + +#[test] +fn a_relay_cannot_alter_the_action_payload() { + let (mut env, tree, notes, keys) = seeded_pool(6); + let memo: Pubkey = MEMO_PROGRAM.parse().unwrap(); + env.svm.add_program(memo, &memo_bytes()).unwrap(); + + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let proof = action_proof( + &keys, + &tree, + ¬es, + 1, + &memo, + &beneficiary, + &relay.pubkey(), + b"stake 0.1", + ); + let nullifier = proof.public_inputs[1]; + + let ix = action_ix( + &env, + &proof, + nullifier, + &memo, + &beneficiary, + &relay.pubkey(), + b"stake 9.9", // proved for a different amount + ); + let err = env + .send(ix, &relay) + .expect_err("a tampered action payload was accepted"); + println!("payload tamper rejected: {err}"); + assert!(err.contains("Custom(18)"), "expected proof failure: {err}"); +} + +#[test] +fn an_action_cannot_re_enter_the_pool() { + // A payload that invokes mirror-pool itself would re-enter settlement in the + // middle of a lamport-moving loop. Refused explicitly rather than left to + // careful reading of the loop. + let (mut env, tree, notes, keys) = seeded_pool(6); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let self_target = env.program_id; + let payload = b"reenter".as_slice(); + let proof = action_proof( + &keys, + &tree, + ¬es, + 2, + &self_target, + &beneficiary, + &relay.pubkey(), + payload, + ); + let nullifier = proof.public_inputs[1]; + let ix = action_ix( + &env, + &proof, + nullifier, + &self_target, + &beneficiary, + &relay.pubkey(), + payload, + ); + env.send(ix, &relay).expect("submitting is allowed"); + + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + + // Alone, so wait out the timeout. + let mut clock = env.svm.get_sysvar::(); + clock.unix_timestamp += mirror_pool_program::processor::SETTLE_TIMEOUT_SECONDS + 1; + env.svm.set_sysvar(&clock); + + let batch = vec![(spend_pda, beneficiary, relay.insecure_clone())]; + let ix = settle_ix_with_targets(&env, &batch, &settler.pubkey(), &[Some(self_target)]); + let err = env.send(ix, &settler).expect_err("the pool invoked itself"); + println!("self-invocation rejected: {err}"); + assert!( + err.contains("Custom(23)"), + "expected SelfInvocationRefused: {err}" + ); +} + +/// The griefing vector an adversarial review found: `action_accounts` was +/// relay-supplied, written verbatim into the record, and outside the binding. +/// +/// A relay handed a valid transfer proof could submit it with a count that +/// settlement can never satisfy. The nullifier burns, the record cannot be +/// amended, there is no refund instruction, and the note is destroyed for free. +/// The relay forfeits only its fee. +#[test] +fn a_relay_cannot_declare_an_account_count_the_member_did_not_authorise() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + // Proved for a plain transfer, which takes no action accounts. + let proof = proof_for(&keys, &tree, ¬es, 0, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: SELECTOR, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 1, // the member authorised zero + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let err = env + .send(ix, &relay) + .expect_err("a relay inflated the account count and burnt the note"); + println!("inflated action_accounts rejected: {err}"); + assert!( + err.contains("Custom(1)"), + "expected MalformedInstruction: {err}" + ); + + // The nullifier must still be spendable: the griefing attempt cost the + // member nothing. + assert!( + env.svm.get_account(&spend_pda).is_none(), + "the spend record was created, so the note is now unspendable" + ); + let ok = spend_ix(&env, &proof, nullifier, &beneficiary, &relay.pubkey()); + env.send(ok, &relay) + .expect("the note must remain spendable after a failed griefing attempt"); +} + +#[test] +fn an_unknown_selector_is_refused_before_the_nullifier_burns() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let merkle_proof = tree.proof(1).unwrap(); + let binding = mirror_core::action_binding( + 99, + &[0u8; 32], + &beneficiary.to_bytes(), + &relay.pubkey().to_bytes(), + RELAY_FEE, + 0, + &[], + ); + let witness = Witness { + note: notes[1], + merkle_proof: &merkle_proof, + root: tree.root().unwrap(), + action_binding: binding, + }; + let mut rng = { + use ark_std::rand::SeedableRng; + ark_std::rand::rngs::StdRng::from_seed([77u8; 32]) + }; + let proof = prove(&keys, &witness, &mut rng).expect("proving"); + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + + let ix = Instruction::new_with_bytes( + env.program_id, + &MirrorIx::SubmitSpend { + proof_a: proof.proof_a, + proof_b: proof.proof_b, + proof_c: proof.proof_c, + root: proof.public_inputs[0], + nullifier, + selector: 99, + target_program: [0u8; 32], + beneficiary: beneficiary.to_bytes(), + relay_fee: RELAY_FEE, + action_accounts: 0, + payload: Vec::new(), + } + .pack(), + vec![ + AccountMeta::new(relay.pubkey(), true), + AccountMeta::new(env.pool, false), + AccountMeta::new(spend_pda, false), + AccountMeta::new_readonly(solana_system_interface::program::ID, false), + ], + ); + let err = env + .send(ix, &relay) + .expect_err("an unknown selector was stored"); + assert!( + err.contains("Custom(22)"), + "expected UnknownSelector: {err}" + ); + assert!( + env.svm.get_account(&spend_pda).is_none(), + "the nullifier burnt for a selector settlement can never execute" + ); +} + +/// Squatting a PDA must not brick anything. +/// +/// Every address this program creates is derived from public data — a spend PDA +/// from the nullifier, which is visible in the `submit_spend` instruction +/// itself. `create_account` fails when the destination already holds lamports, +/// so a bystander who front-runs the transaction with the rent-exempt minimum +/// would have made the note permanently unspendable for about 0.00089 SOL. The +/// relay the proof was handed to is the obvious candidate. +/// +/// The three-step create is immune: a squatter can send lamports but cannot +/// allocate or assign without the PDA's seeds, so their deposit only reduces +/// what the legitimate payer owes. +#[test] +fn squatting_a_spend_pda_does_not_brick_the_note() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + + let proof = proof_for(&keys, &tree, ¬es, 0, &beneficiary, &relay.pubkey()); + let nullifier = proof.public_inputs[1]; + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + + // The attacker reads the nullifier and funds the PDA first. + let squatter = Keypair::new(); + env.svm.airdrop(&squatter.pubkey(), 10_000_000_000).unwrap(); + let squat = Instruction::new_with_bytes( + solana_system_interface::program::ID, + &solana_system_interface::instruction::transfer(&squatter.pubkey(), &spend_pda, 890_880) + .data, + vec![ + AccountMeta::new(squatter.pubkey(), true), + AccountMeta::new(spend_pda, false), + ], + ); + env.send(squat, &squatter).expect("squatting the pda"); + assert!( + env.svm.get_account(&spend_pda).unwrap().lamports > 0, + "precondition: the pda is funded by a stranger" + ); + + // The spend must still work. + let ix = spend_ix(&env, &proof, nullifier, &beneficiary, &relay.pubkey()); + env.send(ix, &relay) + .expect("a squatted pda made the note unspendable"); + + let mut data = env.svm.get_account(&spend_pda).unwrap().data; + let record = Spend::load(&mut data).unwrap(); + assert_eq!(record.status(), STATUS_PENDING); + assert_eq!(record.beneficiary(), beneficiary.to_bytes()); +} + +#[test] +fn squatting_a_pool_pda_does_not_prevent_the_pool() { + let mut env = setup(); + let squatter = Keypair::new(); + env.svm.airdrop(&squatter.pubkey(), 10_000_000_000).unwrap(); + + // Deny the canonical pool for this denomination, for the price of rent. + for target in [env.pool, env.vault] { + let squat = Instruction::new_with_bytes( + solana_system_interface::program::ID, + &solana_system_interface::instruction::transfer(&squatter.pubkey(), &target, 890_880) + .data, + vec![ + AccountMeta::new(squatter.pubkey(), true), + AccountMeta::new(target, false), + ], + ); + env.send(squat, &squatter).expect("squatting"); + } + + env.init_pool(); + let mut data = env.pool_state(); + let pool = Pool::load(&mut data).unwrap(); + assert_eq!(pool.denomination(), DENOMINATION); + assert_eq!(pool.k_floor(), K_FLOOR); +} + +/// A batch whose members paid different relay fees settles into visibly +/// different payouts, and that is an anonymity set an observer can partition by +/// reading balances — no proof broken, no secret learned. +/// +/// The crowd rule, the single settling signature and the shared timestamp all +/// exist to prevent exactly that partition, so a mixed-fee batch is refused +/// rather than documented. It is a property of the batch and not of any record, +/// which is why the check lives in settlement: a member may agree any fee with +/// their relay, and settles with the members who agreed the same one. +#[test] +fn a_batch_whose_members_paid_different_fees_is_refused() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + + // Four members — the pool's floor — identical in every respect except what + // the last one's relay charged. + let fees = [RELAY_FEE, RELAY_FEE, RELAY_FEE, RELAY_FEE + 1]; + let mut batch = Vec::new(); + for (i, fee) in fees.iter().enumerate() { + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let (nullifier, ix) = spend_ix_at_fee( + &env, + &keys, + &tree, + ¬es, + i, + &beneficiary, + &relay.pubkey(), + *fee, + ); + env.send(ix, &relay).expect("submitting at an agreed fee"); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + batch.push((spend_pda, beneficiary, relay)); + } + + let err = env + .send(settle_ix(&env, &batch, &settler.pubkey()), &settler) + .expect_err("a mixed-fee batch must not settle"); + assert!( + err.contains("Custom(25)"), + "expected FeeNotUniform, got {err}" + ); + + // Refused, not partially applied: neither member was paid and neither record + // was consumed, so both can still settle with somebody who paid what they did. + for (spend, beneficiary, _) in &batch { + let mut data = env.svm.get_account(spend).unwrap().data; + assert_eq!(Spend::load(&mut data).unwrap().status(), STATUS_PENDING); + // The beneficiary was never funded, so the account does not exist at + // all — which is the strongest form of "nothing was paid". + assert_eq!( + env.svm + .get_account(beneficiary) + .map(|a| a.lamports) + .unwrap_or(0), + 0 + ); + } +} + +/// The same two members, once their fees agree, settle normally — so the check +/// above rejects the mixture and not the members. +#[test] +fn the_same_members_settle_once_their_fees_agree() { + let (mut env, tree, notes, keys) = seeded_pool(5); + let settler = Keypair::new(); + env.svm.airdrop(&settler.pubkey(), 10_000_000_000).unwrap(); + + let odd_fee = RELAY_FEE + 1; + let mut batch = Vec::new(); + for i in 0..4 { + let beneficiary = Pubkey::new_unique(); + let relay = Keypair::new(); + env.svm.airdrop(&relay.pubkey(), 10_000_000_000).unwrap(); + let (nullifier, ix) = spend_ix_at_fee( + &env, + &keys, + &tree, + ¬es, + i, + &beneficiary, + &relay.pubkey(), + odd_fee, + ); + env.send(ix, &relay).expect("submitting"); + let (spend_pda, _) = spend_address(&env.program_id, &env.pool, &nullifier); + batch.push((spend_pda, beneficiary, relay)); + } + + env.send(settle_ix(&env, &batch, &settler.pubkey()), &settler) + .expect("a uniform batch settles whatever the fee is"); + + // Equal payouts is the property, and it is the thing to assert. + let paid: Vec = batch + .iter() + .map(|(_, b, _)| env.svm.get_account(b).unwrap().lamports) + .collect(); + assert!( + paid.iter().all(|p| *p == DENOMINATION - odd_fee), + "members were paid different amounts: {paid:?}" + ); +} diff --git a/programs/mirror-pool/tests/fixtures/spl_memo.so b/programs/mirror-pool/tests/fixtures/spl_memo.so new file mode 100644 index 00000000..88385a01 Binary files /dev/null and b/programs/mirror-pool/tests/fixtures/spl_memo.so differ diff --git a/programs/mirror-pool/tests/vk_drift.rs b/programs/mirror-pool/tests/vk_drift.rs new file mode 100644 index 00000000..fe5e698f --- /dev/null +++ b/programs/mirror-pool/tests/vk_drift.rs @@ -0,0 +1,97 @@ +//! The verifying key compiled into the program is the one the published seed +//! produces — checked here, not by an operator remembering to run a command. +//! +//! `README.md` publishes a digest and tells a reader they can re-derive the key +//! from the committed seed and compare. That claim is only worth anything if +//! something enforces it: `vk.rs` is a generated file of plain byte arrays, and +//! a wrong byte in it is not a compile error, not a test failure anywhere else, +//! and not visible in a diff anyone reads carefully. It is a silent break of the +//! one property this setup does offer — that it is *reproducible*, since it is +//! openly not *secure*. +//! +//! What a drift here would mean is worse than a broken build. The program would +//! keep verifying proofs, against a key nobody can derive, and every claim about +//! reproducibility in this repository would be false while every test stayed +//! green. +//! +//! So this compares element by element rather than by digest alone. A digest +//! tells you *that* something moved; the element comparison tells you *which* +//! part of the key did, which is the difference between a five-minute fix and an +//! afternoon. + +use mirror_circuit::generate_reproducible; +use mirror_pool_program::vk; + +/// The same seed `mirror setup` and `mirror verify-setup` use. Committed in +/// plain sight, because the whole point is that anyone can run the setup again. +const SEED: &[u8] = b"mirror-pool-reproducible-dev-setup-v1"; + +/// The digest `README.md` publishes. +/// +/// Pinned here so that changing the number in the documentation without changing +/// the key — or the reverse — fails rather than passes. The preimage is the +/// concatenation of every element in the order below, which is what makes this +/// a statement about the whole key rather than about one point of it. +const PUBLISHED_DIGEST: &str = "b0165d5eac6fe8273b6564c78e8ba548c97e6050ae785e9142de63c81aa905b7"; + +#[test] +fn the_compiled_verifying_key_is_the_one_the_published_seed_derives() { + let derived = generate_reproducible(SEED) + .expect("the committed seed must produce a setup") + .solana_vk(); + + assert_eq!( + derived.alpha_g1, + vk::VK_ALPHA_G1, + "alpha_g1 in the program does not match the seed" + ); + assert_eq!( + derived.beta_g2, + vk::VK_BETA_G2, + "beta_g2 in the program does not match the seed" + ); + assert_eq!( + derived.gamma_g2, + vk::VK_GAMMA_G2, + "gamma_g2 in the program does not match the seed" + ); + assert_eq!( + derived.delta_g2, + vk::VK_DELTA_G2, + "delta_g2 in the program does not match the seed" + ); + + // The IC points are per public input, so a mismatch in their *count* means + // the circuit's shape changed and the program is verifying a different + // statement than the one this repository documents. + assert_eq!( + derived.ic.len(), + vk::VK_IC.len(), + "the program expects {} public inputs and the circuit produces {}", + vk::VK_IC.len(), + derived.ic.len() + ); + for (i, point) in derived.ic.iter().enumerate() { + assert_eq!(*point, vk::VK_IC[i], "IC point {i} does not match the seed"); + } +} + +/// The number in the README, enforced. +/// +/// Deliberately a separate test from the element comparison above. If both fail, +/// the key moved; if only this one fails, the documentation is stale and the key +/// is fine — and knowing which without reading any code is the point. +#[test] +fn the_published_digest_is_the_digest_of_the_derived_key() { + use sha2::{Digest, Sha256}; + let derived = generate_reproducible(SEED) + .expect("the committed seed must produce a setup") + .solana_vk(); + let mut hasher = Sha256::new(); + hasher.update(derived.digest_preimage()); + let digest = hex::encode(hasher.finalize()); + assert_eq!( + digest, PUBLISHED_DIGEST, + "the digest published in README.md is not the digest of the key this seed derives" + ); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..8565ca6b --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.97.1" +components = ["rustfmt", "clippy"]