Skip to content
Landseed NRD-DAO Atlas
← Modules (Layer 2)

Architecture · Modules

The six modules

Six audited governance modules. Every template is a configuration of these six. M1 is the substrate everything else reads.

Templates differ by configuration of the same six modules, not by having different modules. The audit surface is therefore bounded: six modules · parameter ranges · template-specific compositions. This page renders the canonical specification at audit-scoping rigor.

Module index

Every governance vehicle (Tier 1 LLC or Tier 2 DAO) is composed from the same six modules. The differentiator across templates is each module’s configuration, not the modules themselves.

This document is written to smart-contract-audit-scoping rigor. For each module it specifies purpose, Tier 1 implementation (operating-agreement and multi-sig encoding), Tier 2 implementation (state variables, function signatures, events, modifiers), invariants, threat model, per-template variations, external dependencies, and audit-scoping notes. Solidity-style pseudocode is used for concreteness; (framework-agnostic; specific framework choice deferred) — the spec must be implementable on Aragon OSx, Tally, OpenZeppelin Governor, or a custom Solidity codebase. No syntax in this document locks in any of these.

Where a claim turns on legal counsel or jurisdictional law, it is marked (counsel-confirmation required). Where it turns on technology not yet built, (not yet built).

The modules — one-line summary

ModuleFunctionTier 1 implementationTier 2 implementation
M1 — Beneficiary RegistryNamed participant list with seats, KYC reference, voting weight, distribution shareOperating-agreement membership clauses; KYC records held off-chain by Landseed complianceSmart-contract registry; KYC reference held off-chain; on-chain seat designation
M2 — GovernanceProposal types, voting rules, supermajority thresholds, time delays, FPIC checkpoints, guardian vetoesOperating-agreement procedures; signed amendments; institutional governance integrationSmart-contract governance with on-chain proposal lifecycle, voting, and execution
M3 — EconomicsDistribution rules — the benefits modelOperating-agreement distribution clauses; multi-sig executes distributionsSmart-contract distribution module with parameterized splits and cadences
M4 — Mgmt Plan RatificationVersioned forest/invasive/harvest/restoration plans; the LLC/DAO ratifies versions through M2Operating-agreement amendment procedure; institutional plan approvalContent-addressed plan ratification; on-chain version tracking
M5 — Attestation HooksConsumes EC-M-1.1 attestations from receipts; recognizes credit-issuance eventsManual recording in books and records; Landseed compliance verifiesSmart-contract listener for attestations and credit-issuance events; on-chain state updates
M6 — Upgrade PathModule-by-module upgrades with supermajority + time delay + guardian vetoOperating-agreement amendment procedure; standard signature-based amendmentSmart-contract upgrade governance with audit-required new module deployment

Cross-module dependencies (read once before reading the module sections):

M1 (Registry) ──► M2 (Governance) ──► M4 (Mgmt Plan)
   │                  │
   │                  ├──► M3 (Economics) ──► (treasury → wrapper LLC)
   │                  │                                 ▲
   │                  └──► M6 (Upgrade)                 │
   │                                                    │
   └──► M5 (Attestation Hooks) ◄──── Registry contract (off-DAO; per `05-interfaces/04`)

                                          └──► Buffer pool (Foundation; per `05-interfaces/05`)

M1 is the membership substrate; M2 reads M1 for voting weight; M3 reads M1 for distribution share; M5 is a passive listener that updates state used by M3; M4 is content-addressed state ratified through M2; M6 governs replacement of any module.


M1 — Beneficiary Registry

1. Purpose

The list of named participants and their seats. Permissioned-only — entries added through governance, not market mechanism. M1 is the on-chain (or operating-agreement) source of truth for who has what authority and what economic share in this property’s vehicle. Every other module reads from M1.

2. Tier 1 implementation (Vermont LLC + multi-sig + operating-agreement clauses)

Encoded in operating agreement:

  • Named members with legal identity and seat designation (landowner-primary, family member, land-trust-officer, Landseed-steward, etc.)
  • Per-decision-class voting weight (use decisions, methodology decisions, treasury actions)
  • Distribution share for each member (M3 input)
  • Successor-designation clauses (per template; see Successor mechanics below)
  • Membership-admission procedure (signature requirements, notice periods)
  • Resignation and removal procedure
  • KYC representations and warranties

Encoded in multi-sig:

  • Signer set corresponding to operating-agreement-named members or their designated wallet operators
  • Threshold (typically 2-of-3 for Template A; institutional N-of-M for Template B; composed for F)
  • Daily/per-transaction limits aligned with operating-agreement treasury authority

Held off-chain by Landseed compliance:

  • KYC vendor records (Persona, Veriff, or Sumsub per 06-risks/04-proposed-resolutions.md Q10) — (vendor selection counsel-confirmation required)
  • KYC re-verification calendar (every 5 years, on succession, on material membership change)
  • Wallet-to-legal-identity mapping (the on-chain identifier in Tier 2 is opaque; the mapping lives only in compliance records)

3. Tier 2 implementation

(framework-agnostic; specific framework choice deferred — Aragon, Tally Governor, OpenZeppelin Governor, or custom Solidity all acceptable)

3.1 State variables

struct Beneficiary {
    address holder;              // current wallet (Q9 hybrid custodial/hardware/paper auth)
    uint8 class;                 // SeatClass enum: LANDOWNER, FAMILY, LAND_TRUST,
                                 //                 COMMUNITY_COUNCIL, CULTURAL_GUARDIAN,
                                 //                 ELDER, CORPORATE, SOVEREIGN,
                                 //                 LANDSEED_STEWARD, METHODOLOGY_GUARDIAN
    bytes32 kycRefHash;          // opaque pointer to off-chain KYC record (no PII on-chain)
    uint64 admittedAt;           // block.timestamp of admission ratification
    uint64 kycExpiresAt;         // block.timestamp at which KYC must be re-verified
    uint64 successorDeadline;    // block.timestamp; 0 if no pending succession
    bool active;                 // false on resignation/death/removal pending succession
}

mapping(uint256 => Beneficiary) internal _registry;     // memberId => Beneficiary
mapping(address => uint256) internal _holderToMemberId; // wallet => memberId (0 = none)
mapping(uint256 => mapping(uint8 => uint256)) internal _votingWeight;
                                                        // memberId => decisionClass => weight
mapping(uint256 => uint256) internal _distributionShareBps;
                                                        // memberId => basis points (sum ≤ 10_000)

bytes32 public successorRoot;     // merkle root of pre-declared successor designations
                                  // (used for fast-path replacement; see §3.4)
uint256 public memberCount;       // count of active members
uint256 public nextMemberId;      // monotonic; never reused
bool public kycRequired;          // template-level toggle (always true in current architecture)

uint8 public constant DECISION_USE = 0;
uint8 public constant DECISION_METHODOLOGY = 1;
uint8 public constant DECISION_TREASURY = 2;
uint8 public constant DECISION_CULTURAL = 3;          // Template C / F-with-C only
uint8 public constant DECISION_STEWARDSHIP = 4;
uint8 public constant DECISION_UPGRADE = 5;

3.2 Public function signatures

// Admission — gated by M2 governance proposal
function admitMember(
    address holder,
    uint8 class,
    bytes32 kycRefHash,
    uint256[6] calldata weightsByDecisionClass,
    uint256 distributionShareBps,
    bytes calldata governanceProof   // proof that an M2 proposal authorized this admission
) external onlyGovernance returns (uint256 memberId);

// Succession — gated by template-specific successor mechanic
function succeedMember(
    uint256 memberId,
    address newHolder,
    bytes32 newKycRefHash,
    bytes calldata successorProof    // template-dependent; merkle proof, FPIC ratification,
                                     // or institutional-procedure attestation
) external returns (bool);

// Resignation — member-initiated; triggers successor procedure per template
function resign(uint256 memberId) external;

// Removal — gated by M2 supermajority
function removeMember(
    uint256 memberId,
    bytes calldata governanceProof
) external onlyGovernance;

// KYC refresh — Landseed-compliance-officer-only update of expiration
function refreshKyc(
    uint256 memberId,
    bytes32 newKycRefHash,
    uint64 newExpiry
) external onlyComplianceOfficer;

// Successor root update (pre-declared successor merkle tree, per template)
function setSuccessorRoot(bytes32 newRoot, bytes calldata governanceProof)
    external onlyGovernance;

// Read-side
function getBeneficiary(uint256 memberId) external view returns (Beneficiary memory);
function getVotingWeight(uint256 memberId, uint8 decisionClass)
    external view returns (uint256);
function getDistributionShareBps(uint256 memberId) external view returns (uint256);
function isActive(uint256 memberId) external view returns (bool);
function totalVotingWeight(uint8 decisionClass) external view returns (uint256);
function totalDistributionShareBps() external view returns (uint256);

3.3 Internal/private functions

function _verifyKycLive(uint256 memberId) internal view;
    // reverts if kycExpiresAt < block.timestamp

function _validateWeights(uint256[6] memory weights) internal pure;
    // reverts on overflow; reverts on weight > MAX_PER_CLASS

function _validateDistributionShareInvariant() internal view;
    // sum of distributionShareBps across active members ≤ 10_000

function _verifySuccessorProof(
    uint256 memberId,
    address newHolder,
    bytes calldata proof,
    uint8 templateMechanic
) internal view returns (bool);

3.4 Events

event MemberAdmitted(
    uint256 indexed memberId,
    address indexed holder,
    uint8 indexed class,
    bytes32 kycRefHash,
    uint256 timestamp
);
event MemberSucceeded(
    uint256 indexed memberId,
    address indexed oldHolder,
    address indexed newHolder,
    bytes32 mechanism      // hash of successor mechanic + proof
);
event MemberResigned(uint256 indexed memberId, address indexed holder, uint256 timestamp);
event MemberRemoved(uint256 indexed memberId, bytes32 indexed governanceProposalId);
event KycRefreshed(uint256 indexed memberId, bytes32 newKycRefHash, uint64 newExpiry);
event SuccessorRootUpdated(bytes32 oldRoot, bytes32 newRoot);
event WeightUpdated(uint256 indexed memberId, uint8 indexed decisionClass, uint256 weight);
event DistributionShareUpdated(uint256 indexed memberId, uint256 oldBps, uint256 newBps);

3.5 Modifiers and access control

modifier onlyGovernance();         // msg.sender == address(governanceModule)
                                   // AND a current proposal authorizes the call
modifier onlyComplianceOfficer();  // msg.sendercomplianceOfficerSet
                                   // (multi-sig of Landseed compliance officers)
