Assessment reports>Hyperliquid>Threat Models>emergencyUnlock

Function: emergencyUnlock(ValidatorSetUpdateRequest newValidatorSet, ValidatorSet activeColdValidatorSet, address[] signers, Signature[] signatures, uint64 nonce)

This function can be used to change the validator set and unlock the contract.

Inputs

  • newValidatorSet

    • Control: Arbitrary.

    • Constraints: hotAddresses, coldAddresses, and powers array lengths must match; newValidatorSet.epoch > activeHotValidatorSet.epoch; and cumulative power must be greater than zero.

    • Impact: New validator set.

  • activeColdValidatorSet

    • Control: Arbitrary.

    • Constraints: Hash must match the stored active cold validator set hash.

    • Impact: Set of active cold validators --- used to validate signatures.

  • signers

    • Control: Arbitrary.

    • Constraints: Length must match signatures.

    • Impact: List of signers for the unlock action.

  • signatures

    • Control: Arbitrary.

    • Constraints: Each element must be a valid signature for the corresponding address in signers.

    • Impact: Signatures authorizing the action.

  • nonce

    • Control: Arbitrary.

    • Constraints: None.

    • Impact: Nonce used as part of the signed message.

Branches and code coverage (including function calls)

Intended branches

  • Checks that the same action has not already been performed and that the signatures are valid, updates the validator set, and unlocks the contract.

Negative behavior

  • Reverts if the same message has already been used.

  • Reverts if the hash of the provided validator set does not match the stored one.

  • Reverts if a signature does not correspond with the signer.

  • Reverts if the signers' cumulative voting power is insufficient.

  • Reverts if the length of the signers and signatures do not match.

Function call analysis

  • rootFunction -> checkMessageNotUsed(message)

    • What is controllable? message, indirectly (some parts of the hash).

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy cannot happen (no external calls).

  • rootFunction -> updateValidatorSetInner(...)

    • What is controllable? newValidatorSet, activeColdValidatorSet, signers, signatures, and message (indirectly, it is a hash).

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • updateValidatorSetInner -> checkNewValidatorPowers(newValidatorSet.powers)

    • What is controllable? newValidatorSet.powers.

    • If return value controllable, how is it used and how can it go wrong? Used as the sum of the voting powers.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • updateValidatorSetInner -> checkValidatorSignatures(message, activeValidatorSet, signers, signatures, validatorSetHash)

    • What is controllable? message, activeValidatorSet, signers, and signatures.

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • checkValidatorSignatures -> makeValidatorSetHash(activeValidatorSet)

    • What is controllable? activeValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Not meaningfully controllable, compared against the expected validator set hash.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy cannot happen (no external calls).

  • checkValidatorSignatures -> recoverSigner(message, signatures[signerIdx], domainSeparator)

    • What is controllable? message and signatures[signerIdx].

    • If return value controllable, how is it used and how can it go wrong? Not meaningfully controllable, compared against the expected signer; it is not possible to forge a signer's address.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy cannot happen (no external calls).

  • updateValidatorSetInner -> makeValidatorSetHash(newHotValidatorSet)

    • What is controllable? newHotValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Used as the hash of the new hot validator set.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • updateValidatorSetInner -> makeValidatorSetHash(newColdValidatorSet)

    • What is controllable? newHotValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Used as the hash of the new cold validator set.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • rootFunction -> finalizeValidatorSetUpdateInner()

    • What is controllable? N/A.

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • rootFunction -> _unpause()

    • What is controllable? N/A.

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts or reentrancy are not possible.

Zellic © 2025Back to top ↑