Introduction to SH500

StandardHook500 (SH500) is a Uniswap V4 Hook that creates a pool where users can trade a synthetic token tracking the S&P 500 index. It is the first DeFi protocol to offer dynamic, oracle-driven fee adjustment based on real-world equity market volatility — entirely on-chain, non-custodial, and open source.

The protocol sits at the intersection of DeFi and traditional finance (TradFi/RWA). Users who want long-term exposure to US equities no longer need to leave the crypto ecosystem. $SH500 tokens represent synthetic index exposure, and the hook's mechanics ensure the pool behaves like an intelligent, self-adjusting ETF.

Note: SH500 is a synthetic exposure instrument, not a direct ownership of S&P 500 shares. Price tracking is maintained via Chainlink oracle feeds and automated rebalancing. This is not financial advice.

Architecture

SH500 is composed of four smart contracts deployed on Ethereum Mainnet, all centered around the Uniswap V4 hook system:

ContractTypeDescription
SH500HookV4 HookCore hook — dynamic fees, oracle reads, rebalance triggers
SH500TokenERC20VotesGovernance token — 500M supply, voting delegation
SH500VaultYield VaultDeploys idle LP liquidity to Aave v3 for extra yield
SH500TWAMMModuleDCA EngineTime-weighted average buys — spread orders over time

The hook is the brain. Every swap that touches the SH500 pool passes throughbeforeSwap andafterSwap callbacks, where the protocol reads the oracle, adjusts the fee, and checks if rebalancing is needed.

How It Works

Every swap through the SH500 pool follows this sequence:

User submits swap
ETH / USDC / WBTC → SH500
beforeSwap fires
Chainlink oracle read → fee computed
Uniswap V4 executes
Swap at dynamic fee rate
afterSwap fires
Drift check → rebalance queued if needed
Vault yield accrues
Idle liquidity earns via Aave v3

SH500Hook.sol

The main contract. It extends BaseHook from Uniswap v4-periphery and implements afterInitialize, beforeSwap, and afterSwap.

Constructor parameters

ParameterTypeDescription
_poolManageraddressUniswap V4 PoolManager — 0x000000000004444c5dc75cB358380D2e3dE08A90
_sp500OracleaddressChainlink AggregatorV3 feed for S&P 500 (CSPX/USD)
_owneraddressInitial owner — can update fee params and keeper

Key functions

FunctionAccessDescription
getCurrentFee()viewReturns current computed dynamic fee based on latest oracle data
refreshOraclePrice()publicAnyone can call to force an oracle price refresh
executeRebalance(key)keeperTriggers a pool rebalance — only callable by the keeper address
setFeeParams(...)ownerUpdate feeMin, feeMax, volThreshLow, volThreshHigh
setKeeper(addr)ownerUpdate the keeper address
setDriftThreshold(bps)ownerSet drift % before rebalance is triggered
Hook address mining: Uniswap V4 requires the hook contract address to encode its permissions in the lower bits. Before deploying SH500Hook via Remix, you must mine a salt that produces an address with the correct flags: AFTER_INITIALIZE | BEFORE_SWAP | AFTER_SWAP. Use the HookMiner utility or the Python script included in the repo.
Solidity// Hook flags required Hooks.AFTER_INITIALIZE_FLAG // 0x0200 Hooks.BEFORE_SWAP_FLAG // 0x0080 Hooks.AFTER_SWAP_FLAG // 0x0040 // The deployed address must have these bits set // in its lower 14 bits — mine the CREATE2 salt first

Oracle Integration

SH500Hook reads the S&P 500 price via Chainlink's AggregatorV3Interface. The feed used is CSPX/USD — CSPX is the iShares Core S&P 500 ETF, which closely tracks the underlying index.

PropertyValue
FeedCSPX / USD
Address (Mainnet)0x4b531A318B0e44B549F3b2f824721b3D0d51930A
Decimals8
Staleness threshold3600 seconds (1 hour)
Update frequencyHeartbeat: 24h / Deviation: 0.5%

If the oracle price is older than 1 hour, beforeSwap will revert with StaleOraclePrice. This protects the pool from operating on stale data during oracle downtime.

Note: The protocol stores the last valid price and a 24h-ago reference price. The delta between these two is what drives the dynamic fee calculation. Both values are updated on every successful beforeSwap call.

Dynamic Fee Model

The fee is not fixed. It is computed on every swap using the absolute percentage change of the S&P 500 over the last 24 hours. When markets are calm, fees drop to attract traders. When volatility spikes, fees rise to protect LPs from impermanent loss.

Fee scale

< 1% move0.01%Calm
1–2% move0.05%Normal
2–3% move0.20%Elevated
3–5% move0.50%Volatile
> 5% move1.00%Crisis

