Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-8328: Subject-Linked Compliance Event Log

Defines append-only subject-linked compliance records with attribution, evidence, indexing, and correction provenance

Authors Chris Turner <c.turner@kula.com>, David Hay (@david-hay), Reagan Simpson (@krumg111), Collins Musyimi (@Musyimi97)
Created 2026-07-05
Discussion Link https://ethereum-magicians.org/t/erc-8328-subject-linked-compliance-event-log/28937
Requires EIP-165

Abstract

This ERC defines an append-only interface for subject-linked compliance event records. Each record includes a subject, event type, outcome, technical actor, claimed authority, involved parties, evidence commitment, optional evidence location, versioned payload profile, operation reference, occurrence time, and recording time.

Events are indexed per subject and by event type. Corrections are recorded as new events linked to earlier records. A forward pointer on the corrected record prevents correction forks and allows consumers to resolve the terminal event in a correction chain.

This ERC is a reporting interface. It does not define compliance policy, identity verification, transfer restrictions, legal authority, or regulatory compliance. Stored records are attributable assertions, not proof that the reported action occurred or was lawful.

Motivation

Compliance-relevant lifecycle actions are currently represented through application-specific events, token-local state changes, generic attestations, and off-chain databases. This fragmentation makes it difficult for contracts, indexers, auditors, and reporting systems to query comparable records across implementations.

Existing token and compliance standards primarily define token behavior, holder eligibility, transfer validation, or entity classification. Those capabilities do not provide a common stored record for subject-level lifecycle actions such as issuance, redemption, freezing, know-your-customer (KYC) status changes, regulatory holds, policy changes, and forced transfers.

A shared event-log interface provides:

  • one query surface for records attached to an application-defined subject;
  • explicit separation between the recorder and the claimed authority;
  • structured party roles rather than untyped address arrays;
  • evidence commitments and optional retrieval references;
  • versioned payload profiles for interoperable event-specific data;
  • per-type indexing without scanning an entire subject history; and
  • append-only, fork-free correction provenance.

The log can be called by a token, compliance module, governance executor, multisig, or other authorized recorder. It does not require any particular token standard or enforcement architecture.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Definitions

A subject is an application-defined entity identified by subjectId and, optionally, contextualized by subjectType.

A compliance event is a stored assertion about a compliance-relevant action or state transition concerning a subject.

An actor is msg.sender at the time recordEvent is called. It identifies the technical recorder, not necessarily the human decision-maker or legal authority.

An authority is the recorder’s claimed legal, regulatory, contractual, or governance basis for the event. The claim is not verified by the log.

A party is an EVM address associated with an explicit role in the event.

A payload profile is a versioned schema declaring how payload is encoded.

A correction chain is a linear sequence of events linked by correctsIndex and correctedByIndex.

A terminal event is an event whose correctedByIndex equals NO_CORRECTED_BY.

Sentinel Values

Implementations MUST use:

uint256 constant NO_CORRECTION = type(uint256).max;
uint256 constant NO_CORRECTED_BY = 0;

NO_CORRECTION indicates that an event does not correct an earlier event.

NO_CORRECTED_BY indicates that an event has no successor correction. Event index zero is safe for this sentinel because a correction’s index is always greater than the index it corrects and therefore can never be zero.

Core Interface

A compliant log MUST implement:

interface IComplianceEventLog {
    struct Party {
        address addr;
        bytes32 role;
    }

    struct ComplianceEvent {
        bytes32 subjectId;
        bytes32 subjectType;
        bytes32 eventType;
        bytes32 outcome;
        address actor;
        bytes32 authority;
        Party[] parties;
        bytes32 evidenceHash;
        string evidenceURI;
        bytes32 payloadProfileId;
        bytes payload;
        bytes32 operationRef;
        uint64 occurredAt;
        uint64 recordedAt;
        uint256 correctsIndex;
        uint256 correctedByIndex;
    }

    event ComplianceEventRecorded(
        bytes32 indexed subjectId,
        bytes32 indexed eventType,
        address indexed actor,
        uint256 eventIndex,
        bytes32 outcome,
        bytes32 authority,
        uint64 occurredAt,
        uint256 correctsIndex
    );

