--- eip: 7752 title: Lot-based Token description: A token treating each acquisition (lot) as an on-chain record with cost-basis and lineage. author: Matt Rosendin (@mrosendin) discussions-to: https://ethereum-magicians.org/t/erc-7752-equity-token/20735 status: Draft type: Standards Track category: ERC created: 2024-08-06 --- ## Abstract [ERC-7752](./eip-7752.md) defines a **lot-based** token model where each issuance or acquisition event creates a unique **lot** (`lotId`) with its own quantity, basis, acquisition date, and lineage. This standard provides core lot management functions while enabling modular extensions for transfer controls, compliance, and administrative features. ## Motivation Traditional token standards excel at _fungibility_ ([ERC-20](./eip-20.md)) or _single, indivisible items_ ([ERC-721](./eip-721.md)). Real-world assets—equity certificates, debt notes, real-estate fractions—require granular tracking: - **Distinct lots** with individual basis and acquisition dates - **Lineage tracking** for audit trails and compliance - **Modular architecture** supporting jurisdiction-specific extensions - **Deterministic events** for tax engines and regulatory reporting ERC-7752 provides the foundational interface for lot-based tokens while enabling specialized implementations through modular extensions. ## 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. ### Core Interface ```solidity // SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.20; /** * @title ERC-7752 Lot Token (Core Interface) * @notice Core lot management */ interface IERC7752 { /*────────────────────────────────── Data Structures ──────────────────────────────────*/ enum TransferType { INTERNAL, // Administrative transfers, splits, merges SALE, // Market transactions for consideration GIFT, // Gratuitous transfers INHERITANCE, // Estate/probate transfers INCOME // Compensation, dividends, staking rewards, airdrops } struct Lot { bytes32 parentLotId; // Parent lot for lineage tracking uint256 quantity; // Amount in this lot address currency; // Currency used for acquisition uint256 basis; // Total cost basis (in currency) uint256 acquisitionDate; // Unix timestamp of original acquisition uint256 lastUpdate; // Unix timestamp of last modification address owner; // Current owner address TransferType transferType; // How this lot was acquired string uri; // Metadata URI bytes data; // Additional lot-specific data } /*────────────────────────────────── Events ──────────────────────────────────*/ /** * @notice Emitted when a new lot is created */ event LotCreated( address indexed owner, bytes32 indexed lotId, bytes32 indexed parentLotId, uint256 quantity, address currency, uint256 basis, uint256 acquisitionDate, TransferType transferType, string uri, bytes data ); /** * @notice Emitted when a lot is transferred (full or partial) */ event LotTransferred( bytes32 indexed lotId, bytes32 indexed newLotId, address indexed from, address indexed to, uint256 quantity, uint256 newBasis, TransferType transferType, string uri, bytes data ); /** * @notice Emitted when lots are merged into a new lot */ event LotsMerged( bytes32[] sourceLotIds, bytes32 indexed newLotId, address indexed owner, uint256 totalQuantity, string uri, bytes data ); /*────────────────────────────────── Core Read Functions ──────────────────────────────────*/ /** * @notice Returns the token name */ function name() external view returns (string memory); /** * @notice Returns the token symbol */ function symbol() external view returns (string memory); /** * @notice Returns lot details for a given lot ID * @param lotId The lot identifier * @return lot The lot data structure */ function getLot(bytes32 lotId) external view returns (Lot memory lot); /** * @notice Returns all lot IDs owned by an address * @param owner The owner address * @return lotIds Array of lot identifiers */ function getLotsOf(address owner) external view returns (bytes32[] memory lotIds); /** * @notice Returns total quantity across all lots for an owner * @param owner The owner address * @return totalQuantity Sum of quantities across all lots */ function balanceOf(address owner) external view returns (uint256 totalQuantity); /** * @notice Checks if a lot ID exists and is valid * @param lotId The lot identifier * @return exists True if lot exists */ function lotExists(bytes32 lotId) external view returns (bool exists); /*────────────────────────────────── Core Lot Operations ──────────────────────────────────*/ /** * @notice Creates a new lot * @param owner Initial owner of the lot * @param quantity Amount in the lot * @param currency Currency used for acquisition (address(0) for native) * @param basis Total cost basis in currency * @param acquisitionDate Unix timestamp of acquisition * @param transferType How this lot was acquired * @param uri Metadata URI for the lot * @param data Additional lot-specific data * @return lotId The created lot identifier */ function createLot( address owner, uint256 quantity, address currency, uint256 basis, uint256 acquisitionDate, TransferType transferType, string calldata uri, bytes calldata data ) external returns (bytes32 lotId); /** * @notice Transfers full or partial lot to another address * @param lotId Source lot identifier * @param to Recipient address * @param quantity Amount to transfer (must be ≤ lot quantity) * @param transferType Type of transfer for the new lot * @param newBasis Cost basis for the transferred portion * @param uri Metadata URI for the new lot * @param data Additional data for the new lot * @return newLotId Identifier of the newly created lot for recipient */ function transfer( bytes32 lotId, address to, uint256 quantity, TransferType transferType, uint256 newBasis, string calldata uri, bytes calldata data ) external returns (bytes32 newLotId); /** * @notice Transfers lot on behalf of owner (requires approval) * @param lotId Source lot identifier * @param from Owner address * @param to Recipient address * @param quantity Amount to transfer * @param transferType Type of transfer * @param newBasis Cost basis for transferred portion * @param uri Metadata URI for new lot * @param data Additional data for new lot * @return newLotId Identifier of newly created lot */ function transferFrom( bytes32 lotId, address from, address to, uint256 quantity, TransferType transferType, uint256 newBasis, string calldata uri, bytes calldata data ) external returns (bytes32 newLotId); /** * @notice Merges multiple lots into a single new lot * @param sourceLotIds Array of lot identifiers to merge (must have same owner) * @param uri Metadata URI for merged lot * @param data Additional data for merged lot * @return newLotId Identifier of the merged lot */ function mergeLots( bytes32[] calldata sourceLotIds, string calldata uri, bytes calldata data ) external returns (bytes32 newLotId); /*────────────────────────────────── Approval System ──────────────────────────────────*/ /** * @notice Approve an operator for a specific lot * @param lotId The lot identifier * @param operator Address to approve * @param approved True to approve, false to revoke */ function approveLot(bytes32 lotId, address operator, bool approved) external; /** * @notice Approve an operator for all lots owned by caller * @param operator Address to approve * @param approved True to approve, false to revoke */ function setApprovalForAll(address operator, bool approved) external; /** * @notice Check if operator is approved for a specific lot * @param lotId The lot identifier * @param operator Address to check * @return approved True if approved */ function isApprovedForLot(bytes32 lotId, address operator) external view returns (bool approved); /** * @notice Check if operator is approved for all lots of an owner * @param owner The owner address * @param operator Address to check * @return approved True if approved for all */ function isApprovedForAll(address owner, address operator) external view returns (bool approved); } ``` ### Lot ID Generation Lots are identified with a `bytes32` ID. Implementations MUST ensure lot IDs are: - **Deterministic**: Same inputs produce same lot ID within the contract - **Collision-resistant**: Unique within the contract scope - **Contract-scoped**: Include contract identifier to prevent cross-contract collisions #### Recommended Approach: ```solidity function _generateLotId( address owner, uint256 quantity, uint256 timestamp ) internal view returns (bytes32) { return keccak256(abi.encodePacked( owner, quantity, timestamp, address(this) // Ensures contract-scoped uniqueness )); } ``` **Note**: This is a recommended implementation. Alternative approaches are permitted provided they meet the uniqueness and collision-resistance requirements above. ### Transfer Type Usage The `TransferType` enum enables implementations to capture transfer context for compliance and tax purposes: - `INTERNAL`: Administrative transfers, splits, merges (typically no taxable event) - `SALE`: Market transactions for consideration (usually triggers capital gains) - `GIFT`: Gratuitous transfers (carry-over basis treatment varies by jurisdiction) - `INHERITANCE`: Estate transfers (step-up basis rules vary by jurisdiction) - `INCOME`: Compensation, dividends, staking rewards, airdrops (usually ordinary income) Implementations MAY use this information for automated compliance reporting but SHOULD consult applicable regulations. ## Rationale ### Why Lot-Based Architecture? Traditional fungible tokens aggregate all holdings into a single balance, losing crucial information needed for: - **Tax compliance**: Basis tracking for capital gains calculations - **Regulatory reporting**: Audit trails for compliance officers - **Corporate actions**: Proper handling of stock splits, dividends, vesting - **Estate planning**: Clear lineage for inheritance and probate ### Core vs Extensions ERC-7752 Core focuses on essential lot operations while enabling modular extensions: **Core Standard (ERC-7752):** - Lot creation, transfer, merge operations - Basic approval system - Essential events for tracking - No administrative controls or transfer restrictions **Potential Extensions:** - Lot splitting functionality - Transfer controls and compliance checks - Pause/freeze functionality - Forced transfers and administrative overrides - Multi-signature requirements - Time-based restrictions - Custom lot ID functionality (for legacy systems) This separation allows: - Simple implementations for basic use cases - Complex compliance layers when needed - Clear upgrade paths - Regulatory flexibility ### Event Design Events are designed for deterministic compliance reporting: - All lot state changes emit structured events - Transfer types enable automated tax categorization - Lineage tracking supports audit requirements - Consistent event signatures across implementations ## Backwards Compatibility ERC-7752 is not backward-compatible with [ERC-20](./eip-20.md), [ERC-721](./eip-721.md), or [ERC-1155](./eip-1155.md) because: - Each `lotId` represents a semi-fungible slice with unique properties - Transfer operations create new lots rather than moving balances - Approval system operates on lot-level rather than token-level Implementations MAY provide compatibility layers but this is not required by the standard. ## Security Considerations ### Lot ID Uniqueness Implementations MUST ensure lot IDs are unique across the entire token contract to prevent: - Accidental overwrites of existing lots - Unauthorized access to lot data - Inconsistent state between lot records ### Approval Management The two-tier approval system (lot-specific and owner-wide) requires careful implementation: - Lot-specific approvals SHOULD take precedence over global approvals - Approval checks MUST occur before any transfer operation - Approvals SHOULD be revoked when lots are transferred or modified ### Arithmetic Safety Lot operations involving quantities and basis calculations MUST: - Check for integer overflow/underflow - Validate that split quantities sum to original lot quantity - Ensure basis calculations maintain precision ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).