Interpolation formula

Between the low and high volatility thresholds, the fee is linearly interpolated:

Solidity — _computeDynamicFee()uint256 absDeltaBps = |currentPrice - price24hAgo| * 10_000 / price24hAgo; if (absDeltaBps <= volThreshLow) return feeMin; // calm market if (absDeltaBps >= volThreshHigh) return feeMax; // crisis mode // linear interpolation between thresholds uint256 position = absDeltaBps - volThreshLow; uint256 range = volThreshHigh - volThreshLow; return feeMin + (feeMax - feeMin) * position / range;

Default parameters

ParameterDefaultDescription
feeMin100 (0.01%)Fee during calm markets
feeMax10,000 (1.00%)Fee during crisis
volThreshLow100 bps (1%)Daily move below this = min fee
volThreshHigh300 bps (3%)Daily move above this = max fee
driftThresholdBps200 bps (2%)Pool drift before rebalance triggers
Governance: All fee parameters are updatable by the protocol owner (eventually by SH500 token holders via governance). Parameter changes are subject to a timelock delay before taking effect.

Auto-Rebalancing

After each swap, the hook checks whether the pool's composition has drifted more than driftThresholdBps (default 2%) from the target S&P 500 price weight. If it has, a RebalanceQueued event is emitted.

An off-chain keeper bot monitors these events and calls executeRebalance(poolKey)on the hook. In Phase II the keeper will use Uniswap V4's modifyLiquidityto adjust the pool's tick range and proportions, bringing it back in line with the index.

Phase I (current): Rebalance events are emitted but full liquidity repositioning is not yet active. The keeper infrastructure is being built in Phase II.

SH500Token.sol

The protocol's governance token. Built on OpenZeppelin's ERC20Votes + ERC20Permit. Total supply is fixed at 500,000,000 SH500 — minted once at deploy time.

AllocationAmount%
Liquidity Mining175,000,00035%
Treasury100,000,00020%
Team & Advisors75,000,00015%
Community & Grants75,000,00015%
Public Sale50,000,00010%
Ecosystem Partners25,000,0005%
Vesting:Team & Advisors allocation is subject to a 12-month cliff + 24-month linear vesting. All other allocations are distributed via smart contract on a schedule defined by governance.

SH500Vault.sol

The yield vault collects a portion of swap fees and deploys them to Aave v3 on Ethereum Mainnet. LPs receive proportional shares that represent their claim on the vault's assets + accrued yield.

How shares work

When fees are deposited, the vault mints shares proportional to the deposit relative to total assets. On withdrawal, shares are burned and the underlying tokens + yield are returned. This follows the ERC-4626 vault pattern (simplified implementation).

FunctionWho callsDescription
deposit(token, amount, lp)HookDeposit fees, mint LP shares
withdraw(token, shares, recipient)LPBurn shares, receive tokens + yield
harvestYield(token)Hook / KeeperRealize Aave yield back into vault
previewRedeem(token, lp)viewCheck how many tokens a given LP can redeem
setAllocationBps(token, bps)OwnerSet % of deposits to send to Aave (max 80%)

TWAMM / DCA Module

The TWAMM module lets users accumulate $SH500 over time without hitting large price impact. Instead of buying all at once, you define a total amount and an interval — the contract executes small buys periodically, averaging your entry price.

Creating a DCA order

