-
Notifications
You must be signed in to change notification settings - Fork 10
feat(collateral): harden dual-state collateral contract and validator integration #372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
itzlambda
wants to merge
56
commits into
main
Choose a base branch
from
collateral-integration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
073a2e9
fix(collateral): resolve alpha reclaim accounting bugs
itzlambda 5abfe7b
fix(collateral): prevent nodeToMiner premature clearing with pending …
itzlambda f7e7721
docs(collateral): add CLAUDE.md with Bittensor EVM and contract docs
itzlambda 1f3b205
docs(collateral): expand CLAUDE.md with alpha flows, key model, and s…
itzlambda 95152c4
fix(collateral): update testnet RPC URL to correct domain
itzlambda ed348a9
fix(collateral): add storage gap and reject zero-value deposits
itzlambda ec43c3f
fix(collateral): clear nodeToMiner in denyReclaimRequest when balance…
itzlambda 3931232
Derive contract coldkey at init and remove mutable setter
itzlambda 26e65c5
refactor(collateral): rename CONTRACT_HOTKEY to VALIDATOR_HOTKEY
itzlambda aac31ce
docs(collateral): fix misleading alpha reclaim and slash descriptions
itzlambda e7d935b
sync dual-collateral event state and reclaim lifecycle
itzlambda dde9cd3
Standardize collateral evidence checksums on full SHA-256
itzlambda 6ba1721
Align collateral to alpha-primary dual-state policy
itzlambda 00ac9ff
Disable EVM deployment whitelist in localnet init scripts
itzlambda 649c585
Harden collateral reclaim/slash invariants and align reclaim ABI
itzlambda f022816
refactor(collateral-contract): remove legacy contracts and use upgrad…
itzlambda 67a2369
Rename collateral query APIs to tao_collaterals
itzlambda 3a9894c
collateral-contract: switch to solc 0.8.24 cancun
itzlambda 7387e4f
chore(collateral-contract): resolve forge lint issues
itzlambda 837e39f
fix(collateral-contract): harden reentry and slash semantics
itzlambda 1dd442f
style(collateral-contract): apply forge fmt formatting
itzlambda a50b72a
fix(collateral-contract): require explicit deploy env vars
itzlambda 57c5d67
fix(collateral): sync ABI artifacts and getter calls
itzlambda a773ddd
fix(collateral-contract): harden trustee auth and OZ safety checks
itzlambda 37a9033
feat(collateral): add localnet setup scripts and deploy flow
itzlambda 0ded5f5
fix(collateral-cli): default network and contract from env
itzlambda 506c2b4
fix(collateral-cli): default event scan range and drop block env
itzlambda 6c74149
fix(collateral): drop .env.local backup on localnet setup
itzlambda 754fa1d
feat(collateral): add TAO and alpha deposit type toggles
itzlambda c83f7ad
fix(collateral): correct storage gap and update init calldata for dep…
itzlambda e5ed770
feat(collateral): add rpc_url override for Docker connectivity
itzlambda 0ccf20c
fix(localnet): update btcli commands for latest bittensor-cli
itzlambda c39c56a
feat(localnet): integrate collateral contract deploy into startup flow
itzlambda 3b90ed5
feat(localnet): add subnet start to init and document precompile RAO …
itzlambda e66634c
fix(collateral): send slashed TAO to trustee instead of burning
itzlambda bfc6fea
feat(collateral): add integration test and seed localnet AMM pool
itzlambda 880a45b
fix(collateral): use fixed alpha amounts in integration tests
itzlambda 96377ef
feat(collateral): add e2e validator test and improve deploy idempotency
itzlambda 40cbd6e
fix(collateral): correct NatSpec and internal comments in CollateralU…
itzlambda 16b9489
docs(collateral): fix inaccuracies in CLAUDE.md
itzlambda 992302c
fix(collateral): send slashed alpha to trustee address consistently
itzlambda 784dbc4
fix(collateral): use percentage precision for slash fraction calculation
itzlambda f7641aa
feat(collateral): add minAlphaCollateralIncrease and fix alpha RAO units
itzlambda 8defaf0
fix lints
itzlambda 4a47f3f
docs(collateral): document staking guarantees and update deploy defaults
itzlambda 19c4a34
refactor(rental): centralize node release into single catch-all in st…
itzlambda 17a631f
refactor(collateral): remove grace period and exclusion mechanism
itzlambda f4b050e
feat(collateral): add background reconciliation service
itzlambda fa52f24
feat(collateral): add combined getCollaterals query to halve RPC roun…
itzlambda 596cb66
fix(collateral): prevent sub-1% slash_fraction from triggering full s…
itzlambda 653f1d1
refactor(collateral): add graceful shutdown to scan and reconcile loops
itzlambda bc93801
fix(collateral): use GRANDPA-finalized block for event scanning
itzlambda 3e3cc4e
feat(collateral): add persistent event log for contract events
itzlambda 72b72d7
fix(collateral): normalize hex encoding to use 0x prefix consistently
itzlambda 5225409
refactor(collateral): remove redundant get_collateral_amount wrapper
itzlambda 3b9a6da
refactor(collateral): extract event handling and enforce idempotency
itzlambda File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| ## Collateral Contract TODOs (feat/incentive_revamp) | ||
|
|
||
| ### Security Audit (2026-02-06): Critical/High Collateral-Loss Findings | ||
|
|
||
| 1) ~~Critical - Alpha pending-reclaim counter is never decremented on finalize~~ **DONE** | ||
| - Problem: `reclaimCollateral` increments `alphaCollateralUnderPendingReclaims`, but `finalizeReclaim` only decrements `collateralUnderPendingReclaims` and never clears the alpha pending counter. After one successful alpha reclaim, later alpha deposits on the same `(hotkey, nodeId)` can become non-reclaimable due to stale pending alpha accounting. | ||
| - Impact: legitimate miner alpha collateral can become permanently locked. | ||
| - Fix: | ||
| - In `finalizeReclaim`, decrement `alphaCollateralUnderPendingReclaims[hotkey][nodeId]` by `alphaAmount` before external calls. | ||
| - Enforce invariant checks that pending alpha never exceeds tracked alpha. | ||
| - Regression test: | ||
| - alpha deposit -> reclaim -> finalize -> alpha deposit again -> reclaim/finalize must still succeed. | ||
| - Files: `crates/collateral-contract/src/CollateralUpgradeable.sol` | ||
|
|
||
| 2) ~~High - Pending reclaim plus slash can deadlock collateral (non-finalizable and non-deniable)~~ **DONE** | ||
| - Problem: `slashCollateral` mutates live balances while pending reclaim keeps snapshot amounts. Later `finalizeReclaim` can revert when snapshot reclaim amount exceeds remaining balance. For alpha-only requests, `denyReclaimRequest` currently treats `reclaim.amount == 0` as "not found", preventing trustee cleanup. | ||
| - Impact: remaining collateral can become permanently stuck (cannot be finalized by miner and cannot be denied by trustee). | ||
| - Fix: | ||
| - Change reclaim existence check to: `if (reclaim.amount == 0 && reclaim.alphaAmount == 0) revert ReclaimNotFound();` | ||
| - Implemented partial finalize: `finalizeReclaim` caps transfer to available balance instead of reverting. Slash and reclaim are now fully independent operations. | ||
| - Regression tests: | ||
| - pending alpha reclaim + partial alpha slash must not leave unrecoverable remainder. | ||
| - alpha-only reclaim must be deny-able before timeout. | ||
| - Files: `crates/collateral-contract/src/CollateralUpgradeable.sol`, `crates/collateral-contract/src/lib.rs`, `crates/basilica-validator/src/collateral/slash_executor.rs` | ||
|
|
||
| ### ~~Upgrade Safety (Critical)~~ **DONE** | ||
| - Problem: Storage layout is not append‑only. New fields (`CONTRACT_COLDKEY`, `VALIDATOR_HOTKEY`, `alphaCollaterals`, `alphaCollateralUnderPendingReclaims`, plus new fields in `Reclaim`) are inserted before existing mappings/struct fields, which will corrupt state on upgrade for any already‑deployed proxy. | ||
| Fix: | ||
| - Contract is not yet deployed, so current layout becomes canonical V1 (no reordering needed). | ||
| - Added `uint256[50] private __gap` storage gap after `nextReclaimId` for future upgrade safety. | ||
| Files: `crates/collateral-contract/src/CollateralUpgradeable.sol` | ||
|
|
||
| ### ~~Reclaim Deny Logic (High)~~ **DONE** | ||
| - Problem: `denyReclaimRequest` treats `reclaim.amount == 0` as "not found". Alpha‑only reclaims have `amount == 0`, so they cannot be denied. | ||
| Fix: | ||
| - Change existence check to `if (reclaim.amount == 0 && reclaim.alphaAmount == 0) revert ReclaimNotFound();` | ||
| Files: `crates/collateral-contract/src/CollateralUpgradeable.sol` | ||
|
|
||
| ### ~~Pending Alpha Accounting + Underflow (High)~~ **DONE** | ||
| - Problem: `finalizeReclaim` never decrements `alphaCollateralUnderPendingReclaims`. Also no alpha‑side sufficiency check is performed before subtracting `alphaAmount`, so slashes during the pending window can cause underflow/revert. | ||
| Fix: | ||
| - Decrement `alphaCollateralUnderPendingReclaims[hotkey][nodeId]` in `finalizeReclaim`. | ||
| - Instead of reverting on insufficiency, `finalizeReclaim` now caps the transfer to the available balance (partial finalize), preventing both underflow and deadlock. | ||
| Files: `crates/collateral-contract/src/CollateralUpgradeable.sol` | ||
|
|
||
| ### ~~Zero‑Value Deposit Ownership (Medium)~~ **DONE** | ||
| - Problem: `deposit` allows `msg.value == 0` and `alphaAmount == 0`, yet still claims `nodeToMiner`, enabling ownership griefing without collateral. | ||
| Fix: | ||
| - Added `if (msg.value == 0 && alphaAmount == 0) revert AmountZero()` guard at top of `deposit()`. | ||
| Files: `crates/collateral-contract/src/CollateralUpgradeable.sol` | ||
|
|
||
| ### ~~Contract Coldkey Mutability (Medium)~~ **DONE** | ||
| - Problem: `setContractColdkey` can change the coldkey even if the contract already holds stake, potentially orphaning existing alpha collateral. | ||
| Fix: | ||
| - Removed `setContractColdkey` entirely. | ||
| - `CONTRACT_COLDKEY` is now derived once in `initialize()` via AddressMapping precompile (`0x...080C`) using `address(this)` and is never externally mutable. | ||
| Files: `crates/collateral-contract/src/CollateralUpgradeable.sol`, `crates/collateral-contract/src/lib.rs`, `crates/collateral-contract/src/main.rs` | ||
|
|
||
| ### ~~Partial Slash Persistence Desync (Medium)~~ **DONE** | ||
| - Problem: Validator persistence set `miner=0` on every slash, but on‑chain clears `nodeToMiner` only when collateral ownership is truly exhausted, causing desync after partial slashes. | ||
| Fix: | ||
| - Ownership clearing is now rule-based: only set `miner=0` when live and pending collateral are all zero (`tao_collateral == 0 && alpha_collateral == 0 && pending_tao_reclaim == 0 && pending_alpha_reclaim == 0`). | ||
| - Added regression coverage for full slash while pending reclaim exists; miner remains set until pending is resolved. | ||
| Files: `crates/basilica-validator/src/persistence/collateral_persistence.rs` | ||
|
|
||
| ### ~~Evidence Checksum Consistency (Integration)~~ **DONE** | ||
| - Problem: On-chain checksum fields previously used MD5 naming while validator slash execution submitted a truncated SHA-256 value. | ||
| Fix: | ||
| - Standardized all checksum interfaces on full SHA-256 (`bytes32` / `[u8; 32]`) and renamed fields to `urlContentSha256`. | ||
| - Updated contract ABI/events, CLI parsing/flags (`--url-content-sha256`), validator slash checksum computation, and persistence column naming to `url_content_sha256`. | ||
| - Added migration `018_rename_md5_checksum_to_sha256.sql` to rename the persistence column and null out non-64-hex legacy values. | ||
| Verification: | ||
| - `forge test` (collateral-contract) passed. | ||
| - `cargo test -p collateral-contract --lib` passed. | ||
| - `cargo test -p collateral-contract --bin collateral-cli` passed. | ||
| - `cargo test -p basilica-validator --test collateral_e2e` passed. | ||
| - `cargo test -p basilica-validator --test collateral_slash_flow` passed. | ||
| - `cargo test -p basilica-validator test_handle_slashed_with_url_data` passed. | ||
| Completed: 2026-02-18 | ||
| Files: `crates/collateral-contract/src/CollateralUpgradeable.sol`, `crates/collateral-contract/src/main.rs`, `crates/collateral-contract/src/lib.rs`, `crates/basilica-validator/src/collateral/slash_executor.rs`, `crates/basilica-validator/src/persistence/collateral_persistence.rs` | ||
|
|
||
| ### ~~Alpha-Primary, Dual-State Alignment (Integration)~~ **DONE** | ||
| - Decision: | ||
| - Keep **dual-state** contract/event sync for TAO + alpha. | ||
| - Keep **alpha-only policy** for validator eligibility/limits/slash sizing. | ||
| - Keep **alpha-only tx surface** in CLI/Rust bindings (`msg.value=0`, `slashAmount=0` in tx helpers). | ||
| - Require **non-zero alpha** to claim ownership on first deposit (prevents TAO-only ownership claims). | ||
| - Fix: | ||
| - Added `AlphaRequiredForOwnership` guard in `deposit()` when `nodeToMiner` is empty. | ||
| - Preserved TAO write paths for already-owned nodes (deposits/reclaims/slashes remain contract-supported). | ||
| - Added/updated tests for: | ||
| - TAO-only first claim reverts. | ||
| - Alpha-backed first claim succeeds. | ||
| - TAO top-up remains valid after alpha-backed ownership claim. | ||
| - Clarified alpha-primary policy in CLI/lib comments and operator docs. | ||
| - Added validator regression proving TAO is non-authoritative for eligibility (high TAO + zero alpha remains undercollateralized). | ||
| - Completed: 2026-02-18 | ||
| - Files: `crates/collateral-contract/src/CollateralUpgradeable.sol`, `crates/collateral-contract/test/CollateralBasic.t.sol`, `crates/collateral-contract/test/CollateralUpgradeable.t.sol`, `crates/collateral-contract/src/lib.rs`, `crates/collateral-contract/src/main.rs`, `docs/collateral-contract.md`, `crates/collateral-contract/README.md`, `crates/collateral-contract/flow.sh`, `crates/basilica-validator/src/collateral/manager.rs`, `crates/basilica-validator/src/collateral/evaluator.rs`, `crates/basilica-validator/src/persistence/collateral_persistence.rs` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
crates/basilica-validator/migrations/017_dual_collateral_event_state.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| -- Switch collateral persistence to dual-collateral state with reclaim request tracking. | ||
| -- Collateral is not enabled yet, so we intentionally rebuild these tables instead of | ||
| -- preserving legacy rows. | ||
|
|
||
| ALTER TABLE collateral_status RENAME TO collateral_status_legacy; | ||
|
|
||
| CREATE TABLE IF NOT EXISTS collateral_status ( | ||
| id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| hotkey TEXT NOT NULL, | ||
| node_id TEXT NOT NULL, | ||
| miner TEXT NOT NULL, | ||
| tao_collateral TEXT NOT NULL DEFAULT '0', | ||
| alpha_collateral TEXT NOT NULL DEFAULT '0', | ||
| pending_tao_reclaim TEXT NOT NULL DEFAULT '0', | ||
| pending_alpha_reclaim TEXT NOT NULL DEFAULT '0', | ||
| url TEXT, | ||
| url_content_md5_checksum TEXT, | ||
| updated_at TEXT DEFAULT CURRENT_TIMESTAMP, | ||
| UNIQUE(hotkey, node_id) | ||
| ); | ||
|
|
||
| CREATE TABLE IF NOT EXISTS collateral_reclaims ( | ||
itzlambda marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| reclaim_request_id TEXT PRIMARY KEY, | ||
| hotkey TEXT NOT NULL, | ||
| node_id TEXT NOT NULL, | ||
| miner TEXT NOT NULL, | ||
| requested_tao_amount TEXT NOT NULL, | ||
| requested_alpha_amount TEXT NOT NULL, | ||
| deny_timeout TEXT NOT NULL, | ||
| updated_at TEXT DEFAULT CURRENT_TIMESTAMP | ||
| ); | ||
|
|
||
| DROP TABLE collateral_status_legacy; | ||
8 changes: 8 additions & 0 deletions
8
crates/basilica-validator/migrations/018_rename_md5_checksum_to_sha256.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| -- Rename checksum column to SHA-256 semantics and drop legacy-sized values. | ||
| ALTER TABLE collateral_status | ||
| RENAME COLUMN url_content_md5_checksum TO url_content_sha256; | ||
|
|
||
| UPDATE collateral_status | ||
| SET url_content_sha256 = NULL | ||
| WHERE url_content_sha256 IS NOT NULL | ||
| AND length(url_content_sha256) != 64; |
4 changes: 4 additions & 0 deletions
4
crates/basilica-validator/migrations/019_clear_organic_grace_periods.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| -- Clear stale organic grace period entries so only future force_exclude (slash) | ||
| -- entries remain. Without this, old organic entries with expired grace periods | ||
| -- would incorrectly appear as slash-excluded nodes. | ||
| DELETE FROM collateral_grace_periods; |
1 change: 1 addition & 0 deletions
1
crates/basilica-validator/migrations/020_drop_collateral_grace_periods.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| DROP TABLE IF EXISTS collateral_grace_periods; |
17 changes: 17 additions & 0 deletions
17
crates/basilica-validator/migrations/021_collateral_event_log.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| CREATE TABLE IF NOT EXISTS collateral_event_log ( | ||
| id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| event_type TEXT NOT NULL, -- 'Deposit', 'ReclaimProcessStarted', 'Denied', 'Reclaimed', 'Slashed' | ||
| block_number INTEGER NOT NULL, | ||
| tx_hash TEXT NOT NULL, | ||
| log_index INTEGER NOT NULL, | ||
| hotkey TEXT, -- common field, extracted for querying | ||
| node_id TEXT, -- common field, extracted for querying | ||
| event_data TEXT NOT NULL, -- JSON blob with all decoded event fields | ||
| created_at TEXT DEFAULT CURRENT_TIMESTAMP, | ||
| UNIQUE(tx_hash, log_index) -- natural dedup key | ||
| ); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS idx_event_log_block ON collateral_event_log(block_number); | ||
| CREATE INDEX IF NOT EXISTS idx_event_log_hotkey ON collateral_event_log(hotkey); | ||
| CREATE INDEX IF NOT EXISTS idx_event_log_node_id ON collateral_event_log(node_id); | ||
| CREATE INDEX IF NOT EXISTS idx_event_log_type ON collateral_event_log(event_type); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.