Direct Issuance Program
A Direct Issuance Program allows a public company to issue new tokenized shares directly to eligible investors, with purchases executed using real-time market prices and settled in stablecoins.
1. Overview
The Direct Issuance Program (DIP) enables discounted token purchases of Superstate equity instruments at oracle-derived pricing. It is composed of three on-chain contracts and a set of off-chain APIs for user onboarding and allowlist management.
What partners can do with this integration:
Onboard users (individuals or entities) via API, passing KYC data
Get users allowlisted for specific equity instruments
Enable users to purchase equity tokens at a market-configured discount via
buyTheDip
2. Architecture
Partner Backend
┌─────────────────┐
│ KYC + Wallet │
│ Collection │
└────────┬────────┘
│
┌───────────────┼───────────────┐
│ HTTP API │ │ On-chain
▼ │ ▼
┌────────────────┐ │ ┌──────────────────┐
│ Superstate │ │ │ Ethereum Mainnet │
│ Onboard API │ │ │ │
│ │ │ │ ┌────────────┐ │
│ POST /onboard │ │ │ │ Allowlist │ │
│ POST /add- │ │ │ │ (V4.0) │ │
│ allowlist │ │ │ └────────────┘ │
│ PUT /update │ │ │ ▲ │
└────────────────┘ │ │ │ reads │
│ │ ┌──────┴─────┐ │
│ │ │ EquityToken│ │
│ │ │ (Dippable) │──┼── User calls
│ │ └──────┬─────┘ │ buyTheDip()
│ │ │ │
│ │ ┌──────▼─────┐ │
│ │ │ DIP │ │
│ │ │ Contract │ │
│ │ └────────────┘ │
│ └──────────────────┘
│
┌────────▼─────────┐
│ Partner User │
│ (EOA Wallet) │
└──────────────────┘Contract interaction flow for a purchase:
3. Prerequisites & Setup
3.1 API Key & Request Signing
Contact Superstate to receive an API key and secret for the External Onboard API. Partners will be registered as an ExternalOnboardPartner.
Authentication uses HMAC-SHA256 request signing. To implement request signing, either:
Use the npm package:
@superstateinc/api-key-requestOr implement manually using the reference implementation: https://github.com/superstateinc/request-with-api-key
3.2 Contract Addresses
Contract addresses for the specific equity instrument will be provided by Superstate at integration time. You will need:
EquityToken (Proxy)
The token contract users interact with for buyTheDip and isAllowed
DIP Contract
Pricing engine for calculateOutput (users do not call buyTheDip on this directly)
USDC
0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (Ethereum Mainnet)
3.3 Supported KYC Providers
When submitting onboarding requests, specify which KYC provider was used:
4. User Onboarding API
The External Onboard API allows partners to create user entities in Superstate's system and get them allowlisted in a single flow.
Full API documentation: Onboarding API
Base URL: Provided by Superstate
Authentication: HMAC-SHA256 signed requests (see Section 3.1)
The sections below summarize the key endpoints. Refer to the API documentation above for the authoritative reference.
4.1 Available Endpoints
POST
/v1/accounts/onboard/evm
Create user entity and initiate allowlisting
POST
/v1/accounts/onboard/evm/add-allowlist
Add additional wallet to an existing user
PUT
/v1/accounts/onboard/update
Update user KYC information
POST
/v1/accounts/onboard/evm/mock
Test endpoint (no database writes, returns mock data)
4.2 Key Concepts
forInstrument: Pass the equity instrument symbol to get users allowlisted for that specific token. Required for DIP equity tokens.userData: User PII (name, address, SSN/TIN, email). If omitted, Superstate queries the KYC provider directly usingkycProviderId.kycProvider+kycProviderId: Reference to the user's completed KYC verification in your provider's system.Response: All creation endpoints return
{ entityId, walletAddress, encodedTransaction }. StoreentityIdfor future API calls.Add-allowlist: Identify the existing user by either
emailorexistingWalletAddress(exactly one, mutually exclusive). Only the partner that originally onboarded the entity can add wallets.Mock endpoint: Same request format as the real endpoint. Returns
entityId: 0and an unbroadcastable transaction. Useful for integration testing.
5. Allowlisting
5.1 How Allowlisting Works
Before a user can hold or purchase equity tokens, their wallet address must be allowlisted. Allowlisting is handled by Superstate's infrastructure as part of the onboarding flow (Section 4). Partners do not need to interact with the Allowlist contract directly.
5.2 Checking Allowlist Status
Call isAllowed on the EquityToken contract to check if a user is ready to purchase:
5.3 Allowlist Integration with Onboarding
When using the External Onboard API with forInstrument specified:
Superstate creates the entity and initiates allowlisting
The response includes an
encodedTransactionfor the on-chain allowlist updateOnce the allowlist transaction is confirmed, the user can interact with the token
The allowlist transaction is submitted by Superstate's infrastructure. Partners should poll equityToken.isAllowed(userAddress) to confirm readiness before enabling purchases.
6. DIP Contract Specification
6.1 Market Lifecycle
States:
Initialized
0
Created but not yet accepting purchases
Active
1
Live. One active market per instrument enforced.
Paused
2
Temporarily suspended. Can be reactivated.
Closed
3
Terminal. Target reached or manually closed.
Cancelled
4
Terminal. Admin-terminated.
Rules:
Only one market per instrument can be
Activeat any timeCannot transition to the same state
Cannot transition back to
InitializedClosedandCancelledare terminal (no further transitions)Market auto-closes when remaining capacity <
minPayment
6.2 Market Configuration
6.3 Market Data Structure
6.4 Constants
BASIS_POINTS
10000
100% in basis points
PRICE_CLAMP_DECIMALS
8
Decimal precision for price clamp values
PAYMENT_TOKEN_DECIMALS
6
Decimal precision for USDC (set at deployment)
7. Executing a Purchase (buyTheDip)
7.1 User-Facing Function
The user calls buyTheDip on the EquityToken contract (not the DIP contract directly):
7.2 Step-by-Step Integration
7.3 Slippage Protection
Calculate minOutAmount using the preview and a slippage tolerance:
The DIP contract will revert with InsufficientOutput(actual, minRequired) if the calculated output falls below minOutAmount.
7.4 Partial Fills
If the paymentAmount exceeds the market's remaining capacity, the DIP contract automatically reduces it:
The user only pays actualPaymentAmount and only that amount of USDC is transferred. The excess stays in the user's wallet.
7.5 Auto-Close Behavior
After each purchase, if the remaining capacity drops below minPayment, the market automatically transitions to Closed:
8. Querying Market State
8.1 Read Functions
8.2 Useful Derived Values
9. Events & Indexing
9.1 DIP Contract Events
Purchase — Emitted on every successful purchase:
MarketCreated — Emitted when a new market is created:
MarketStateUpdated — Emitted on state transitions (including auto-close):
MarketConfigUpdated — Emitted when market parameters change:
9.2 Token Events
Standard ERC20 Transfer events are emitted on the EquityToken when tokens are minted:
9.3 Indexing Recommendations
To track DIP purchases, index the Purchase event on the DIP contract. The buyer field is indexed for efficient filtering by user.
To detect market closures (including auto-close), watch for MarketStateUpdated events where curr = 3 (Closed).
10. Error Reference
10.1 DIP Contract Errors
NotCurrentMarket()
buyTheDip
Caller is not the instrument token of the active market
NotPaymentToken()
buyTheDip
Payment token doesn't match market config
InsufficientPayment()
buyTheDip
Payment amount (after normalization) < minPayment
PriceOutOfBounds()
buyTheDip
Discounted price outside [minPriceClamp, maxPriceClamp]
InsufficientOutput(uint256 actual, uint256 minRequired)
buyTheDip
Output tokens < minOutAmount (slippage)
PriceFeedExceedsMaxLatency()
buyTheDip
Oracle price is stale
PriceFeedInvalidOutput()
buyTheDip
Oracle returned invalid data
ZeroActualPayment()
buyTheDip
Calculated payment is zero after normalization
InvalidMarketId()
Various
Market ID does not exist
AlreadyMarketClosedOrCancelled()
Config/State changes
Market is in terminal state
10.2 EquityToken (Dippable) Errors
ZeroPaymentAmount()
buyTheDip
paymentAmount is 0
ZeroMinOutAmount()
buyTheDip
minOutAmount is 0
DipContractNotSet()
buyTheDip
DIP contract address not configured
10.3 Common ERC20 Errors
ERC20InsufficientAllowance
buyTheDip
User hasn't approved enough USDC for the EquityToken
ERC20InsufficientBalance
buyTheDip
User doesn't have enough USDC
10.4 Allowlist Errors
InsufficientPermissions
buyTheDip / transfer
User's wallet is not allowlisted. Onboard via External Onboard API first.
11. Decimal & Pricing Math
11.1 Decimal Conventions
USDC
6
1000 USDC = 1000000000 (1000 * 1e6)
EquityToken
6
100 tokens = 100000000 (100 * 1e6)
Price clamps
8
$1.00 = 100000000 (1e8)
Oracle price
Variable (Pyth)
Normalized internally
Discount rate
Basis points
500 = 5% discount
11.2 Pricing Formula
Example:
Oracle price: $10.00 per token
Discount rate: 500 bps (5%)
Discounted price: $10.00 * (10000 - 500) / 10000 = $9.50
Payment: 1000 USDC
Tokens received: 1000 / 9.50 = ~105.26 tokens
11.3 Payment Normalization
All payment amounts are normalized to PAYMENT_TOKEN_DECIMALS (6) internally:
If USDC (6 decimals): no conversion needed
If DAI (18 decimals): truncation occurs when normalizing down to 6 decimals
The actualPaymentAmount returned to the caller is denormalized back to the payment token's native decimals.
12. End-to-End Examples
12.1 Full Integration Flow (TypeScript / viem)
12.2 Full Integration Flow (ethers.js v6)
Appendix A: Market Management (Reference)
These functions are owner-only (Superstate-managed) but documented here for completeness.
Create Market
Update Market Config
Cannot be called on Closed or Cancelled markets.
Transition Market State
Valid transitions:
Initialized → ActiveActive → Paused | Closed | CancelledPaused → Active | Closed | Cancelled
Last updated