Skip to content

Repository files navigation

ERC-1450: RTA-Controlled Security Token Standard

Reference Implementation

This repository contains the official reference implementation of ERC-1450, a standard for compliant security tokens controlled by a Registered Transfer Agent (RTA).

Production Proven

This standard is backed by real-world production experience. StartEngine has tokenized over $1 billion in securities on the blockchain using the patterns and architecture formalized in ERC-1450. The standard captures lessons learned from years of operating compliant security token infrastructure under SEC regulations.

Project Structure

This reference implementation is part of a two-repository system:

  1. Specification Repository: StartEngine/ERCs

    • Fork of ethereum/ERCs
    • Contains the formal ERC-1450 specification
    • Location: /Users/devendergollapally/StartEngineRepositories/ERCs
    • Spec file: ERCS/erc-1450.md
    • Our pull request PR
  2. Reference Implementation (this repository): StartEngine/erc1450-reference

    • Solidity smart contracts implementing the spec
    • Comprehensive test suite
    • Location: /Users/devendergollapally/StartEngineRepositories/erc1450-reference
    • Contracts: contracts/ERC1450.sol, contracts/RTAProxy.sol

Important: Any changes to the contracts in this repository should be validated against the formal specification in the ERCs repository to ensure compliance.

Overview

ERC-1450 enables compliant securities offerings under SEC regulations by providing:

  • Exclusive RTA Control: Only the designated transfer agent can execute token operations
  • Multi-Signature Security: RTAProxy pattern prevents single key compromise
  • Transfer Request System: Compliant transfer workflow with fees and approvals
  • Regulatory Compliance: Built for SEC Rule 17Ad requirements
  • Court Order Support: Forced transfers for legal compliance
  • Account Restrictions: Freeze/unfreeze capabilities

White Paper

For a non-technical overview of ERC-1450 — the regulatory background, design rationale, and operational workflows — see the ERC-1450 White Paper (v1.0, December 2025).

Key Features

1. RTA-Exclusive Operations

  • All transfers must go through the Registered Transfer Agent
  • Direct ERC-20 transfer() and approve() functions are disabled
  • Minting and burning controlled by RTA only

2. Transfer Request System

  • Token holders or authorized brokers request transfers
  • Fees collected at request time
  • RTA reviews and approves/rejects requests
  • Full audit trail of all transfer activities

3. Multi-Sig Security (RTAProxy)

  • 2-of-3 multi-signature requirement for critical operations
  • Protection against single point of failure
  • Immutable transfer agent once set to RTAProxy

4. Compliance Features

  • Account freezing for regulatory compliance
  • Court order execution capabilities
  • Broker registration and management
  • Configurable fee structures
  • KYC/AML verification requirements
  • Extended reason codes (0-14, 999) for detailed rejection tracking

Upgradeability (New!)

This implementation now includes upgradeable versions of the contracts using OpenZeppelin's UUPS proxy pattern, allowing critical bug fixes without requiring token holder action.

Upgradeable Contracts Available

  • ERC1450Upgradeable.sol - Upgradeable token implementation
  • RTAProxyUpgradeable.sol - Upgradeable multi-sig RTA

Benefits

  • Bug Fixes: Deploy patches without changing contract addresses
  • No Migration: Token holders keep the same addresses and balances
  • Secure: Upgrades require multi-sig RTA approval
  • Gas Efficient: UUPS pattern minimizes overhead

Deployment Options

# Deploy standard (immutable) contracts
npx hardhat run scripts/deploy.js --network polygon
# Deploy upgradeable contracts (recommended for production)
npx hardhat run scripts/deploy-upgradeable.js --network polygon

Upgrade Process

# Upgrade contracts (requires multi-sig approval)
npx hardhat run scripts/upgrade.js --network polygon

For detailed upgradeability documentation, see UPGRADEABILITY.md.

Contract Versioning

All contracts include a version() function that returns the current contract version. This version is automatically synced with package.json to ensure consistency between the npm package version and deployed contracts.

How It Works

// All contracts expose this functionfunction version() externalpurereturns (stringmemory) {
return"1.10.1"; // Matches package.json version
}

Checking Deployed Contract Version

// Query version from a deployed contractconstrtaProxy=newethers.Contract(proxyAddress,RTAProxyABI,provider);constversion=awaitrtaProxy.version();console.log(`Deployed version: ${version}`);// e.g., "1.10.1"

Version Sync Mechanism

The version in contracts is automatically synchronized via:

  1. Pre-commit hook: Runs scripts/sync-version.js before every commit
  2. Pre-compile hook: Runs before npm run compile

This ensures:

  • Contract version() always matches package.json version
  • No manual updates needed when releasing new versions
  • Deployed contracts can be compared against local code

Why This Matters