modifier onlyHolder(uint256 memberId);
modifier kycCurrent(uint256 memberId);
                                   // reverts if KYC expired
modifier nonTransferableInvariant();
                                   // ensures no path other than succeedMember / removeMember
                                   // changes the holder of a position

4. Invariants

The auditor must verify each of these holds across all reachable contract states:

#Invariant
M1.1Non-transferable: only succeedMember and removeMember can change the holder of an existing memberId. No transfer, no approve, no setHolder external function exists.
M1.2KYC-gated: any state-changing function on a member’s behalf reverts if _verifyKycLive(memberId) reverts. (Read functions exempt.)
M1.3Sum-of-shares ≤ 100%: Σ distributionShareBps[i] for active i ≤ 10_000. Enforced atomically on every admitMember, removeMember, resign.
M1.4Per-class total voting weight is computable and non-zero: totalVotingWeight(class) > 0 for every class active in the deployed configuration.
M1.5Succession completeness: a memberId in successorDeadline > 0 state cannot vote, propose, or receive distributions until succession resolves.
M1.6Monotonic memberIds: nextMemberId only increases; memberIds are never reused.
M1.7No self-admission: admitMember cannot be invoked except via onlyGovernance. The contract itself is not a holder.
M1.8Wallet uniqueness: at any block, each holder address maps to at most one active memberId.
M1.9KYC-hash opacity: no on-chain logic interprets kycRefHash semantically; it is treated as an opaque pointer.
M1.10Successor root consistency: when successorRoot is non-zero, every fast-path succession proof must verify against it; absence of root falls back to template-procedural succession with explicit governance ratification.

5. Threat model

ThreatMechanismMitigation
Sybil admissionAdversary causes M2 to admit a synthetic identityKYC-hash gate; off-chain KYC vendor; admission requires governance proof; admission events surface in attestation chain
Voting-weight inflationAdmit, resign, re-admit cycle to boost weight, or admit with inflated weight_validateWeights cap per class; M2 supermajority required for admission; M1.6 monotonic memberIds prevent re-use
Identity theft / wallet compromiseAdversary acquires holder’s private keyQ9 hybrid custodial/hardware/paper auth; succession path with _verifySuccessorProof allows override; compliance officer can flag KYC and force re-verification
KYC bypassCaller invokes state-changing function with stale KYCModifier kycCurrent reverts; kycExpiresAt enforced
Distribution-share overflowSum > 10_000 bps via reentrancy or out-of-order updatesAtomic _validateDistributionShareInvariant on every mutation; nonReentrant on admission/succession/removal
Successor-root tamperingAdversary persuades governance to set a successor root that pre-authorizes their own admissionsetSuccessorRoot requires governance proof; M2 supermajority; 30-day delay (per M6); guardian veto (M2)
Removal-as-coupCoalition removes a dissenting member via M2 majorityremoveMember requires supermajority threshold (template-defined; see M2); guardian veto applies; cultural-guardian veto in C/F-with-C
Front-running of admissionMEV attack on admission to extract valueAdmission has no economic side-effect that can be MEV-extracted; distribution share is set at admission and unchanged until governance acts
PII leakAn on-chain field reveals KYC contentkycRefHash is bytes32 opaque pointer; no PII on-chain by construction (M1.9)

6. Per-template variations

TemplateSeat compositionSuccessor mechanicNotable variations
A — SoloLandowner-primary + family seats (1–4) + Landseed stewardOperating-agreement inheritance (Tier 1 only); merkle-tree pre-declaration if Tier 2 ever appliedKYC re-verification on inheritance event; family-disagreement fallback per OA
B — Land TrustLand-trust-officer + Landseed steward (+ optional independent stewardship advisor)Institutional procedure (board action); successor land trust on M&A inherits per OAOA carves out measurement-standing if conservation easement involves same trust
C — IndigenousCommunity-council seats (multiple) + cultural-guardian + elder seats + Landseed stewardCommunity-determined; DAO ratifies procedurally, does not vote substantivelySuccessor-determination is community-internal; on-chain ratification is procedural; cultural-guardian seat has distinct veto class (DECISION_CULTURAL)
D — CorporateCorporate officer + ESG-observer + Landseed stewardCorporate succession (board action, M&A)Quarterly disclosure obligations encoded in OA; no FPIC class
E — SovereignSovereign-agency designee + local management + Landseed stewardPer agency succession; political-disruption fallbackSovereign seat has residual authority on national-policy class; treaty-reporting OA hook
F — HybridComposed seats from underlying templates (e.g., E + C)Per-seat: each follows underlying template’s mechanicCross-stakeholder dispute path required (M2); per-deployment audit required
G — StewardshipFoundation officers + Landseed stewardFoundation successionAll distribution to stewardship reserve (M3 reduces in size)

7. External dependencies

  • M2 (Governance) — caller of admitMember, removeMember, setSuccessorRoot
  • M3 (Economics) — reads getDistributionShareBps
  • M5 (Attestation hooks) — reads beneficiary set for distribution-event correlation only
  • M6 (Upgrade Path) — controls upgradeability of M1 itself
  • Off-chain KYC vendor — produces kycRefHash; vendor outage stalls admissions but does not affect existing operations (vendor selection counsel-confirmation required)
  • Compliance officer multi-sig — external multi-sig contract address held in complianceOfficerSet; no DAO-internal cycle

8. Audit-scoping notes

  • Estimated audit hours: 60–90 hours for M1 standalone in initial library audit
  • Required auditor expertise: Solidity; access-control and modifier patterns; merkle-proof verification (for successorRoot); familiarity with OpenZeppelin AccessControl or equivalent
  • Highest-risk areas: succession path (especially Template C’s procedural-ratification distinction); distribution-share invariant under reentrancy; KYC expiry handling under clock manipulation; opacity of kycRefHash
  • Test coverage required: 100% for admitMember, succeedMember, removeMember, _validateDistributionShareInvariant; fuzzing on weight/share inputs; symbolic execution on M1.1 non-transferability invariant
  • Known pseudocode gaps: _verifySuccessorProof is template-dependent; per-template instantiation must be re-audited
  • Audit-first dependency: M1 must be audited before M2, M3, or M5 since they read M1 state

M2 — Governance

1. Purpose

The decision-making layer. Encodes proposal types, voting rules, supermajority thresholds, time delays, FPIC checkpoints, and guardian vetoes. M2 is the only module authorized to mutate M1, M3 parameters, M4 plan-version pointer, and M5 configuration. M6 upgrades go through M2 with additional time-delay and guardian gates.

2. Tier 1 implementation

Encoded in operating agreement:

  • Decision classes (use, methodology, treasury, cultural where applicable, stewardship-reserve, module-upgrade) and which member classes vote on each
  • Voting thresholds per decision class (simple majority, supermajority, unanimous)
  • Notice periods per decision class (typically 60 days for methodology adoption; 30 days for module upgrade)
  • FPIC checkpoint procedures (Template C/F-with-C only)
  • Methodology-guardian veto procedure (Landseed-officer multi-sig); cultural-guardian veto (community-designated)
  • Quorum requirements; tie-breaking; abstention treatment
  • Recordkeeping: written notice, signed ratification, retention period
  • Dispute and mediation clauses

Encoded in multi-sig:

  • Treasury-action ratification by multi-sig signature (typically 2-of-3 for A/B; N-of-M composed for F)
  • Daily/per-transaction limits below which multi-sig acts without separate operating-agreement procedure
  • Emergency procedures for guardian veto execution

Held off-chain by Landseed compliance:

  • Proposal records (PDF, signed scans, board-meeting minutes for B)
  • FPIC deliberation transcripts (Template C only; community-controlled retention)

3. Tier 2 implementation

3.1 State variables

struct Proposal {
    uint256 id;
    address proposer;            // must hold a member seat with proposer rights
    uint8 decisionClass;         // see DECISION_* constants from M1
    uint8 proposalKind;          // ADMIT_MEMBER, REMOVE_MEMBER, AMEND_PARAMETER,
                                 // RATIFY_PLAN, UPGRADE_MODULE, EXECUTE_TREASURY,
                                 // ADOPT_METHODOLOGY, RATIFY_SUCCESSOR, ...
    bytes32 contentHash;         // hash of off-chain proposal description (IPFS / Software
                                 // Heritage)
    bytes payload;               // calldata to execute on success
    address target;              // contract to call on execution
    uint64 createdAt;
    uint64 votingStartsAt;       // createdAt + noticePeriod[decisionClass]
    uint64 votingEndsAt;
    uint64 timelockEndsAt;       // votingEndsAt + delay[decisionClass]
    uint64 guardianVetoEndsAt;   // timelockEndsAt + guardianWindow
    uint8 status;                // PENDING, ACTIVE, PASSED, FAILED, VETOED, EXECUTED, EXPIRED
    uint256 yesWeight;           // weighted by voting power for decisionClass
    uint256 noWeight;
    uint256 abstainWeight;
    bool fpicRequired;           // C / F-with-C only
    bytes32 fpicEvidenceHash;    // 0 until cultural guardian non-objection / community
                                 // ratification recorded
}

mapping(uint256 => Proposal) internal _proposals;
mapping(uint256 => mapping(uint256 => bool)) internal _hasVoted;
                                                  // proposalId => memberId => voted

uint256 public nextProposalId;
mapping(uint8 => uint64) public noticePeriod;     // by decisionClass; seconds
mapping(uint8 => uint64) public votingPeriod;     // by decisionClass; seconds
mapping(uint8 => uint64) public timelockDelay;    // by decisionClass; seconds
mapping(uint8 => uint256) public passingThresholdBps;
                                                  // basis points of total weight needed
mapping(uint8 => uint256) public quorumBps;       // basis points of total weight
uint64 public guardianWindow;                     // typically 7–30 days

address public methodologyGuardian;               // multi-sig (Landseed officers)
address public culturalGuardian;                  // 0x0 unless C / F-with-C
mapping(uint8 => bool) public requiresMethodologyGuardianNonObjection;
mapping(uint8 => bool) public requiresCulturalGuardianNonObjection;
mapping(uint8 => bool) public requiresFPIC;       // by decisionClass

3.2 Public function signatures

function propose(
    uint8 decisionClass,
    uint8 proposalKind,
    bytes32 contentHash,
    address target,
    bytes calldata payload
) external onlyMember returns (uint256 proposalId);

function castVote(uint256 proposalId, uint8 support)
    external onlyMember kycCurrent(memberIdOfSender);
    // support: 0 = no, 1 = yes, 2 = abstain