    function recordEvent(
        bytes32 subjectId,
        bytes32 subjectType,
        bytes32 eventType,
        bytes32 outcome,
        bytes32 authority,
        Party[] calldata parties,
        bytes32 evidenceHash,
        string calldata evidenceURI,
        bytes32 payloadProfileId,
        bytes calldata payload,
        bytes32 operationRef,
        uint64 occurredAt,
        uint256 correctsIndex
    ) external returns (uint256 eventIndex);

    function getEvent(
        bytes32 subjectId,
        uint256 eventIndex
    ) external view returns (ComplianceEvent memory);

    function currentEventIndex(
        bytes32 subjectId,
        uint256 eventIndex
    ) external view returns (uint256);

    function isEventCurrent(
        bytes32 subjectId,
        uint256 eventIndex
    ) external view returns (bool);

    function eventCount(
        bytes32 subjectId
    ) external view returns (uint256);

    function eventCountByType(
        bytes32 subjectId,
        bytes32 eventType
    ) external view returns (uint256);

    function eventByTypeAt(
        bytes32 subjectId,
        bytes32 eventType,
        uint256 ordinal
    ) external view returns (uint256 eventIndex);

    function lastRecordedEventByType(
        bytes32 subjectId,
        bytes32 eventType
    ) external view returns (uint256 eventIndex);
}

Recording Semantics

Event indices MUST be zero-based and scoped per subjectId. The returned eventIndex MUST equal the subject’s event count immediately before the new event is appended.

recordEvent MUST be restricted to authorized recorders. The authorization mechanism is implementation defined and MUST be documented.

For every accepted event, the implementation MUST:

  • store every supplied field without changing its value, except as explicitly specified by this ERC;
  • set actor to msg.sender;
  • set recordedAt to uint64(block.timestamp);
  • initialize correctedByIndex to NO_CORRECTED_BY;
  • append the event index to the subject and event-type index;
  • emit ComplianceEventRecorded; and
  • return the new event index.

The implementation MUST reject the call if block.timestamp cannot be represented as uint64.

evidenceHash MUST NOT be bytes32(0). evidenceURI MAY be empty when the evidence location is private, unavailable on-chain, or exchanged out of band. An empty URI does not weaken the requirement for a nonzero commitment.

The parties array MUST contain no more than 10 entries. payload MUST contain no more than 2048 bytes. Empty party arrays and empty payloads are allowed.

This ERC does not require nonzero values for subjectId, subjectType, eventType, outcome, authority, operationRef, party addresses, party roles, or payloadProfileId. Applications requiring stricter semantics MUST enforce and document them before calling recordEvent.

Temporal Semantics

occurredAt represents when the reported action occurred. recordedAt represents when the record was appended on-chain.

recordEvent MUST revert when occurredAt > block.timestamp.

Implementations SHOULD impose and document a maximum backdating interval. Different deployments can require different intervals, so the duration is not standardized by this ERC.

The log does not independently verify occurredAt. It is an assertion by the recorder.

Append-Only Semantics

Once recorded, every event field MUST remain immutable except correctedByIndex. Events MUST NOT be deleted.

Updating correctedByIndex is permitted only when accepting a valid correction under the correction rules below.

Correction Semantics

An original or non-correction event MUST use NO_CORRECTION and MUST NOT use EVT_CORRECTION, which is defined in the Event Types section below:

correctsIndex = NO_CORRECTION
eventType != EVT_CORRECTION

A correction event MUST use:

correctsIndex = index of the corrected event
eventType = EVT_CORRECTION

For a correction, recordEvent MUST:

  • require correctsIndex to identify an earlier event under the same subjectId;
  • require the target event’s correctedByIndex to equal NO_CORRECTED_BY;
  • authorize the correction under the implementation’s documented correction policy;
  • set the target’s correctedByIndex to the new correction event index; and
  • append the correction as a new event.

The correction policy MUST NOT permit an ordinary recorder to correct another actor’s event merely because both addresses can record events. It MAY authorize the original actor, a designated corrector, or an administrator. The policy MUST be documented.

Each event can be corrected at most once, preventing forks. A correction event can itself be corrected later, producing a linear chain.

The correcting record does not rewrite the original event’s event type or payload. Recorders MUST place the corrected assertion in the new event’s fields or an application-defined correction payload. Consumers MUST interpret the terminal event under the applicable profile and application policy.

Current-State Queries

currentEventIndex MUST revert when eventIndex >= eventCount(subjectId). Otherwise, it MUST follow correctedByIndex until reaching NO_CORRECTED_BY and return the terminal event index. Calling it on a terminal event MUST return the supplied index.

