Evidence - peaq root key cancelled an unstake on 2026-07-12

Forensic record for account 0x076727fD87bf5f02E5262314C5fbcCA53545AFC1. Every fact below was read from peaq mainnet state and block data; the verification method for each is given at the bottom.

Account under examination

EVM address0x076727fD87bf5f02E5262314C5fbcCA53545AFC1
Substrate account5DrLJKz6PUAjzK4Cwev7CA3Ut8yU41NDvTu2YfaasG2d5UuT
relationshipdefault Frontier derivation blake2_256("evm:" ++ h160) - unclaimed, no Substrate private key exists
chainpeaq mainnet (peaq-network), specVersion 110, SS58 prefix 42, EVM chain id 3338

1. The unstake that was cancelled

Transaction 0x996a6bacc2c0ffd2d48e36a0f1062dd919fa527dd2b5e0a0c2dc27bbaab923b3

block10,641,119 (0xa25edf)
from → to0x076727fD87bf5f02E5262314C5fbcCA53545AFC10x0000000000000000000000000000000000000807 (parachain-staking precompile)
calldelegatorStakeLess(bytes32,uint256), selector 0xb7e8947f, nonce 749
amount632,912.89 PEAQ (0x860646c9cacac9590000)
resulting chunkunlock at block 10,842,719 = 10,641,119 + 201,600 (StakeDuration)

2. The cancellation

Block 10,839,084 - 2026-07-12T16:41:36Z - 3,635 blocks (~8.1 hours) before the chunk would have unlocked.

multisig.asMulti                    signed by 5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW
└─ sudo.sudoUncheckedWeight
   └─ sudo.sudoAs(5DrLJKz6PUAjzK4Cwev7CA3Ut8yU41NDvTu2YfaasG2d5UuT)                   ← dispatched AS the account under examination
      └─ parachainStaking.delegatorStakeMore(collator, 632,912.89 PEAQ)

Events emitted in that block:

  • parachainStaking.DelegatorStakedMore [5DrLJKz6PUAjzK4Cwev7CA3Ut8yU41NDvTu2YfaasG2d5UuT, 5CAWdUMni9HUmCaxJ8fP37EMaVe9apCmW3tCMp4R9m3vFXEP, 19,543,840.249191565229000000 → 20,176,753.139191565229] - delta exactly 632,912.89 PEAQ, matching the pending chunk to the token
  • sudo.SudoAsDone { Ok }
  • sudo.Sudid { Ok }
  • multisig.MultisigExecuted { approving: 5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW, timepoint: { height: 10,837,080, index: 2 }, multisig: 5GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic, callHash: 0xfc0fe9bb6eb322664e85270d3fab42c87f7b54773505ed14c79580f6095bb5f9 }
  • fee 0.002152101934920413 PEAQ, paid by 5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW

Signatories - multisig 5GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic, threshold 2 of 4:

roleaccount
initiated (timepoint 10,837,080, ~4.5 h earlier; its 0.26 PEAQ deposit is refunded in the same block via balances.Unreserved)5HMB2tcnaoGJfrxk5x53HAuRx5HRqdKTuTSmchRdgojLS5xR
executed, paid the fee5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW
other co-signers5GQbNeMzL5eywZi7DPKrrASUQYNU39aCksm5jYcsGp2ekyYy, 5GcDEue4J86Msu83SacFvf2tvCJ1cF9HMmjwsyymqg6GM5DN

