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:

3.2 Contract Addresses

Contract addresses for the specific equity instrument will be provided by Superstate at integration time. You will need:

Contract
Description

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

Method
Endpoint
Purpose

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 using kycProviderId.

  • kycProvider + kycProviderId: Reference to the user's completed KYC verification in your provider's system.

  • Response: All creation endpoints return { entityId, walletAddress, encodedTransaction }. Store entityId for future API calls.

  • Add-allowlist: Identify the existing user by either email or existingWalletAddress (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: 0 and 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:

  1. Superstate creates the entity and initiates allowlisting

  2. The response includes an encodedTransaction for the on-chain allowlist update

  3. Once 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:

State
Value
Description

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 Active at any time

  • Cannot transition to the same state

  • Cannot transition back to Initialized

  • Closed and Cancelled are terminal (no further transitions)

  • Market auto-closes when remaining capacity < minPayment

6.2 Market Configuration

6.3 Market Data Structure

6.4 Constants

Constant
Value
Description

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

1

Check allowlist status

2

Get the active market ID

3
4

Approve USDC spending

The user must approve the EquityToken contract (not the DIP contract) to spend their USDC:

5

Execute the purchase

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

Error
When
Description

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

Error
When
Description

ZeroPaymentAmount()

buyTheDip

paymentAmount is 0

ZeroMinOutAmount()

buyTheDip

minOutAmount is 0

DipContractNotSet()

buyTheDip

DIP contract address not configured

10.3 Common ERC20 Errors

Error
When
Description

ERC20InsufficientAllowance

buyTheDip

User hasn't approved enough USDC for the EquityToken

ERC20InsufficientBalance

buyTheDip

User doesn't have enough USDC

10.4 Allowlist Errors

Error
When
Description

InsufficientPermissions

buyTheDip / transfer

User's wallet is not allowlisted. Onboard via External Onboard API first.


11. Decimal & Pricing Math

11.1 Decimal Conventions

Token/Value
Decimals
Example

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)

circle-info

Note on smart contract integration: The buyTheDip function on EquityToken uses msg.sender as the buyer for both the USDC transferFrom and the token mint. This means users must call buyTheDip directly from their EOA wallet — router or proxy contracts are not supported. Partners should build their integration as a frontend that constructs and submits transactions on behalf of the user's wallet.


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 → Active

  • Active → Paused | Closed | Cancelled

  • Paused → Active | Closed | Cancelled

Last updated