function recordFpicEvidence(uint256 proposalId, bytes32 evidenceHash)
    external onlyCulturalGuardian;
    // For C / F-with-C: cultural guardian or community council records FPIC ratification

function vetoMethodology(uint256 proposalId)
    external onlyMethodologyGuardian;
    // callable only during guardianVetoEndsAt window;
    // restricted to proposals affecting ecological-condition floor

function vetoCultural(uint256 proposalId)
    external onlyCulturalGuardian;
    // restricted to DECISION_CULTURAL or culturally-relevant proposals

function execute(uint256 proposalId) external;
    // anyone may trigger; reverts unless status == PASSED && now > timelockEndsAt
    // && guardianVetoEndsAt has passed && all required non-objections recorded

function cancel(uint256 proposalId) external onlyProposer;
    // proposer can withdraw before votingStartsAt

// Read-side
function getProposal(uint256 proposalId) external view returns (Proposal memory);
function votingPower(uint256 memberId, uint8 decisionClass)
    external view returns (uint256);
function quorumReached(uint256 proposalId) external view returns (bool);
function passingThresholdMet(uint256 proposalId) external view returns (bool);

3.3 Internal/private functions

function _validateProposal(uint8 decisionClass, uint8 proposalKind) internal view;
function _snapshotVotingWeights(uint256 proposalId) internal;
    // captures M1 weights at proposal creation; prevents re-admission gaming
function _checkFpicCompliance(uint256 proposalId) internal view returns (bool);
function _checkGuardianClearance(uint256 proposalId) internal view returns (bool);
function _enforceTimelock(uint256 proposalId) internal view;
function _executeCall(address target, bytes memory payload) internal returns (bytes memory);

3.4 Events

event ProposalCreated(
    uint256 indexed proposalId,
    address indexed proposer,
    uint8 indexed decisionClass,
    uint8 proposalKind,
    bytes32 contentHash,
    uint64 votingStartsAt,
    uint64 votingEndsAt
);
event VoteCast(
    uint256 indexed proposalId,
    uint256 indexed memberId,
    uint8 support,
    uint256 weight
);
event FpicEvidenceRecorded(uint256 indexed proposalId, bytes32 evidenceHash);
event ProposalPassed(uint256 indexed proposalId, uint256 yesWeight, uint256 totalWeight);
event ProposalFailed(uint256 indexed proposalId, uint8 reason);
event ProposalVetoed(uint256 indexed proposalId, address indexed guardian, uint8 vetoKind);
event ProposalExecuted(uint256 indexed proposalId, bytes returnData);
event ProposalCancelled(uint256 indexed proposalId);
event ParameterChanged(uint8 indexed decisionClass, bytes32 indexed paramKey, uint256 oldVal, uint256 newVal);

3.5 Modifiers and access control

modifier onlyMember();              // msg.sender is active holder of an M1 memberId
modifier onlyMethodologyGuardian(); // msg.sender == methodologyGuardian multi-sig
modifier onlyCulturalGuardian();    // msg.sender == culturalGuardian; reverts if 0x0
modifier onlyProposer(uint256 proposalId);
modifier inVotingWindow(uint256 proposalId);
modifier afterTimelock(uint256 proposalId);

4. Invariants

#Invariant
M2.1One vote per member per proposal: _hasVoted[proposalId][memberId] enforces idempotency.
M2.2Voting-weight snapshot immutability: weights are snapshotted at proposalId creation; subsequent M1 mutations do not change this proposal’s tallies.
M2.3No execution before timelock: execute reverts unless block.timestamp > timelockEndsAt && block.timestamp > guardianVetoEndsAt.
M2.4Guardian veto is irreversible per proposal: once vetoed, status = VETOED and proposal cannot be re-executed without a new proposal.
M2.5FPIC gate in C/F-with-C: for proposals where fpicRequired == true, execute reverts unless fpicEvidenceHash != 0.
M2.6Quorum required: passingThresholdMet requires quorumReached.
M2.7Self-call only via execution: M2 cannot mutate its own parameters except via execute of a UPGRADE_MODULE or AMEND_PARAMETER proposal.
M2.8Methodology guardian cannot veto cultural decisions and vice versa: vetoCultural reverts on non-cultural decision class; vetoMethodology reverts on cultural-only decisions. The two guardian roles are non-overlapping (per current architecture).
M2.9Proposer must be active member at proposal creation: propose checks M1.isActive.
M2.10Timelock cannot be set to zero by parameter change: minimum non-zero timelock for DECISION_UPGRADE is 30 days hardcoded as a MIN_UPGRADE_DELAY constant.
M2.11Re-entrant execution prevented: execute is nonReentrant; payloads cannot recursively call execute on the same proposal.

5. Threat model

ThreatMechanismMitigation
Majority captureCoalition with >threshold weight passes self-serving proposalsSupermajority for high-stakes classes (UPGRADE, METHODOLOGY); guardian veto on destruction; FPIC in C; cultural guardian veto in C
Vote-weight gamingRe-admit a member with inflated weight before a critical voteM2.2 snapshot immutability; M1 admission requires governance; admission notice period exposes the maneuver
Front-running governance proposalsMEV-bot front-runs propose to claim rewards or blockNo economic reward for proposing; proposer is identified; proposals are not value-extractable
Flash-loan voting (theoretical)Acquire voting weight via flash loanNon-transferable membership (M1.1) eliminates this attack vector by construction
Censorship of votesBlock producer censors castVote near votingEndsAtVoting periods are days/weeks long; sub-block-level censorship is not material
Guardian collusionMethodology guardian and cultural guardian collude to veto everythingM2.8 limits each guardian’s veto domain; guardian roles are external multi-sigs with documented signers; collusion requires both multi-sigs to act in concert; recourse is M2 governance to replace guardians (with Foundation-level escalation)
Guardian unresponsivenessMethodology guardian is offline during a critical proposalguardianVetoEndsAt is a fixed window; absence of veto = clearance; quorum on the multi-sig can be re-established off-chain
Timelock bypass via reentrancyPayload calls execute recursivelyM2.11 nonReentrant; M2.3 timestamp gate
FPIC forgeryBad actor records false fpicEvidenceHashrecordFpicEvidence is onlyCulturalGuardian; cultural guardian is community-designated and held to community-internal audit (NURJ §IV.E)
Time-warp attacks (block.timestamp manipulation)Validator manipulates timestamp to bypass timelockTimelocks measured in days; ±15s validator drift immaterial; flagged for L2-specific audit
Proposal-storm DoSMember spams proposals to clog the pipelineMember-class proposer rights gate; off-chain proposal-content cost (IPFS pinning) imposes friction; M2 may add per-member proposal cooldowns at deployment
Calldata smuggling in payloadProposal payload calls unauthorized functions on target_executeCall only invokes whitelisted targets; M1, M3, M4, M5, M6 contracts each enforce onlyGovernance independently

6. Per-template variations

TemplateVoting modelFPICCultural guardianNotable
A — SoloLandowner supermajority on use; Landseed-ratified methodology; multi-sig treasuryn/an/aTier 1; not on-chain. If Tier 2 ever applied, simple Governor pattern.
B — Land TrustInstitutional board-style majority; two-key on material plan changesn/an/aTier 1; institutional governance referenced in OA.
C — IndigenousCommunity-council supermajority; FPIC-gated on every methodology/plan change; cultural-guardian non-objection on culturally relevant actionsRequired for methodology adoption, plan amendment, sensor deployment, external publication, non-community-member admissionRequired seat; veto on DECISION_CULTURALTier 2 mandatory; per-deployment audit; longer notice periods (60 days minimum)
D — CorporateCorporate-officer-board majority; ESG observer non-bindingn/an/aQuarterly disclosure obligation; ESG observer has read access to proposal stream
E — SovereignSovereign-residual on national-policy class; operational delegationn/an/aTreaty-reporting obligation; political-disruption fallback (operating-agreement-defined)
F — HybridDecision-class routing across composed seats; mediation-first dispute resolutionRequired if C-componentRequired if C-componentPer-deployment audit; explicit conflict resolution mechanism in M2 (mediator address; fallback to OA arbitration)
G — StewardshipFoundation board-style majorityn/an/aTier 1; foundation procedures govern

7. External dependencies

  • M1 (Beneficiary Registry) — voting weights and active-member set
  • M3, M4, M5, M6 — execution targets
  • Methodology guardian multi-sig — external multi-sig contract (Landseed officers); address stored in methodologyGuardian
  • Cultural guardian — for C/F-with-C; community-designated multi-sig
  • Off-chain proposal content — IPFS / Software Heritage pinning (not yet built); content-hash referenced on-chain

8. Audit-scoping notes

  • Estimated audit hours: 120–180 hours for M2 standalone in initial library audit (largest module by complexity)
  • Required auditor expertise: Solidity governance patterns; OpenZeppelin Governor / Aragon OSx / Tally Governor familiarity strongly preferred; timelock and access-control patterns; reentrancy and snapshot semantics
  • Highest-risk areas: weight snapshot consistency under M1 mutations during a proposal; timelock bypass via payload calldata; guardian-veto window edge cases; FPIC-gate enforcement for C; cross-module call routing
  • Test coverage required: 100% for propose, castVote, execute, vetoMethodology, vetoCultural; fuzzing on threshold and quorum boundaries; invariant testing on M2.2, M2.3, M2.5, M2.10
  • Audit-first dependency: depends on M1 audit completion. Cross-module integration tests with M3/M4/M5/M6 happen after each is independently audited.

M3 — Economics

1. Purpose

Distribution rules. Splits inflows from credit sales according to the template’s distribution philosophy. The benefits model lives here. M3 is parametric within bright-line constraints (no tradeable units, no DeFi, conservative treasury). It reads M1 for distribution shares and M5 for inflow events (so that distributions can be correlated with the attestation that produced them).

2. Tier 1 implementation

Encoded in operating agreement:

  • Distribution percentages per recipient (within parameter ranges; see deploy parameters below)
  • Distribution cadence (annual, quarterly, on-event)
  • Distribution form: cash only (Bright Line 6 in 04-perimeter/); in-kind credit distribution only if Q1 in 06-risks/ resolves favorably (counsel-confirmation required; currently set aside)
  • Stewardship reserve drawdown procedure (documented work; multi-sig signoff)
  • Landseed protocol fee rate (2–5%)
  • Reserve maintenance and reinvestment policy
  • Tax-treatment representations (counsel-confirmation required per jurisdiction)