3. That multisig is peaq's chain root key

  • sudo.key() == 5GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic, verified both at block 10,839,084 and at present head.

  • The signatory set is cryptographically confirmed, not assumed. A Substrate multisig address is blake2_256("modlpy/utilisuba" ++ sorted(signatories) ++ threshold). Deriving it from the four accounts listed in §2 with threshold 2 reproduces 5GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic exactly. Those four accounts, and no others, control root; two of them suffice to act.

  • Custody chain, each link signed by its predecessor (the only way sudo.setKey can be called):

    whenblocksudo key
    2024-01-03 (genesis era)15Cfmbo2WGEnhLctZa7Jt6BWrZci1RwPfdzqf8jBTghpiXxJx
    by 2024-03-29~500,0005GLWXiETENCdieTVpFYfsSAqZzUseMoAEPMEofnTaoVuymtS
    2024-11-09T13:31:36Z2,594,9055GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic

    The final rotation is extrinsic #2 of block 2,594,905: sudo.setKey { new: 5GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic } signed by the previous sudo key 5GLWXiETENCdieTVpFYfsSAqZzUseMoAEPMEofnTaoVuymtS, emitting sudo.KeyChanged { old: 5GLWXiETENCdieTVpFYfsSAqZzUseMoAEPMEofnTaoVuymtS, new: 5GeZPhuVtn6Q9h3rQcZPEuEsczKE5EaghpGdFoamE4bp7Bic }.

  • It authorizes peaq's runtime upgrades - confirmed by decoding raw chain data, independently of any indexer. Three upgrade authorizations were fetched from the node and decoded locally:

    blockextrinsicsigned byoutcome
    6,331,626multisig.asMulti containing parachainSystem.authorizeUpgrade5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW (signatory)success
    6,149,603multisig.asMulti containing parachainSystem.authorizeUpgrade5GQbNeMzL5eywZi7DPKrrASUQYNU39aCksm5jYcsGp2ekyYy (signatory)success
    5,452,470multisig.asMulti containing parachainSystem.authorizeUpgrade5GQbNeMzL5eywZi7DPKrrASUQYNU39aCksm5jYcsGp2ekyYy (signatory)success

    In each, the other_signatories list is exactly the remaining three accounts of the same 2-of-4 set. Indexed history shows 17 authorize_upgrade and 9 enact_authorized_upgrade calls in total through this key. specVersion during its tenure: 103 → 104 → 105 → 106 → 109 → 110. The only other root path, the council, has 6 members and 1 proposal in the chain's entire history.

    This is the key that upgrades peaq's runtime. It is not a lookalike, a stale key, or a misread.

  • The rotation was a hardening step: a single key (5GLWXiETENCdieTVpFYfsSAqZzUseMoAEPMEofnTaoVuymtS) handed authority to a 2-of-4 multisig, adding three required co-signers.

  • peaq runs the stock pallet-sudo, not a modified fork: runtime/peaq/Cargo.toml declares the upstream pallet-sudo workspace dependency, and the repo's own pallets/ directory contains only address-unification, block-reward, inflation-manager, parachain-staking, xc-asset-config. Every call in upstream pallet-sudo (sudo, sudoAs, sudoUncheckedWeight, setKey) begins by requiring sender == sudo.key(). So the actor is, by construction, whoever controls that multisig - and a multisig call additionally requires 2 of its 4 keys.

Therefore: the cancellation was performed by peaq's legitimate, long-standing chain root authority. There is no mechanism in the runtime by which compromising a user wallet key confers sudo - sudo can only be handed over by the current sudo holder.

4. Nothing was taken - this was not a liquidity grab

The sudoAs call re-staked the funds into this account's own delegation, with the collator it was already delegating to. No value moved to peaq or anywhere else. Free balance across the cancel block, unchanged to the last digit:

blockfree balancereserved
10,839,0832,533,283.441872764086297866 PEAQ0
10,839,084 (the cancel)2,533,283.441872764086297866 PEAQ0
10,839,0852,533,283.441872764086297866 PEAQ0

The only effect was to convert 632,912.89 PEAQ from about to be withdrawable back into staked and locked. The sole beneficiary of the action is whoever wants these funds to stay put.

5. The 2026-07-12 action in isolation

  • Block 10,839,084 contains exactly one DelegatorStakedMore event, for this account and no other.
  • It is the only sudo activity in the 401-block window 10,838,884 - 10,839,284 (~54 minutes).
  • The multisig was initiated ~4.5 hours before execution - a deliberate, planned, multi-party action.
  • These are rarely-used keys. Lifetime extrinsic counts (account nonce) of the four signatories: 5HMB2tcnaoGJfrxk5x53HAuRx5HRqdKTuTSmchRdgojLS5xR 53, 5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW 34, 5GQbNeMzL5eywZi7DPKrrASUQYNU39aCksm5jYcsGp2ekyYy 23, 5GcDEue4J86Msu83SacFvf2tvCJ1cF9HMmjwsyymqg6GM5DN 5. peaq's root authority has been exercised a small number of times in total, so this was a hand-made intervention, not automation.

5a. Full-history audit: every sudoAs ever made on peaq targets this one account

Indexed audit of every extrinsic ever signed by all six accounts that have held or exercised sudo (the four current multisig signatories, plus both earlier sudo keys) - 121 sudo/multisig extrinsics in total, each decoded.

Result: 15 sudo.sudo_as calls exist in peaq's entire history. All 15 name 5DrLJKz6PUAjzK4Cwev7CA3Ut8yU41NDvTu2YfaasG2d5UuT. None names any other account.

They correspond to ~8 distinct interventions (each needs 2 multisig approvals):

