STBU · static analysis, 18 September 2026
Every high and medium severity result sits in libraries we did not write.
This is the static analysis run of the three STBU contracts on Base, published in full with its caveats. The sources analysed were not taken from a working copy: they were pulled from the verified contracts on chain, so the code examined here is the code that is deployed. It is a static analysis report and not a security audit, and that difference is set out at the foot of this page rather than buried in it.
Scope
Three contracts, each verified in two places.
A report that does not say exactly what it looked at is asking to be taken on trust. These are the addresses, the compilers that produced them, and the date each was independently verified in Sourcify.
| Contract | Address on Base | Compiler | Verified in Sourcify |
|---|---|---|---|
| STBUToken | 0xe0c0F44A84CC4a60206360006ebA237a5e8fC2dd | solc 0.8.28 | 18 September 2026 |
| MigrationClaim | 0xec5B3e512de13cb5DdFD84B2DF3167230F2e66a4 | solc 0.8.28 | 2 September 2026 |
| FeeHook | 0x0507140088aa5b266d6b44eef02ad55cf1fb40c0 | solc 0.8.26 | 16 September 2026 |
Method
The code analysed is the code that is deployed.
Analysing a working copy proves something about the working copy. These sources came off the chain.
For each address the verified standard JSON input was pulled from the explorer and its 52 source files written to disk with their paths intact. The compiler settings mirror the ones that produced the deployed bytecode: optimizer enabled at 10,000 runs, EVM version cancun, intermediate representation disabled, metadata hash set to none. Two profiles are needed because the deployed compilers differ, 0.8.28 for the token and the claim contract and 0.8.26 for the pool hook. Both profiles compile before anything is analysed, and Slither 0.11.6 then runs its full detector set against each.
Anyone can repeat this. The sources are public in two independent places, the compiler settings are published above, and the tool is open source.
Results
134 results, ten of them in our own code.
The split matters more than the total. A result inside an unmodified library is a property of that library, not of this token.
| Run | Contracts analysed | Results | In Stobox code | In dependencies |
|---|---|---|---|---|
| STBUToken and MigrationClaim | 31 | 46 | 3 | 43 |
| FeeHook | 33 | 88 | 7 | 81 |
| Severity, Stobox-authored code only | STBUToken and MigrationClaim | FeeHook |
|---|---|---|
| High | 0 | 0 |
| Medium | 0 | 0 |
| Low | 2 | 3 |
| Informational | 1 | 4 |
What was found in our code
Ten results, each one named and answered.
Three of the ten describe something a future version should change. None of them describes a way to lose money today, and the reasoning is given rather than asserted.
Low · timestamp
MigrationClaim.sol:211-255 · MigrationClaim.sol:341-347 · FeeHook.sol:181-194
The detector flags any comparison against block.timestamp. In all three places the value compared is a gate measured in days: the claim start, a signed voucher deadline and an external volume voucher deadline. The manipulation window this detector exists for is measured in seconds, and Base orders transactions through a single sequencer rather than competing block producers. The comparisons are deliberate, and the granularity mismatch makes the flagged risk inapplicable.
No change required.
Low · shadowing-local
FeeHook.sol:79
A constructor parameter named _owner shadows the state variable of the same name in OpenZeppelin Ownable. The parameter is passed straight through to the Ownable constructor, so there is no path on which the wrong variable is read. This is a naming choice, not a behaviour.
Cosmetic. Worth renaming in any future version; it does not justify redeploying an immutable contract.
Low · missing-zero-check
FeeHook.sol:79 · FeeHook.sol:84
The constructor assigns the trusted router without checking it against the zero address. This is a fair observation about the code. Its practical exposure is bounded by two facts: the value is set once at construction and cannot be changed afterwards, and a zero value would have made the pool non functional immediately and visibly rather than silently. The deployed value was read back from the chain and is not zero.
The theoretical failure mode is closed by the deployed state. A zero-address guard belongs in any future version.
Informational · assembly, missing-inheritance, unimplemented-functions, pragma
FeeHook.sol · IFeePolicy.sol · across files
Five informational results across the three contracts. The unimplemented-functions result is expected for a Uniswap v4 hook, which implements only the callbacks it declares permissions for. None of the five describes a defect.
No change required.
What was found in the libraries
The one high severity result is in stock OpenZeppelin.
This is the part most reports leave as a shrug. It is checkable, so we checked it.
Every high and medium severity result in both runs is located in third-party library code. The single high severity result, and most of the medium ones, sit in OpenZeppelin’s arithmetic library. The rest sit in Uniswap v4-core.
That claim is only worth something if the libraries are unmodified, so all 29 OpenZeppelin files present in the deployed sources were compared byte for byte against the official OpenZeppelin Contracts v5.2.0 release. 29 matched exactly, none differed, and none was absent from the release. The file carrying the high severity result is among the exact matches.
So the result is a property of a widely used, audited library compiled by a large part of the ecosystem, and the same output appears for anyone who compiles stock OpenZeppelin v5.2.0. It is not a property of these contracts, and it is not something an issuer fixes by editing someone else’s library.
What this report does not tell you
Read this before quoting the zeroes above.
A clean scan is routinely presented as a safety guarantee. It is not one, and we would rather say so ourselves.
Static analysis is not a security audit.
The tool reasons about code structure and patterns. It does not reason about economic design, incentive failures, governance assumptions, behaviour when integrated with other protocols, or whether the contract does the right thing at all.
A clean run is not proof of safety.
It means one pattern set produced no high or medium severity hits in the code under review. That is a narrower statement than it is usually made to sound.
Detector output needs human triage.
Several results above are limitations of the detector rather than defects in the code. Saying which, and why, is part of the report rather than a footnote appended to it.
The scope is three contracts.
Off-chain components, the voucher signer, the indexer and the reconciler are outside this report.
This is a snapshot.
18 September 2026, against Slither 0.11.6 and the deployed bytecode of that date. The contracts are immutable, so the code will not change. The detector set will.
Check it yourself
Two independent sources, neither of them us.
The point of publishing the method is that you do not have to believe the conclusion.
All three contracts are verified on BaseScan and in Sourcify, an independent public repository of contract sources. You can fetch the sources, rebuild the bytecode with the settings above and compare the result against the chain, without trusting Stobox and without trusting any single explorer.
The STBU page carries the contract addresses, the pool and the claim schedule, each figure read from the chain and dated. Verified contracts are a different question from the pool you trade in, and telling our pool from the ones that copy its name covers that one.
Straight answers
The questions this report gets asked.
Has STBU been audited?
No independent third-party security audit of the STBU contracts has been published, and calling what exists an audit would be wrong. This page is a static analysis report: Slither 0.11.6 run against sources pulled from the verified contracts on Base, 102 detectors across two compiler profiles. The difference between the two is set out in the limitations above and is not a formality.
Is the STBU contract safe?
This report cannot answer that, and a report that claims to is overselling itself. What it establishes is narrower and checkable: no high and no medium severity result in code written by Stobox, ten low and informational results named and answered, and every high and medium result in the two runs located in unmodified third-party libraries. Static analysis reasons about code structure. It does not reason about economic design, incentives, governance assumptions or behaviour when integrated with other protocols.
What is the difference between a static analysis and a security audit?
A static analysis is a tool run: it matches the code against a set of known patterns and reports what it matches. An audit is human review with a scope, a methodology and a firm putting its name to a judgement about whether the system does the right thing. A clean static analysis means one pattern set produced no high or medium severity hits in the code under review. That is a narrower statement than it is usually made to sound.
Which contracts does this report cover?
Three, all on Base: STBUToken at 0xe0c0F44A84CC4a60206360006ebA237a5e8fC2dd and MigrationClaim at 0xec5B3e512de13cb5DdFD84B2DF3167230F2e66a4, both compiled with solc 0.8.28, and FeeHook at 0x0507140088aa5b266d6b44eef02ad55cf1fb40c0, compiled with solc 0.8.26. Off-chain components, the voucher signer, the indexer and the reconciler are outside it.
Was the high severity finding in Stobox code?
No. The single high severity result, and most of the medium ones, sit in OpenZeppelin’s arithmetic library, and the rest sit in Uniswap v4-core. That claim is only worth something if the libraries are unmodified, so all 29 OpenZeppelin files in the deployed sources were compared byte for byte against the official OpenZeppelin Contracts v5.2.0 release. All 29 matched exactly, and the file carrying the high severity result is among them.
Can I repeat this analysis myself?
Yes, and that is the point of publishing the method. The sources are public in two independent places, BaseScan and Sourcify; the compiler settings are on this page, optimizer at 10,000 runs, EVM version cancun, intermediate representation disabled, metadata hash none; and Slither is open source. You can rebuild the bytecode and compare it against the chain without trusting Stobox and without trusting any single explorer.