When you deploy a contract and later update the codebase, you need to know:

  • What version is deployed on-chain?
  • Is there a newer version available locally?
  • Does the deployed contract need an upgrade?

The version() function enables automated tracking and comparison of deployed contracts against the current codebase.

Upgrade Detection Example

// Compare deployed version with local artifactsconstdeployedVersion=awaitcontract.version();// "1.10.0"constlocalVersion=require('erc1450-reference/package.json').version;// "1.10.1"if(deployedVersion!==localVersion){console.log(`Upgrade available: ${deployedVersion}${localVersion}`);}

Architecture

┌─────────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Token Holder │────▶│ ERC1450 │◀────│ RTAProxy │
└─────────────────┘ └──────────────┘ └─────────────────┘
▲ ▲
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ Brokers │ │ RTA Signers │
└─────────────┘ └─────────────┘

Prerequisites

  • Node.js v16+ (tested with v22.14.0)
  • npm v7+ (tested with v10.9.2)

Installation

# Clone the repository
git clone https://github.com/StartEngine/erc1450-reference.git
cd erc1450-reference
# Install dependencies (also installs git hooks via Husky)
npm install
# Compile contracts
npx hardhat compile
# Run tests
npm test# Check test coverage
npx hardhat coverage
# Run security analysis (requires Python + Slither)
slither . --print human-summary

Note: The npm install command automatically sets up git hooks via Husky. These hooks will run hardhat compile and npm test before each commit to ensure code quality.

Developer Workflow

For contributors and developers working on this project:

  1. Clone & Setup

    git clone https://github.com/StartEngine/erc1450-reference.git
    cd erc1450-reference
    npm install # Auto-installs Husky pre-commit hooks
  2. Compile Contracts

    npx hardhat compile
  3. Run Tests

    npm test# Runs all 643 tests
  4. Check Coverage

    npx hardhat coverage # Current: 86.2% branch coverage
  5. Security Analysis (optional, requires Slither)

    pip install slither-analyzer
    slither .
  6. Pre-Commit Hooks (automatic)

    • Husky automatically runs before each commit:
      • ✅ Compiles all Solidity contracts
      • ✅ Runs full test suite (643 tests)
    • To bypass (not recommended): git commit --no-verify

Deployment

Deploy to Local Network

# Start local Hardhat node
npx hardhat node
# Deploy contracts (in new terminal)
npx hardhat run scripts/deploy.js --network localhost

Deploy to Testnet

# Set up environment variablesexport PRIVATE_KEY="your_private_key"export RPC_URL="your_rpc_url"# Deploy
npx hardhat run scripts/deploy.js --network sepolia

Usage

Quick Demos

Run these scripts to see the ERC-1450 system in action:

# Display token information and run basic demo
npx hardhat run scripts/info.js
# Demo minting tokens through multi-sig
npx hardhat run scripts/demo-mint.js
# Demo complete transfer request workflow
npx hardhat run scripts/demo-transfer.js

RTA Operations

For production deployments, use the deployment and operations scripts:

# Deploy contracts
npx hardhat run scripts/deploy.js --network localhost
# After deployment, manage operations using the deployment file# (Requires deployment-{network}.json file from deploy.js)

Token Holder Operations

// RTA sets fee token (one-time setup, typically USDC)awaittoken.connect(rta).setFeeToken(usdcAddress);awaittoken.connect(rta).setFeeParameters(0,feeValue);// 0=flat, 1=percentage// Token holder approves fee token spendawaitfeeToken.connect(holder).approve(tokenAddress,feeAmount);// Request a transfer (single fee token - no ETH)awaittoken.requestTransferWithFee(fromAddress,toAddress,amount,feeAmount);// Check transfer request statusconstrequest=awaittoken.transferRequests(requestId);console.log("Status:",request.status);

Multi-Sig Operations

// Submit operation (first signer)constoperationId=awaitrtaProxy.submitOperation(targetContract,encodedFunctionData,ethValue);// Confirm operation (second signer)awaitrtaProxy.confirmOperation(operationId);// Auto-executes when threshold reached// Check operation statusconstop=awaitrtaProxy.getOperation(operationId);console.log("Executed:",op.executed);

Contract Interfaces

IERC1450

The main security token interface extending ERC-20:

interfaceIERC1450isIERC20, IERC165 {
// RTA Functionsfunction changeIssuer(addressnewIssuer) external;
function setTransferAgent(addressnewTransferAgent) external;
function mint(addressto, uint256amount) externalreturns (bool);
function burnFrom(addressfrom, uint256amount) externalreturns (bool);
// Fee Configuration (single ERC-20 fee token)function setFeeToken(addresstoken) external;
function getFeeToken() externalviewreturns (address);
function setFeeParameters(uint8feeType, uint256feeValue) external;
function getTransferFee(addressfrom, addressto, uint256amount) externalviewreturns (uint256);
// Transfer Request Systemfunction requestTransferWithFee(
addressfrom,
addressto,
uint256amount,
uint256feeAmount
) externalreturns (uint256requestId);
function processTransferRequest(uint256requestId, boolapproved) external;
function rejectTransferRequest(uint256requestId, uint16reasonCode, boolrefundFee) external;
// Fee Withdrawalfunction withdrawFees(uint256amount, addressrecipient) external;
// Compliancefunction setAccountFrozen(addressaccount, boolfrozen) external;
function executeCourtOrder(addressfrom, addressto, uint256amount, bytes32documentHash) external;
}