dateblock(s)call dispatched as this accountamount
2025-11-207,842,458join_delegators2,533,682.1 PEAQ
2026-01-038,459,892 · 8,460,031join_delegators2,533,682.1 PEAQ
2026-01-168,641,809 · 8,641,828join_delegators2,533,682.1 PEAQ
2026-05-0610,064,460 · 10,065,747delegator_stake_more2,531,751.57 PEAQ
2026-05-06/0710,066,088 · 10,072,495join_delegators2,531,751.57 PEAQ
2026-05-22/2310,254,121 · 10,266,514delegator_stake_more1,300,000 PEAQ
2026-06-1210,497,076 · 10,499,398delegator_stake_more59,000 PEAQ
2026-07-1210,837,080 · 10,839,084delegator_stake_more632,912.89 PEAQ

The 2026-07-12 entry is the cancellation documented above. It is the eighth such intervention, not an isolated event: each time this account's funds were unstaked, root re-staked them. The pattern runs continuously from 2025-11-20 to 2026-07-12.

For completeness, root has also used force_transfer (20×), force_remove_vesting_schedule (10×) and force_set_balance (1×) elsewhere on the chain - so root does act on other accounts, but never once via sudoAs, and never to reverse another account's unstaking.

Method: Subscan indexed extrinsic history for 5HMB2tcnaoGJfrxk5x53HAuRx5HRqdKTuTSmchRdgojLS5xR (53 extrinsics), 5DuKzHP6BiCdMZtCuHq1Bio5FvpqtUEhwuUTwev34UJoiVfW (34), 5GQbNeMzL5eywZi7DPKrrASUQYNU39aCksm5jYcsGp2ekyYy (23), 5GcDEue4J86Msu83SacFvf2tvCJ1cF9HMmjwsyymqg6GM5DN (5), 5GLWXiETENCdieTVpFYfsSAqZzUseMoAEPMEofnTaoVuymtS (39, previous sudo key), 5Cfmbo2WGEnhLctZa7Jt6BWrZci1RwPfdzqf8jBTghpiXxJx (7, first sudo key). Every as_multi and sudo.* payload was decoded and its account arguments extracted. approve_as_multi / cancel_as_multi carry only a call hash and add no targets.

5b. Was the root key itself acting as a thief? The evidence says no

The obvious suspicion, given that this account is the only sudoAs target in the chain's history, is that the root holders are themselves the attackers. Three findings weigh against it:

  1. They can move funds arbitrarily, and never moved these. Root has used balances.force_transfer 20 times on other accounts (e.g. block 10,577,019: 5EYCAe5cKPAoFioiNofJ5BLTBbhsYn7anzfPTNUi1mvrMFdv5Dkn5fEkWshwmxunwgM8Z5FzN7upMChjG58vrdfNi2Md4Mf6, a sweep of block-reward pot accounts) and force_set_balance once. Taking this account's 2.53M PEAQ would have been a single call, available at any moment for nine months. It was never made.
  2. Nothing has ever left this account by root's hand. Every one of the 15 sudoAs calls is a staking call - join_delegators or delegator_stake_more - with the funds remaining on the account throughout. Balances across the 2026-07-12 cancellation are identical to the last digit (§4).
  3. None of root's force_transfer / force_remove_vesting_schedule actions touch this account. Decoded from chain data at blocks 10,642,172, 10,642,742, 10,577,019 and 10,566,254 - the targets are other accounts (0x74cc13dc7f50d645a07ffc9e398507b57ede27d7, 5EYCAe5cKPAoFioiNofJ5BLTBbhsYn7anzfPTNUi1mvrMFdv reward pots), not 5DrLJKz6PUAjzK4Cwev7CA3Ut8yU41NDvTu2YfaasG2d5UuT.

A root holder intent on stealing would transfer, not repeatedly re-lock. The observed behaviour immobilizes the funds while leaving ownership untouched.

The counter-argument, stated fairly: if root's aim were to protect a compromised account, it could have force-transferred the balance to a safe address - as it demonstrably knows how to do. It did not. One explanation is that moving funds requires choosing a beneficiary, which is impossible to do safely while ownership is contested or unverified; re-staking is the minimal intervention that blocks extraction without root taking custody or adjudicating ownership. That is consistent with the evidence but is not established by it.

6. Why re-staking destroys a pending unstake

pallets/parachain-staking/src/lib.rs, increase_lock():

// update Unstaking by consuming up to {amount | more}
<Unstaking<T>>::try_mutate(who, |unstaking| -> DispatchResult {
    // reduce {amount | more} by unstaking until either {amount | more} is zero or
    // no unstaking is left
    // if more is set, we only want to reduce by more to achieve 100 - 40 + 30 = 90
    // locked
    let mut amt_consuming_unstaking = if more.is_zero() { amount } else { more };
    unstaking_len = unstaking.len().saturated_into();
    for (block_number, locked_balance) in unstaking.clone() {
        if amt_consuming_unstaking.is_zero() {
            break;
        } else if locked_balance > amt_consuming_unstaking {
            // amount is only reducible by locked_balance - amt_consuming_unstaking
            let delta = locked_balance.saturating_sub(amt_consuming_unstaking);
            // replace old entry with delta
            unstaking
                .try_insert(block_number, delta)
                .map_err(|_| Error::<T>::NoMoreUnstaking)?;
            amt_consuming_unstaking = Zero::zero();
        } else {
            // amount is either still reducible or reached
            amt_consuming_unstaking =
                amt_consuming_unstaking.saturating_sub(locked_balance);
            unstaking.remove(&block_number);
        }
    }
    Ok(())
})?;

