Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · September 2026

WHUF Transfer Lock

for Ethos Network

Guardian's review of WHUF Transfer Lock for Ethos Network, published September 2026. The report records 5 findings, including 5 informational.

Published
Language
Solidity
Chains
Base
Sector
Infrastructure
  • 0 Critical
  • 0 High
  • 0 Medium
  • 0 Low
  • 5 Informational

5 acknowledged

Scope

4 files in scope · 35 nSLOC
FilenSLOCLines
src/errors/WhuffieErrors.sol019
src/EthosWhuffie.sol18174
src/interfaces/IWhuffieLockList.sol310
src/WhuffieLockList.sol1444

Findings 5

  1. I-01 Informational Deployment tooling omits the new lock-list constructor argument Configuration Acknowledged
    Location
    https://github.com/GuardianOrg/mirror-trust-ethos-ethos-protocol-5ccc445c0c31d01

    Description

    The change makes every EthosWhuffie implementation deployment require an IWhuffieLockList constructor argument. The supplied deployUpgradeable() path still uses deployViaCreate2(signer, factory, [], salt) for deterministic deployment and factory.deploy() for the legacy path, so neither provides that argument. The ethosWhuffie configuration supplies only the three proxy initializer arguments, and the market-stack deployment sequence does not deploy a WhuffieLockList first. The compiled EthosWhuffie artifact confirms one mandatory constructor input. Fresh proxy deployments and implementation upgrades through the supplied flow cannot encode or deploy this implementation. Solidity fixtures pass the list directly and miss the mismatch. This audit mirror omits package.json, deploy.ts, and abi/index.ts, so the TypeScript path could not be executed end to end here; the code and compiled ABI establish the argument mismatch. Downstream code: scripts/deploy-contract.ts:944-951 and scripts/ops/deploy-market-stack.ts:22-46.

    Recommendation

    Be aware.

  2. I-02 Informational Scheduled unlock observability is lazy and its timestamp depends on the trigger Events Acknowledged
    Location
    https://github.com/GuardianOrg/mirror-trust-ethos-ethos-protocol-5ccc445c0c31d01

    Description

    At UNLOCK_AT, the launch lock no longer prevents a balance change, but transfersUnlocked remains false and no TransfersUnlocked event is emitted until a successful balance change lazily updates the flag. That automatic path emits UNLOCK_AT even if the triggering transaction occurs later. The owner may instead call unlockTransfers() after UNLOCK_AT before any balance change; that path emits the later block.timestamp. Thus the same scheduled release can produce either the deadline or a later transaction time depending on which post-deadline transaction arrives first. During the gap, the public flag is false even though a transfer would succeed. The event NatSpec calls its field the block timestamp when transfers were unlocked, leaving its meaning inconsistent for frontends and monitors. On-chain transfer enforcement remains correct. Prior I-30 concerned a missing manual-unlock event; that was fixed before this scheduled path was introduced.

    Recommendation

    Either acknowledge the finding or apply one of the proposed fixes:

    • emit block.timestamp at both places
    • emit min(block.timestamp, UNLOCK_AT) in unlockTransfers()
  3. I-03 Informational Market and Rewards documentation does not respond to actual behavior Documentation Acknowledged
    Location
    https://github.com/GuardianOrg/mirror-trust-ethos-ethos-protocol-5ccc445c0c31d01

    Description

    The documentation states that Market trading and Rewards claims are not expected to work for locked accounts because EthosMarket and EthosRewards are included in WhuffieLockList . However, _update() applies the restriction based only on whether the WHUF sender is locked, making the actual behavior dependent on the direction of each transfer.

    ```solidity

    Which WHUF flows should work before transfers unlock?

    The lock is per account, not global. Accounts on WhuffieLockList (pre-launch mint recipients other than Treasury, and Ethos proxies other than EthosVouchV2 and EthosReview ) cannot send WHUF before UNLOCK_AT except into or out of EthosVouchV2 , or as an EthosReview fee pull. Accounts not on the list, including market makers funded by Treasury, transfer freely. Market trading and Rewards claims are not expected to work for locked accounts before UNLOCK_AT because EthosMarket and EthosRewards are themselves on the list. ```

    When buying from the Market, the buyer is the WHUF sender. Purchases therefore fail for locked buyers but remain available to buyers who are not included in WhuffieLockList , regardless of the Market’s locked status. When selling, EthosMarket is the WHUF sender, so the payout fails while the Market remains locked even if the seller is not locked. Similarly, EthosRewards is the WHUF sender during claim() . Consequently, Rewards claims fail while EthosRewards remains locked even when the claimant is not included in WhuffieLockList . I- Market and Rewards documentation does not respond to actual C O N T I N U E D 03 behavior

    Therefore, before the global transfer unlock, an unlocked user can buy a Market position but cannot sell it or claim accrued rewards.

    Recommendation

    Revisit whether this is the intended behavior and if yes, fix the documentation. Otherwise, apply the needed changes

  4. I-04 Informational TransfersUnlocked owner parameter documentation is ambiguous Documentation Acknowledged
    Location
    https://github.com/GuardianOrg/mirror-trust-ethos-ethos-protocol-5ccc445c0c31d01

    Description

    The owner parameter is described as “the token owner,” which could mean either a WHUF holder or the EthosWhuffie contract owner. The emitted value represents the contract owner.

    Recommendation

    Describe owner as “the EthosWhuffie contract owner.”

  5. I-05 Informational UNLOCK_AT documentation incorrectly requires a balance change Documentation Acknowledged
    Location
    https://github.com/GuardianOrg/mirror-trust-ethos-ethos-protocol-5ccc445c0c31d01

    Description

    The comment states that the first balance change after UNLOCK_AT triggers unlocking. However, zero-value transfers, mints, and burns also invoke _update() and unlock transfers without changing any balance.

    Recommendation

    Replace “balance change” with “transfer, mint, or burn operation.”

More from Ethos Network

  1. Vouching and Slashing

    56 findings 56 findings: 5 medium, 17 low, 34 informational

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote