Building the contracts
The source is in the repository and the build is pinned, so the bytecode is reproducible: two people building the same commit get identical runtime code. That is what makes it possible to check, later, that a deployed address really runs the source documented here — and to notice if it does not.
The pinned settings
| Tree | solc | Optimizer | EVM version | Pipeline |
|---|---|---|---|---|
launchpad-v1 | 0.8.30 | on, 300 runs | cancun | viaIR |
launchpad-v2 | 0.8.35 | on, 200 runs | cancun | viaIR |
Both live in each tree's own foundry.toml. They are not stylistic preferences: change any one
of them and the compiler emits different bytes for the same source, which means a byte comparison against a
deployed contract fails and a verifier cannot tell a settings mismatch from a source mismatch. The two
trees are not interchangeable — v1 and v2 pin different compilers and different optimizer runs.
viaIR is not optional either: without it the V1 factory does not compile at all
(stack too deep).
# Model V2 — bonding curve, graduates to Uniswap V4
cd contracts/launchpad-v2
forge build --profile parity # solc 0.8.35, optimizer 200 runs, cancun, viaIR
# Model V1 — no curve, direct Uniswap V3 pool
cd ../launchpad-v1
forge build --profile parity # solc 0.8.30, optimizer 300 runs, cancun, viaIR
The parity profile is the one that pins the exact solc version rather than
accepting whatever the toolchain has installed, so it is the profile a verifier must use. The first build
needs network access, because Foundry downloads that compiler binary.
Checking a deployed address
The addresses will be listed under Addresses when the launchpad opens. Then, comparingThe addresses are under Addresses. Comparing the compiled runtime bytecode against the code at an address is not a plain string equality, because two differences are expected even when the source is identical:
-
Immutables. Values written at construction appear as zeros in a compiled artifact and as
real data on chain. Their byte positions come from the artifact's own
deployedBytecode.immutableReferences, so they can be masked exactly rather than guessed at. -
Metadata of embedded child contracts. A contract that does
new X()carries X's creation code inside itself, ending in a CBOR blob that encodes a hash of X's source and compiler settings. Anything that changes a source file — even a comment — changes that blob without moving a single instruction, so each solc CBOR block is masked too.AgiV2LaunchDeployercarries three of them, because it embeds both the curve and the token and each embedded child contributes its own.
The explorer pairs a contract whose bytecode matches, metadata aside, a source that was already verified for another project, and labels that pairing a partial match. Our sources were uploaded as a full match, but anyone who compares bytecode will see that these contracts are a byte-for-byte fork of an existing launchpad — and redeploying would not change that, because the same source compiles to the same bytes. If the explorer shows a partial match, or attaches a name that is not ours to one of our addresses, that is why. Verify by the address, never by the name a verifier displays next to it.
A reproducible build proves that the deployed code is the code you can read. It proves nothing about whether that code is right. 613 Solidity tests and 564 indexer tests exist; no external audit does, and a byte-for-byte match with a buggy source is still a buggy deployment.