Solidity — createOrder()SH500TWAMMModule.createOrder( tokenIn, // USDC, ETH, WBTC tokenOut, // SH500 token address totalAmount, // e.g. 1000 USDC total amountPerInterval,// e.g. 100 USDC per buy intervalSeconds // e.g. 86400 = once a day ); // → returns orderId
ConstraintValue
Min interval1 hour (3,600 seconds)
Max interval30 days (2,592,000 seconds)
ExecutionAnyone can call executeOrder() when time has passed
CancellationOwner can cancel anytime — unexecuted amount refunded

Deploy on Remix

All four contracts can be deployed directly from remix.ethereum.org. Follow this exact order — each contract depends on the one before it.

Step 1 — SH500Token

No dependencies. Deploy first. Constructor takes 7 addresses: liquidityMining, treasury, team, community, publicSale, ecosystem, owner. For initial deploy you can use your own wallet for all of them, then transfer to multisigs later.

Step 2 — SH500Vault

Needs the hook address — but the hook isn't deployed yet. Pass a placeholder address (address(0) or your wallet) and call setHook(hookAddress) after Step 4. Also pass the Aave v3 pool address: 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2

Step 3 — Mine the hook address

This is the most important step. Uniswap V4 requires the hook address to have specific bits set. You need to find a CREATE2 salt that produces an address with the correct flags. Run the HookMiner tool before deploying SH500Hook.

Required flags: AFTER_INITIALIZE (0x0200) | BEFORE_SWAP (0x0080) | AFTER_SWAP (0x0040) — the lower bits of the deployed address must match these values.

Step 4 — SH500Hook

Deploy with the mined salt. Constructor: IPoolManager address (0x000000000004444c5dc75cB358380D2e3dE08A90), Chainlink oracle (0x4b531A318B0e44B549F3b2f824721b3D0d51930A), and owner address.

Step 5 — SH500TWAMMModule

Pass the deployed SH500Hook address as the single constructor argument.

Step 6 — Wire everything up

Post-deploy calls// On SH500Vault — set the real hook address vault.setHook(sh500HookAddress); // On SH500Hook — set the vault and keeper hook.setKeeper(keeperWalletAddress); // On SH500Vault — set Aave allocation (e.g. 60%) vault.setAllocationBps(usdcAddress, 6000);

Frontend Setup

The frontend is built with Next.js 16, no Tailwind. To run it locally:

Terminal# Install dependencies npm install # Copy and fill the env file cp .env.example .env.local # → fill in your Alchemy key, WalletConnect ID, # and deployed contract addresses # Run dev server npm run dev # Build for production npm run build && npm start

Environment Variables

VariableRequiredDescription
NEXT_PUBLIC_WALLETCONNECT_PROJECT_IDYesFrom cloud.walletconnect.com
NEXT_PUBLIC_ALCHEMY_KEY_MAINNETYesEthereum RPC — dashboard.alchemy.com
NEXT_PUBLIC_SH500_HOOK_ADDRESSYesDeployed SH500Hook contract address
NEXT_PUBLIC_SH500_TOKEN_ADDRESSYesDeployed SH500Token address
NEXT_PUBLIC_SH500_VAULT_ADDRESSYesDeployed SH500Vault address
NEXT_PUBLIC_SH500_TWAMM_ADDRESSNoDeployed TWAMM module (Phase II)
NEXT_PUBLIC_POOL_MANAGER_MAINNETYesUniswap V4 PoolManager on mainnet
NEXT_PUBLIC_CHAINLINK_SP500_FEEDYesCSPX/USD Chainlink feed address
NEXT_PUBLIC_SWAP_ENABLEDNoFeature flag — set false to disable swap UI

Revenue Model

The protocol generates revenue from three sources, all distributed on-chain:

SourceSplit
Swap feesLPs 70% · Treasury 20% · Burn 10%
Vault yield (Aave)LPs 80% · Treasury 20%
Performance feeTreasury 50% · Buyback & burn 50%

Governance

SH500 token holders vote on protocol parameters using on-chain governance (Governor Bravo pattern). Proposals require a minimum quorum and are subject to a 48-hour timelock before execution.

Governable parameters include: fee min/max, volatility thresholds, drift threshold, vault allocation percentages, keeper address, and treasury spending.

Phase I: Owner-controlled (deployer wallet / multisig). Phase IV: Full on-chain governance via SH500 token voting.

Development Phases

Phase I — Hook MVP · Q3 2025
  • Dynamic fee logic
  • Chainlink oracle integration
  • Ethereum mainnet pool deployment
  • Foundry test suite 95%+
  • First security audit
Phase II — Rebalancing · Q4 2025
  • afterSwap rebalancing logic
  • Keeper bot infrastructure
  • Drift threshold governance
  • Ethereum full deployment
  • Mainnet beta launch
Phase III — Yield & App · Q1 2026
  • Aave v3 vault live
  • TWAMM / DCA module
  • Frontend dashboard
  • Portfolio tracker
  • Public mainnet launch
Phase IV — Full Protocol · Q2–Q3 2026
  • SH500 governance token launch
  • Performance fee model
  • Multi-index expansion
  • Institutional onboarding
  • Full audit + launch

Security

SH500 contracts are written in Solidity 0.8.24 with overflow protection enabled by default. The codebase follows checks-effects-interactions patterns and uses OpenZeppelin's ReentrancyGuard on all vault functions that move funds.

RiskMitigation
Oracle manipulationStaleness check (1h), Chainlink decentralized aggregator
ReentrancyReentrancyGuard on vault, checks-effects-interactions
Hook address spoofonlyPoolManager modifier on all hook callbacks
Admin key compromiseMultisig owner + 48h timelock on parameter changes
Stale price attackStaleOraclePrice revert if feed older than 1 hour
Audit status: First security audit scheduled for Phase I completion (Q3 2025). Do not deposit significant funds until audit is complete and published.