diff --git a/ARCs/arc-1594.md b/ARCs/arc-1594.md new file mode 100644 index 000000000..cbfc8e069 --- /dev/null +++ b/ARCs/arc-1594.md @@ -0,0 +1,113 @@ +--- +arc: 1594 +title: Core Security Token Operations +description: Issuance, redemption, and validation primitives for Algorand security tokens +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: 88, 200 +replaces: +--- + +# ARC-1594: Core Security Token Operations + +## Abstract + +ARC-1594 specifies core issuance, redemption, and transfer validation semantics for security tokens on Algorand. It provides deterministic pre-transfer checks and standardized status / error codes enabling wallets, exchanges, and compliance services to integrate with regulated token flows. + +## Motivation + +Security tokens require pre-trade eligibility checks (KYC/AML, jurisdiction, lock-up expirations) that are not expressible purely via permissionless transfers. ERC-1594 defines these on Ethereum; this ARC maps them to Algorand leveraging atomic transaction groups and AVM logic for predictable, low-latency enforcement. + +## Specification + +### Interfaces (ABI Recommendations) + +(All method identifiers in snake*case with ARC-4 type signatures. ARC-1594 methods are namespaced with `arc1594*`. Simplification: this core profile drops explicit partition parameters; partition-aware functionality is delegated to ARC-1410.) + +- `arc1594_issue(to: address, amount: uint256, data: bytes)` +- `arc1594_redeem(amount: uint256, data: bytes)` (caller/self redemption) +- `arc1594_redeemFrom(from: address, amount: uint256, data: bytes)` (owner/governance or holder-authorized redemption) +- `arc1594_set_issuable(flag: bool)` (owner toggles global issuance enable switch) +- `arc1594_is_issuable() -> (flag: bool)` (readonly global issuance enable flag) +- `arc1594_transfer_with_data(to: address, amount: uint256, data: bytes)` (standard transfer emitting/accepting opaque metadata) +- `arc1594_transfer_from_with_data(from: address, to: address, amount: uint256, data: bytes)` (allowance/operator transfer with metadata) + +Partitioned behavior (if needed) MUST be layered by simultaneously implementing ARC-1410; ARC-1594 then operates on the default/unrestricted partition implicitly. + +Note: Per-account KYC / lockup admin setter methods have been removed from the core; such compliance layers MAY be specified by an extension ARC to keep ARC-1594 minimal. + +### Codes + +Return codes: + +- `0` Success +- `10` SenderNotEligible +- `11` RecipientNotEligible +- `12` PartitionRestricted +- `13` AmountExceedsPartitionBalance +- `14` GlobalTransferHalted +- `15` LockupActive +- `16` DocumentDisclosureRequired + (Code 20 removed in partitionless core profile; unknown partition is handled by ARC-1410 layer.) +- `30` InvalidSignatureOrAuth +- `40` InternalError + +Codes MUST be logged as the first 8 bytes of a log entry or written to a well-known box/state key `last-val-code` keyed by sender address. Reason strings are optional and SHOULD be UTF-8. + +### State Model + +Minimum required state keys / boxes: + +- Global: `halt` (uint64; 1 = transfers disabled except controller) +- Local (per investor): `kyc` (uint64; 1 = eligible), `lockup-until` (uint64; round or timestamp), optional jurisdiction code `jur` (uint64) +- Boxes (optional extended): `elig-` for arbitrary packed compliance flags. + +### Authorization + +Issuance / Redemption MUST be restricted to governance authority (Issuer) or delegated operators (multi-sig, logic signature) recorded in global state keys (`issuer`, `operator-`). Validation is permissionless but enforces rules. + +### Events (Logging Conventions) + +Implementations SHOULD log compact structured events (CBOR or msgpack) for indexing: + +- arc1594_issue: tag 0x01 | addr | amount | partition (partition omitted in core partitionless profile) +- arc1594_redeem: tag 0x02 | addr | amount | partition (partition omitted in core partitionless profile) + +### Failure Semantics + +If validation fails, the subsequent ARC-200 transfer MUST fail or be omitted. No partial state changes should misrepresent balances. + +## Security Considerations + +- Ensure replay protection: include group ID or txn ID in validation ephemeral state so old approvals can't be reused. +- Prevent redemption of locked or escrowed partitions unless explicitly allowed. +- Use constant-time comparisons for signature attestations if verifying off-chain oracle attestations. + +## Reference Types + +Suggested canonical encoding for address lists in boxes: msgpack array of raw 32-byte addresses. + +## Compliance Oracle Pattern (Optional) + +An oracle signs `(from, to, amount, partition, round, expiryRound)`; contract verifies signature against authorized oracle key, bypassing on-chain local flags where policy allows. + +## Backwards Compatibility + +Can coexist with a plain ARC-200 token; if wallet ignores validation flow, controller enforcement can still reverse unauthorized transfers (with ARC-1644) though this is discouraged for UX predictability. + +## Reference Implementation + +[arc1594.algo.ts](https://github.com/scholtz/arc-1400/blob/main/projects/arc-1400/smart_contracts/security_token/arc1594.algo.ts) + +## Rationale + +Partition-independent core keeps minimal surface, delegating complexity to optional ARCs (1410, 1643, 1644) for modular adoption. + +## Copyright + +CC0 1.0 Universal.