Encoded in multi-sig:

  • Disbursement transactions (USDC or stablecoin-of-record)
  • Daily/per-transaction limits
  • Multi-sig threshold for distribution execution

Held off-chain by Landseed compliance:

  • Per-distribution worksheets (pre-distribution computation, recipient acknowledgments)
  • Tax-form generation (1099-MISC for US; equivalents per jurisdiction)
  • Annual financial statements (Form 990 for nonprofit-held templates)

3. Tier 2 implementation

3.1 State variables

struct Recipient {
    uint8 kind;                 // RECIPIENT_MEMBER, RECIPIENT_RESERVE, RECIPIENT_PROTOCOL_FEE,
                                // RECIPIENT_COMMUNITY_FUND, RECIPIENT_SOVEREIGN_FUND,
                                // RECIPIENT_STEWARDSHIP_RESERVE, RECIPIENT_BUFFER_POOL_FEE
    address payoutAddress;      // wallet or contract receiving funds (e.g., Foundation
                                // buffer-pool address per `05-interfaces/05`)
    uint256 shareBps;           // basis points of net inflow
    uint256 memberId;           // M1 reference if kind == RECIPIENT_MEMBER, else 0
    bool active;
}

mapping(uint256 => Recipient) internal _recipients;  // recipientId => Recipient
uint256 public nextRecipientId;
uint256 public totalShareBps;                        // must always equal 10_000

uint8 public distributionCadence;                    // ANNUAL, QUARTERLY, ON_EVENT
uint64 public lastDistributionAt;
uint64 public nextDistributionWindowOpensAt;

address public stablecoinOfRecord;                   // USDC or template-deployment-defined
                                                     // *(not yet locked; specific address
                                                     // configured at deployment)*
uint256 public stewardshipReserveBalance;            // accounting balance, not held tokens
uint256 public protocolFeeBps;                       // 200..500 (2–5%)
uint256 public bufferPoolFeeBps;                     // 0 here; buffer is taken pre-DAO at
                                                     // registry layer (per `05-interfaces/05`)

mapping(bytes32 => uint256) internal _inflowsByAttestation;
                                                     // attestationReceiptHash => amount
mapping(bytes32 => bool) internal _attestationDistributed;

3.2 Public function signatures

function recordInflow(
    uint256 amount,
    bytes32 attestationReceiptHash,    // links revenue to specific cryptographically
                                        // attested credit-issuance event (M5)
    bytes calldata registryProof        // proves inflow originated from registry
                                        // (per `05-interfaces/04`)
) external onlyAttestationHook;

function distribute(bytes32 attestationReceiptHash) external nonReentrant;
    // anyone may trigger; reverts unless cadence window open or ON_EVENT triggered
    // executes split per active recipients

function addRecipient(
    uint8 kind,
    address payoutAddress,
    uint256 shareBps,
    uint256 memberId
) external onlyGovernance returns (uint256 recipientId);

function updateRecipientShare(uint256 recipientId, uint256 newShareBps)
    external onlyGovernance;

function deactivateRecipient(uint256 recipientId) external onlyGovernance;

function drawStewardshipReserve(
    uint256 amount,
    address recipient,
    bytes32 documentationHash,    // hash of work-order / invoice / approval record
    bytes calldata governanceProof
) external onlyGovernance;

function setCadence(uint8 newCadence, uint64 newWindowStart) external onlyGovernance;

function setStablecoinOfRecord(address newStablecoin)
    external onlyGovernance;
    // requires M2 supermajority + 30-day delay; ties to migration-safety commitment

// Read-side
function getRecipient(uint256 recipientId) external view returns (Recipient memory);
function previewDistribution(uint256 amount)
    external view returns (uint256[] memory shares, address[] memory payouts);
function distributionHistory(bytes32 attestationReceiptHash)
    external view returns (uint256 amount, uint64 distributedAt);

3.3 Internal/private functions

function _validateShareSum() internal view;
    // sum of active shareBps == 10_000 exactly
function _allocate(uint256 amount) internal returns (uint256[] memory);
function _settle(uint256[] memory shares, Recipient[] memory rs) internal;
    // ERC-20 transfer per recipient; failure reverts the entire batch (atomicity)
function _accrueStewardshipReserve(uint256 amount) internal;

3.4 Events

event InflowRecorded(
    bytes32 indexed attestationReceiptHash,
    uint256 amount,
    address stablecoin
);
event DistributionExecuted(
    bytes32 indexed attestationReceiptHash,
    uint256 totalAmount,
    uint64 timestamp
);
event RecipientPaid(
    uint256 indexed recipientId,
    address indexed payout,
    uint256 amount,
    uint8 kind
);
event RecipientAdded(uint256 indexed recipientId, uint8 kind, uint256 shareBps);
event RecipientShareUpdated(uint256 indexed recipientId, uint256 oldBps, uint256 newBps);
event RecipientDeactivated(uint256 indexed recipientId);
event StewardshipDrawn(uint256 amount, address recipient, bytes32 documentationHash);
event CadenceChanged(uint8 oldCadence, uint8 newCadence, uint64 windowStart);
event StablecoinChanged(address oldStablecoin, address newStablecoin);

3.5 Modifiers and access control

modifier onlyAttestationHook();    // msg.sender == address(M5)
modifier onlyGovernance();         // msg.sender == address(M2)
modifier nonReentrant();
modifier inDistributionWindow();

4. Invariants

#Invariant
M3.1Sum-of-shares == 100%: Σ shareBps for active recipients == 10_000. Enforced atomically on add/update/deactivate.
M3.2Cash-only: distributions are in stablecoinOfRecord. No path emits ERC-20 transfers other than the configured stablecoin. (Bright Line 6.)
M3.3No DeFi yield: M3 has no lend, stake, swap, or external-protocol-call surface beyond ERC-20 transfer to recipients.
M3.4Inflow→distribution traceability: every distribution references a non-zero attestationReceiptHash; _attestationDistributed[hash] prevents double-distribution.
M3.5Stewardship reserve only by governance: drawStewardshipReserve requires onlyGovernance.
M3.6Atomic settle: a failure on any recipient transfer reverts the entire distribute call; partial distributions are impossible.
M3.7No tradeable units emitted: M3 emits no ERC-20-token-mint or ERC-721-mint operation. (Per Principle 2.)
M3.8No cross-property inflows: M3 accepts inflows only from the registered registry contract for this property; cross-property routing is prevented at recordInflow via registryProof validation.
M3.9Protocol fee rate bounded: protocolFeeBps ∈ [200, 500] (2–5%); changes require M2 supermajority.

5. Threat model

ThreatMechanismMitigation
Distribution-share manipulationAdversary updates shares pre-distribution to redirect fundsupdateRecipientShare is onlyGovernance (M2 vote + timelock + guardian window); 30-day delay exposes the maneuver
Double-distributionSame attestationReceiptHash distributed twiceM3.4 mapping prevents replay
Inflow spoofingAdversary calls recordInflow with fake registryProofonlyAttestationHook modifier; registryProof validated against registry contract address (per 05-interfaces/04)
Cross-property contaminationInflows from one property reach another’s M3M3.8; per-property isolation hardcoded at deployment
Stablecoin migration risk (USDC depeg / sanction freeze)Configured stablecoin loses value or freezessetStablecoinOfRecord migration path; 30-day delay; graceful migration plan documented in OA
Fee-rate creepProtocol fee gradually raised by Landseed-aligned majorityM3.9 hardcoded bounds; M2 supermajority; counsel-confirmed at deployment
DeFi-integration creepFuture M3 upgrade adds yield farmingM6 upgrade path requires guardian veto; “no DeFi” is a Bright Line; deviating triggers Foundation escalation
Reentrancy on distributeRecipient contract reenters during transfernonReentrant; recipients should be EOAs or audited multi-sigs (validated at addRecipient)
Stewardship-reserve raidDrawn without documented workdocumentationHash required; onlyGovernance; multi-sig signoff on Tier 1 mirror
Buffer-pool double-takeBuffer fee deducted at registry AND at DAOM3.bufferPoolFeeBps == 0 by construction; buffer is taken pre-DAO per 05-interfaces/05; auditor must verify zero
Recipient-address poisoningGovernance adds an attacker-controlled recipientaddRecipient requires M2 + timelock + guardian window; addresses logged in events for outside scrutiny

6. Per-template variations

The distribution waterfall differs substantially across templates. Parameter ranges:

RecipientTemplate ATemplate BTemplate CTemplate DTemplate ETemplate FTemplate G
Direct landowner / institutional principal60–85%60–80% (land trust)n/a (community fund)70–90% (corporate)n/acomposedn/a (foundation)
Community fundn/an/a40–80%n/an/acomposedn/a
Sovereign environmental fundn/an/an/an/a60–80%composedn/a
Stewardship reserve (property-specific)5–25%10–25%5–15%5–15%10–25%composedAll to stewardship
Cultural-guardian discretionary fundn/an/a5–15%n/an/acomposed (if C component)n/a
Landseed protocol fee2–5%2–5%2–5%2–5%2–5%2–5%2–5%
Reserve / residual5–25%5–10%per community5–25%per agencycomposedper foundation

Sum must equal 100% per deployment. Specific values are configured in operating-agreement (Tier 1) or at constructor / governance-set parameters (Tier 2).

Template C: distribution-within-community-fund logic is intentionally not encoded in M3. The community fund payout is a single payoutAddress from M3’s perspective; how the community then distributes internally (elder fund, language preservation, youth education) is community-internal and off-DAO. This is a NURJ-paper-grounded choice (data sovereignty; cultural protocols are not Landseed’s to encode).

7. External dependencies

  • M1 (Registry) — distribution shares for RECIPIENT_MEMBER recipients
  • M5 (Attestation Hooks) — calls recordInflow
  • Registry contract (off-DAO) — origin of inflows; attestation receipts; per 05-interfaces/04
  • Methodology Foundation buffer pool — separate registry account; receives buffer-pool credits at issuance time, not through M3 (per 05-interfaces/05)
  • Stablecoin contract — USDC or deployment-configured; (specific address counsel-and-treasury-confirmation required)

8. Audit-scoping notes

  • Estimated audit hours: 60–80 hours for M3 standalone in initial library audit
  • Required auditor expertise: Solidity; ERC-20 transfer patterns; reentrancy and atomicity guarantees; familiarity with payment-router and PaymentSplitter patterns (OpenZeppelin)
  • Highest-risk areas: invariant M3.1 (sum-of-shares) under concurrent governance updates; reentrancy on settle; cross-property-contamination-prevention proof; stewardship-reserve drawdown audit trail
  • Test coverage required: 100% for recordInflow, distribute, addRecipient, updateRecipientShare; fuzzing on share sums; reentrancy fuzzing; multi-recipient settlement testing
  • Per-template variation: distribution shares are parameter-only, not code; M3 contract code is uniform across templates A through G
  • Audit-first dependency: depends on M1; integrates with M5

