
Loading...
Loading
Loading...
LoadingLoading audit report...

WalletGuard.ai, powered by Gestalt Labs
Forge fork-validation ran but no findings met the threshold for PoC inclusion. See the per-finding "Forge validated" badges in the report below for individual results.
The analyzed contract is an identity staking protocol (IdentityStaking) implementing a UUPS upgradeable pattern, allowing users to self-stake and community-stake GTC tokens that can be slashed, released, or burned by privileged roles. The analysis identified 0 critical (after scope gating), 1 high, 4 medium, 4 low, and 4 informational findings of substance, with 3 findings dropped or consolidated. The single most dangerous pattern is the missing disableInitializers() call in the UUPS implementation constructor, which allows any actor to initialize the bare implementation contract, seize DEFAULT_ADMIN_ROLE, and subsequently execute a malicious upgrade. The contract carries meaningful risk in its current state and should not be considered production-ready without addressing the initialization vulnerability and the release() accounting bug that permanently undercounts user stake after an appeal.
Any person on the internet can call the initialize function directly on the underlying contract (not the proxy users interact with) and claim full administrative control. Once they are admin, they can swap out the contract logic for a malicious version. This is a well-documented attack pattern that has led to protocol takeovers and fund losses in multiple real-world incidents.
When a user is wrongly slashed and successfully appeals, the contract restores their staked token balance internally but forgets to update the counter that tracks their total staked amount. Any system or reputation score that reads this counter will permanently show the user as having less stake than they actually do, even after a successful appeal. This permanently harms innocent users who win their appeal.
When the contract tries to calculate how much to slash from a large stake, it does the math in a storage type that is too small to hold the intermediate result. For stakes above roughly 3 million GTC, the calculation overflows and the transaction reverts, meaning large stakers cannot be slashed at all. This gives wealthy stakers an unintended immunity from the protocol's enforcement mechanism.
1 centralization point identified
The open access is acknowledged in the contract comments as intentional. The 90-day minimum duration is the only gate. This is a design property the buyer should know about regarding governance discretion over burns.
lockAndBurn()An attacker calls initialize() directly on the deployed implementation contract (not the proxy) because no constructor calls _disableInitializers(). The attacker passes their own address as initialAdmin, gaining DEFAULT_ADMIN_ROLE on the implementation. They then call _authorizeUpgrade() (which checks onlyRole(DEFAULT_ADMIN_ROLE)) and upgrade the implementation to a malicious contract. Any future proxy deployments pointed at this implementation, or the implementation itself if used directly, fall under the attacker's control. This chain is enabled solely by the missing disableInitializers() pattern.
A staker accumulates a position exceeding approximately 3.09 million GTC (achievable given GTC's 100M total supply). When a SLASHER_ROLE attempts to slash this user at any non-trivial percent, the uint88 multiplication in the slash calculation overflows and reverts in Solidity 0.8+. Because the slash function iterates over arrays, even one overflowing entry in a batch causes the entire batch to revert, meaning other valid slashings in the same call also fail. The attacker retains their stake and their identity score is unaffected, while the slasher is forced to batch differently. This is confirmed across two independent agent findings describing the same root cause.
| Agent | Status | Findings | Severity | Confidence | Duration | Coverage |
|---|---|---|---|---|---|---|
| reentrancy | success | 5 | 2M | 52% | 60.0s | Cross-function reentrancy in selfStake, communityStake, withdrawSelfStake, withdrawCommunityStake, CEI (Checks-Effects-Interactions) pattern compliance in all state-mutating functions, ERC-777 / token hook reentrancy via transferFrom and transfer calls, lockAndBurn accounting and round management logic, slash() function duplicate address handling and over-slashing, release() function boundary conditions and accounting correctness, UUPS upgrade authorization (onlyRole(DEFAULT_ADMIN_ROLE) correctly applied), Access control role assignments in initialize(), Integer overflow/underflow in uint88 and uint16 arithmetic, Read-only reentrancy via IIdentityStaking view functions, Flash loan attack surface (none present - no flash loan callback), GTC mock token - test-only code, not production |
| access control | success | 4 | 1H1L | 78% | 59.7s | Access control on all admin, staking, slash, and burn functions, UUPS upgradeability pattern and initializer protection, Slash/release/burn accounting consistency including userTotalStaked, Reentrancy in staking and withdrawal functions (CEI pattern adherence), Signature-based authentication (not present in main contract), Role management and DEFAULT_ADMIN_ROLE protection, Integer overflow/underflow in uint88/uint64/uint16 arithmetic, Lock time validation logic, Cross-round slash migration logic in slash(), release() function correctness including userTotalStaked restoration, lockAndBurn() access restrictions, GTC test mock contract (test-only, not production) |
| economic | success | 4 | 1M | 76% | 1.0m | Flash loan attack vectors - staking/withdrawal functions with balance dependencies, Oracle manipulation - no price feeds present, not applicable, Governance attacks - RBAC role management, no on-chain governance voting, Reentrancy - CEI pattern in all transfer-containing functions, Slash accounting logic - round transitions, totalSlashed, userTotalStaked consistency, Release (appeal) function accounting - restoration of slashedAmount and userTotalStaked, lockAndBurn appeal window enforcement and timing, Integer overflow/underflow in uint88/uint64 arithmetic, Access control on privileged functions (slash, release, burn), MEV exposure - no swaps or liquidations present, UUPS upgrade authorization, Pause mechanism correctness, Fee-on-transfer token compatibility (GTC does not appear to have transfer fees), GTC mock token allowance bypass in transferFrom (test-only, not production) |
| logic validation | success | 6 | 1M2L | 61% | 1.5m | Input validation on all public/external functions (zero-address, bounds, amounts), Arithmetic safety: uint88 multiplication overflow in slash calculations, Slash accounting logic: totalSlashed tracking across rounds, Release function: race condition with lockAndBurn, State machine integrity: slash round transitions, burn round enforcement, Reentrancy: CEI pattern analysis in stake/withdraw/slash/release functions, Access control: role-based permissions on admin functions, Timestamp dependence: burnRoundMinimumDuration check, DoS vectors: unbounded loops in slash function, UUPS upgrade safety: _authorizeUpgrade access control, ERC-20 transfer return value checking, Precision loss in slash percentage calculation, Integer type truncation (uint88, uint64, uint16) |
| code quality | success | 6 | 74% | 1.2m | Reentrancy patterns in staking and withdrawal functions, Access control on admin, slash, release, and burn functions, Integer arithmetic and potential overflows in slash calculations, Storage accounting consistency across slash, release, and burn operations, UUPS upgrade safety and _authorizeUpgrade protection, Lock time validation in selfStake, communityStake, extendSelfStake, extendCommunityStake, Slash round state machine transitions, Token transfer return value checks, ERC-20 compliance of the GTC test mock, Cross-round slash migration logic in slash(), Release function bounds and round validation, userTotalStaked accounting in stake, withdraw, and slash paths | |
| compiler bugs | success | 3 | 82% | 45.8s | Reentrancy in staking/withdrawal functions (CEI pattern check), Access control on admin, slasher, releaser, and pauser functions, Integer overflow/underflow in stake amount calculations (uint88/uint64/uint16), Slash accounting consistency: totalSlashed vs individual slashedAmount fields, Release function accounting: userTotalStaked not restored on release, lockAndBurn timing and round progression logic, Duplicate entries in slash arrays, Lock time validation logic, UUPS upgrade authorization, ERC20 transfer return value checks, Self-stake vs community-stake segregation, Compiler bug patterns for pragma ^0.8.23 (outside all affected ranges) | |
| assembly safety | success | 5 | 1M | 81% | 1.4m | Full codepoint-by-codepoint scan for non-ASCII characters in all identifiers, strings, and comments across all files, Assembly blocks: GTC.sol contains `assembly { chainId := chainid() }` — safe standard pattern, no issues, IdentityStaking.sol: no inline assembly blocks present, Integer arithmetic overflow in slash percent calculation (uint88 multiplication), Slash round accounting and migration logic (previous round move logic), totalSlashed accounting consistency across lockAndBurn and slash interactions, Access control patterns (SLASHER_ROLE, RELEASER_ROLE, PAUSER_ROLE, DEFAULT_ADMIN_ROLE), UUPS upgrade authorization (_authorizeUpgrade with onlyRole guard), Reentrancy: state changes occur before external token transfers in all staking/withdrawal functions, Lock time validation in selfStake, communityStake, extendSelfStake, extendCommunityStake, Release function round validation and amount checks, lockAndBurn minimum duration enforcement, Initializer pattern and storage layout for UUPS proxy, ERC20 transfer return value checking (FailedTransfer revert pattern), Homoglyph and keyword obfuscation scan, Yul shift instruction ordering (not present), delegatecall patterns (not present in IdentityStaking), GTC test mock: transferFrom allowance check removed (test-only contract, noted as non-production) |
| l2 specific | success | 6 | 1L | 80% | 1.3m | Reentrancy patterns in withdraw functions (state updated before transfer - CEI followed), Access control on admin, slash, release, and burn functions, Integer overflow/underflow in stake amounts (uint88 bounds), Slash calculation precision loss for small amounts, totalSlashed accounting consistency across slash, release, and lockAndBurn, userTotalStaked accounting across all stake/withdraw/slash/release operations, Lock time validation logic in selfStake, extendSelfStake, communityStake, extendCommunityStake, UUPS upgrade authorization and storage layout, Round transition logic in lockAndBurn and its interaction with release, ERC20 transfer return value handling (FailedTransfer checks), L2-specific patterns: no L2 imports, predeploy addresses, or cross-chain calls found - contract is chain-agnostic, Chain ID: 1 (mainnet) - no L2 sequencer uptime feed concerns for this contract, Pause mechanism coverage across all user-facing functions, GTC test mock contract (marked as test-only, not production code) |
| upgrade | success | 4 | 1C | 71% | 52.2s | UUPS proxy pattern - _authorizeUpgrade access control, Missing disableInitializers() in implementation constructor, Initialize function - reentrancy and replay protection via initializer modifier, Storage layout - slot collision between inherited upgradeable contracts, Slash logic - accounting correctness across rounds, release() function - userTotalStaked synchronization, lockAndBurn() - race conditions and minimum duration enforcement, selfStake/communityStake - lock time validation, withdrawSelfStake/withdrawCommunityStake - locked stake enforcement, Access control roles - SLASHER_ROLE, RELEASER_ROLE, PAUSER_ROLE, DEFAULT_ADMIN_ROLE, ERC20 token interaction - transferFrom/transfer return value checks, Integer overflow/underflow on uint88 and uint16 operations, GTC test mock - allowance bypass in transferFrom (test only, not production) |
This automated audit has inherent limitations. The following areas are not covered.
This report is an automated point-in-time assessment and does not guarantee protection against all possible attacks. It does not cover off-chain components, economic modeling, or business logic correctness unless explicitly noted. Changes to the contract after the audit commit are not reviewed. This is not financial or legal advice. WalletGuard, powered by Gestalt Labs, provides this analysis as-is with no warranty of completeness.
[](https://walletguard.ai/audit/8ee20a60-f296-420f-96be-b06110d8c822)
<a href="https://walletguard.ai/audit/8ee20a60-f296-420f-96be-b06110d8c822"> <img src="https://walletguard.ai/api/badge/8ee20a60-f296-420f-96be-b06110d8c822" alt="WalletGuard Audit Badge" /> </a>