v8.0.0 "Alpha" — emergency security upgrade - #534
Merged
Merged
Conversation
* feat(claims): team member budgets for shared subscription pools
Add per-member periodic spend budgets on claim collections so multiple
members can share one deed's credit pool with individually enforced limits.
- New MemberBudget state (prefix 0x05) keyed by collection_id/member_address.
Independent KV entries keep per-member ops O(1) regardless of team size.
- member_address threaded through SubmitClaimConstraints, CCAA constraints,
MsgClaimIntent, MsgSubmitClaim, Intent and Claim with strict-equality
matching at every step (empty == empty for individual subscriptions).
- Anti-spoofing: admin locks member_address into the CCAA constraint at
grant time; Accept() enforces equality, blocking grantees from minting
authorizations tagged for other members.
- Budget enforced at intent time (real spend gate, funds to escrow).
Deducted on intent, restored on rejection / dispute / invalidation /
intent expiration via EndBlocker.
- Lazy period reset (feegrant PeriodicAllowance pattern, no cron).
- New msgs: MsgSetCollectionMembers / MsgRemoveCollectionMembers (batch).
New events: MemberBudget{Created,Updated,Removed}Event carrying full
state for indexers. New queries: CollectionMember(List).
All new fields are optional with empty defaults — backward compatible.
Spec docs updated (concepts, state, messages, events, README).
Authored by: Michael Pretorius <michael@ixo.world>
* feat(liquidstake): v7 multi-pool refactor + cross-module denom collision defences
Reshape liquidstake from a single global ZERO/uzero pool into N independent
pools, each with its own LST denom, validator whitelist, admin, fees, paused
flag, and proxy account. Pool creation is gov-only; per-pool config edits are
admin-or-gov. Mint stays 1:1 (admin-only LiquidStake preserves the pre-v7
invariant); unstake rate captures all value accrual.
- Proto: split Params into ModuleParams (global: min_liquid_stake_amount,
module_paused) + Pool (per-pool); new MsgCreatePool / MsgUpdatePool /
MsgUpdateModuleParams / MsgSetPoolPaused / MsgSetModulePaused; pool_id
threaded through every per-pool message and event. Per-tx/per-epoch event
fields upgraded from formatted strings to typed Coin / Timestamp / uint32
while preserving v6 field tag numbers (pool_id appended at the end).
- Keeper: per-pool LiquidValidator storage (prefix 0x11 + lp(poolID) + valAddr),
Pool CRUD + registerPool, per-pool NetAmountState, per-pool LiquidStake /
LiquidUnstake / autocompound / rebalance, BeginBlock and epoch hooks iterate
pools, ModuleParams.module_paused as global kill switch.
- Denom collision defence (3 layers): registerPool refuses IBC-shape denoms,
bond denom, denoms with non-zero bank supply OR existing bank metadata;
RegisterLSTDenomMetadata claims the denom in bank with the standard
u-prefix two-unit shape (uzero@0 + zero@6); MintCoinsRestriction installed
in app/keepers/keepers.go rejects any non-liquidstake module trying to mint
a pool's LST denom. Bonds.CreateBond gains the same supply/metadata guard
so collisions are caught at the front door instead of halting the chain
in EndBlocker.
- v7 upgrade migration: legacy Params -> ModuleParams + "zero" Pool with
proxy_account_address pinned to the pre-v7 LiquidStakeProxyAcc bech32
(preserves all existing delegations untouched), re-keys legacy 0x02
LiquidValidator records under 0x11+lp("zero"), claims uzero metadata.
Skips pool construction entirely if no legacy denom was set.
- Local-test mode: x/epochs/types/genesis.go, x/liquidstake/types/keys.go,
and x/mint/types/params.go each carry a commented "2min" alternative the
operator can flip on for fast local autocompound/rebalance testing. All
three files default to mainnet values; comments at each call site
document that the three files must be flipped together.
- Spec docs: x/liquidstake/spec/{README,01_concepts,02_state,03_messages,
04_events,05_params}.md cover every type, message, event, parameter,
and the v7 migration mechanics.
Authored by: Michael Pretorius <michael@ixo.world>
* feat(names): add chain-level name service module
x/names: governance-managed namespaces mapping human-readable handles
to DIDs. Self-register and registrar-on-behalf flows, status lifecycle
(no hard-delete), reverse-lookup index by owner DID, and dual-emit
NameUpdatedEvent + action events for clean indexer integration.
- Messages: gov Create/UpdateNamespace; user RegisterName/TransferName;
registrar RegisterNameByRegistrar / UpdateNameByRegistrar /
SetNameStatus.
- Six query rpcs (Namespace, Namespaces, ResolveName, GetName,
NamesByNamespace, NamesByOwner) — all wasm-whitelisted.
- Defensive length caps on namespace text fields and registrar-supplied
evidence_hash / source, dual-enforced at ValidateBasic and inside the
keeper handler so Wasm sub-message dispatches can't bypass.
- v7 upgrade adds the new store key.
- Also fills wasm-whitelist gaps for claims (CollectionMember,
CollectionMemberList) and entity (EntityMetaData, EntityIidDocument).
- Spec docs under x/names/spec/.
Authored by: Michael Pretorius <michael@ixo.world>
* feat(claims): add FLAGGED non-terminal evaluation status
Add `EvaluationStatus.FLAGGED (5)` — an escape-hatch outcome for
evaluators who want to defer a final call (e.g. AI oracles escalating
ambiguous cases to a human reviewer). FLAGGED skips payment and the
intent-escrow refund branch and keeps funds locked in escrow until
terminal finalisation; it still consumes AgentQuota (only INVALIDATED
skips).
A FLAGGED claim may be re-evaluated by any authorized evaluator,
including the original flagger if they later get more information. The
same agent cannot re-flag a claim they've already flagged — checked
across both the current evaluation and the full evaluation_history,
so flag-bombing across an intervening flag from another agent is also
rejected (ErrSelfReFlag).
State additions: Claim.evaluation_history (prior evaluations in
chronological order, latest stays in evaluation), Collection.flagged
(cumulative event counter, never decremented), Collection.flagged_active
(claims currently in FLAGGED state).
ClaimEvaluatedEvent / ClaimUpdatedEvent are reused; indexers distinguish
flag events by inspecting evaluation.status. Spec docs updated across
concepts / state / messages / events / future improvements.
* feat(claims): v7 dispute resolution and performance deposits
- Adds rolling AgentDepositBalance per (collection, agent) with a
min_deposit_period lock on withdrawals to close the
deposit-submit-withdraw exploit; slash path bypasses the lock.
- Adds Dispute target_role (SUBMITTER/EVALUATOR), at-most-one-OPEN-per-
pair semantics, AWARDED permanently blocks, DISMISSED supersedes.
- Adds MsgAdjudicateDispute with DID-key auth (IID ante + keeper
re-check), per-adjudicator AdjudicationDid.reward_percentage so each
whitelisted DID self-sets their fee, configurable AWARDED/DISMISSED
split, intended-vs-actual penalty captured on DisputeResolution.
- DisputeResolution.data and MsgAdjudicateDispute.data replace the v6
free-form reason string with a DisputeData payload (uri + proof +
type + encrypted), symmetric with MsgDisputeClaim.data.
- FLAGGED evaluations cannot be disputed as EVALUATOR; re-evaluating
to a terminal status re-enables that path.
- New events for ClaimDisputed / DisputeResolved and the
AgentDepositBalance lifecycle; v3→v4 migration stamps legacy
disputes as DISMISSED; spec docs (01/02/03/04/README) updated.
* feat(claims): add MsgUpdateCollectionQuota
Adds the missing admin-mutation path for collection.quota — the only
user-facing Collection field without an update msg until now. Handler
rejects new quota < current count with ErrCollectionQuotaBelowCount so
already-submitted claims can't be retroactively invalidated; quota = 0
keeps its unlimited semantics. Wired into msg_server, codec,
ValidateBasic, and the cli (update-collection-quota); spec
(03_messages.md) updated.
* feat(iid): block module-reserved DID namespaces on MsgCreateIidDocument
Adds a guard rejecting user-submitted MsgCreateIidDocument for DIDs
under a module-reserved prefix (currently did:ixo:entity:...). Those
prefixes are minted deterministically by their owning module via
IidKeeper.SetDidDocument, so without this guard a malicious user could
squat a DID the entity module's CreateSequence will later try to mint,
deadlocking the module. Enforced in ValidateBasic (catches at antehandler)
and again at the msgServer handler (defense in depth for direct
callsites). New ErrReservedDidNamespace, ReservedDidPrefixes registry
in iid/types/keys.go, and spec note in iid/spec/03_messages.md.
Authored by: Michael Pretorius <michael@ixo.world>
* test(app): comprehensive L1+L2+L3 suite + GH Actions wiring
Adds a multi-layer test harness for ixo-blockchain:
L1 (keeper unit tests) — every custom module
- x/iid, x/bonds, x/entity, x/claims, x/token, x/epochs, x/mint,
x/names, x/liquidstake, x/smart-account, app/ante
- Testify suite + apptesting/ harness (app/apptesting/) for
keeper-level tests against a real IxoApp instance.
L2 (simulator) — tests/simulator/
- sim_test, sim_genesis_test, sim_invariants_test,
sim_module_accounts_test, sim_modules_test, sim_ordering_test,
sim_gov_lifecycle_test, sim_bench_test.
- AppModuleSimulation hooks (Decoder + empty WeightedOperations)
wired on every custom module's module.go.
- scripts/makefiles/tests.mk: test-sim-app, test-sim-determinism,
test-sim-import-export targets.
L3 (interchaintest E2E) — tests/interchaintest/
- Per-module FullScenario tests (bank/staking/distribution/
slashing/gov/wasm/ibc + iid/bonds/entity/claims/token/names/
liquidstake/chaintime/tx-delegation/multi-message-atomicity).
- Dedicated claims flows:
TestIxoClaimsFlagged_FullScenario
TestIxoClaimsDisputes_FullScenario
TestIxoClaimsDisputesValidations_FullScenario
TestIxoClaimsDisputesMultiAdjudicator_FullScenario
- tests/interchaintest/ is a sub-module (its own go.mod) to keep
docker-dependent deps off the main build.
Silent-drop chain bug fixes uncovered while writing tests:
- iid: MsgUpdateIidDocument dropped all fields (msg_server.go
missing `*didDoc = did`)
- iid: MsgDeactivateIID ignored `state` (Deactivate() always
true)
- iid: add-verification-method CLI used wrong args index
- iid: nested message types rendered as {} via autocli; manual
GetQueryCmd added (x/iid/client/cli/query.go)
- bonds: --oracle-did CLI flag not registered + NewMsgCreateBond
dropped OracleDid silently
- liquidstake: autocli + dynamicpb Coin panic; manual GetTxCmd
added (x/liquidstake/client/cli/tx.go)
CI (.github/workflows/tests.yml):
- push to main/master/develop, PRs into main/develop,
workflow_dispatch.
- Unit + race + simulator on every push / PR.
- Full L3 Docker E2E only on PRs into main + manual dispatch.
Lefthook (lefthook.yml): pre-push hook runs make test-unit so the
L1 sweep can't accidentally regress.
Authored by: Michael Pretorius <michael@ixo.world>
* feat(iid): restrict MsgCreateIidDocument DID forms to signer-account and wasm-contract
IXO-2045. Adds ValidateMsgCreateDIDForm: only did:ixo:<bech32-account>
(account must equal signer) and did:ixo:wasm:<bech32-contract> (anyone
may create) are accepted. Reserved did:ixo:entity: stays rejected; any
other form (did:cosmos:, did:x:, did:ixo:foo:bar, malformed wasm) is
refused with ErrDIDFormNotAllowed / ErrDIDAccountSignerMismatch.
Enforced in ValidateBasic + msg-server (defense in depth so Cosmwasm
stargate cannot bypass). Unit + L3 coverage added.
* fix: add legacy proto for indexing services
* chore(upgrade): name v7 upgrade "Opus"
Authored by: Michael Pretorius <michael@ixo.world>
* docs(liquidstake): regenerate proto-docs for legacy MsgUpdateParams
Authored by: Michael Pretorius <michael@ixo.world>
* chore(app): bump go module path v6 -> v7 for the Opus upgrade
Sweep github.com/ixofoundation/ixo-blockchain/v6 -> /v7 across go.mod,
all Go sources, proto go_package options, the interchaintest submodule
(module + local replace), CLAUDE.md and scripts/protoc-gen.sh. go mod
tidy. Root build, vet and the interchaintest test compile all pass.
Authored by: Michael Pretorius <michael@ixo.world>
* chore(docker): default image build version to v7.0.0
GIT_VERSION baked into ixod via ldflags now defaults to v7.0.0 (was the
stale v6.0.0); GIT_COMMIT defaults to zeros and should be overridden with
--build-arg GIT_COMMIT=$(git rev-parse HEAD) at build time.
Authored by: Michael Pretorius <michael@ixo.world>
…zation Emergency v8 upgrade following the 2026-06-20 x/bonds reserve drain, in which bonds handlers moved funds from a DID-resolved address without checking it against the transaction signer. Disables bonds and closes the broader class of DID/authz authorization gaps with keeper-level, route-independent checks. x/bonds — disabled: - Register a disabled msg server: every bonds message returns ErrBondsModuleDisabled, covering all routes (top-level, authz, CosmWasm, ICA). - No-op the batch EndBlocker so existing bonds can no longer move reserves. - Add an ante guard that rejects any bonds message, recursing authz.MsgExec. x/iid — ante MsgExec recursion: - VerifyIidControllersAgainstSignature now unwraps nested authz.MsgExec so IID-controlled messages cannot skip the controller check. x/entity — keeper authorization: - Add VerifyDidSignerAuthentication; UpdateEntity / TransferEntity / UpdateEntityVerified now bind the signer to the acting DID in the keeper, so authorization holds on routes that bypass the ante (CosmWasm, ICA, authz). - BlockNftContractTransferForEntityDecorator now recurses authz.MsgExec. x/claims — scope IidTxMsg to signer-controlled DIDs: - Drop IidTxMsg from MsgSubmitClaim / MsgEvaluateClaim / MsgCreateClaimAuthorization (proto signer is admin_address; the *_did field is agent/creator attribution, authorized in-keeper via collection.Admin). Keep DisputeClaim / AdjudicateDispute, whose signer is the DID's own party. x/token — batch hardening: - ValidateTokenBatch enforces a non-empty batch, per-element id/amount, and a single contract; CancelToken uses checked subtraction (no underflow panic). app — v8 upgrade: - Add app/upgrades/v8 and register it. The handler tightens ICA-host AllowMessages from ["*"] to an ante-safe allow-list (standard Cosmos messages only; ixo identity/asset modules excluded). tests: - Unit, decorator, no-ante router e2e, full signed-tx ante e2e, ICA allow-list guard, and a claims IidTxMsg-membership regression across the changed modules. Authored by: Michael Pretorius <michael@ixo.world>
The MsgSoftwareUpgrade plan.name must equal UpgradeName; binary stays v8.0.0. Authored by: Michael Pretorius <michael@ixo.world>
Their proto signer agent_address may be a delegated agent or an entity module account (e.g. the SUPA onboarding fee account) that is decoupled from AgentDid, which is attribution only. Authorization is enforced in the keeper (SubmitClaimAuthorization grant / dispute deposit) on every route, so the IID ante's signer-controls-DID check wrongly broke these on-behalf flows. MsgAdjudicateDispute stays IidTxMsg: the keeper's AuthorizeAdjudicator itself requires signer to control AdjudicatorDid. Authored by: Michael Pretorius <michael@ixo.world>
Sweep github.com/ixofoundation/ixo-blockchain/v7 -> /v8 across go.mod (module + interchaintest replace directive + its own module path), all .go imports, proto go_package options, CLAUDE.md, CHANGELOG.md and scripts/protoc-gen.sh. The app/upgrades/v7 handler package is left intact — only the module-path prefix changes. go build ./... and all test-package compilation pass. Authored by: Michael Pretorius <michael@ixo.world>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Promotes the v8.0.0 ("Alpha") emergency security release from
developtomain.This upgrade is already enacted on mainnet — gov proposal #482 passed and the
Alphaupgrade applied at height 17871000.Security
Addresses the disclosed vulnerability in
x/bonds— see advisory GHSA-w3rp-4cm2-4wgc. Thex/bondsmodule is disabled in this release.What's included
AllowMessagesrestricted to an ante-safe allow-listapp/upgrades/v8(on-chain nameAlpha)Scope
29 files, +1599 / -38.
Authored by: Michael Pretorius michael@ixo.world