M4 — Management Plan Ratification

1. Purpose

Versioned forest, invasive-species, harvest, and restoration plans. The LLC/DAO ratifies each version through M2; the active version pointer is M4 state. M4 liberates v1.2’s static prescription content from the deed by making it amendable through governance. M4 stores only content hashes; full plan documents live off-chain (IPFS / Software Heritage / counsel-archived).

2. Tier 1 implementation

Encoded in operating agreement:

  • Plan-amendment procedure (proposal, notice, ratification by member signature)
  • Effective-period definition (when does ratified version take effect)
  • Plan-content scope: forestry, invasive species, riparian buffers, harvest schedules, restoration milestones
  • Reference to current plan version by content hash
  • Coordination with conservation easement (Template B) — “more restrictive controls” rule per element 10 of NRD-lite

Held off-chain by Landseed compliance:

  • Plan-content PDFs (signed)
  • Ratification records (board minutes for B; landowner signatures for A)
  • Plan-version history archive

3. Tier 2 implementation

3.1 State variables

struct PlanVersion {
    bytes32 contentHash;        // hash of plan document (off-chain; IPFS or
                                // Software Heritage anchor)
    bytes32 storageUri;         // pointer to retrieval location (URI hash)
    uint64 ratifiedAt;
    uint64 effectiveFrom;
    uint64 effectiveUntil;      // 0 = open-ended until next ratification
    uint256 ratifyingProposalId; // M2 proposalId that ratified
    uint8 status;               // PROPOSED, RATIFIED, ACTIVE, SUPERSEDED, EXPIRED, REVOKED
    bytes32 priorVersionHash;   // chain-of-versions integrity
}

mapping(uint256 => PlanVersion) internal _versions;     // versionId => PlanVersion
uint256 public nextVersionId;
uint256 public activeVersionId;                          // 0 if none
mapping(bytes32 => uint256) internal _versionByHash;

3.2 Public function signatures

function proposePlanVersion(
    bytes32 contentHash,
    bytes32 storageUri,
    uint64 effectiveFrom,
    bytes32 priorVersionHash
) external onlyMember returns (uint256 versionId);

function ratifyPlanVersion(uint256 versionId, uint256 ratifyingProposalId)
    external onlyGovernance;

function activatePlanVersion(uint256 versionId) external onlyGovernance;
    // promotes RATIFIED → ACTIVE; supersedes prior active version

function revokePlanVersion(uint256 versionId, bytes calldata governanceProof)
    external onlyGovernance;
    // rare; emergency only

// Read-side
function getActiveVersion() external view returns (PlanVersion memory);
function getVersion(uint256 versionId) external view returns (PlanVersion memory);
function versionByHash(bytes32 contentHash) external view returns (uint256 versionId);

3.3 Internal/private functions

function _verifyChainIntegrity(uint256 newVersionId) internal view;
    // priorVersionHash must equal contentHash of currently active version (or 0 for genesis)
function _supersedeActive(uint256 newVersionId) internal;

3.4 Events

event PlanVersionProposed(
    uint256 indexed versionId,
    bytes32 indexed contentHash,
    bytes32 priorVersionHash,
    address proposer
);
event PlanVersionRatified(
    uint256 indexed versionId,
    uint256 indexed ratifyingProposalId,
    uint64 effectiveFrom
);
event PlanVersionActivated(
    uint256 indexed versionId,
    uint256 indexed supersededVersionId
);
event PlanVersionRevoked(uint256 indexed versionId, bytes32 reasonHash);

3.5 Modifiers and access control

modifier onlyMember();
modifier onlyGovernance();
modifier validVersion(uint256 versionId);

4. Invariants

#Invariant
M4.1At most one active version: at any block, exactly one or zero versionId has status == ACTIVE.
M4.2Chain-of-versions integrity: priorVersionHash of a new version equals contentHash of the prior active version (or zero for genesis).
M4.3Content-addressed: versionByHash[contentHash] is uniquely defined; no two versions share a contentHash.
M4.4Ratification through M2 only: ratifyPlanVersion and activatePlanVersion are onlyGovernance.
M4.5No content on-chain: M4 never stores plan-document text; only the hash and URI.
M4.6Effective-from monotonicity: a new active version’s effectiveFrom is the prior version’s ratifiedAt.

5. Threat model

ThreatMechanismMitigation
Plan-content swapOff-chain document at URI changes after ratificationContent-addressed (M4.3); URI is a hint, hash is the truth; auditors and members verify hash before voting
Storage availabilityIPFS pin lapses; document unrecoverableTriple archive: IPFS + Software Heritage + counsel-archived paper (per Q-archival-1 in 06-risks/)
Ratification of malicious planCoalition ratifies plan that violates ecological-condition floorM2 supermajority; methodology guardian veto (Landseed); cultural guardian non-objection in C
Chain-of-versions splitTwo competing versions ratified concurrentlyM2 sequential proposal execution; chain-integrity check on activation
Genesis-version disputeFirst version’s priorVersionHash == 0 is contestedGenesis recorded at deployment; cross-referenced in OA and NRD-lite
Revocation abuseActive plan revoked without replacement, leaving property in plan-less staterevokePlanVersion requires governance; OA fallback to prior version on revocation; flagged for audit edge-case testing

6. Per-template variations

TemplatePlan amendment procedureNotable
A — SoloStandard OA amendment (landowner signature)Tier 1
B — Land TrustInstitutional approval (board action) + Landseed methodology checkTier 1; coordination with conservation easement
C — IndigenousFPIC-gated: community-council majority + cultural guardian non-objection60-day deliberation period mandatory
D — CorporateInstitutional approval + ESG observer reviewQuarterly disclosure of plan changes
E — SovereignSovereign approval (agency action)Treaty-reporting obligation
F — HybridComposed: each component approval requiredCross-component conflict resolution per M2
G — StewardshipFoundation approvalTier 1

7. External dependencies

  • M2 (Governance) — proposal/ratification trigger
  • Off-chain content store — IPFS, Software Heritage, paper (triple-archive not yet built; commitment per Q-archival-1)
  • NRD-lite hash pinning — methodology hash referenced; plan version is separate from methodology version

8. Audit-scoping notes

  • Estimated audit hours: 30–50 hours for M4 standalone
  • Required auditor expertise: Solidity; content-addressed-storage patterns; state-machine verification
  • Highest-risk areas: chain-of-versions integrity (M4.2); concurrent ratification race conditions; revocation edge cases
  • Test coverage required: 100% for proposePlanVersion, ratifyPlanVersion, activatePlanVersion; chain-integrity property tests; concurrent-proposal fuzzing

M5 — Attestation Hooks

1. Purpose

The Layer 2 vehicle consumes EC-M-1.1 attestations from registry attestation receipts. M5 listens for cryptographically attested credit-issuance and revenue events from the registry function (per 05-interfaces/04-registry-function-specification.md), records them in DAO state, and surfaces inflows to M3. M5 is a passive listener: the DAO does not issue credits; it consumes evidence of issuance and sale.

2. Tier 1 implementation

Manual recording in books and records:

  • Each attestation receipt (ECI score, threat multiplier, methodology version, issuance timestamp) recorded in LLC books
  • Periodic audits verify books match attestation chain (per registry annual ops audit)
  • Distribution events reference the specific attestation that produced them
  • No on-chain hooks at Tier 1; the cryptographic chain runs at Layer 3 and is consumed manually

Held off-chain by Landseed compliance:

  • Per-property attestation receipt archive
  • Quarterly attestation summaries
  • Methodology-version timeline (for chain-of-attestation integrity over multi-year periods)

3. Tier 2 implementation

3.1 State variables

struct AttestationRecord {
    bytes32 receiptHash;         // canonical hash of the attestation receipt
                                  // (signed by methodology stewards' attestor key)
    bytes32 methodologyVersion;  // hash-pinned methodology document version
    uint256 eciConservativeBp;   // conservative ECI bound × 10_000 (fixed-point)
    uint256 threatMultiplierBp;  // threat multiplier × 10_000
    uint256 verifiedAcres;       // from NRD-lite + survey
    uint256 issuedCredits;       // calculated and reported by registry
    uint64 receivedAt;
    uint8 status;                // RECORDED, INFLOW_BOUND, INFLOW_DISTRIBUTED, INVALIDATED
}

mapping(bytes32 => AttestationRecord) internal _attestations;  // receiptHash => record
mapping(bytes32 => bytes32) internal _attestationsByMethodologyVersion;
                                                               // tracks methodology drift

bytes32 public registryAttestorPubkeyHash;     // expected signer's key hash
address public registryContract;               // expected origin of `notifyIssuance`
bytes32 public propertyId;                     // unique per-property identifier
                                                // (NRD-lite hash anchor)
uint256 public totalAttestationsReceived;
uint256 public totalCreditsIssuedRecord;

3.2 Public function signatures

function notifyIssuance(
    bytes32 receiptHash,
    bytes32 methodologyVersion,
    uint256 eciConservativeBp,
    uint256 threatMultiplierBp,
    uint256 verifiedAcres,
    uint256 issuedCredits,
    bytes calldata attestorSignature
) external onlyRegistry returns (bool);

function notifyRevenue(
    bytes32 receiptHash,
    uint256 amount,
    bytes calldata registryProof
) external onlyRegistry;
    // calls M3.recordInflow(amount, receiptHash, registryProof)

function notifyInvalidation(
    bytes32 receiptHash,
    bytes32 reasonHash,
    bytes calldata foundationProof
) external onlyRegistry;
    // marks attestation INVALIDATED; informational; buffer-pool replacement
    // happens at registry layer, not in this DAO

// Read-side
function getAttestation(bytes32 receiptHash)
    external view returns (AttestationRecord memory);
function attestationsForMethodologyVersion(bytes32 version)
    external view returns (bytes32[] memory receiptHashes);

3.3 Internal/private functions

function _verifyAttestorSignature(
    bytes32 receiptHash,
    bytes calldata signature
) internal view returns (bool);

function _verifyMethodologyPin(bytes32 methodologyVersion) internal view returns (bool);
    // confirms methodologyVersion is in the set ratified for this property
    // (cross-references M2 governance state; methodology-adoption proposals
    // record ratified versions)