isEventCurrent MUST revert when eventIndex >= eventCount(subjectId) and otherwise return whether correctedByIndex == NO_CORRECTED_BY.

Because corrections always point to earlier events and each event has at most one successor, conforming correction chains cannot contain cycles or branches.

Event Retrieval and Counting

getEvent MUST return the complete stored event and MUST revert when eventIndex >= eventCount(subjectId).

eventCount MUST return the number of events stored under a subject.

eventCountByType MUST return the number of events recorded with the exact eventType under a subject.

eventByTypeAt MUST return the event index at the specified zero-based ordinal and MUST revert when the ordinal is outside the type-specific index.

lastRecordedEventByType MUST return the greatest event index recorded with the exact event type and MUST revert when no matching event exists.

lastRecordedEventByType describes recording order. It does not select the event with the greatest occurredAt and does not resolve correction chains.

Correction events are indexed under EVT_CORRECTION, not under the event type they correct. Consumers resolving an earlier event MUST use currentEventIndex rather than assuming the last event of the original type is its current state.

Subject Identifiers

subjectId and subjectType are opaque to the log. Applications SHOULD use a documented, domain-separated derivation and MUST NOT assume that equal subject identifiers from independent logs have equal meaning without an explicit coordination agreement.

The following subject-type identifiers are defined:

bytes32 constant SUBJECT_TOKEN =
    keccak256("ERC-8328:SUBJECT_TYPE:TOKEN");
bytes32 constant SUBJECT_ADDRESS =
    keccak256("ERC-8328:SUBJECT_TYPE:ADDRESS");
bytes32 constant SUBJECT_ASSET =
    keccak256("ERC-8328:SUBJECT_TYPE:ASSET");
bytes32 constant SUBJECT_CASE =
    keccak256("ERC-8328:SUBJECT_TYPE:CASE");

Applications MAY define custom subject types using a documented namespace and version.

Event Types

The following event-type identifiers are defined:

bytes32 constant EVT_ISSUANCE =
    keccak256("ERC-8328:EVENT_TYPE:ISSUANCE:V1");
bytes32 constant EVT_TRANSFER =
    keccak256("ERC-8328:EVENT_TYPE:TRANSFER:V1");
bytes32 constant EVT_REDEMPTION =
    keccak256("ERC-8328:EVENT_TYPE:REDEMPTION:V1");
bytes32 constant EVT_FREEZE =
    keccak256("ERC-8328:EVENT_TYPE:FREEZE:V1");
bytes32 constant EVT_UNFREEZE =
    keccak256("ERC-8328:EVENT_TYPE:UNFREEZE:V1");
bytes32 constant EVT_FORCED_TRANSFER =
    keccak256("ERC-8328:EVENT_TYPE:FORCED_TRANSFER:V1");
bytes32 constant EVT_KYC_APPROVED =
    keccak256("ERC-8328:EVENT_TYPE:KYC_APPROVED:V1");
bytes32 constant EVT_KYC_REVOKED =
    keccak256("ERC-8328:EVENT_TYPE:KYC_REVOKED:V1");
bytes32 constant EVT_KYC_UPDATED =
    keccak256("ERC-8328:EVENT_TYPE:KYC_UPDATED:V1");
bytes32 constant EVT_REGULATORY_HOLD =
    keccak256("ERC-8328:EVENT_TYPE:REGULATORY_HOLD:V1");
bytes32 constant EVT_HOLD_RELEASED =
    keccak256("ERC-8328:EVENT_TYPE:HOLD_RELEASED:V1");
bytes32 constant EVT_ALLOWLIST_ADDED =
    keccak256("ERC-8328:EVENT_TYPE:ALLOWLIST_ADDED:V1");
bytes32 constant EVT_ALLOWLIST_REMOVED =
    keccak256("ERC-8328:EVENT_TYPE:ALLOWLIST_REMOVED:V1");
bytes32 constant EVT_POLICY_CHANGE =
    keccak256("ERC-8328:EVENT_TYPE:POLICY_CHANGE:V1");
bytes32 constant EVT_CORRECTION =
    keccak256("ERC-8328:EVENT_TYPE:CORRECTION:V1");

EVT_TRANSFER is intended for compliance-significant transfer records, not as a replacement for a token’s ordinary transfer event. Applications SHOULD avoid duplicating every routine token transfer unless the additional compliance record is required by their reporting policy.

