CodeQuill is a decentralized registry for repositories, snapshots, and supply-chain attestations. It leverages EIP-712 delegations to enable a secure relayer-mediated workflow, allowing repository owners to authorize specific actions (claiming repos, creating snapshots, or signing attestations) without requiring them to be online for every transaction.
- CodeQuillWorkspaceNFT: ERC-721 collection where each token represents authority over a CodeQuill workspace. Transferring the token transfers authority — designed to be held in a Safe (or any EIP-1271 wallet) for compromise resistance and key rotation. Approvals are disabled (
approve/setApprovalForAllrevert) so the workspace cannot be moved via marketplace operators or accidental "approve all" prompts — only the current holder can transfer it. - CodeQuillWorkspaceRegistry (v2): Manages workspace membership; authority is sourced from
CodeQuillWorkspaceNFT.ownerOf(contextId). Membership operations accept EOA and contract-wallet (EIP-1271) signatures via OpenZeppelin'sSignatureChecker. - CodeQuillDelegation: Context-scoped delegation (owner -> relayer) for granular permissions (scopes) bound to a workspace.
- CodeQuillRepositoryRegistry: Repository claim registry (repoId -> owner) with context-scoped relayer support.
- CodeQuillSnapshotRegistry: Lightweight snapshotting via Merkle roots and off-chain git commit metadata.
- CodeQuillReleaseRegistry: Anchors immutable project releases referencing snapshots with integrated governance.
- CodeQuillPreservationRegistry: Optional registry for anchoring encrypted preservation archives bound to snapshots.
- CodeQuillAttestationRegistry: Records supply-chain attestations (sha256 artifact digests) bound to on-chain releases.
Workspace authority is an ERC-721 NFT, not a flat address mapping. The token holder is the authority for everything the workspace touches: signing membership changes, transferring ownership, controlling governance.
This buys four big properties:
- Compromise resistance: hold the NFT in a Gnosis Safe (M-of-N). Losing one signing key does not lose the workspace, and one compromised key cannot drain it.
- Recovery: rotate authority by transferring the NFT — standard
safeTransferFrom. Safes additionally inherit Safe's existing recovery modules (Zodiac, social recovery cosigner, etc.) without any custom contract logic. - No accidental loss: approvals are disabled at the NFT contract level — there is no way to authorize a third party (marketplace, dapp, sketchy operator contract) to move the workspace. Only the current holder can.
- Workspace-scoped permissions: snapshots, preservations, and release revoke/supersede are gated on live workspace membership rather than the wallet that originally claimed a repo. So rotating the workspace NFT immediately transfers practical authority over every repo in the workspace — no need to also
transferRepoeach one. Historicalauthorfields stay frozen as provenance.
Regular EOA wallets continue to work without changes — the NFT lives in your wallet exactly like any other ERC-721, and signature-based membership operations accept ordinary 65-byte ECDSA signatures.
See docs/CodeQuillWorkspaceNFT.md and docs/CodeQuillWorkspaceRegistry.md for the full design.
For more detailed information on the project's structure and security model, please refer to:
- Architecture Diagram
- Permissions Matrix
- Security Model — threat model, trust assumptions, known limitations
- Audit Findings — self-audit findings, severity-rated, with status
npx hardhat build
npx hardhat test
npx hardhat test --coverage
npx hardhat keystore set SEPOLIA_RPC
npx hardhat keystore set DEPLOYER_PK
npx hardhat ignition deploy ignition/modules/Codequill.ts --network sepolia
Deployment order matters.
CodeQuillWorkspaceNFTmust be deployed first, thenCodeQuillWorkspaceRegistry(nftAddr), then the downstream registries (Delegation, Repository, Snapshot, Preservation, Release, Attestation) which take the registry address in their constructors.
npm run generate-abi
To verify contract source code on block explorers (like Etherscan) using the Standard-Json-Input method:
- Generate the Standard-Json-Input files:
npm run generate-standard-json
- The generated files will be located in the
standard-json-input/folder. - On the block explorer's verification page, select Standard-Json-Input as the compiler type.
- Upload the corresponding
.standard-input.jsonfile for your contract.