3.4 Events

event AttestationReceived(
    bytes32 indexed receiptHash,
    bytes32 indexed methodologyVersion,
    uint256 issuedCredits,
    uint256 verifiedAcres
);
event RevenueNotified(
    bytes32 indexed receiptHash,
    uint256 amount
);
event AttestationInvalidated(
    bytes32 indexed receiptHash,
    bytes32 reasonHash
);
event RegistryConfigChanged(
    address oldRegistry,
    address newRegistry,
    bytes32 oldAttestorPubkeyHash,
    bytes32 newAttestorPubkeyHash
);

3.5 Modifiers and access control

modifier onlyRegistry();    // msg.sender == registryContract
modifier validAttestor(bytes calldata signature, bytes32 messageHash);
modifier methodologyRatified(bytes32 version);

4. Invariants

#Invariant
M5.1DAO does not issue credits: M5 has no mint or issue function. (Per Principle 2 firewall.)
M5.2Attestation deduplication: each receiptHash is processed at most once for notifyIssuance.
M5.3Attestor signature required: notifyIssuance requires valid signature against registryAttestorPubkeyHash; reverts otherwise.
M5.4Methodology pinning: notifyIssuance reverts unless methodologyVersion is in the ratified-for-this-property set.
M5.5Property isolation: M5 only accepts attestations bearing this propertyId; cross-property receipts are rejected.
M5.6Revenue traceability: every notifyRevenue references a previously received receiptHash.
M5.7Invalidation does not unwind distributions: notifyInvalidation is informational; previously distributed inflows are not clawed back from M3. (Buffer-pool replacement happens at registry layer per 05-interfaces/05.)
M5.8Registry config change is governance-only: RegistryConfigChanged only via M2 supermajority + 30-day delay.

5. Threat model

ThreatMechanismMitigation
Forged attestationAdversary submits fake receiptM5.3 signature check against attestor pubkey; M5.4 methodology pin
Replay of old attestationOld receipt resubmittedM5.2 deduplication
Cross-property attestation injectionAttestation for property X submitted to property Y’s M5M5.5; propertyId is constructor-immutable or governance-only-changeable
Methodology version driftAttestation references methodology version not ratified for this propertyM5.4 ratified-set check; M2 ratifies methodology versions explicitly
Attestor key compromiseAttestor private key leakedKey-rotation procedure; M5.8 governance-only change; key compromise disclosed publicly per registry transparency commitment
Registry-contract upgrade attackNew registry contract impersonates old oneM5.8 governance-only change; address is immutable absent explicit M2 supermajority + delay
Inflow double-countingSame revenue event triggers two recordInflow calls in M3M3.4 mapping prevents double-distribution; M5 emits single notifyRevenue per receipt
Methodology error invalidation propagationFoundation invalidates attestations broadlynotifyInvalidation is informational; affects future attestation status only; does not retroactively unwind already-distributed inflows

6. Per-template variations

TemplateM5 implementation
A, B, D, E, G — Tier 1No on-chain M5; manual recording in LLC books
C — IndigenousTier 2 mandatory; permissioned read access on attestation events (CARE: authority to control); aggregated ECI public, raw observations community-only
F — HybridTier 2; per-deployment audit; cross-stakeholder access controls

For Templates A, B, D, E, G the propertyId, receiptHash, and methodology pinning all exist conceptually but are recorded off-chain. The audit-trail rigor is identical; the storage medium differs.

7. External dependencies

  • Registry contract — origin of all notifyIssuance and notifyRevenue calls; per 05-interfaces/04
  • Methodology Foundation buffer pool — handles invalidations; M5 only mirrors them, does not act on them; per 05-interfaces/05
  • M2 — methodology-version ratification governs M5.4
  • M3 — receives recordInflow calls
  • Off-chain attestor key — methodology stewards’ signing key; rotation per registry-governance procedure

8. Audit-scoping notes

  • Estimated audit hours: 50–70 hours for M5 standalone
  • Required auditor expertise: Solidity; signature verification (ECDSA / EIP-712); cross-contract message verification; familiarity with cross-chain or oracle-attestation patterns
  • Highest-risk areas: signature verification under chain-id/replay attacks; methodology-version pinning consistency with M2 state; cross-property isolation enforcement; registry-contract upgrade path
  • Test coverage required: 100% for notifyIssuance, notifyRevenue, _verifyAttestorSignature; cross-chain replay testing if multi-chain; methodology-version drift simulation
  • Audit-first dependency: depends on registry contract spec stability (per 05-interfaces/04); audit M5 in conjunction with registry external-interface review

M6 — Upgrade Path

1. Purpose

Module-by-module upgrade governance with supermajority + time delay + guardian veto. M6 enables the architecture to evolve over the property’s 99-year horizon without re-deploying the entire vehicle. Constitution-guardian veto is the architectural backstop preventing governance from voting to violate per-property isolation, transferability rules, or other founding commitments.

2. Tier 1 implementation

Encoded in operating agreement:

  • Standard amendment procedure (proposal documented; signature-based amendment; possibly notarization)
  • Required signatories (member majority/supermajority; Landseed steward; cultural guardian if applicable)
  • Notice period (30 days minimum; 60 days for material amendments)
  • Effective-on-amendment clause
  • Constitution-guardian non-objection (per founding-principles list in 00-foundations/03-binding-principles.md)
  • Recordkeeping (signed amendment archived; new OA version superseding prior)

Encoded in multi-sig:

  • For Tier 1, no on-chain code to upgrade; multi-sig signer-set rotation follows OA amendment procedure
  • Compliance-officer multi-sig membership changes follow same procedure

3. Tier 2 implementation

3.1 State variables

struct ModuleSlot {
    address current;
    address pending;
    uint64 pendingActivatesAt;
    uint64 guardianVetoEndsAt;
    bytes32 newCodeHash;          // deployed code hash for verifiability
    bytes32 auditAttestationHash; // hash of audit report for the new module
    uint8 moduleKind;             // M1, M2, M3, M4, M5, M6
}

mapping(uint8 => ModuleSlot) internal _slots;       // moduleKind => slot
uint64 public constant MIN_UPGRADE_DELAY = 30 days;
uint64 public constant MIN_GUARDIAN_WINDOW = 7 days;

address public constitutionGuardian;                 // Landseed-officer multi-sig
mapping(uint8 => address) public moduleGuardian;     // optional per-module guardian

3.2 Public function signatures

function proposeUpgrade(
    uint8 moduleKind,
    address newImplementation,
    bytes32 newCodeHash,
    bytes32 auditAttestationHash,
    bytes calldata governanceProof  // M2 supermajority proof
) external onlyGovernance returns (uint256 upgradeId);

function vetoConstitutional(uint8 moduleKind)
    external onlyConstitutionGuardian;
    // callable in window guardianVetoEndsAt; restricted to violations of
    // founding principles list

function vetoModule(uint8 moduleKind)
    external onlyModuleGuardian(moduleKind);
    // module-specific guardian (e.g., methodology guardian for M5 changes,
    // cultural guardian for M2 changes affecting cultural-decision class)

function activateUpgrade(uint8 moduleKind) external;
    // anyone may trigger after guardianVetoEndsAt;
    // performs storage migration, swap address, emit event

function abortUpgrade(uint8 moduleKind, bytes calldata governanceProof)
    external onlyGovernance;

// Read-side
function getModule(uint8 moduleKind) external view returns (ModuleSlot memory);
function isUpgradePending(uint8 moduleKind) external view returns (bool);

3.3 Internal/private functions

function _verifyAuditAttestation(bytes32 attestationHash) internal view returns (bool);
    // confirms an external auditor has signed off on newImplementation
function _verifyCodeHashMatches(address impl, bytes32 expectedHash)
    internal view returns (bool);
function _migrateStorage(uint8 moduleKind, address oldImpl, address newImpl) internal;
    // module-specific migration; reverts on storage incompatibility

3.4 Events

event UpgradeProposed(
    uint8 indexed moduleKind,
    address newImplementation,
    bytes32 newCodeHash,
    bytes32 auditAttestationHash,
    uint64 activatesAt
);
event UpgradeVetoed(
    uint8 indexed moduleKind,
    address indexed guardian,
    uint8 vetoKind  // CONSTITUTIONAL, MODULE
);
event UpgradeActivated(
    uint8 indexed moduleKind,
    address oldImplementation,
    address newImplementation
);
event UpgradeAborted(uint8 indexed moduleKind);
event GuardianRotated(
    uint8 indexed moduleKind,  // 255 for constitution guardian
    address oldGuardian,
    address newGuardian
);

3.5 Modifiers and access control

modifier onlyGovernance();
modifier onlyConstitutionGuardian();
modifier onlyModuleGuardian(uint8 moduleKind);
modifier upgradeReady(uint8 moduleKind);

4. Invariants

#Invariant
M6.1No upgrade without audit: proposeUpgrade reverts unless auditAttestationHash != 0 and _verifyAuditAttestation confirms a signed external auditor attestation.
M6.2Minimum delay: pendingActivatesAt - block.timestamp >= MIN_UPGRADE_DELAY (30 days).
M6.3Guardian window: guardianVetoEndsAt - pendingActivatesAt >= MIN_GUARDIAN_WINDOW (7 days).
M6.4Veto irreversible: once UpgradeVetoed emitted, the slot returns to pending == 0; new proposal required.
M6.5Storage compatibility: _migrateStorage reverts on incompatible layout; auditor must verify storage layout in advance.
M6.6Constitution-guardian scope: vetoConstitutional is restricted to violations enumerated in 00-foundations/03-binding-principles.md.
M6.7No circular upgrade: M6 cannot upgrade itself in the same proposal that upgrades another module (M6 self-upgrade is a separate, longer-delayed proposal class).
M6.8Code-hash binding: _verifyCodeHashMatches confirms newImplementation’s deployed bytecode hash equals newCodeHash recorded at proposal time, preventing post-proposal contract substitution.

5. Threat model

