Overview
A token standard that treats every acquisition (lot) as its own on-chain record, enabling per-lot cost-basis, lineage, and regulatory controls.
Why Lots?
- Precise handling of vesting, lock-ups, and wash-sale rules
- On-chain FIFO/LIFO tax reporting
- Easier partial sales or spin-offs without external databases
Example Use-Cases
Domain | How 7752 helps |
---|---|
Equity & options | Track every certificate / grant as its own lot; carry vesting metadata in uri or data . |
Debt & convertibles | Coupon lots, note splits, or SAFE β equity conversion keep lineage via parentLotId . |
Real-world assets | Home, boat, artworkβall represented as subdividable lots with transparent cost basis. |
Fund accounting | Index 7752 events to generate investor K-1s or Form 8949 automatically. |
TransferType Enum (semantic meaning)
Value | Typical action | Tax context captured |
---|---|---|
INTERNAL |
Move between wallets you control | Usually non-taxable administrative action |
SALE |
Armβs-length sale | Market transaction for consideration |
GIFT |
No-consideration transfer | Gratuitous transfer between parties |
INHERITANCE |
Transfer at death | Estate/probate distribution |
INCOME |
Payroll / airdrop / staking yield / RSU | Compensation or earned income |
Each jurisdiction applies its own tax rules to these transfer contexts.
Minimal-core vs. Extensions
- Core: lot CRUD,
TransferType
, metadata, approvals - Optional extension:
customId
(legacy certificate numbers)- Keeps the base spec lean for DeFi deployments
- Extension interface
ILotTokenCustomId
addsupdateCustomId
+ event
Solidity Interface (core only)
// SPDX-License-Identifier: MIT
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, airdrops, staking rewards
}
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 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
);
/**
* @notice Emitted when a lot is split into multiple lots
*/
event LotSplit(
bytes32 indexed sourceLotId,
bytes32[] newLotIds,
uint256[] quantities,
address indexed owner
);
/*ββββββββββββββββββββββββββββββββββ
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);
/**
* @notice Splits a lot into multiple new lots
* @param lotId Source lot identifier
* @param quantities Array of quantities for new lots (must sum to original)
* @param uris Array of metadata URIs for new lots
* @param dataArray Array of additional data for new lots
* @return newLotIds Array of identifiers for new lots
*/
function splitLot(
bytes32 lotId,
uint256[] calldata quantities,
string[] calldata uris,
bytes[] calldata dataArray
) external returns (bytes32[] memory newLotIds);
/*ββββββββββββββββββββββββββββββββββ
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);
}