RTAProxy

Multi-signature contract for RTA operations:

contractRTAProxy {
function submitOperation(addresstarget, bytesmemorydata, uint256value) externalreturns (uint256);
function confirmOperation(uint256operationId) external;
function revokeConfirmation(uint256operationId) external;
function executeOperation(uint256operationId) external;
}

Testing

The test suite covers all major functionality:

# Run all tests
npx hardhat test# Run specific test file
npx hardhat test test/ERC1450.test.js
# Run with coverage
npx hardhat coverage
# Run with gas reporting
REPORT_GAS=true npx hardhat test

Test coverage includes:

  • ✅ Token deployment and initialization
  • ✅ RTA-exclusive operations (mint, burn, transfer)
  • ✅ Transfer request lifecycle
  • ✅ Fee management
  • ✅ Broker registration
  • ✅ Account freezing
  • ✅ Court order execution
  • ✅ Multi-sig operations
  • ✅ Interface detection (ERC-165)

Extended Capabilities (Non-Normative)

The ERC-1450 specification includes comprehensive documentation for real-world securities operations:

Corporate Actions

  • Stock Splits & Reverse Splits: Proportional mint/burn operations
  • Dividends: Stablecoin distributions with off-chain calculations
  • Mandatory Redemptions: Forced buybacks and bond calls
  • Tender Offers: Voluntary redemption patterns
  • Mergers & Acquisitions: Token swap mechanisms

Shareholder Governance

  • Record Dates: Off-chain snapshots or external snapshot contracts
  • Proxy Voting: Vote recording with on-chain attestation
  • Meeting Quorums: Threshold calculations and verification
  • Document Management: Via ERC-1643 for proxy rules and notices

Tax Compliance

  • W-9/W-8 Collection: Off-chain during KYC process
  • Withholding Calculations: Per-jurisdiction off-chain processing
  • 1099/1042-S Reporting: Annual tax form generation
  • Document References: Encrypted storage via ERC-1643

Secondary Market Integration

  • ATS Adapter Pattern: Integration with regulated trading venues
  • Order Book Visibility: Via TransferRequested events
  • Pre-Matched Trades: Through registered broker submissions
  • Reason Code Analytics: Optimization using rejection reasons

BrokerProxy Pattern (Recommended)

  • Similar to RTAProxy but optional for brokers
  • Enables secure key rotation and multi-sig controls
  • Provides business continuity for broker operations

Security Considerations

  1. Private Key Management: RTA signers must secure their private keys
  2. Multi-Sig Threshold: Choose appropriate signature requirements
  3. Transfer Agent Lock: Once set to RTAProxy, cannot be changed
  4. Fee Token: Single ERC-20 fee token (e.g., USDC) configured by RTA
  5. Reentrancy Protection: All state-changing functions protected
  6. Access Control: Strict RTA-only modifier on critical functions

Gas Optimization

  • Uses custom errors (ERC-6093) for gas efficiency
  • Unchecked blocks where overflow impossible
  • Efficient storage packing
  • Minimal external calls

Regulatory Compliance

This implementation is designed to comply with:

  • SEC Rule 17Ad (Transfer Agent regulations)
  • Regulation S-T (Electronic filing requirements)
  • Regulation A+ (Qualified offerings)
  • Regulation D (Private placements)
  • Regulation CF (Crowdfunding)

Transfer Rejection Reason Codes

The implementation includes standardized reason codes for transfer rejections:

CodeConstantDescription
0REASON_INSUFFICIENT_BALANCESender has fewer tokens than transfer amount
1REASON_INVALID_SENDERSender address is invalid or blacklisted
2REASON_INVALID_RECEIVERReceiver address is invalid or zero
3REASON_COMPLIANCE_FAILUREGeneric compliance check failure
4REASON_TRANSFER_RESTRICTEDTransfer temporarily restricted
5REASON_HOLDER_LIMIT_EXCEEDEDWould exceed maximum holder count
6REASON_TRADING_HALTTrading is currently halted
7REASON_COURT_ORDERTransfer blocked by court order
8REASON_REGULATORY_FREEZEAccount frozen by regulator
9REASON_LOCK_PERIODTokens are in lock-up period
10REASON_RECIPIENT_NOT_VERIFIEDRecipient hasn't completed KYC/AML
11REASON_ADDRESS_NOT_LINKEDAddress not linked to verified identity
12REASON_SENDER_VERIFICATION_EXPIREDSender's KYC has expired
13REASON_JURISDICTION_BLOCKEDRecipient in restricted jurisdiction
14REASON_ACCREDITATION_REQUIREDRecipient not accredited (Reg D)
999REASON_OTHEROther unspecified reason