Custom event types SHOULD use a domain-separated namespace and explicit version.

Party Roles

The following party-role identifiers are defined:

bytes32 constant ROLE_SENDER =
    keccak256("ERC-8328:PARTY_ROLE:SENDER");
bytes32 constant ROLE_RECEIVER =
    keccak256("ERC-8328:PARTY_ROLE:RECEIVER");
bytes32 constant ROLE_TARGET =
    keccak256("ERC-8328:PARTY_ROLE:TARGET");
bytes32 constant ROLE_BENEFICIARY =
    keccak256("ERC-8328:PARTY_ROLE:BENEFICIARY");
bytes32 constant ROLE_CONTROLLER =
    keccak256("ERC-8328:PARTY_ROLE:CONTROLLER");
bytes32 constant ROLE_SUBJECT =
    keccak256("ERC-8328:PARTY_ROLE:SUBJECT");

Custom party roles SHOULD use a documented namespace and version.

The base Party type contains an EVM address. It cannot carry an arbitrary hashed identity without changing the interface. Applications needing private or non-address party identifiers require a separate extension or SHOULD omit those parties from the public record.

Outcomes

The following outcome identifiers are defined:

bytes32 constant OUTCOME_APPROVED =
    keccak256("ERC-8328:OUTCOME:APPROVED");
bytes32 constant OUTCOME_DENIED =
    keccak256("ERC-8328:OUTCOME:DENIED");
bytes32 constant OUTCOME_PENDING =
    keccak256("ERC-8328:OUTCOME:PENDING");
bytes32 constant OUTCOME_EXECUTED =
    keccak256("ERC-8328:OUTCOME:EXECUTED");
bytes32 constant OUTCOME_EXPIRED =
    keccak256("ERC-8328:OUTCOME:EXPIRED");
bytes32 constant OUTCOME_REVOKED =
    keccak256("ERC-8328:OUTCOME:REVOKED");

This ERC does not define or enforce an event-type and outcome compatibility matrix. Applications MAY constrain combinations before recording. Consumers MUST NOT infer that a combination was validated merely because the log accepted it.

Authority Identifiers

The following common authority identifiers are defined:

bytes32 constant AUTHORITY_INTERNAL_POLICY =
    keccak256("ERC-8328:AUTHORITY:INTERNAL_POLICY:V1");
bytes32 constant AUTHORITY_COURT_ORDER =
    keccak256("ERC-8328:AUTHORITY:COURT_ORDER:V1");
bytes32 constant AUTHORITY_REGULATOR =
    keccak256("ERC-8328:AUTHORITY:REGULATOR:V1");

Custom authority identifiers SHOULD use a documented namespace and version. The field records a claim and does not authenticate the named authority.

Payload Profiles

The following payload-profile identifiers and ABI encodings are defined:

bytes32 constant PAYLOAD_TRANSFER_V1 =
    keccak256("ERC-8328:PAYLOAD:TRANSFER:V1");
// abi.encode(
//     address from,
//     address to,
//     uint256 amount,
//     bytes32 routeRef
// )

bytes32 constant PAYLOAD_FREEZE_V1 =
    keccak256("ERC-8328:PAYLOAD:FREEZE:V1");
// abi.encode(
//     address target,
//     uint256 amount,
//     uint64 expiresAt,
//     bytes32 reason
// )

bytes32 constant PAYLOAD_KYC_V1 =
    keccak256("ERC-8328:PAYLOAD:KYC:V1");
// abi.encode(
//     address subject,
//     bytes32 jurisdiction,
//     bytes32 riskTier,
//     uint64 expiresAt
// )

bytes32 constant PAYLOAD_FORCED_TRANSFER_V1 =
    keccak256("ERC-8328:PAYLOAD:FORCED_TRANSFER:V1");
// abi.encode(
//     address from,
//     address to,
//     uint256 amount,
//     bytes32 legalBasis
// )

A recorder declaring one of these profiles MUST encode the payload exactly as specified. Consumers MUST inspect payloadProfileId before decoding.

The log is not required to decode payloads or validate compatibility between a payload profile, event type, parties, and outcome. Consumers SHOULD reject a malformed known profile. Unknown profile identifiers MUST be treated as opaque bytes.

Custom payload profiles SHOULD use a documented namespace and version and MUST define an exact encoding.

