Security

The WTD Token Protocol employs multiple security patterns across all contracts.

Access Control

All contracts use OpenZeppelin's AccessControl for role-based permissions. Each function that modifies state is restricted to specific roles.

Contract
Roles

WTDToken

DEFAULT_ADMIN_ROLE, GOVERNANCE_ROLE

WTDSale

DEFAULT_ADMIN_ROLE, MULTI_SIG_ROLE

WTDVesting

DEFAULT_ADMIN_ROLE, VESTING_ROLE

WTDLiquidityManager

DEFAULT_ADMIN_ROLE

See Roles & Permissions for a full breakdown.

Reentrancy Protection

All contracts that handle token transfers inherit ReentrancyGuard from OpenZeppelin. The nonReentrant modifier is applied to:

  • All purchase functions in WTDSale

  • All claim functions in WTDVesting

  • All withdrawal functions in WTDVesting

  • Lock, unlock, and fee collection in WTDLiquidityManager

Safe Token Transfers

All ERC20 token transfers use OpenZeppelin's SafeERC20 library, which:

  • Checks return values from transfer and transferFrom

  • Handles tokens that don't return a boolean (like some USDT implementations)

  • Reverts on failed transfers

The WTDSale contract validates the Chainlink ETH/USD price feed with:

  • Price check: Reverts if the oracle returns a non-positive price (InvalidOraclePrice)

  • Staleness check: Reverts if the price data is older than 1 hour (StaleOraclePrice)

Pausable Token

The WTDToken can be paused by the admin, which halts all token transfers including:

  • Regular transfers

  • Minting (allocation claims)

  • Burning

This provides an emergency brake if a vulnerability is discovered.

VESTING_ROLE Lock

The WTDVesting contract allows permanently locking the VESTING_ROLE. Once locked:

  • No new addresses can be granted VESTING_ROLE

  • Existing VESTING_ROLE cannot be revoked

  • This ensures only the originally authorized sale contract can create vesting schedules

  • The lock is achieved by setting the role's admin to a role that nobody holds

One-Time Configuration

Several operations are intentionally limited to a single execution:

  • Round configuration (WTDSale) — each round can only be configured once

  • TGE timestamp (WTDVesting) — can only be set once

  • VESTING_ROLE lock (WTDVesting) — can only be locked once

  • Allocation claims (WTDToken) — each category is claimed in full once

Immutable Contract References

WTDSale stores references to WTDToken, WTDVesting, USDC, USDT, and the Chainlink oracle as immutable variables. These cannot be changed after deployment, preventing address substitution attacks.

UUPS Upgrade Safety

The WTDToken implementation constructor calls _disableInitializers() to prevent the implementation contract from being initialized directly (only the proxy can be initialized).

Allocation Invariants

1

Total supply cap

Total supply never exceeds MAX_SUPPLY (100 billion).

2

Allocation sum invariant

Sum of all claimed allocations never exceeds MAX_SUPPLY.