Securitize on Solana: how tokenized stocks and funds enforce compliance with Token-2022
Securitize listed its own stock (SECZ) on the NYSE on July 2, 2026 and tokenized it on Solana and Avalanche the same day. On EVM its DS Protocol is ERC-20 plus external registry contracts; on Solana it's pure Token-2022 extensions. This is a developer's guide to the real mints, the public feed, and why SECZ uses a different extension set than BUIDL and ACRED.
devrels.xyz/a/125short linkOn July 2, 2026, Securitize began trading on the New York Stock Exchange under the ticker SECZ — and on the same day it tokenized its own common stock on Solana and Avalanche. Not a synthetic, not an offshore wrapper: issuer-sponsored tokenization of the exact same NYSE-listed shares, minted by the company that already runs the transfer agent and broker-dealer behind them. Securitize calls it the world's largest tokenized stock at launch. Full announcement.
For a Solana developer, the interesting part isn't the ticker — it's the mint. Securitize tokenizes over $4B in real-world assets: BlackRock's BUIDL, Apollo's ACRED credit fund, VanEck's VBILL treasury fund, and now its own equity. On Ethereum and the other EVM chains, all of this rides on the DS Protocol — an ERC-20 token that delegates every compliance decision to a set of external registry, compliance, and trust-service contracts. On Solana there are no external contracts. The compliance is the token, encoded directly in Token-2022 extensions. This article is about how that works, and how to build against it.
Two designs for the same problem
A regulated security has to answer one question on every transfer: is this move allowed? Only KYC'd, jurisdiction-eligible wallets may hold it; the issuer must be able to freeze, pause, and claw back; and none of that can be bypassed by sending the token to an arbitrary address. Securitize solves this differently on each virtual machine.
On EVM, the DS Protocol keeps the token minimal and pushes the rules into satellite contracts. Every transfer calls out to a Compliance Service; a Registry Service maps wallets to KYC'd investor IDs; a Trust Service assigns roles. A dApp checks eligibility by reading the registry directly:
// EVM (DS Protocol): compliance lives in external contracts.
// Resolve the registry from the token, then look up the investor.
const dsToken = new ethers.Contract(tokenAddress, DS_TOKEN_ABI, provider)
const registry = await dsToken.getDSService(1) // 1 = Registry Service
const investor = new ethers.Contract(registry, DS_REGISTRY_ABI, provider)
const investorId = await investor.getInvestor(wallet) // "" if not whitelisted
const eligible = investorId.length > 0On Solana, none of that exists. There is no registry contract to call and no getInvestor read. Instead, Securitize mints every asset on the Token-2022 program (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb) and turns on the extensions that enforce the same rules at the token-program level. The gate isn't a contract your dApp queries — it's the SPL token program itself rejecting the transfer.
The public feed: discover assets, never hardcode
Every Securitize asset, on every chain, is published in a single feed. Fetch it at runtime — addresses can change, and hardcoding a mint is how you ship a broken integration.
# List every tokenized asset symbol
curl https://public-feed.securitize.io/asset-info
# → {"symbol":["BUIDL","ACRED","VBILL","STAC","HLSCOPE","CURR","SECZ"]}
# Full metadata for one asset (all chains it lives on)
curl "https://public-feed.securitize.io/asset-info?symbol=BUIDL"Two things to know before you wire this in. First, the feed serves no CORS headers — call it from a backend route or edge function and proxy to your client, never fetch() it from the browser. Second, each asset carries one entry per chain, so you filter to Solana yourself:
// Server-side only (no CORS). Pull the Solana leg of an asset.
async function solanaLeg(symbol: string) {
const res = await fetch(`https://public-feed.securitize.io/asset-info?symbol=${symbol}`)
const { data } = await res.json()
return data.find((c: any) => c.blockchain === "solana")
}
// BUIDL on Solana today:
// {
// blockchain: "solana",
// TokenAddress: "GyWgeqpy5GueU2YbkE8xqUeVEokCMMCEeUrfbtMw6phr", // the mint
// RedemptionWalletAddress: "BarF1zwxFb3SJTGcKMTStRA8NT1ARvk3VSgKkGhkpmru",
// chainId: "mainnet-beta", // this is Solana MAINNET, not a testnet
// decimals: "6",
// onramp: "", offramp: "", // no on-chain ramps on Solana (yet)
// rpcURL: "https://api.mainnet-beta.solana.com"
// }A footgun worth calling out: chainId: "mainnet-beta" is Solana's mainnet cluster name, not a beta network. These are live, real-value securities. The current mainnet mints:
Asset Mint (Solana, Token-2022) Issuer / underlying
SECZ 5VzwKkvynPJzcgwhBe7ESEyNgqMbo15yBu7Sehssd9ED Securitize common stock (NYSE: SECZ)
BUIDL GyWgeqpy5GueU2YbkE8xqUeVEokCMMCEeUrfbtMw6phr BlackRock USD Institutional Digital Liquidity Fund
ACRED FubtUcvhSCr3VPXEcxouoQjKQ7NWTCzXyECe76B7L3f8 Apollo Diversified Credit Securitize Fund
VBILL 34mJztT9am2jybSukvjNqRjgJBZqHJsHnivArx1P4xy1 VanEck Treasury Fund
All are 6 decimals. All are owned by the Token-2022 program.Read the mint before you trust it
Because compliance is baked into the mint, the mint tells you exactly how the asset behaves. A single getAccountInfo with jsonParsed encoding returns the full extension set — no ABI, no external lookups.
curl https://api.mainnet-beta.solana.com -s -X POST \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getAccountInfo",
"params":["GyWgeqpy5GueU2YbkE8xqUeVEokCMMCEeUrfbtMw6phr",
{"encoding":"jsonParsed"}]}' \
| jq '.result.value.data.parsed.info.extensions[].extension'Run that against the four mints and a clear pattern falls out. The funds and the stock are built from different extensions, because they are different kinds of security.
The funds (BUIDL, ACRED): a transfer hook does the gating
BUIDL and ACRED carry transferHook, permanentDelegate, and mintCloseAuthority, plus on-chain metadata. The transfer hook is the compliance engine: every single transfer re-enters a Securitize-owned program that checks the sender and receiver against an allowlist and reverts if either isn't eligible.
// BUIDL mint extensions (abridged)
{
"transferHook": {
"authority": "APm3MWbXfMMKAWgsDVnxcAGbLjvRxubPu1A8a5SA2kbJ",
"programId": "FsE8mCJyvgMzqJbfHbJQm3iuf3cRZC6n2vZi1Q8rQCy2" // compliance program
},
"permanentDelegate": { "delegate": "APm3MWbXfMMKAWgsDVnxcAGbLjvRxubPu1A8a5SA2kbJ" },
"mintCloseAuthority": { "closeAuthority": "APm3MWbXfMMKAWgsDVnxcAGbLjvRxubPu1A8a5SA2kbJ" }
}permanentDelegate is the on-chain equivalent of a transfer agent's clawback power: the delegate can move any holder's tokens without their signature — used for redemptions, forced transfers, and court-ordered reversals. If you are building custody or accounting on top of these assets, treat "your keys, your coins" as false here by design. These are regulated securities, and the issuer keeps the keys that matter.
The stock (SECZ): frozen-by-default, pausable, and split-aware
SECZ uses a different toolkit — one that mirrors how a listed equity actually behaves:
// SECZ mint extensions (abridged)
{
"defaultAccountState": { "accountState": "frozen" },
"pausableConfig": { "authority": "D2kG…6jCS", "paused": false },
"permanentDelegate": { "delegate": "D2kG…6jCS" },
"scaledUiAmountConfig": { "authority": "D2kG…6jCS", "multiplier": "1",
"newMultiplier": "1", "newMultiplierEffectiveTimestamp": 0 }
}- defaultAccountState: frozen — every new SECZ token account is created frozen. A holder can't receive shares until Securitize, as freeze authority, thaws their account after KYC. This replaces the funds' transfer-hook allowlist with an allowlist-by-thaw: no whitelist, no thaw, no transfer.
- pausableConfig — the issuer can halt all transfers of the token in one instruction. This is a trading halt, onchain: the same lever the NYSE pulls, now expressible at the mint level.
- scaledUiAmountConfig — the tell that this is real equity infrastructure. A stock split, reverse split, or dividend adjustment changes the UI
multiplierinstead of minting or burning shares. Raw balances stay constant; the displayed amount scales. Your front end must readuiAmount, not the raw amount, or you will misreport holdings the day a corporate action lands.
Why the split? The funds trade as fund units among a closed set of whitelisted holders, so a transfer-hook allowlist is the natural gate. The stock has to behave like an NYSE equity — halts, splits, default-frozen accounts — so it reaches for the extensions that model exactly those corporate actions. When you integrate Securitize assets, the first thing your code should do is branch on which extensions the mint actually has.
Integrating: read balances, respect the gate
Reading is easy and permissionless. Because every asset is Token-2022, you pass the Token-2022 program ID everywhere and the standard SPL helpers work.
import { Connection, PublicKey } from "@solana/web3.js"
import {
TOKEN_2022_PROGRAM_ID,
getAssociatedTokenAddressSync,
getAccount,
getMint,
} from "@solana/spl-token"
const connection = new Connection("https://api.mainnet-beta.solana.com")
const BUIDL = new PublicKey("GyWgeqpy5GueU2YbkE8xqUeVEokCMMCEeUrfbtMw6phr")
// A holder's BUIDL balance — note the Token-2022 program ID on both calls.
async function buidlBalance(owner: PublicKey) {
const ata = getAssociatedTokenAddressSync(BUIDL, owner, false, TOKEN_2022_PROGRAM_ID)
try {
const acct = await getAccount(connection, ata, "confirmed", TOKEN_2022_PROGRAM_ID)
return Number(acct.amount) / 1e6 // 6 decimals
} catch {
return 0 // no ATA => never held it
}
}Writing is where the compliance shows up. An ordinary transferChecked to a fund like BUIDL will fail — the transfer hook requires extra accounts (the compliance program's allowlist PDAs) that a naive instruction never includes. You have to resolve them, which @solana/spl-token does for you:
import { createTransferCheckedWithTransferHookInstruction } from "@solana/spl-token"
// Transfer-hook assets (BUIDL, ACRED): the helper walks the hook program's
// extra-account-meta list and appends the required accounts. Both wallets
// must already be whitelisted or the compliance program reverts on-chain.
const ix = await createTransferCheckedWithTransferHookInstruction(
connection,
sourceAta,
BUIDL,
destAta,
owner,
amount, // bigint, 6 decimals
6,
[],
"confirmed",
TOKEN_2022_PROGRAM_ID,
)
// SECZ has NO transfer hook — a plain transferChecked is correct there.
// But it WILL fail if either token account is still frozen (defaultAccountState),
// so the destination must be KYC'd and thawed by Securitize first.The practical rule: inspect the mint, then pick your path. Transfer-hook assets need createTransferCheckedWithTransferHookInstruction; the frozen-by-default stock needs a plain transferChecked into a thawed account. Either way, eligibility is not something your dApp grants — it is granted off-chain through onboarding, and enforced on-chain by the mint.
Onboarding and redemption: where Solana still differs from EVM
On EVM, Securitize deploys on-chain ramp contracts (DSApps) so a whitelisted wallet can subscribe by swapping USDC and redeem by calling redeem() for stablecoins in the same transaction. On Solana, those ramps don't exist yet — the feed's onramp and offramp fields are empty for every Solana asset today. Two consequences for builders:
- Onboarding is off-chain. A wallet becomes eligible by completing KYC at id.securitize.io (Securitize ID), which whitelists the address in the compliance program (funds) or thaws the token account (SECZ). Your dApp's job is to detect a non-eligible wallet and route the user there — not to try to move tokens it will only watch revert.
- Redemption is a plain transfer to the fund's redemption wallet. The feed gives you the address; the transfer agent processes the redemption off-chain and returns stablecoins separately. Show the user that the tokens leave immediately but cash arrives on a separate, non-atomic timeline.
// Solana redemption = transfer to the asset's RedemptionWalletAddress.
// (from the public feed; processed off-chain by the transfer agent)
const REDEMPTION = {
BUIDL: "BarF1zwxFb3SJTGcKMTStRA8NT1ARvk3VSgKkGhkpmru",
ACRED: "EcK4DFBfqi1qKExggGVZSCQFtfGufheuThZ7FjoxijhT",
VBILL: "EcK4DFBfqi1qKExggGVZSCQFtfGufheuThZ7FjoxijhT",
}
// Build the transfer the same way you'd build any compliant transfer for that
// asset (hook-aware for the funds), sending to REDEMPTION[symbol].For programmatic onboarding and account status, Securitize also exposes the Connect API at connect-gw.securitize.io/api/, which partners use to check investor state and drive KYC flows without rebuilding the front end. The open-source securitize-dapp-sample repo is the reference: it ships a full EVM buy/sell/redeem flow plus a deep-dive builder guide covering the feed, ABIs, and edge cases.
What this means for Solana
SECZ landing on Solana on listing day is a milestone, but the durable story is the pattern underneath it. Securitize didn't port its EVM contract stack to Solana — it re-expressed the entire compliance model in Token-2022 extensions, and in doing so showed that the extension set is expressive enough to encode a regulated fund and a listed equity, with different rules, entirely at the token-program level. Transfer hooks for allowlisted funds; default-frozen accounts, pausability, and scaled amounts for stocks. No external registry, no bespoke program per asset.
For developers, the takeaway is concrete: these are among the most production-serious Token-2022 mints on mainnet, and integrating them is a masterclass in the extensions most tutorials skip. Read the mint, branch on its extensions, resolve the hook when it's there, and route eligibility off-chain. Do that, and you can build wallets, dashboards, and portfolio tools on top of BlackRock, Apollo, VanEck, and now Securitize's own stock — all settling on Solana.
Start from the feed at public-feed.securitize.io/asset-info, and the API landing page at securitize.io/apis.
Keep reading
How does a DeFi app know a wallet passed KYC without seeing the passport? The Solana Attestation Service standardises that: issuers sign on-chain attestations that a wallet meets a credential; verifiers check them; raw data stays off-chain. Optionally tokenized via Token-2022. The model and its limits.
Sanctum has 200+ LSTs and two developer products: a swap API at sanctum-api.ironforge.network (stake, unstake, swap any LST with slippage control and route filtering) and Gateway at gateway.sanctum.so (buildGatewayTransaction + sendTransaction — routes through Jito, SWQoS, Paladin, and refunds Jito tips if the tx lands via RPC).
Collector Crypt has a marketplace program (non-custodial, delegation-based), a gacha program with RFC 9381 VRF for provably fair pack opens, and a shipping API for physical card vault operations. API partnerships are rolling out. Here's what's available to build on today.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.