Phase 3 — mainnet prerequisites · item 3.5
Publish verified sources on the explorer
Every contract in the deployment is now verified on Blockscout. git grep the address and the explorer shows you the source it was compiled from.
This item had been recorded as "mostly done — three remain". It was not. That count only ever considered the shared contracts and the uTSLA mirror. uSPY, uQQQ and uNVDA each have five contracts and none of their four core contracts were verified — including the Certificate tokens holders actually own. The true starting position was 14 of 26, not 23 of 26.
Twelve contracts verified this pass: CertVault, CertOracle, Certificate and BufferBook for each of uSPY, uQQQ and uNVDA.
Recovering the constructor arguments. Neither broadcast file in this repo is usable — one holds an Anvil run, the other the previous deployment — so the chain was the only source. For CertVault and CertOracle the creation input is creationCode || abi.encode(args), and the artifact supplies the creation code, so the tail is the arguments.
Certificate and BufferBook could not be recovered that way at all: CertVault creates both with CREATE from inside its own constructor (CertVault.sol:465-466), so their arguments appear in no transaction's calldata. They were derived from values that are themselves on chain rather than guessed — Certificate(name_, symbol_, address(this)) where name_ and symbol_ are the last two fields of the vault's own recovered arguments, and BufferBook(address(this), 200) where 200 is a literal at the call site. That the explorer accepted all six is the check on that derivation: a wrong argument fails to match the deployed bytecode.
Two measurement traps worth recording, because both produced a confident wrong answer.
is_verified on the v2 API is not reliable. TestUSDG, and every ReplayAggregator, return is_verified: false while the same endpoint serves their full source. Counting that flag gave 17 unverified when the real number was 12. Presence of source_code is the signal that matches what a reader actually gets.
And the submission script reported 12 of 12 FAILED while all twelve succeeded: it grepped forge's output for "successfully verified", and a successful submission prints a GUID and a URL instead. The status was only settled by re-reading the explorer, which is the thing that was being claimed in the first place.
Still outstanding: Blockscout reports these as a partial match, so the metadata hash differs even though the runtime bytecode agrees. A full match needs the exact compiler metadata settings used at deploy. Keeping a real broadcast record for the live deployment would make the next verification a one-liner, and is the same provenance gap as 0.3 and 3.4.
Evidence


On GitHub
1898c4d2026-09-26docs(roadmap): 3.5 done - 26 of 26 contracts verified
The change itself

UseCert delivery record. Unlisted: this page is reachable only by its link. Generated from demo/ROADMAP.md at 507a7eb479f1.