ThreatMechanismMitigation
Malicious upgrade slipping inAttacker drafts module that violates a bright line (introduces tradeable token, DeFi yield, cross-property primitive)M6.1 audit requirement; M2 supermajority; constitution-guardian veto; bright-line list is public and enumerated
Storage corruption on upgradeNew module has incompatible storage layout, corrupting stateM6.5 storage migration check; auditor required to review storage layout
Code substitution post-proposalAdversary swaps the contract at newImplementation between proposal and activationM6.8 code-hash binding
Constitution-guardian compromiseLandseed-officer multi-sig compromisedMulti-sig threshold (e.g., 3-of-5); officer rotation per Foundation governance; backup guardian designation; (specific recovery procedure counsel-confirmation required)
Constitution-guardian unresponsivenessMulti-sig signers offlineM6.3 fixed window; absence = clearance; emergency convening protocol off-chain
Guardian removal as coupM2 supermajority votes to remove guardianGuardian rotation requires M2 + 30-day delay + Foundation-level escalation; (Foundation-formation-dependent; not yet built)
Self-upgrade exploitM6 upgrades itself to disable guardianM6.7 separate-proposal-class requirement; longer delay (60 days minimum); Foundation oversight
Audit-attestation forgeryFake audit hash submitted_verifyAuditAttestation requires signed attestation from one of a registered auditor public-key set; auditor set governance-managed

6. Per-template variations

TemplateUpgrade procedureNotable
A, B, D, E, G — Tier 1OA amendment; signature-based; 30-day notice; constitution-guardian non-objectionNo on-chain upgrade; M6 is OA structure only
C — IndigenousSmart-contract upgrade with FPIC-gated M2 supermajority; cultural-guardian non-objection on culturally-relevant modules; 60-day noticePer-deployment audit on each upgrade
F — HybridSmart-contract upgrade with composed-stakeholder approvals; per-component guardian non-objections; 60-day noticePer-deployment audit on each upgrade

7. External dependencies

  • External auditor public-key set — registered list; auditor signatures verified
  • Foundation governance (not yet built) — long-term oversight of guardian rotation
  • M2 — supermajority proposals
  • All other modules — upgrade target

8. Audit-scoping notes

  • Estimated audit hours: 80–110 hours for M6 standalone (high due to cross-module storage-migration verification)
  • Required auditor expertise: Solidity; proxy and upgradeability patterns (UUPS, transparent proxy, beacon, diamond); storage-layout analysis; OpenZeppelin Upgrades familiarity; experience with timelock + guardian-veto patterns
  • Highest-risk areas: storage-layout compatibility (M6.5); code-hash binding (M6.8); guardian-rotation paths; M6 self-upgrade path
  • Test coverage required: 100% for proposeUpgrade, activateUpgrade, vetoConstitutional, vetoModule; storage-migration property tests per module type; guardian-window timing tests
  • Audit-last dependency: M6 should be audited last in the initial library audit because it depends on the storage layouts and module interfaces of M1–M5 being stable

Per-template module composition table

The table below specifies, for each template, which modules are deployed in Tier 1 vs. Tier 2 form and the per-module configuration choices that the auditor will need to verify. Configuration parameters (specific percentages, weights, thresholds) are deployment-time inputs, not template properties.

TemplateM1 (Registry)M2 (Governance)M3 (Economics)M4 (Mgmt Plan)M5 (Attestation)M6 (Upgrade)
A — SoloTier 1 (OA + multi-sig signers); landowner-primary + family + Landseed steward seats; OA inheritance successionTier 1 (OA procedures); landowner supermajority on use; Landseed methodology authority; methodology-guardian multi-sigTier 1 (OA + multi-sig disbursement); landowner 60–85%; stewardship reserve 5–25%; protocol fee 2–5%; cash onlyTier 1 (OA amendment); standard signature procedureTier 1 (manual recording in LLC books); per-attestation reference in distribution recordsTier 1 (OA amendment; 30-day notice; constitution-guardian non-objection)
B — Land TrustTier 1 (OA + multi-sig); land-trust-officer + Landseed steward + optional advisor; institutional successionTier 1 (OA + institutional board procedures); land-trust majority; methodology-guardian veto; two-key on material plan changesTier 1; land-trust 60–80%; reserve 10–25%; protocol fee 2–5%Tier 1 (OA + institutional approval); coordinated with conservation easementTier 1 (manual recording)Tier 1 (OA amendment)
C — IndigenousTier 2 (smart contract); community-council + cultural-guardian + elder + Landseed-steward seats; community-determined succession; permissioned read accessTier 2; FPIC-gated supermajority; cultural-guardian non-objection on cultural class; methodology-guardian veto on destructionTier 2; community fund 40–80%; cultural-guardian discretionary 5–15%; stewardship 5–15%; protocol fee 2–5%; cash onlyTier 2 (content-addressed; FPIC-gated ratification); 60-day deliberationTier 2 (smart-contract listener); permissioned access; aggregated ECI public, raw obs. community-onlyTier 2; FPIC-gated supermajority on upgrade; cultural-guardian non-objection on culturally relevant modules; per-deployment audit
D — CorporateTier 1; corporate-officer + ESG observer + Landseed steward; corporate successionTier 1; corporate-board supermajority; ESG observer non-bindingTier 1; corporate 70–90%; reserve 5–25%; protocol fee 2–5%Tier 1; institutional approval + quarterly disclosureTier 1 (manual recording + quarterly disclosure)Tier 1 (OA amendment)
E — SovereignTier 1; sovereign-agency designee + local management + Landseed steward; agency succession; political-disruption fallbackTier 1; sovereign residual on national-policy class; operational delegation; treaty-reporting hookTier 1; environmental fund 60–80%; local management 10–25%; protocol fee 2–5%Tier 1; sovereign approvalTier 1 (manual recording + treaty reporting)Tier 1 (OA amendment per sovereign procedures)
F — HybridTier 2; composed seats from underlying templates; per-seat succession (per underlying template)Tier 2; decision-class routing across composed seats; mediation-first dispute resolution; FPIC if C-component; cultural-guardian if C-componentTier 2; composed distribution; protocol fee 2–5%; cash onlyTier 2 (content-addressed; composed approval); cross-component conflict resolutionTier 2; cross-stakeholder access controlsTier 2; composed-stakeholder approvals; per-deployment audit on every upgrade
G — StewardshipTier 1; foundation officers + Landseed steward; foundation successionTier 1; foundation procedures; methodology-guardian vetoTier 1; all to stewardship reserve; protocol fee 2–5%Tier 1; foundation approvalTier 1 (manual recording)Tier 1 (OA amendment)

Templates F and G are flagged in 02-governance-templates/CLAUDE.md as deferred to per-deployment audit (current position). The initial library audit covers Templates A, B, C, D, E.


What’s NOT in the modules

These exclusions are template-level expressions of the bright lines in 04-perimeter/:

  • No tradeable tokens. M1 enforces non-transferability (M1.1); M3 emits no token (M3.7).
  • No public participation. M1 enforces permissioned membership (M1.7); admission requires governance proof.
  • No DeFi interactions. M3 holds treasury in stablecoin only; no lend, stake, swap, or external-protocol calls (M3.3).
  • No cross-DAO calls. Each property’s modules are isolated; propertyId (M5.5) and per-property registryContract configuration prevent contamination (M3.8).
  • No automated yield. Treasury management is conservative; only configured stablecoin held; rebalancing requires governance.
  • No DAO credit issuance. M5 has no mint (M5.1); the DAO consumes evidence of issuance, never produces it.

These properties must remain after every M6 upgrade. The constitution-guardian veto exists specifically to enforce this.


Audit-scoping summary

Total estimated audit hours — initial library audit

The initial library audit covers M1–M6 in the form deployed for Templates A through E (Templates F and G are deferred to per-deployment audits).

ModuleHoursAudit-sequence position
M1 — Beneficiary Registry60–90First (foundation for M2/M3/M5)
M2 — Governance120–180Second (depends on M1)
M3 — Economics60–80Third (depends on M1; integrates with M5)
M4 — Management Plan30–50Fourth (depends on M2)
M5 — Attestation Hooks50–70Fifth (depends on registry interface; integrates with M3)
M6 — Upgrade Path80–110Last (depends on storage layouts of M1–M5 being stable)
Cross-module integration tests60–100After all modules independently audited
Bright-line verification (no tokens, no DeFi, no cross-property)30–50Final pass
Report writing + remediation review40–80Final
Total530–810 hours

At a $400/hour blended audit rate, this is $210k–$325k for the initial library audit. This is consistent with the $200k Template C budget noted in 02-governance-templates/CLAUDE.md plus margin for the broader library scope.

Per-template incremental audit hours

After the library audit, each template deployment requires incremental audit work to verify deployment-specific configuration:

TemplateIncremental audit hoursNotes
A — Solo10–20Mostly OA review; multi-sig configuration check
B — Land Trust20–40OA review; institutional-procedure-mapping check; easement coordination review
C — Indigenous200–375Per-deployment partial bespoke build per templates/C-indigenous-co-design.md; FPIC encoding review; cultural-protocol encoding; permissioned-access controls; outside review by indigenous-rights advocate (separate budget)
D — Corporate30–50OA review; ESG-observer permission scope; quarterly disclosure mechanics
E — Sovereign40–80OA review; treaty-reporting integration; political-disruption fallback verification
F — Hybrid200–375Per-deployment audit required; composition-specific securities review; deadlock prevention verification; cross-stakeholder dispute path
G — Stewardship20–40OA review; foundation-procedure mapping

Template C and F costs are partly bespoke. The library audit does not amortize fully across them because the deployment-specific composition is genuine, not parameterization.

Required auditor expertise

The audit team should collectively possess:

  • Solidity / EVM — necessary for all module audits; ≥3 years deep experience
  • Governance patterns — OpenZeppelin Governor, Aragon OSx, or Tally Governor; one of these strongly preferred (the implementation may use any; the auditor benefits from familiarity with the chosen toolchain). For M2 specifically.
  • Proxy / upgradeability — UUPS, transparent, beacon, or diamond proxy patterns; storage-layout analysis. For M6.
  • Access control — OpenZeppelin AccessControl, role-based modifiers, multi-sig integration. For M1, M2, M6.
  • Signature verification — ECDSA, EIP-712, cross-chain attestation patterns. For M5.
  • Reentrancy and atomicity — payment-router patterns; PaymentSplitter familiarity. For M3.
  • Token standards (negative) — auditor must verify absence of ERC-20 / ERC-721 / ERC-1155 mint paths; experience with token standards required to know what to look for.
  • Indigenous-rights review (not auditor expertise per se; separate review track) — for Template C, an indigenous-rights advocate must review FPIC encoding, cultural-guardian scope, and CARE-principle implementation in parallel with smart-contract audit.

Suggested audit firms (per templates/C-indigenous-co-design.md): Trail of Bits, OpenZeppelin, ConsenSys Diligence, Spearbit, or specialized DAO auditor with governance-pattern experience. Boutique firms acceptable for the initial library audit if they bring governance-pattern fluency.