Operation References

operationRef is an application-defined correlation identifier linking the record to an underlying action or workflow. It MAY be bytes32(0) when no such reference is available.

A contract cannot access its transaction hash or final log index while executing. Therefore, this ERC does not require a transaction-hash and log-index derivation. Applications SHOULD compute a correlation identifier before the underlying action and recordEvent calls when both occur in one transaction.

Recording an event in the same transaction as the underlying action provides stronger linkage than recording it later, but the log still does not prove that the record accurately describes that action.

Interface Detection

Compliant logs MUST implement ERC-165 and return true for type(IComplianceEventLog).interfaceId.

ERC-165 indicates interface support only. It does not establish recorder trustworthiness, evidence validity, authority, policy correctness, or legal compliance.

Rationale

Why Subject-Linked Records?

An address-only or token-only key would exclude projects, assets, cases, policies, and application-defined entities. An opaque subject identifier allows one query model while leaving identity and namespace semantics to the application.

Why Separate Actor and Authority?

The technical account recording an event and the claimed basis for the action are different facts. A module can execute several actions under different mandates, while multiple modules can act under the same mandate.

Why Structured Parties?

An untyped address list cannot distinguish a sender, receiver, target, beneficiary, or controller. Explicit roles improve machine interpretation while keeping the set extensible.

Why Require an Evidence Commitment but Permit an Empty URI?

Every record should commit to the evidence representation used by the recorder, but public retrieval can be inappropriate for confidential or regulated data. A nonzero hash preserves the commitment while an optional URI permits private distribution.

Why Versioned Payload Profiles?

Opaque bytes without a declared schema prevent interoperable decoding. Versioned profile identifiers let consumers recognize stable base encodings and safely preserve unknown custom payloads.

Why Correction Events Instead of Mutable Records?

Replacing an event would erase the prior assertion. A correction chain retains the full history and identifies the current terminal record. The forward pointer and single-successor rule prevent competing corrections to the same event.

Why Index Corrections Under Their Own Type?

A correction is a distinct lifecycle action. Indexing it under EVT_CORRECTION preserves the original event-type history and lets consumers query correction activity directly. Chain-resolution helpers provide current state when needed.

Why Store Records Rather Than Emit Events Only?

EVM contracts cannot read historical logs. Storing records allows on-chain consumers to retrieve event details, traverse correction chains, and iterate by event type. Emitted events remain useful for off-chain indexing.

Why Keep Policy Validation Outside the Log?

The same event and outcome identifiers can be used under different legal and application policies. The log standardizes representation and provenance, not the rule engine deciding which combinations are valid.

Prior Art

ERC-8106 defines ERC-20 value-flow observations, Compliance Entity and Decentralized Entity (CE/DE) classification, compliance flags, and bizId correlation. This ERC instead stores subject-linked lifecycle records with authority and evidence fields, versioned payloads, type indexing, and correction chains. It does not define CE/DE classification or require each record to correspond to an ERC-20 balance change.

ERC-3643 defines regulated-token behavior, identity registries, compliance modules, and lifecycle operations. This ERC is a reporting layer that such a system may call; it does not replace enforcement or identity checks.

ERC-7943 defines real-world asset (RWA) token behavior including transfer eligibility, freezing, and forced transfers. This ERC records attributed lifecycle assertions independently of any token interface.

ERC-7512 defines an on-chain representation of audit reports. This ERC instead defines a subject-indexed compliance-event timeline and correction model.

ERC-5851 defines on-chain verifiable credentials. Credentials can authorize or identify a recorder, but they do not define this event-log schema.

Generic attestation systems can represent compliance assertions through custom schemas. This ERC defines a dedicated stored interface, base identifiers, payload profiles, indexing behavior, and correction provenance.

Backwards Compatibility

This ERC introduces a new interface and does not modify existing token, identity, attestation, or compliance standards.

An existing token or compliance module can call a companion IComplianceEventLog without changing its base token interface. Systems that do not integrate with the log are unaffected.

The subject identifier is application defined, so adoption does not require a particular asset registry or token standard.

Test Cases