// Either set a new lock or potentially extend the existing one if amount
// exceeds the currently locked amount
T::Currency::extend_lock(STAKING_ID, who, amount, WithdrawReasons::all());

Any stake-increase consumes pending unstaking chunks to fund the new stake. The chunk is destroyed, not shortened or paused - the full 201,600-block (~18-19 day) wait restarts from zero on the next unstake. increase_lock is reached from join_delegators, delegator_stake_more, delegate_another_candidate, join_candidates and candidate_stake_more.

7. State as of 2026-07-28 (block ~11,013,900)

free2,532,440.54589810641383412 PEAQ
frozen (largest lock)2,531,751.57 PEAQ
transferable688.97589810641383412 PEAQ
active delegation100 PEAQ (= MinDelegatorStake) to 5CAWdUMni9HUmCaxJ8fP37EMaVe9apCmW3tCMp4R9m3vFXEP
unstaking chunk 11,500,000 PEAQ - submitted 2026-07-26 (block 10,992,058), unlocks block 11,193,658 (~Aug 14)
unstaking chunk 21,031,651.57 PEAQ - submitted 2026-07-27 (block 11,004,505), unlocks block 11,206,105 (~Aug 15)
vesting3,021,514.55 PEAQ original, ~817,455 still locked, fully vests ~2027-02-12

Both current chunks are exposed to the same cancellation, and the July precedent came ~8 hours before maturity - so speed on unlock day is no defence against a repeat.

8. Proven vs. inferred

Proven by chain data: that the actor was the account holding sudo.key(); how (sudoAs -> delegatorStakeMore); when; that no value left the account; that this account is the only account ever named in a sudoAs call on peaq, across ~8 interventions since 2025-11-20; and that a compromised user wallet cannot yield sudo.

Inference, not proof - identity. Chain data never proves who holds a key. That this multisig is "the peaq team" follows from it holding root since 2024-11-09 and authorizing the chain's runtime upgrades (observed directly, §3) on a chain running peaq's official node builds: whoever controls it controls peaq. The residual alternative - that peaq's own 2-of-4 root multisig is itself compromised - cannot be excluded from chain data, though anyone holding it could mint or drain the entire chain rather than re-stake one account. The identities behind the four signatory addresses are not verifiable on-chain.

Not determinable from chain data: why, and whether root acted on its own initiative or was induced to act by a third party. Two readings fit the facts - (a) peaq believes the account is compromised and is keeping funds away from whoever holds the key, noting they cannot distinguish the owner's withdrawal from a thief's since both use the same key; or (b) peaq treats this allocation as contractually locked and is enforcing that. Only peaq can say which.

9. How to verify independently

  1. The cancel - peaq.subscan.io, block 10,839,084: extrinsic multisig.asMulti and the DelegatorStakedMore / SudoAsDone / Sudid events.
  2. The root key - chain state query sudo.key(), at present head and at block 10,839,084.
  3. The rotation - block 2,594,905, extrinsic sudo.setKey and event sudo.KeyChanged.
  4. The chunk's disappearance - historical storage query parachainStaking.unstaking(5DrLJKz6PUAjzK4Cwev7CA3Ut8yU41NDvTu2YfaasG2d5UuT): the entry keyed 10,842,719 is present at block 10,839,083 and absent at 10,839,084. (Located by binary search over the range 10,641,120 → head.)
  5. The original unstake - eth_getTransactionByHash("0x996a6bacc2c0ffd2d48e36a0f1062dd919fa527dd2b5e0a0c2dc27bbaab923b3") on any peaq EVM RPC.

Block hashes, so the referenced blocks can be pinned exactly:

blockhash
10,839,084 (the cancellation)0x19cf553ae08d474aa42540b0cc6c295a25291f1f8e6c5817cf34b1f754136707
10,641,119 (the unstake)0xab283a2a71fb1cc56d065f641da6603f2f78997c674f118871faed38d3a3976d
2,594,905 (the sudo rotation)0x09bd2bbf640b6e0b104631d16d4c79c20b478276c99effa3357407b949e9e43b

Public RPC endpoints used (no key required): wss://peaq.api.onfinality.io/public, wss://mpfn1.peaq.network. EVM JSON-RPC: https://evm.peaq.network.

Built with LogoFlowershow