1. Purpose
Establish a cryptographically verifiable, reproducible CI/CD pipeline for TLaaS (LEX) smart contracts, DApp, and supporting services. The pipeline must provide: deterministic builds, automated unit/integration/fuzz testing, formal checks, supply-chain security (SLSA) attestations, staged deployments (local → testnet → staging → mainnet), governance‑aware approvals, and post‑deploy monitoring hooks. Integrations include TLAAS (DLA) validation gates and DAL governance signals to gate production rollouts.
2. Architectural Overview
- Source Control: GitHub (repo:
- CI Runners: GitHub Actions + self‑hosted runners for private networks.
- Build System: Hardhat (contracts), Node/PNPM (DApp), Docker for deterministic packaging.
- Security Tooling: Slither, Mythril, Echidna, Foundry fuzz, Semgrep, npm‑audit.
- Supply Chain: Sigstore/Cosign for image & artifact signing; SLSA provenance.
- Secrets: GitHub OIDC to cloud KMS (AWS KMS / GCP KMS) + repository environments for staged secrets.
- Environments:
- Approvals: DAL‑backed governance check before
3. Deterministic Build Configuration
- Solc: Pin exact compiler (
- Node: Pin Node (e.g.,
- Docker: Build in container to eliminate host variance; export SBOM.
hardhat.config.ts (excerpt)
import "@nomicfoundation/hardhat-toolbox";
import "@openzeppelin/hardhat-upgrades";
import { HardhatUserConfig } from "hardhat/config";
const config: HardhatUserConfig = {
solidity: {
version: "0.8.24",
settings: {
optimizer: { enabled: true, runs: 20000 },
metadata: { bytecodeHash: "ipfs" }
}
},
networks: {
hardhat: { forking: { url: process.env.MAINNET_RPC ?? "", blockNumber: 19700000 } },
sepolia: { url: process.env.SEPOLIA_RPC!, accounts: [process.env.DEPLOYER!] },
mainnet: { url: process.env.MAINNET_RPC!, accounts: [process.env.DEPLOYER!] }
},
etherscan: { apiKey: { mainnet: process.env.ETHERSCAN!, sepolia: process.env.ETHERSCAN! } },
mocha: { timeout: 120000 }
};
export default config;
4. Repository Policies
- CODEOWNERS: Enforce reviews from
- Conventional Commits + semantic‑release for versions/tags.
- Branch Protection: Required checks (lint, test, fuzz, slither) and signed commits.
- DCO: Developer Certificate of Origin.
.github/CODEOWNERS
/contracts/* @protocol-team @security-team
/deploy/* @protocol-team @devops
/scripts/* @protocol-team @devops
5. CI Workflow (GitHub Actions)
.github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [ develop, main ]
push:
branches: [ develop ]
permissions:
contents: read
id-token: write
attestations: write
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'pnpm' }
- uses: pnpm/action-setup@v4
with: { version: 9 }
- name: Install deps
run: pnpm i --frozen-lockfile
- name: Compile
run: pnpm hardhat compile
- name: Lint (solhint, eslint)
run: pnpm lint
- name: Unit tests
run: pnpm test
- name: Coverage
run: pnpm hardhat coverage --testfiles "test/**/*.ts"
- name: Slither static analysis
uses: crytic/[email protected]
with:
slither-config: .slither.json
- name: Echidna fuzz (smoke)
run: |
docker run --rm -v $PWD:/src trailofbits/eth-security-toolbox:latest \
bash -lc "echidna-test . --contract LicenseMarketplace --config echidna.yml || true"
- name: SBOM (syft)
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b . v1.5.0
./syft packages dir:. -o spdx-json > sbom.spdx.json
- name: Attest build (SLSA)
uses: slsa-framework/[email protected]
with:
base64-subjects: true
Static Analysis Configs
- .slither.json
6. CD Workflow (Staged Deployments)
.github/workflows/cd.yml
name: CD
on:
workflow_dispatch:
inputs:
network:
description: 'testnet|staging|mainnet'
required: true
default: 'testnet'
push:
branches: [ main ]
permissions:
contents: read
id-token: write
deployments: write
attestations: write
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ github.event.inputs.network || 'staging' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'pnpm' }
- uses: pnpm/action-setup@v4
with: { version: 9 }
- name: Install deps
run: pnpm i --frozen-lockfile
- name: Build
run: pnpm hardhat compile
- name: DAL governance gate (mainnet)
if: ${{ inputs.network == 'mainnet' }}
run: node scripts/check-dal-approval.js --proposal ${{ secrets.DAL_PROPOSAL_ID }}
- name: Deploy
run: pnpm ts-node deploy/01_orchestrator.ts --network ${{ inputs.network }}
- name: Verify on explorer
run: pnpm hardhat verify --network ${{ inputs.network }} $(cat ./artifacts/addresses/${{ inputs.network }}/PaymentOrchestrator.json | jq -r .address)
- name: Generate release notes
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ github.run_number }}
name: TLaaS LEX Release ${{ github.run_number }}
draft: false
prerelease: ${{ inputs.network != 'mainnet' }}
Environment Protections
- staging
- mainnet
7. Deployment Scripts (TypeScript)
deploy/01_orchestrator.ts
import { ethers } from "hardhat";
import fs from "fs";
async function main() {
const [deployer] = await ethers.getSigners();
const Orchestrator = await ethers.getContractFactory("PaymentOrchestrator");
const orchestrator = await Orchestrator.deploy(
process.env.WETH!, process.env.TREASURY!, process.env.ROUTER!, process.env.COMPLIANCE!, process.env.FX!, process.env.FEEMODULE!
);
await orchestrator.waitForDeployment();
const addr = await orchestrator.getAddress();
console.log("PaymentOrchestrator:", addr);
fs.mkdirSync(`artifacts/addresses/${process.env.NETWORK}`, { recursive: true });
fs.writeFileSync(`artifacts/addresses/${process.env.NETWORK}/PaymentOrchestrator.json`, JSON.stringify({ address: addr }, null, 2));
}
main().catch((e) => { console.error(e); process.exit(1); });
scripts/check-dal-approval.js (DAL Gate)
const { getDalApproval } = require('./dal-client');
(async () => {
const proposalId = process.argv.pop();
const ok = await getDalApproval(proposalId);
if (!ok) { console.error('DAL approval missing'); process.exit(1); }
console.log('DAL approval verified');
})();
8. Security Gates & Policies
- Upgradeable Safety: Use OpenZeppelin Upgrades plugin; require
- Timelocks: Production admin actions pass through timelock + Safe.
- Kill Switch: Emergency pause via multi‑sig + DAL signal; monitored by alerting.
- Key Rotation: Quarterly rotation for deployer and relayers; attest via audit log.
Storage Layout Check (hardhat)
pnpm hardhat storage:verify --contract contracts/PaymentOrchestrator.sol:PaymentOrchestrator
9. Formal & Fuzz Testing
- Echidna: invariants (no asset loss; escrow invariant; reentrancy‑free routes).
- Foundry: property tests with randomization, mainnet‑fork shadow tests.
- Mythril: symbolic execution for reentrancy, tx‑ordering issues.
- Slither: detectors + custom detectors for DAL/TLAAS hooks.
foundry.toml
[profile.default]
src = 'contracts'
out = 'out'
libs = ['lib']
optimizer = true
optimizer_runs = 20000
Echidna Invariant (snippet)
contract Invariants {
PaymentOrchestrator internal p;
function echidna_no_unexpected_sweep() public view returns (bool) {
// treasury balance must increase or stay the same after payments
return true; // implement delta tracking in harness
}
}
10. Supply-Chain Security & Provenance
- SBOM: Generate SPDX JSON via Syft; store with release assets.
- Provenance Attestations: SLSA v1.0 builder with OIDC identity; cosign sign images and artifacts.
- Dependency Pinning: exact versions in
- Rebuild Verification: Nightly job recompiles and byte‑compares deployed artifact hashes.
cosign (example)
cosign sign-blob --key $KMS_KEY artifacts/addresses/mainnet/PaymentOrchestrator.json
cosign verify-blob --key $KMS_PUB artifacts/addresses/mainnet/PaymentOrchestrator.json --signature sig.cosign
11. Observability & Post-Deploy Checks
- On-chain Health: scrape events (
- Dashboards: Grafana + Prometheus for indexer nodes; Blocknative/Alchemy alerts for tx failures.
- Anomaly Detection: Trigger alerts for abnormal fee splits, DAL freezes, or validator slashes.
- Runbooks: Incident response playbooks bound to pager rotations.
12. Governance-Linked Release Management
- Release Tags: include DAL proposal id and EIP‑712 domain salt in release notes.
- Changelog: auto‑generated conventional commits.
- Upgrade Plan: announce timelock ETA; provide storage layout diff; attach audit deltas.
13. Local Developer UX (Makefile)
.PHONY: init test fuzz fork deploy-staging
init: ; pnpm i --frozen-lockfile && pnpm hardhat compile
fork: ; pnpm hardhat node --fork $(MAINNET_RPC)
test: ; pnpm hardhat test
fuzz: ; forge test -vvv
deploy-staging: ; NETWORK=staging pnpm ts-node deploy/01_orchestrator.ts
14. Compliance & Legal Artifacts
- Attestation Bundle: attach SBOM, audit reports, prover logs to each release.
- Jurisdiction Maps: include compiled rule tables used by fee/renewal modules.
- Data Retention: retain CI logs and artifacts for 7 years (configurable) for auditability.
15. Acceptance Criteria
- Reproducible builds (byte‑equal) across runners.
- 95%+ unit coverage, passing fuzz/property tests.
- No critical Slither/Mythril findings; medium findings triaged.
- DAL approval enforced for
- Post‑deploy verification and event heartbeat green for 24h.
Next Article: Proxy Upgradability Patterns — Delegate‑Call Proxies for Contract Upgrades