Suggested audit sequence

  1. M1 Beneficiary Registry first. Foundation for all other modules’ state reads.
  2. M2 Governance second. The largest module; all execution paths flow through it.
  3. M3 Economics third. Smallest cross-module surface; can be audited in parallel with M4.
  4. M4 Management Plan fourth. Content-addressed, low complexity; can run parallel to M3.
  5. M5 Attestation Hooks fifth. Depends on registry interface stability.
  6. M6 Upgrade Path last. Requires M1–M5 storage layouts to be stable.
  7. Integration tests after all modules. Cross-module call paths; reentrancy across contract boundaries; bright-line verification (no tokens / no DeFi / no cross-property primitives).
  8. Per-template configuration review for the chosen pilot templates (A and B for Tier 1; C deferred per 02-governance-templates/CLAUDE.md to a partnered deployment).

What’s NOT in the audit scope (deferred)

  • Foundation buffer-pool contract audit — separate from per-property module audit; covered under registry/Foundation audit (per 05-interfaces/05-buffer-pool-specification.md audit budget)
  • Registry contract audit — separate; per 05-interfaces/04-registry-function-specification.md
  • Coalition entity contractsExchange, Fund; out of scope per 05-interfaces/CLAUDE.md (coalition entities are counterparties, not parts of the per-property vehicle)
  • NRD-lite legal-instrument review — not a smart-contract audit; counsel-led legal review per 01-nrd-lite/
  • Templates F and G — deferred to per-deployment audits (current position per 02-governance-templates/CLAUDE.md); revisit if deployment frequency justifies library inclusion

Open audit-scoping questions

QuestionOwnerStatus
Specific framework choice (Aragon vs. Tally vs. custom)Engineering + counselOpen; specification is framework-agnostic
L1 vs. L2 deployment chainEngineering + counselOpen; affects timestamp-attack and gas-cost analysis
Auditor selectionLandseed PBC + the co-architectOpen; shortlist in templates/C-indigenous-co-design.md
Storage layout finalizationEngineeringRequired before M6 audit
Methodology-version-pinning data structureMethodology stewards + engineeringRequired before M5 audit
Wallet-auth pattern (Q9: hybrid custodial / hardware / paper)Engineering + UX + counselRequired before M1 audit; current position is hybrid per 06-risks/04-proposed-resolutions.md
Cross-chain or multi-chain considerationsEngineeringOpen; bears on M5 signature verification
External auditor public-key registration (M6.1)Engineering + counselOpen; affects M6 audit-attestation verification

These are execution-phase decisions that follow from the architecture. The architecture itself is settled at the level of this specification. (Specific framework choice deferred; counsel-confirmation required across regulatory dimensions.)

Cross-module consistency — phase-9.5 audit findings and resolutions

The following inconsistencies were surfaced by an internal cross-module audit at the close of the fourth iteration. Each is a specification-level fix that the implementation must respect; auditors should treat these as binding refinements to the per-module sections above.

Fix 1 — M3.10: bufferPoolFeeBps must be constant 0 (no governance setter)

The bufferPoolFeeBps state variable in M3 is declared uint256 public bufferPoolFeeBps with the documentation “0 here; buffer is taken pre-DAO at registry layer.” There must be no setter exposed to governance, no constructor-time value other than 0, and a new invariant M3.10: bufferPoolFeeBps == 0; enforced by deployment as constant; no governance path can change it. This prevents an inadvertent governance proposal from creating a DAO-side buffer fee on top of the registry-layer buffer.

Fix 2 — M3._verifyRegistryProof: M3 must independently validate the registry proof

M3’s recordInflow is gated by onlyAttestationHook (msg.sender == address(M5)). M3 also receives bytes calldata registryProof from M5 but does not validate it. Add internal function _verifyRegistryProof(bytes calldata registryProof) to M3 §3.3 that confirms the proof was signed by the registry’s attestor key (independently of M5’s prior validation). This closes the gap where an upgraded M5 could pass invalid proofs to M3 without M3 re-checking. M3.8 enforcement now reads: “via independent _verifyRegistryProof validation of registryProof parameter; M5’s prior validation is not relied upon.”

Fix 3 — M1 and M6 governanceProof parameter discipline

M1’s admitMember and M6’s proposeUpgrade accept bytes calldata governanceProof AND are gated by onlyGovernance. The governanceProof parameter is redundant if onlyGovernance enforces M2-only origin. Resolution: remove the governanceProof parameter from both functions. Access control is enforced solely by onlyGovernance. This simplifies the spec and eliminates an under-defined verification surface.

Fix 4 — M2 must publish ratifiedMethodologyVersions for M5 to consume

M5’s _verifyMethodologyPin references “the set of methodology versions ratified for this property” but M2 has no state variable, getter, or event documenting this set. Add to M2 §3.1: mapping(bytes32 => bool) public ratifiedMethodologyVersions populated by execution of ADOPT_METHODOLOGY proposals. Add public getter: function isMethodologyRatified(bytes32 version) external view returns (bool). M5 now calls this getter directly. The cross-module dependency is explicit, not implicit.

Fix 5 — M2 declares its own kycCurrent modifier; M1 exposes getMemberIdByHolder

M2’s castVote references kycCurrent(memberIdOfSender) but kycCurrent is defined only on M1. Resolution: declare a M2-local modifier kycCurrent(uint256 memberId) that calls M1.isKycCurrent(memberId). Also add to M1 §3.2: function isKycCurrent(uint256 memberId) external view returns (bool) and function getMemberIdByHolder(address holder) external view returns (uint256) (the latter exposes what is currently internal _holderToMemberId). M2’s onlyMember modifier and its castVote’s memberIdOfSender lookup now use the public getter.

Fix 6 — M5.setRegistryConfig: governance-controlled registry rotation

M5.8 invariant requires that registryContract and registryAttestorPubkeyHash changes require M2 supermajority + 30-day delay, but no setRegistryConfig function exists. Add to M5 §3.2: function setRegistryConfig(address newRegistry, bytes32 newAttestorPubkeyHash) external onlyGovernance with the 30-day delay enforced via M2’s standard DECISION_UPGRADE timelock. Emits the previously declared RegistryConfigChanged event. This closes the governance-control gap on the most security-critical M5 state.

Fix 7 — Emergency-path key rotation (Test 23 mitigation)

The 30-day delay on registry-attestor key rotation is too slow during force-majeure events. Add to M5 §3.2 a separate emergency path: function emergencyRotateAttestor(address newRegistry, bytes32 newAttestorPubkeyHash, bytes calldata foundationApproval) external with a 72-hour timelock instead of 30 days, gated by Foundation methodology stewards’ multi-sig (≥3 of 5) + audit committee non-objection. This is bounded by M5.8.E (new invariant): emergency rotation requires Foundation multi-sig + audit committee + ≥48-hour public notice; cannot reduce timelock below 72 hours.

Fix 8 — M4 chain integrity: dual storageUri (Attack A-5 mitigation)

M4’s proposePlanVersion accepts a single storageUri. Adversary substitution at the URI source is detectable but creates a governance race window. Add to M4 §3.1: PlanVersion.storageUriPrimary and PlanVersion.storageUriBackup (both content-addressed). Ratification must verify content-hash from BOTH URIs before activation. M4.7 (new invariant): ratification requires byte-equal content from primary AND backup URIs; otherwise revert.

Fix 9 — Replacement-credit receipt flagging (Attack A-12 mitigation)

Cross-spec gap: buffer pool replacement credits could double-count revenue if M5/M3 treat them as new attestations. Resolution: buffer pool reversal generates attestation receipts with explicit flag isReplacement: true and replacementFor: bytes32 (original receipt hash). M5 §3.1 adds mapping(bytes32 => bytes32) public replacementOf populated when a replacement attestation is consumed. M3 §3.3 adds invariant: if replacementOf[receiptHash] != 0, recordInflow reverts with REPLACEMENT_NO_REVENUE — replacement credits do not generate fresh revenue distribution. Coordinated update with 05-interfaces/05-buffer-pool-specification.md reversal-process step 5.

Fix 10 — Cross-module call/event matrix (canonical reference)

The canonical cross-module dependency graph after the above fixes:

Caller / EmitterTargetMechanism
M1 → M2governance reads voting weightM2 calls M1.getVotingWeight(memberId, decisionClass) (public getter)
M1 → M3distribution shareM3 calls M1.getDistributionShareBps(memberId) at addRecipient time
M1 → M2KYC currencyM2 calls M1.isKycCurrent(memberId) (Fix 5)
M1 → M2member resolutionM2 calls M1.getMemberIdByHolder(holder) (Fix 5)
M2 → M1executionM2 calls M1.admitMember, M1.removeMember, M1.setSuccessorRoot (Fix 3 — no governanceProof param)
M2 → M3executionM2 calls M3.addRecipient, M3.updateRecipientShare, etc.
M2 → M4executionM2 calls M4.ratifyPlanVersion, M4.activatePlanVersion, M4.revokePlanVersion
M2 → M5registry configM2 calls M5.setRegistryConfig (Fix 6)
M2 → M6executionM2 calls M6.proposeUpgrade (Fix 3 — no governanceProof param)
M2 → M5methodology ratificationM5 calls M2.isMethodologyRatified(version) (Fix 4)
M5 → M3revenueM5 calls M3.recordInflow(amount, receiptHash, registryProof); M3 independently validates registryProof (Fix 2)
Registry → M5attestation lifecycleRegistry calls M5.notifyIssuance, M5.notifyRevenue, M5.notifyInvalidation
Registry → M5replacement creditRegistry calls M5.notifyReplacement(receiptHash, replacementFor) (Fix 9)
M6 → M1–M5upgrade activationM6 swaps module addresses; storage migration follows M6 invariants

What this means for audit scoping

The 530–810 hours estimate from the per-module summary remains valid post-fixes. The fixes are surgical clarifications that strengthen the audit posture without expanding scope. M5 sees the largest delta (Fix 6, Fix 7, Fix 9) — auditor should add ~20 hours for verification of the registry-config rotation paths and replacement-credit flagging logic. M3 sees a smaller delta (Fix 1, Fix 2, Fix 9) — add ~10 hours. Net audit-hour increase: ~30 hours; revised total 560–840 hours for the initial library audit.

These fixes are mandatory before the M5 audit and the M3 audit. M1, M2, M4, M6 fixes (Fix 3, Fix 4, Fix 5, Fix 8) are mandatory before their respective module audits.