Quantstamp reviewed TokenOps on 20 Sep 2023: 5 findings, 0 critical; 3 marked fixed, 2 acknowledged.
Report hosted on certificate.quantstamp.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 1 |
| Medium | 0 | 1 | 0 |
| Low | 0 | 1 | 2 |
An admin can revoke a grant through function `revokeGrant()`, resulting in the vesting being stopped and all yet unvested tokens being freed to be used for other grants. Importantly, the unvested, yet unwithdrawn tokens by end-users should still be able to be withdrawn by them, as the user has rightfully vested all tokens until then. However, this becomes impossible, as the user becomes unable to call the `withdraw()` function, as the modifier in the `hasActiveGrant()` function requires the `isActive` field to be `true` for a given user. This is however set to false during the revocation process. These vested, but unwithdrawn funds, therefore, become stuck in the contract, as these funds are contained in the sum of reserved tokens `numTokensReservedForVesting` for granted users, but are non-withdrawable by the user with the revoked grant, as they are not able to perform any withdrawals anymore. Notice that the `isActive` flag can also never be toggled again to true, making the vested, unwithdrawn funds permanently stuck.
An implementation of `AccessProtected` contract is used in `TokenVesting`, which essentially maintains the set of admins. However, while admins can add other admins, they can also remove every other admin, including themselves. If that would ever happen to be the case, no additional grants could ever be granted nor revoked. Furthermore, all unallocated tokens (i.e. tokens not contract balance - `numTokensReservedForVesting`) would be frozen.
Smart contracts will often have operations that can only be executed by a limited amount of addresses with special privileges. The access control mechanism of the current contract is mainly enforced based on allowing specific actions to addresses stored as state variables of the associated contracts. The contract `AccessProtected.sol` gives the following privileges: an address with the role `admin` can grant that role to or revoke that role from any address via the function `setAdmin()`. The contract `TokenVesting.sol` gives the following privileges: 1. an address with the role `admin` can allocate tokens owned by the contract to a given recipient through a vesting agreement via the functions `createGrant()` (one by one) and `createGrantBatch()` (batch). 2. an address with the role `admin` can withdraw unallocated tokens owned by the contract via the function `withdrawAdmin()`. 3. an address with the role `admin` can revoke an active grant for a given address via the function `revokeGrant()`. 4. an address with the role `admin` can withdraw any ERC20 token owner by the contract and different than the vested token via the function `withdrawOtherToken()`.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (1)
236 projects reviewed · 332 reports · latest Oct 2026
See Quantstamp’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us