Skip to content

m0-platform/saturn-dollar

 
 

Repository files navigation

Saturn Dollar (USDat)

USDat is a compliance-enabled extension token built on M (by M^0). Users deposit/withdraw through the M0 SwapFacility to wrap M (and JMI-allowed assets) into USDat; yield generated by the underlying M is routed to a configured yield recipient. On top of the base M-extension behaviour, USDat adds:

  • Whitelist gating — when enabled, deposits, withdrawals and transfers are restricted to whitelisted accounts (managed via WHITELIST_MANAGER_ROLE).
  • Compliance controls — account freezing and forced transfers (ForcedTransferable) for regulatory requirements.
  • Pausing & role-based access control inherited from the M-extension base.

The contract is built with Foundry and Solidity 0.8.26.

Architecture

USDat is deployed behind a transparent upgradeable proxy:

Contract Role
Proxy User-facing address. Holds all state and funds. Deployed deterministically via CREATE3 (CreateX).
Implementation src/USDat.sol — the audited logic. Stateless aside from immutables.
ProxyAdmin Controls implementation upgrades; owned by the admin.

USDat extends JMIExtension and ForcedTransferable from m-extensions. Its constructor takes two immutables baked into the bytecode — the M token and the SwapFacility — while operational parameters (admin, compliance, processor, yield recipient) are set at initialize() time and live in proxy storage.

USDat is IUSDat, JMIExtension, ForcedTransferable
  ├─ immutables : M_TOKEN, SWAP_FACILITY            (constructor → bytecode)
  └─ init params: yieldRecipient, admin, compliance, processor   (proxy storage)

Repository layout

src/
  USDat.sol            # implementation (logic)
  IUSDat.sol           # public interface
script/
  USDat.s.sol          # DeployUSDat — deploys impl + proxy + ProxyAdmin
  UpgradeUSDat.s.sol    # implementation upgrade
  VerifyCodeHash.s.sol  # code-consistency proof helper (see below)
  README.md            # deployment details & addresses
test/                  # Foundry tests
lib/                   # dependencies (forge-std, m-extensions, OZ-upgradeable, solady)
verify.sh              # one-command on-chain code verification

Development

Requires Foundry.

forge build       # compile
forge test        # run tests
forge fmt         # format
forge snapshot    # gas snapshots

Build settings (see foundry.toml): solc 0.8.26, optimizer enabled (200 runs), via_ir = true.

Deployment

See script/README.md for full deployment details. In short, the proxy is deployed deterministically via the CreateX factory (0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed) with salt "USDat", so it resolves to the same address on every chain for a given deployer.

source .env && forge script script/USDat.s.sol:DeployUSDat \
  --rpc-url $RPC_URL --broadcast

Supply a signer via your preferred Foundry method (e.g. --account <keystore> or a hardware wallet flag).

Required environment variables: RPC_URL, M_TOKEN, SWAP_FACILITY, ADMIN, COMPLIANCE, PROCESSOR, YIELD_RECIPIENT.

Mainnet deployment (chain ID 1)

Item Address
Proxy (user-facing) 0x23238f20b894f29041f48D88eE91131C395Aaa71
Implementation 0x17cac25c6d6bbcb592837fea083a5c8eb4d1e52e
M_TOKEN (immutable) 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b
SWAP_FACILITY (immutable) 0xB6807116b3B1B321a390594e31ECD6e0076f6278

Audit & code-consistency verification

The implementation was audited at commit 8735152da4d5182f34cf29771757737d33894064. The script below proves — with a single hash on each side — that the code deployed on mainnet is exactly the audited source.

Compile the source at the audited commit, deploy it in a local EVM with the production constructor arguments, and confirm the resulting runtime code hash equals the code hash of the live mainnet implementation.

Run it

bash verify.sh          # reads RPC_URL, M_TOKEN, SWAP_FACILITY from .env.production

No checkout required: verify.sh first runs a read-only git diff to confirm the source in your tree is byte-identical to the audited commit, then builds and compares. (It does not move your checkout or modify the repo.)

Expected output:

  network              : Ethereum mainnet (chain id 1)
  implementation       : 0x17cac25c6d6bbcb592837fea083a5c8eb4d1e52e
  audited commit       : 8735152da4d5182f34cf29771757737d33894064  (source verified identical)
  local  code hash     : 0x5cc574845a8fd858923a985ab3c6417713aa473b0aafe6c8e0081a101bf2bb68
  production code hash : 0x5cc574845a8fd858923a985ab3c6417713aa473b0aafe6c8e0081a101bf2bb68

  MATCH - mainnet 0x17cac25c6d6bbcb592837fea083a5c8eb4d1e52e runs the audited code (commit 8735152da4d5182f34cf29771757737d33894064)

Reference values

Item Value
Audited commit 8735152da4d5182f34cf29771757737d33894064
Implementation 0x17cac25c6d6bbcb592837fea083a5c8eb4d1e52e (mainnet)
Runtime code hash (EXTCODEHASH) 0x5cc574845a8fd858923a985ab3c6417713aa473b0aafe6c8e0081a101bf2bb68
Metadata IPFS hash (embedded in bytecode) 45472ce17e1ff7ff1ddeb6da763cf1f2d545305b71f993a3304b5d68bdd6ce45

How it works

  • script/VerifyCodeHash.s.sol deploys USDat(M_TOKEN, SWAP_FACILITY) in a local EVM and prints address(impl).codehash. The local deploy links the two immutables exactly as mainnet did, so the hash is directly comparable to the on-chain EXTCODEHASH — no byte-diffing or immutable handling required.
  • verify.sh confirms — with a read-only git diff — that the source here is identical to the audited commit, gets that local hash, fetches the production hash via cast codehash, and asserts the two hashes match. No checkout or other state-changing git command is used.

The runtime code hash is fully determined by (audited source + compiler settings + the two immutable addresses). A match therefore proves the deployed implementation bytecode is the audited code built from this commit with these arguments. As an independent cross-check, the metadata IPFS hash Solidity embeds in the bytecode (a fingerprint of the source files + compiler settings) is identical in the local build and on-chain.

Scope: this verifies the implementation logic. The operational parameters set at initialize() (ADMIN, COMPLIANCE, PROCESSOR, YIELD_RECIPIENT) are proxy storage state, not part of the implementation bytecode, and are verified separately by reading the proxy's roles/configuration.

License

Business Source License 1.1 (BUSL-1.1). See SPDX headers in src/.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Solidity 94.5%
  • Shell 5.5%