Implementations should test at least:

  • zero-based, per-subject event indexing;
  • subject isolation and event-type indexing;
  • actor assignment to msg.sender;
  • recording-time assignment and future-event rejection;
  • the configured backdating policy;
  • rejection of zero evidence commitments;
  • empty and non-empty evidence URIs;
  • party and payload size boundaries;
  • original-event and correction-event guards;
  • correction target bounds and same-subject behavior;
  • original-actor, administrator, and unauthorized correction paths;
  • correction fork prevention and multi-step linear chains;
  • currentEventIndex from original, intermediate, and terminal events;
  • isEventCurrent for corrected and terminal events;
  • invalid event and ordinal queries;
  • recording-order behavior of lastRecordedEventByType;
  • correction indexing under EVT_CORRECTION;
  • exact base payload-profile encodings;
  • opaque handling of unknown payload profiles;
  • acceptance of unconstrained event-type and outcome combinations; and
  • positive and negative ERC-165 detection.

Reference Implementation

A Solidity reference implementation, constants library, unit tests, Medusa property tests, and independent audit are linked from the official discussion thread.

The reference implementation:

  • uses recorder and administrator roles;
  • permits the original actor or an administrator with recorder authority to correct an event;
  • limits party arrays to 10 entries;
  • limits payloads to 2048 bytes;
  • rejects events backdated by more than 30 days;
  • stores unknown payload profiles without decoding them; and
  • does not validate event-type and outcome combinations.

Role design and the 30-day backdating window are reference deployment choices. The size limits and externally observable interface behavior are requirements of this ERC.

Security Considerations

Recorder Trust

The log proves that an authorized address recorded particular bytes. It does not prove that the record is true. A compromised, malicious, or incorrectly authorized recorder can submit false or misleading events.

Claimed Authority

authority is self-asserted. A recorder can claim a court order, regulator, or internal policy that does not exist or does not authorize the action. Consumers must verify authority evidence independently.

Underlying Action Verification

A compliance event is not proof that the underlying issuance, transfer, freeze, KYC decision, or other action occurred. Consumers requiring that proof must verify the referenced operation and its relationship to the record.

Correction Authorization

Fork prevention does not determine who is entitled to correct a record. A weak correction policy can let one recorder supersede another recorder’s assertions. Implementations must document and enforce correction authority.

Long Correction Chains

currentEventIndex traverses on-chain correction pointers. Although chains are linear and acyclic, a long chain can consume substantial gas or make an on-chain call impractical. Applications should avoid unnecessary repeated corrections and may resolve long histories off-chain.

Backdating

occurredAt is supplied by the recorder. Rejecting future timestamps prevents one class of invalid input but does not establish historical accuracy. A documented backdating limit reduces, but does not eliminate, fabricated history.

Privacy and Data Protection

All event fields, dynamic payloads, party addresses, and URIs stored on a public chain are permanently observable. Implementations must not place personal, confidential, investigative, or legally restricted information on-chain merely because the interface permits it.

Public-chain deployments should use opaque or salted subject identifiers, minimal party arrays, generalized outcomes, redacted payloads, and evidence commitments whose preimages are distributed through appropriate access controls. Hashing low-entropy personal data without a secret salt does not provide meaningful privacy.

Evidence Availability and Ambiguity

A nonzero evidence hash does not make evidence available or identify the hashing and document scheme by itself. Implementations must document how evidence commitments are derived and how authorized consumers obtain the preimage.

Payload Confusion

The log can store malformed known payloads and arbitrary unknown profiles. A consumer that decodes without first checking payloadProfileId can misinterpret attacker-controlled bytes. Consumers must use profile-aware decoding and reject malformed known profiles.

Event-Type and Outcome Confusion

The base log does not validate event-type and outcome combinations. Consumers must not treat a stored combination as policy-approved unless the recorder’s application enforces the applicable matrix.

Storage Growth and Retrieval Costs

The log is append-only and grows monotonically. Authorization, bounded dynamic fields, reporting-frequency policy, and operational monitoring are necessary to control storage costs and spam.

Event and Storage Interpretation

Off-chain indexers can reconstruct timelines from events, but on-chain contracts cannot read historical logs. On-chain consumers must use storage getters. Indexers should reconcile events with storage when resolving correction chains and current state.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Chris Turner <c.turner@kula.com>, David Hay (@david-hay), Reagan Simpson (@krumg111), Collins Musyimi (@Musyimi97), "ERC-8328: Subject-Linked Compliance Event Log [DRAFT]," Ethereum Improvement Proposals, no. 8328, July 2026. Available: https://eips.ethereum.org/EIPS/eip-8328.