Documentation

Contributing

This is a reference implementation maintained by StartEngine. For questions or issues, please open a GitHub issue.

License

MIT License

Support

For questions and support:

  • Open an issue in this repository
  • Join the discussion on Ethereum Magicians
  • Contact the StartEngine team

npm Package Integration 📦

This repository can be used as an npm package via git dependencies for JavaScript/TypeScript projects. The package provides both basic (immutable) and upgradeable contract implementations.

Installation

Add to your package.json:

{
"dependencies": {
"erc1450-reference": "git+https://github.com/StartEngine/erc1450-reference.git#v1.4.0"
}
}

Or install directly:

npm install git+https://github.com/StartEngine/erc1450-reference.git#v1.4.0

Usage

Import contract artifacts in your JavaScript/TypeScript project:

// Method 1: Import via main index.js (recommended)const{ERC1450, RTAProxy, ERC1450Upgradeable, RTAProxyUpgradeable, ERC1967Proxy }=require('erc1450-reference');// Method 2: Import specific artifacts directlyconstRTAProxyUpgradeable=require('erc1450-reference/artifacts/contracts/upgradeable/RTAProxyUpgradeable.sol/RTAProxyUpgradeable.json');constERC1450Upgradeable=require('erc1450-reference/artifacts/contracts/upgradeable/ERC1450Upgradeable.sol/ERC1450Upgradeable.json');// Use with ethers.js or web3.jsconstabi=RTAProxyUpgradeable.abi;constbytecode=RTAProxyUpgradeable.bytecode;// Example: Deploy with ethers.jsconstfactory=newethers.ContractFactory(abi,bytecode,signer);constcontract=awaitfactory.deploy(...args);

Available Contracts

This package includes both basic and upgradeable versions:

Basic Contracts (Immutable)

  • ERC1450 - Standard ERC1450 token implementation
  • RTAProxy - Multi-sig RTA proxy

Upgradeable Contracts (UUPS Pattern)

  • ERC1450Upgradeable - Upgradeable ERC1450 token
  • RTAProxyUpgradeable - Upgradeable multi-sig RTA
  • ERC1967Proxy - OpenZeppelin proxy for deployment

Interfaces & Libraries

  • IERC1450 - ERC1450 interface
  • ERC1450Constants - Shared constants library

Release Process

When updating contracts:

  1. Make contract changes and compile: npm run compile
  2. Update version in package.json (follow semantic versioning)
  3. Compile again to sync version to contracts: npm run compile
    • This automatically runs scripts/sync-version.js which updates the version() function in all contracts
  4. Commit changes: git commit -am "Release v1.10.1"
    • Pre-commit hook will verify version sync and run tests
  5. Create git tag: git tag v1.10.1
  6. Push to GitHub:
    git push origin main
    git push origin v1.10.1
  7. Update dependent projects to use the new version tag in their package.json

Note: Contract versions are automatically synced from package.json - no manual contract edits needed!

Security & Audit Status

Initial Security Analysis ✅

  • Slither Analysis: Completed (November 2024) - No critical vulnerabilities found
  • Static Analysis: All high-priority issues resolved in commit 9805925
  • Test Coverage: 643 comprehensive tests passing
  • Security Score: 9.5/10 based on automated analysis

Professional Audit Status ✅

This implementation has completed a comprehensive security audit by Halborn Security (December 2025).

Audit Results:

SeverityCountStatus
Critical1✅ Solved
High0-
Medium0-
Low63 Solved, 3 Risk Accepted
Informational111 Solved, 10 Acknowledged

100% of all findings have been addressed. The single critical finding (fee bypass vulnerability) was resolved by implementing a single ERC-20 fee token design.

Key fixes implemented:

  • Single ERC-20 fee token design (commit 3901950)
  • Replaced .transfer() with .call() for ETH transfers (commit 1b273d8)
  • Added 7-day expiration for stale multisig operations (commit 42f000a)
  • Double rejection prevention (commit 2b7c52f)
  • Batch cleanup consistency (commit 3a25d8c)

The full audit report published by Halborn is available here.

Production deployment should proceed after:

  • Thorough legal review for your jurisdiction
  • Comprehensive integration testing

Built with ❤️ by StartEngine for the Ethereum community

About

Reference implementation of ERC-1450 — an SEC-compliant, RTA-controlled security-token standard. Halborn-audited UUPS contracts with multi-sig transfer authority.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages