Quantstamp reviewed Subscription Token Protocol V2 on 30 May 2024: 16 findings, 0 critical; 12 marked fixed, 4 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 | 0 | 1 |
| Low | 0 | 4 | 10 |
The identifier of a reward curve is stored in an `uint8`. As a result, the function `RewardPoolLib.createCurve()` will revert if there are already `256` created reward curves. This limitation should be documented to creators.
The addresses receiving the fees for the client and the protocol can be updated with the functions `updateClientFeeRecipient()` and `updateProtocolFeeRecipient()`. However, only the current recipient can execute this function. As a result, if an incorrect address owned by no one or unable to receive fees is set, the amount transferred to this address can be considered lost. The likelihood is assessed as Low.
We include the observed privileged roles and their capabilities below: `STPV2Factory` - `owner` as in the owner of the Subscription Factory contract; the Subscription Token Protocol team. - `setProtocolFeeRecipient()` - `setDeployFee()` - Client fee recipient - `updateClientFeeRecipient()` - Protocol fee recipient - `updateProtocolFeeRecipient()` `STPV2` - `owner`, as in, the deployer of the Subscription Token contract; the entity to which people are subscribing - `refund()` an account and clear their subscription - `grantTime()` or `revokeTime()` to an address subscribing - `issueRewardShares()` to grant rewards to a user, independent of any reward curves defined - `transferFunds()` to an address different from the `_transferRecipient` stored in the contracts; although, anyone can invoke this function to transfer to the defined `_transferRecipient` address - `updateMetadata()` to redefine the URI used for the NFTs - `setTransferRecipient()` defining a new address to receive the owner's portion of the subscription revenue - `setGlobalSupplyCap()` defining the amount of subscriptions that can exist for this given Subscription - `createTier()` defining a new subscription tier available for subscribers, or `updateTier()` redefining the parameters for an existing tier - `setReferralCode()` assigning a basis points reward for a specified referrer address - `issueRewardShares()` to give reward shares to a specified account - `createRewardCurve()` for a subscription - `recoverCurrency()` to withdraw any funds that are not the currency defined for the subscription to any specified address - `ROLE_MANAGER` - `grantTime()` or `revokeTime()`to an address subscribing - `updateMetadata()` to redefine the URI used for the NFTs - `createTier()` defining a new subscription tier available for subscribers, or `updateTier()` redefining the parameters for an existing tier - `createRewardCurve()` for a subscription - `ROLE_AGENT` - `grantTime()` or `revokeTime()` to an address subscribing
While there are some mitigation strategies to prevent users from withdrawing the contract-denominated currency in the contract, as shown in `recoverCurrency()`, it does not actually prevent the owner from stealing all the funds in the contract. Note that users deposit currency into the contract through `purchase()`, which allocates the deposited amount as a reward. So, to drain the contract's currency, it suffices to claim all the rewards available allocated in the contract. To this end, the owner can call `issueRewardShares()` to issue a large number of shares to an account he controls, diluting the shares of other users and effectively stealing the rewards from other users.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (52)
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