reading the source

the contracts are short. here is how to navigate them, what each file is responsible for, and how to verify the deployment matches.

the entire protocol is three solidity files. this page describes where each lives, what each holds, and how to confirm that what is on chain is exactly what the source says.

repo layout

SatoToken.sol
~80 lines. one openzeppelin ERC20 inheritance, one setMinter, one mint, one burn, four custom errors. no other logic.
SatoHook.sol
~450 lines. fourteen hook permission entry points (four of which do real work), the buy and sell paths, the entropy multiplier, the cooldown, and a manifesto getter. all guardrails and reverts live here.
lib/Curve.sol
~120 lines. totalMinted, mintFor, burnFor, marginalPrice, ethAt, plus four UD60x18 helpers and two custom errors. pure functions, no state.

dependencies

  • v4-core — uniswap's singleton PoolManager and hook interfaces. vendored at a specific commit; never modified.
  • openzeppelin-contracts — the standard ERC20. SatoToken overrides nothing; it uses it as-is.
  • prb-math UD60x18 fixed-point with exp and ln. the curve library uses only these two functions plus its own thin wrappers around arithmetic.

verifying a deployment

the source compiles deterministically under compiler_config.json. given the address of a deployed contract you can verify it has the expected bytecode by comparing hashes:

# 1. clone the source at the deployment commit
git clone <repo> sat0 && cd sat0
git checkout <deployment-tag>

# 2. compile with the locked config
solc --standard-json < compiler_config.json > out.json

# 3. hash the deployed runtime bytecode
cast code <SatoHook-address> | keccak

# 4. hash the compiled runtime
jq -r '.contracts."src/SatoHook.sol".SatoHook.evm.deployedBytecode.object' out.json \
  | keccak

# the two hashes must match

on top of bytecode equivalence, a deployment can be tied to a specific point in chain history with GENESIS_BLOCK and GENESIS_HASH— both immutable, both readable via single eth_calls.

reading order

if you want to read the contracts in the order that makes them easiest to follow:

  • 1. lib/Curve.sol— the math first. pure functions, no surprises.
  • 2. SatoToken.sol— the trivial erc-20 surrounding the locked minter.
  • 3. SatoHook.sol, top to bottom — the implementation note, then the constants and immutables, then beforeSwap and its two internal helpers _executeBuy and _executeSell. the unused hook entry points sit at the bottom; skip them on a first pass.

what to grep for

revert
ten total in SatoHook.sol, three in SatoToken.sol, two in Curve.sol. each is named; reading them tells you every failure mode.
immutable
tells you which values are set at construction and never change. the token has four, the hook has six.
public constant
everything else baked into bytecode: K_SUPPLY, S, MAX_BUY_WEI, COOLDOWN_BLOCKS, POOL_FEE, ENTROPY_BLOCKS, EXHAUSTION_*.
onlyPoolManager
every entry point on the hook. the only address with the ability to call those entry points is the v4 PoolManager.

this page describes deployed code. nothing here is a promise — it is a description of what the contract does and what it doesn't.