
GitHub Actions 智能合约自动化发布流水线多签提案自动创建与 CI 联调在企业级智能合约开发中主网核心合约的管理员权限通常属于Gnosis Safe 多签钱包如 3/5 签名门限。传统的发布流程往往非常原始且割裂开发者在本地跑脚本部署了新版的 Implementation 合约然后开发者手动打开 Safe Web 界面手动拼接 ABI 和复杂的十六进制 Calldata手动提交一笔upgradeTo(address)升级提案其他多签人无法快速验证这个提案的字节码与 Git 仓库里的源码是否 100% 对应存在极大的“暗度陈仓”投毒隐患。如何打造一条从代码合并到多签提案全自动化的可信流水线本文复盘如何利用GitHub Actions结合Safe Core SDK在代码合并到main分支时自动完成编译、Dry-run 模拟、部署新实现、并在 Safe 中自动创建带完整可解释元数据的升级提案。一、端到端自动化多签发布流水线拓扑graph TD Merge[PR 合并至 main 分支] -- CI[GitHub Actions 触发部署 Workflow] CI -- Step1[阶段 1: Forge 编译与本地 EVM 状态机 Fork 模拟执行] Step1 -- Step2[阶段 2: 广播部署 Implementation 合约并完成 Etherscan 验证] Step2 -- Step3[阶段 3: Safe SDK 自动化构造 upgradeToAndCall 提案] Step3 -- Step4[阶段 4: 提交提案至 Safe Transaction Service 并打上 Git Commit 标签] Step4 -- Notify[发送 Telegram / 钉钉通知多签成员进行移动端指纹签名]二、Safe 升级提案自动创建脚本实现// scripts/proposeUpgrade.ts import Safe from safe-global/protocol-kit; import SafeApiKit from safe-global/api-kit; import { parseAbi, encodeFunctionData } from viem; const RPC_URL process.env.MAINNET_RPC_URL!; const SAFE_ADDRESS process.env.SAFE_MULTISIG_ADDRESS!; const PROPOSER_PRIVATE_KEY process.env.PROPOSER_PRIVATE_KEY!; // 具有提案权但无单方执行权的专用 CI 密钥 const proxyAdminAbi parseAbi([ function upgradeAndCall(address proxy, address implementation, bytes memory data) external payable, ]); export async function automateMultiSigUpgradeProposal( proxyAddress: 0x${string}, newImplementationAddress: 0x${string}, gitCommitHash: string ) { const apiKit new SafeApiKit({ chainId: 1n }); const protocolKit await Safe.init({ provider: RPC_URL, signer: PROPOSER_PRIVATE_KEY, safeAddress: SAFE_ADDRESS, }); // 1. 构造升级调用的 Calldata const upgradeCalldata encodeFunctionData({ abi: proxyAdminAbi, functionName: upgradeAndCall, args: [proxyAddress, newImplementationAddress, 0x], }); // 2. 构造 Safe 交易对象 const safeTransaction await protocolKit.createTransaction({ transactions: [ { to: proxyAddress, value: 0, data: upgradeCalldata, operation: 0, }, ], }); // 3. 计算交易哈希并由 CI Proposer 签名 const safeTxHash await protocolKit.getTransactionHash(safeTransaction); const signature await protocolKit.signHash(safeTxHash); const senderAddress await protocolKit.getSignerAddress(); // 4. 提交至 Safe 官方中继服务 await apiKit.proposeTransaction({ safeAddress: SAFE_ADDRESS, safeTransactionData: safeTransaction.data, safeTxHash, senderAddress: senderAddress!, senderSignature: signature.data, origin: GitHub Actions CI (Commit: ${gitCommitHash}), }); console.log( [Safe Upgrade Proposed] Hash: ${safeTxHash}); console.log(多签提案已创建请多签成员在 Safe{Wallet} App 中审核并签名。); return safeTxHash; }三、GitHub Actions CI 完整 Workflow 配置# .github/workflows/deploy-and-propose.yml name: Deploy Contract Propose Safe Upgrade on: push: branches: [ main ] paths: - src/**/*.sol jobs: deploy-and-propose: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkoutv4 - name: Install Foundry uses: foundry-rs/foundry-toolchainv1 - name: Run Full Test Suite Invariants run: forge test -vvv - name: Deploy New Implementation via Forge Script id: deploy env: RPC_URL: ${{ secrets.MAINNET_RPC_URL }} ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} DEPLOYER_PRIVATE_KEY: ${{ secrets.DEPLOYER_PRIVATE_KEY }} run: | # 部署 Implementation 并捕获返回的合约地址 OUTPUT$(forge script script/DeployImpl.s.sol --rpc-url $RPC_URL --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY) IMPL_ADDR$(echo $OUTPUT | grep -oE 0x[a-fA-F0-9]{40} | tail -n 1) echo NEW_IMPL_ADDRESS$IMPL_ADDR $GITHUB_ENV - name: Create Safe Multisig Proposal env: MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} SAFE_MULTISIG_ADDRESS: ${{ secrets.SAFE_MULTISIG_ADDRESS }} PROPOSER_PRIVATE_KEY: ${{ secrets.PROPOSER_PRIVATE_KEY }} PROXY_ADDRESS: ${{ secrets.PROXY_ADDRESS }} run: | npx ts-node scripts/proposeUpgrade.ts \ --proxy $PROXY_ADDRESS \ --impl $NEW_IMPL_ADDRESS \ --commit ${{ github.sha }}四、极客安全审计闭环确定性元数据绑定Origin Tagging提案中的origin字段强制注入了当前 CI 运行的github.sha与 Action URL。多签成员在手机上点击审核时可以直接跳转查看对应的代码变更 Diff 与测试报告杜绝“盲签Blind Signing”权限最小化隔离CI 环境中的PROPOSER_PRIVATE_KEY仅具有向 Safe 提交提案的权利不具备执行权限即使 CI 密钥意外泄露攻击者也无法单方面升级合约。将智能合约工程的最后一步彻底融入现代 DevOps 规范让去中心化治理在自动化流水线的加持下精密如钟表。