EIP.tools

EIP.tools

⚠️ DraftStandards Track: ERC

ERC-1643: Document Management for Security Tokens

Interface to attach, update, remove, and enumerate legal or operational documents for token contracts.

Authors
Created2018-09-09
Discussion Linkhttps://ethereum-magicians.org/t/erc-1643-document-management-standard-erc-1400/27437

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#1754PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationInterfaceInterface Detection (ERC-165)Function RequirementsRationaleBackwards CompatibilityTest CasesReference ImplementationSecurity ConsiderationsCopyright

Abstract

This ERC defines a standard interface for associating documents with a token contract and for notifying off-chain systems when those documents change. Documents can represent legal agreements, offering materials, disclosures, or other issuer-provided references needed for security token operations.

Motivation

Security tokens commonly represent assets with legal rights and obligations that depend on external documents. Wallets, exchanges, custodians, and compliance tools need a predictable way to discover those documents and track updates.

Without a standard, each implementation exposes different storage and retrieval methods, increasing integration cost and operational risk. A common interface allows ecosystem participants to read and monitor document metadata consistently.

Within security token frameworks, the document management component highlights that security tokens usually have associated documentation such as offering documents and legend details. The ability to set, remove, and retrieve these documents, with events emitted on those actions, allows investors and integrators to remain up to date.

This ERC intentionally does not define an on-chain mechanism for investors to attest they have read or agreed to any document.

Although originally designed for security tokens built on ERC-20 as part of a broader real-world asset token suite, this interface is not restricted to that context. It can be adopted by any token standard, including ERC-721 non-fungible tokens and ERC-1155 multi-tokens, as well as by decentralized applications, vaults, and any other on-chain product that requires structured document management.

Historically, this proposal was authored as part of a broader security token standards suite that had not yet been merged in this repository when this proposal was added.

Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Implementations MUST support querying and subscribing to updates on any relevant documentation for the security.

A document entry is identified by a name (bytes32) and stores:

  • A URI (string) pointing to the document location.
  • A content hash (bytes32) for integrity checks.
  • A last-modified timestamp (uint256) set when the entry is written.

Interface

/// @title IERC1643 Document Management
interface IERC1643 {
    /// @notice Emitted when a document is created or updated.
    /// @param name Identifier of the document.
    /// @param uri Document location.
    /// @param documentHash Hash of the document contents.
    event DocumentUpdated(bytes32 indexed name, string uri, bytes32 documentHash);

    /// @notice Emitted when a document is removed.
    /// @param name Identifier of the document.
    /// @param uri Document location at the time of removal.
    /// @param documentHash Hash of the document contents at the time of removal.
    event DocumentRemoved(bytes32 indexed name, string uri, bytes32 documentHash);

    /// @notice Reverts when `setDocument` is called with `name == bytes32(0)`.
    error ERC1643InvalidName();

    /// @notice Reverts when `removeDocument` is called for a missing document.
    error ERC1643MissingDocument();

    /// @notice Creates or updates a document entry.
    /// @dev MUST emit `DocumentUpdated` on success.
    /// @param name Identifier of the document.
    /// @param uri Document location.
    /// @param documentHash Hash of the document contents.
    function setDocument(bytes32 name, string calldata uri, bytes32 documentHash) external;

    /// @notice Removes an existing document entry.
    /// @dev MUST emit `DocumentRemoved` on success.
    /// @param name Identifier of the document to remove.
    function removeDocument(bytes32 name) external;

    /// @notice Returns metadata for a document identified by `name`.
    /// @param name Identifier of the document.
    /// @return uri Document location.
    /// @return documentHash Hash of the document contents.
    /// @return lastModified Last update timestamp.
    function getDocument(bytes32 name)
        external
        view
        returns (string memory uri, bytes32 documentHash, uint256 lastModified);

    /// @notice Returns all document names currently tracked by the contract.
    /// @return documentNames Names of all documents that are currently set.
    function getAllDocuments() external view returns (bytes32[] memory documentNames);
}

Interface Detection (ERC-165)

Implementations SHOULD support ERC-165 interface detection.

When ERC-165 is implemented, supportsInterface SHOULD return true for type(IERC1643).interfaceId and for the ERC-165 interface id.

