Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,51 @@ appropriate time to react, analyze and develop a fix to mitigate the found secur

To report the vulnerability, please open a draft
[GitHub security advisory report](https://github.com/zama-ai/fhevm/security/advisories/new)

## Audit & verification status

Top-level index for the security verification status of contracts in this repository. Each package maintains its own status matrix in `contracts/<package>/audits/README.md`.

### Packages

| Package | Tag prefix | Upgradability | Status matrix |
| ------- | ---------- | ------------- | ------------- |
| Confidential Wrapper | `wrapper` | Upgradable (UUPS) | [`contracts/confidential-wrapper/audits`](./contracts/confidential-wrapper/audits/README.md) |
| Confidential Token Wrappers Registry | `registry` | Upgradable (UUPS) | [`contracts/confidential-token-wrappers-registry/audits`](./contracts/confidential-token-wrappers-registry/audits/README.md) |
| Staking | `staking` | Mixed | [`contracts/staking/audits`](./contracts/staking/audits/README.md) |
| Governance | `governance` | Immutable | [`contracts/governance/audits`](./contracts/governance/audits/README.md) |
| Token (EVM) | `token` | Immutable | [`contracts/token/audits`](./contracts/token/audits/README.md) |
| Solana OFT | `solanaOFT` | Immutable | [`contracts/solanaOFT/audits`](./contracts/solanaOFT/audits/README.md) |
| Fees Burner | `fees` | Immutable | [`contracts/feesBurner/audits`](./contracts/feesBurner/audits/README.md) |
| Pauser Set Wrapper | `pauserSetWrapper` | Immutable | [`contracts/pauserSetWrapper/audits`](./contracts/pauserSetWrapper/audits/README.md) |
| Safe (Admin Module) | `safe` | Immutable | [`contracts/safe/audits`](./contracts/safe/audits/README.md) |

### Conventions

#### Git tags

Each package uses its own scoped semver tag: `<prefix>-vX.Y.Z`. See the Tag prefix column above.

- For **upgradable** contracts, a tag is a candidate source snapshot for a proxy upgrade; the matching row in the package's status matrix is filled in once the tag has been audited and/or deployed.
- For **immutable** contracts, a tag is the source snapshot for a specific on-chain deployment.

#### Verification tracks

Columns used in each package's status matrix:

- **Pre-deploy audit** — external audit on the source contracts and deployment scripts before deployment.
- **Post-deploy audit** — external review of the deployed bytecode, configuration, and state against the audited source.
- **Fuzzing and invariants** — property-based fuzzing and invariant tests run against the release.

#### Status

Each row in a package's status matrix carries a **Status** value indicating where that tag sits in its lifecycle:

- **Upcoming** — tag is planned or in audit, not yet deployed.
- **Active** — tag is the currently deployed source for at least one chain.
- **Sunset** — tag has been superseded by a later version and is no longer the active deployment.
- **Skipped** — tag existed (and may have been audited) but was never deployed and has been passed over in favor of a later version.

#### Deployed addresses

See [`docs/addresses/`](./docs/addresses/README.md) for the current on-chain addresses of each package across all supported chains.
2 changes: 1 addition & 1 deletion contracts/chains-config-checker/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
.env
node_modules/
node_modules/
77 changes: 77 additions & 0 deletions contracts/chains-config-checker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Currently, most useful scripts are:
[*] get-current-pausers
[*] get-token-roles
[*] get-oft-owners
[*] verify-bytecode (see "Bytecode verification" at the bottom)
[*] verify-solana-program (see "Bytecode verification" at the bottom)
```
### getCurrentPausers

Expand Down Expand Up @@ -225,3 +227,78 @@ Example output:
Admin, Upgrade Authority, and Delegate should be IDENTICAL on Solana,
and it should be a Squads multisig wallet owned by Zama FB_i operators
```

## Bytecode verification

Verifies that the source at each audit commit (tracked in each package's
`audits/README.md`) produces the bytecode that is currently live on-chain.
Addresses stay single-source in `docs/addresses/mainnet/*.md` — the scripts
parse those files at runtime, together with a small mapping in
`bytecode-verification/config.js` (display-name → source contract + proxy
flag).

The verification uses **partial match**: the CBOR metadata suffix is
stripped and `immutableReferences` / `linkReferences` byte ranges are
zeroed before comparison. Two builds with identical compiled logic but
different formatting / paths / comments will match.

### Prerequisites

- Node.js (v18+)
- `.env` with `RPC_ETHEREUM`, `RPC_GATEWAY`, `RPC_BSC`, `RPC_HYPEREVM`,
and (for Solana) `SOLANA_RPC_URL`.
- Corepack enabled (`corepack enable` once) so `pnpm` is available.
Inside each contract worktree the script installs and compiles using
whichever package manager that package uses — currently `token` uses
pnpm, the others use npm.
- Solana only: Docker running (required by `anchor build --verifiable`),
and optionally the Solana CLI for the `solana program dump` fast path.

### Usage

Two-step pipeline:

```bash
# Step 1: gather markdown + config -> one JSON file
npm run gather-contract-infos
# -> writes bytecode-verification/contract-infos.json
# -> prints a "skipped" summary so you can audit coverage

# Step 2: EVM verify (auto-runs step 1 if JSON missing)
npm run verify-bytecode

# Step 3: Solana verify
npm run verify-solana-program
```

### Files

```
bytecode-verification/
config.js display-name -> source mapping + overrides
gather-contract-infos.js script 1: parse markdown -> JSON
verify.js script 2: EVM compile + compare
verify-solana.js script 3: Solana verifiable build + compare
contract-infos.json generated, gitignored
lib/
parse-audits-readme.js parser for contracts/*/audits/README.md
parse-addresses-doc.js parser for docs/addresses/**/*.md
bytecode-compare.js strip CBOR metadata, zero immutables, compare
worktree.js git worktree + package manager detection
```

### Sample output (verify-bytecode)

```
[token-v1.0.0 @ 157e6c4] contracts/token
solc 0.8.27
[ethereum] Zama Token (ZamaERC20) @ 0xA12C... => ok (... bytes)
[ethereum] Zama OFT Adapter (ZamaOFTAdapter) @ 0xa798... => ok (... bytes)
[gateway] Zama OFT (ZamaOFT) @ 0xcE76... => ok (... bytes)
[bsc] Zama OFT (ZamaOFT) @ 0x6907... => ok (... bytes)
[hyperevm] Zama OFT (ZamaOFT) @ 0x43cd... => ok (... bytes)

...

Summary: 39 ok, 0 mismatch/error (of 39)
```
90 changes: 90 additions & 0 deletions contracts/chains-config-checker/bytecode-verification/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Maps the human-authored markdown docs to source-code metadata.
*
* Addresses stay single-source in docs/addresses/**; audit tags + commits stay
* single-source in contracts/<pkg>/audits/README.md. This file only provides
* what is NOT in those docs:
* - display name / section -> source contract + proxy flag
* - per-row tag overrides (e.g. Luganodes uses a different staking tag)
* - chain -> RPC env var + addresses doc path
* - optional per-package packageManager override for worktree compiles
*
* contracts vs sections:
* - contracts: a specific display name maps to one source (distinct rows)
* - sections: every row under a given markdown section maps to one source
* (long tables where each row is an instance of the same contract)
* - overrides: per-display-name deviations within a section (e.g. Luganodes)
*/
module.exports = {
packages: {
token: {
// token uses pnpm; auto-detect should catch this from the lockfile,
// but we set it explicitly as a safety net.
packageManager: 'pnpm',
contracts: {
'Zama Token': { source: 'ZamaERC20', proxy: false },
'Zama OFT': { source: 'ZamaOFT', proxy: false },
'Zama OFT Adapter': { source: 'ZamaOFTAdapter', proxy: false },
},
},
governance: {
contracts: {
'Governance OApp Sender': { source: 'GovernanceOAppSender', proxy: false },
'Governance OApp Receiver': { source: 'GovernanceOAppReceiver', proxy: false },
},
},
'confidential-wrapper': {
sections: {
'Confidential wrappers': { source: 'ConfidentialWrapper', proxy: true },
},
},
'confidential-token-wrappers-registry': {
contracts: {
'Wrappers Registry': { source: 'ConfidentialTokenWrappersRegistry', proxy: true },
},
},
staking: {
sections: {
'Protocol staking': { source: 'ProtocolStaking', proxy: true },
'Operator staking': { source: 'OperatorStaking', proxy: true },
},
// (**) footnote in staking audits README: Luganodes uses a different tag
// than the other Operator staking rows.
overrides: {
'Operator staking': {
Luganodes: { tag: 'staking-v1.0.1-luganodes' },
},
},
},
feesBurner: {
contracts: {
ProtocolFeesBurner: { source: 'ProtocolFeesBurner', proxy: false },
FeesSenderToBurner: { source: 'FeesSenderToBurner', proxy: false },
},
},
pauserSetWrapper: {
contracts: {
'Pauser Set Wrapper (minting)': { source: 'PauserSetWrapper', proxy: false },
},
},
safe: {
contracts: {
'Admin Module': { source: 'AdminModule', proxy: false },
},
},
solanaOFT: {
solana: {
programAddress: 'A8W6AL4JhE4EDDcfXZ1Q8vQpwp83AnPj4UZ6y86gVFKN',
anchorBin: 'zama_oft',
},
},
},

chains: {
ethereum: { rpcEnv: 'RPC_ETHEREUM', addressesDoc: 'docs/addresses/mainnet/ethereum.md' },
gateway: { rpcEnv: 'RPC_GATEWAY', addressesDoc: 'docs/addresses/mainnet/gateway.md' },
bsc: { rpcEnv: 'RPC_BSC', addressesDoc: 'docs/addresses/mainnet/bsc.md' },
hyperevm: { rpcEnv: 'RPC_HYPEREVM', addressesDoc: 'docs/addresses/mainnet/hyper_evm.md' },
solana: { rpcEnv: 'SOLANA_RPC_URL', addressesDoc: 'docs/addresses/mainnet/solana.md' },
},
};
Loading