diff --git a/ARCs/arc-1400.md b/ARCs/arc-1400.md new file mode 100644 index 000000000..6c4937c06 --- /dev/null +++ b/ARCs/arc-1400.md @@ -0,0 +1,140 @@ +--- +arc: 1400 +title: Security Token Standard Suite +description: Composite specification aggregating core security token capabilities (issuance, partitioning, documents, controller) +author: Ludovit Scholtz (@scholtz) +discussions-to: https://github.com/algorandfoundation/ARCs/discussions +status: Draft +type: Standards Track +category: Interface +sub-category: Application +created: 2025-09-03 +requires: 4, 88, 1594, 1410, 1643, 1644 +replaces: ERC-1400 +--- + +# ARC-1400: Security Token Standard Suite + +## Abstract + +ARC-1400 defines a composable suite of Algorand smart contract application layer specifications enabling compliant issuance, partitioned holdings, document disclosure, and controller / regulatory actions for tokenized securities. It adapts the semantics of the Ethereum ERC-1400 family (ERC-1594, ERC-1410, ERC-1643, ERC-1644) to Algorand primitives including ARC-200 (ERC-20 port), smart contract global/local state, boxes, logic signatures, and rekeyed multi-signature governance accounts. + +## Motivation + +Security tokens require: + +- Transfer restriction checks (jurisdiction, KYC/AML, lock-up) with informative rejections. +- Partitioned balances (e.g., unrestricted, restricted, escrow, tranches) with atomic transfer semantics. +- Off-chain document disclosure with on-chain integrity proofs. +- Regulator / controller powers for forced transfers, seizures, or redemptions under predefined governance. + +On Ethereum these are expressed via a set of interfaces across multiple ERCs composing ERC-1400. Algorand's architecture (ARC-200 base fungible token primitive plus AVM smart contracts) provides distinct affordances: fast finality, stateless/stateful TEAL, and logic signature / rekey features. ARC-1400 maps required behaviors into deterministic AVM logic while minimizing transaction overhead and preserving auditability. + +## Specification Overview + +ARC-1400 is an umbrella designation; compliance implies conformance with the component ARCs it aggregates: + +- ARC-1594 (Core Security Token Operations & Transfer Validation) +- ARC-1410 (Partitioned Balances) +- ARC-1643 (Document Registry) +- ARC-1644 (Controller Operations) + +An implementation MAY provide a unified application (single App ID) coordinating all modules, or deploy multiple composable applications with standardized ABI method names and box/global state keys. + +## Roles + +- Issuer: Originates and manages supply, documents, compliance data. +- Controller: Authorized entity (could be same as Issuer) with limited override powers (ARC-1644). +- Investor: Holder of ARC-200 units. +- Registrar / Compliance Oracle: Off-chain / on-chain service that signs or writes eligibility data (e.g., KYC flags, jurisdiction codes) into contract state. +- Document Provider: Pushes document hashes / URIs (ARC-1643). +- Governance Multisig: Rekeyed address or LogicSig controlling privileged calls. + +## Algorand Mapping + +| Concept | Ethereum (ERC-1400) | Algorand (ARC-1400) | +| ------------------ | ------------------------------------- | ----------------------------------------------------------------------------------------- | +| Token Units | ERC-20 ledger | ARC-200 | +| Partition Balances | Mapped in contract storage | Boxes (partition -> uint balance) per holder or local state schema | +| Transfer Pre-Check | Smart contract hook or off-chain call | Group transaction including App call performing eligibility logic before ARC-200 transfer | +| Force Transfer | Controller function | App call + inner transaction transferring ARC-200 units using controller authority | +| Document Hashes | On-chain mapping | App global state / boxes storing (name -> struct {hash, URI, timestamp}) | +| Compliance Data | Contract storage | Local state (per address flags) + boxes for extended KYC metadata | + +## Transaction Patterns + +Implementations SHOULD leverage atomic groups: + +1. Validate transfer: App call (method: `arc1594_validate_transfer(partition, from, to, amount, data)` ) returning success code via log or state write. +2. Execute ARC-200 transfer: Subsequent token transfer (or inner transaction) referencing validated parameters. App SHOULD enforce replay protection by tagging group ID / round. + +Forced operations (ARC-1644) MUST be executed as: governance-signed App call + inner ARC-200 transfer using controller-managed authority. + +### ARC-200 vs Partition Balance Interaction + +To avoid ambiguity implementers MUST document and adhere to the following normative rules (recommended defaults provided): + +- Invariant: For each holder `sum(partition_balances) == arc200_balance` at all times. +- Moving units between partitions (reclassification) DOES NOT change `arc200_balance`; it debits one partition and credits another atomically. +- Plain ARC-200 transfers without an accompanying partition parameter SHOULD operate solely on the default/unrestricted (zero-address) partition. If insufficient balance exists there, the transfer MUST fail rather than implicitly sourcing from other partitions. +- Implementations MAY disable plain ARC-200 transfers (enforcing `arc1410_transfer_by_partition` exclusively). If so, they MUST expose clear failure reason codes when a bare transfer attempt is made. +- Receiving units via a plain ARC-200 transfer credits only the default partition; no auto-allocation across other partitions occurs. +- Issuance / redemption via partition-aware methods adjusts both ARC-200 total supply and the specified partition balance in one atomic group. + +Rationale: Explicit partition context prevents inadvertent regulatory circumvention and preserves audit clarity. + +## Standard Keys and ABI + +Recommended ABI method names (snake_case) with ARC-4 type signatures (arguments then return types where applicable). Unless specified otherwise `uint64` refers to ARC-4 `uint64`, `byte[]` to ARC-4 `bytes`, and addresses to ARC-4 `address`. + +Divergence vs original ERC family: ERC-1410/1594 use `bytes32` for partition identifiers; ARC-1400 standardizes on `address` for partition identifiers to leverage native authorization semantics and zero-address default partition. + +- `arc1594_issue(to: address, amount: uint64, partition: address, data: bytes)` +- `arc1594_redeem(from: address, amount: uint64, partition: address, data: bytes)` +- `arc1594_validate_transfer(partition: address, from: address, to: address, amount: uint64, data: bytes) -> (code: uint64, reason: bytes)` +- `arc1410_transfer_by_partition(from: address, to: address, partition: address, amount: uint64, data: bytes) -> (code: uint64, reason: bytes)` +- `arc1643_set_document(name: bytes, uri: bytes, hash: bytes32)` +- `arc1643_get_document(name: bytes) -> (uri: bytes, hash: bytes32, timestamp: uint64)` +- `arc1643_document_hash(name: bytes) -> (hash: bytes32)` +- `arc1643_document_names() -> (names: bytes[])` +- `arc1644_controller_transfer(from: address, to: address, partition: address, amount: uint64, data: bytes, operator_data: bytes) -> (code: uint64)` +- `arc1644_controller_redeem(from: address, partition: address, amount: uint64, operator_data: bytes) -> (code: uint64)` +- `arc1644_is_controllable() -> (flag: uint64)` +- `arc1644_set_controller(new_controller: address)` +- `arc1644_add_controller(addr: address)` / `arc1644_remove_controller(addr: address)` +- `set_investor_flag(addr: address, flag_key: bytes, value: uint64)` (un-prefixed governance/compliance helper; MAY be optionally namespaced `arc1594_set_investor_flag`) + +Notes: + +- `partition` is always an ARC-4 `address`; the zero address MAY denote the default/unrestricted partition. +- Implementations MAY expose supplementary view methods for pagination; those should follow the same snake_case + ARC-4 typing convention. + +Box / state key naming MUST be canonical ASCII lowercase with hyphen separation where applicable. + +## Return Codes + +ARC-1594 defines standardized failure codes; see that spec. Implementations MUST log the code (uint64) in the validate call and MAY log a reason (UTF-8 string) for discovery off-chain. + +## Security Considerations + +- Use logic to prevent double-spend across partitions (sum of partitions == ARC-200 balance). +- Ensure controller authority cannot bypass validation except where explicitly permitted. +- Off-chain document URIs must be integrity-protected by cryptographic hash; consider IPFS CID v1. +- Governance multisig threshold changes must be timelocked. +- Avoid storing PII on-chain; store only hashed or coded references. + +## Backwards Compatibility + +ARC-1400 implementers MAY simultaneously expose standard ARC-200 metadata fields. Non-partitioned wallets can still transfer unrestricted partition units if exposed as standard ARC-200 units where appropriate. + +## Reference Implementation + +[Security token](https://github.com/scholtz/arc-1400/blob/main/projects/arc-1400/smart_contracts/security_token/) + +## Rationale + +Aggregation clarifies compatibility claims for integrators; a single ARC number signals presence of all subordinate capabilities. + +## Copyright + +Copyright and related rights waived via CC0 1.0 Universal.