Function Requirements

  • getDocument:

    • MUST return the latest values for the provided document name.
    • MUST return empty values when the entry does not exist ("", bytes32(0), 0).
    • MUST NOT revert solely because the entry does not exist.
    • Implementations SHOULD ensure that a stored entry always has a non-zero lastModified, so that lastModified == 0 identifies an absent entry. Since uri and documentHash MAY both be empty for a stored document, they cannot distinguish an absent entry from one stored with empty metadata, and lastModified is the only value that can. Integrators should treat this as advisory rather than guaranteed when interacting with deployments predating this guidance.
  • setDocument:

    • MUST create a new entry when name is not present.
    • MUST overwrite the existing entry when name already exists.
    • MUST update the stored last-modified timestamp.
    • MUST emit DocumentUpdated after state changes.
    • MUST revert if the update cannot be persisted.
    • SHOULD revert when name == bytes32(0) to avoid ambiguous/default-key usage.
    • uri and documentHash MAY be empty ("" and bytes32(0)), depending on issuer workflow and document lifecycle stage.
    • Implementations MAY decide to reject empty uri and/or empty documentHash based on policy requirements.
    • Implementations SHOULD use the custom error defined in the interface (ERC1643InvalidName()) when rejecting name == bytes32(0).
    • Implementations MAY use different error names/signatures than those shown in this specification.
  • removeDocument:

    • MUST remove the entry identified by name.
    • MUST emit DocumentRemoved with the removed metadata.
    • MUST revert if removal cannot be completed.
    • Implementations SHOULD use the custom error defined in the interface (ERC1643MissingDocument()) when the named document does not exist.
    • Implementations MAY use different error names/signatures than those shown in this specification.
  • getAllDocuments:

    • MUST include every document name added by setDocument and not removed by removeDocument.
    • MUST NOT include removed document names.
    • The order of the returned names is unspecified. Removing a document MAY change the position of unrelated names, so consumers MUST NOT rely on a stable ordering, and MUST NOT treat a change in position as a change to a document.

Rationale

  • The standard uses bytes32 names to keep keys compact and deterministic, while leaving naming conventions to implementations. A URI-based pointer is used instead of on-chain document storage to avoid high gas costs and to support existing off-chain document systems.
  • Including a document hash enables clients to verify that fetched off-chain content matches issuer-published metadata.
  • Emitting update and removal events supports indexing and near-real-time monitoring without repeated full-state polling.
  • While a human-readable document title cannot always be represented directly in bytes32 without hashing or canonicalization, bytes32 remains practical for on-chain identifiers because fixed-size values can be compared directly (a == b). By contrast, string comparisons generally require hashing (for example, keccak256(bytes(s))), which increases contract code size and gas usage when repeated comparisons are needed on-chain, such as locating and removing a document name from an array.

Backwards Compatibility

This ERC is additive and does not alter base token transfer semantics. It can be implemented alongside existing token standards and permissioning systems without changing their core behavior.

Test Cases

Implementations should verify at least the following:

  • Adding a new document and reading it through getDocument.
  • Reading a name that was never set, confirming getDocument returns empty values ("", bytes32(0), 0) and does not revert.
  • Updating an existing document and validating changed URI/hash/timestamp.
  • Removing a document and ensuring it is no longer returned by getAllDocuments.
  • Emission of DocumentUpdated on create/update and DocumentRemoved on delete.
  • Enumeration consistency after multiple add/update/remove operations.

Reference Implementation

The interface is provided in the reference interface. A reusable abstract module implementing the full interface is provided in the reference module.

Example integrations attaching the module to ERC-20 and ERC-721 tokens are provided in the ERC-20 example and the ERC-721 example.

These examples use the OpenZeppelin library and restrict document mutation to the contract owner. They are provided for educational purposes only and have not been audited.

The module maintains:

  • Mapping from bytes32 name to document metadata.
  • Array/set for enumeration of active names.
  • Index tracking to support O(1) removals from the enumeration set.

Security Considerations

  • Document URIs may reference mutable off-chain content. Consumers are strongly encouraged to verify content using the published documentHash and trusted retrieval channels.
  • Implementations should protect setDocument and removeDocument with appropriate authorization, otherwise unauthorized actors can modify legal or operational references.
  • Applications should treat event streams as advisory and reconcile against on-chain state when correctness is critical.
  • getAllDocuments returns the entire set of names in a single call, and its response grows with the number of stored documents. It is the only enumeration path defined here, so a contract holding a large document set may produce a call that exceeds the gas limit an eth_call provider applies, leaving no standard way to enumerate. Implementations expecting large sets should consider exposing an additional paginated accessor alongside this interface.
  • Document names may not always fit cleanly into bytes32, especially for long legal titles. Implementations should avoid lossy truncation of human-readable names; using a deterministic hash-based identifier (for example, the document content hash or a hash of a canonical full title) as the bytes32 name is a safer alternative.
  • The custom errors ERC1643InvalidName() and ERC1643MissingDocument() are defined in this interface but were absent from the earlier draft text of this proposal. Older implementations may not define these errors and may instead revert with strings or implementation-specific error patterns. Integrators should not assume all ERC-1643 contracts expose identical revert data.
  • ERC-165 interface detection was also not part of the earlier ERC-1643 draft text. Older implementations may not expose supportsInterface for ERC-165 or IERC1643, so integrators should treat ERC-165 support as optional when interacting with legacy deployments.

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth