x/license keeper.
The four states
State transitions
ISSUED → BOUND
Triggered byMsgBindLicense. Requirements:
- License status must be
ISSUED - Category policy must permit the binding
- Any cooldown from a prior unbind must have elapsed
- For Sovereign: binding target must be the owner’s own validator address
- For Prime/Core: target validator must exist, be bonded, and not be jailed
BOUND → ACTIVE
Triggered automatically when delegation is created or increased on the bound validator:ACTIVE → BOUND
A license moves back toBOUND when:
- Owner fully undelegates from the bound validator
- Validator is jailed (JailInterceptor fires)
- Governance revokes the license
Partial undelegation does not change license status. The license remains ACTIVE as long as any delegation with positive token value exists.
BOUND → ISSUED (unbinding)
Triggered byMsgUnbindLicense. Requirements:
- No active delegation to the bound validator
- Cooldown period from any prior unbind must have elapsed
CooldownPeriod in the category policy has elapsed.
Any → REVOKED
Triggered only byMsgRevokeLicense via governance proposal. For Sovereign revocations, the validator is immediately jailed. For Prime/Core revocations, only same-owner sibling licenses are affected.
REVOKED → ISSUED
Triggered only byMsgReinstateLicense via governance. The owner must complete the full recovery sequence manually:
1
Governance reinstates
MsgReinstateLicense → license status: ISSUED2
Owner binds
MsgBindLicense → license status: BOUND3
Operator unjails
MsgUnjail — JailInterceptor allows because Sovereign license is no longer REVOKED4
Owner delegates
MsgDelegate → license status: ACTIVETransfer restrictions
OnlyISSUED licenses can be transferred. The category policy must have Transferable = true. Transferring a license does not clear the unbind cooldown timer — the new owner inherits it.