Exchange Integration
This topic describes how to integrate SUI into a cryptocurrency exchange. Specific requirements and processes vary between exchanges. Before you ship an integration to production, confirm the API and SDK examples you use against the current references linked from each section.
Requirements to configure a SUI integration
Sui's primary data access APIs are gRPC and GraphQL RPC. JSON-RPC has been deprecated. New integrations should use gRPC or GraphQL.
The requirements to configure a SUI integration include:
-
A Sui full node. You can operate your own Sui full node or use a full node from a node operator.
-
Suggested hardware requirements to run a Sui full node:
- CPU: 8 physical cores / 16 vCPUs
- RAM: 128 GB
- Storage (SSD): 4 TB NVMe drive
For software prerequisites, snapshots, observability, and the full setup walkthrough, see Run a Sui Full Node.
Infrastructure
An exchange integration needs reliable access to Sui network data and the ability to submit transactions. You have two options:
-
Run your own Sui full node. This gives you full control over availability, retention, and read performance. The full node operator guide covers hardware sizing, setup, snapshots, logging, and monitoring.
-
Use an RPC or data provider. Several providers operate gRPC-enabled and GraphQL-enabled Sui endpoints. See the list of RPC and data providers for current options.
The public endpoints at https://fullnode.<network>.sui.io and https://graphql.<network>.sui.io/graphql are rate-limited and intended for development. Do not point a production exchange at them. Run your own full node or use a provider endpoint with a contract that meets your throughput and uptime needs.
Sui APIs
gRPC
gRPC is the recommended high-performance API for backend services. It supports FieldMask-based projection so you only fetch the fields you need, and includes checkpoint subscriptions that stream finalized checkpoints along with the transaction and event data you select through the response mask. For a complete tutorial including grpcurl, TypeScript, Go, and Python examples, see Querying Data with gRPC.
For the Rust client, use the sui-rust-sdk crate (gRPC) for new code. The legacy sui-sdk JSON-RPC client remains available for migration purposes only.
GraphQL RPC
GraphQL exposes a single endpoint where you select exactly the fields you need across addresses, objects, transactions, checkpoints, events, and balances. It is well suited for monitoring dashboards, custom indexers, and queries that join data across several resources. For practical examples including pagination, checkpoint scoping, and transaction submission, see Querying Data with GraphQL RPC.
JSON-RPC (deprecated)
Existing integrations should plan a migration to gRPC or GraphQL. New integrations should not adopt JSON-RPC.
Sui addresses
Sui addresses do not need onchain initialization. You can spend from an address as soon as it corresponds to a private key you control.
For the key-pair schemes Pure Ed25519, ECDSA Secp256k1, ECDSA Secp256r1, and Passkey, a Sui address is a 32-byte value derived as BLAKE2b-256 of the 1-byte signature scheme flag concatenated with the public key bytes (flag || pubkey).
Multisig and zkLogin use scheme-specific derivations and do not follow the basic flag || pubkey rule:
-
Multisig:
BLAKE2b-256(flag_MultiSig || threshold || flag_1 || pk_1 || weight_1 || ... || flag_n || pk_n || weight_n), wherethresholdand eachweight_iare encoded as little-endian bytes. -
zkLogin:
BLAKE2b-256(flag_zkLogin || iss_len || iss || address_seed), whereiss_lenis the 1-byte length of the issuer string andaddress_seedis the unpadded form with leading zero bytes removed.
For every scheme, derive addresses through the Sui SDKs or the Sui CLI rather than hand-rolling the computation. Hand-rolling the keypair formula for a multisig or zkLogin account produces the wrong address. See Signing and Sending Transactions for the per-scheme details, and the SuiAddress implementations in crates/sui-types/src/base_types.rs for the byte-exact layout.
Sui currently supports the following schemes and flag bytes:
| Scheme | Flag |
|---|---|
| Pure Ed25519 | 0x00 |
| ECDSA Secp256k1 | 0x01 |
| ECDSA Secp256r1 | 0x02 |
| Multisig | 0x03 |
| zkLogin | 0x05 |
| Passkey | 0x06 |
For full details on address derivation, signature formats, and key derivation paths (BIP-32, BIP-39, BIP-44, SLIP-0010), see Signing and Sending Transactions.
Displaying addresses
Sui accepts addresses with or without the 0x prefix. Always include the 0x prefix when you display addresses to users and when you pass them to API calls.
Tracking balances
Sui supports two ways to hold fungible value at an address:
-
Coin objects. Individual
Coin<T>objects owned by an address. -
Address balances. A canonical per-coin-type balance tied directly to an address, introduced in SIP-58. Funds sent through
sui::coin::send_fundsandsui::balance::send_fundsmerge automatically into a single balance per coin type with no object management required. See Using Address Balances for details.
When you query a balance, account for both representations. In the GraphQL schema, Balance.totalBalance returns the sum across coin objects and the address-balance accumulator. Balance.coinBalance and Balance.addressBalance expose each component separately, so you can reconcile against your own bookkeeping.
Exchange ledgers must account for both coin objects and address-balance accumulators. An address's funds can move between the two without a transfer between addresses, especially while users hold a mix of legacy coin objects and newer address balances. Reconcile by summing Balance.coinBalance and Balance.addressBalance, not by tracking only one.
Query balances for an address using the address(address:).balances(...) connection in GraphQL. The GraphQL query guide shows the pagination pattern and how to scope queries to a specific checkpoint for consistent reads. For a typed client, use StateService.GetBalance for a single coin type or StateService.ListBalances for all balances over gRPC. Both return the balance, coinBalance, and addressBalance fields.
Blocks vs Checkpoints
Sui is a DAG-based blockchain and uses checkpoints for node synchronization and global transaction ordering. Checkpoints differ from blocks in the following ways:
-
Sui creates checkpoints and adds finalized transactions. Transactions are finalized before they are included in a checkpoint.
-
Checkpoints do not fork, roll back, or reorganize.
-
Sui creates about 4 checkpoints every second. Find the most current statistic on the Sui public dashboard.
Checkpoint API operations
Read checkpoints through the current gRPC or GraphQL APIs:
-
gRPC: Use
LedgerService.GetCheckpointfor point lookups. Subscribe withSubscriptionService.SubscribeCheckpointsfor an ordered, gapless stream of finalized checkpoints. See Querying Data with gRPC. -
GraphQL: Query the
checkpoint(sequenceNumber:)field for a specific checkpoint, or paginatecheckpointsfor a range. See Querying Data with GraphQL RPC.
Tracking transactions and events
Use checkpoints as the canonical, ordered stream of finalized activity:
-
Checkpoints do not fork. Once a checkpoint is final, it does not roll back or reorganize.
-
Transactions are final before they are included in a checkpoint. Checkpoints group finalized transactions for ordered downstream consumption.
For real-time pipelines, subscribe to the checkpoint stream over gRPC, and read each checkpoint's transaction and event data from the response through a FieldMask. For ad hoc queries and replays, paginate over checkpoints, transactions, and events with GraphQL, which supports cursor-based pagination and checkpoint-scoped consistency.
For event consumption patterns, including filtering by sender, package, or event type, see Using Events.
SUI transfers
Build transfers as programmable transaction blocks (PTBs) using the SDK of your choice. PTBs let you split, merge, and transfer coins in a single atomic transaction.
A few points that matter for exchange flows:
-
Coin selection. When you pay from coin objects, the network performs gas smashing automatically if you pass multiple gas coins. You do not need to merge coins offline before paying.
-
Address balance gas payments. When the address balances feature is enabled on the target network, the gas payment can be drawn directly from the sender or sponsor address balance, removing the need to manage gas coin objects entirely. Transactions that use address-balance gas payments must set a
ValidDuringexpiration with both a minimum and maximum epoch. Confirm the feature is enabled and review the expiration requirement in Paying for gas from address balances. -
Sponsored transactions. For user-facing flows, you can sponsor a user's transaction so they pay no gas. See Sponsored Transactions.
Signing transactions
Sui signs over the Blake2b-256 hash of the BCS serialization of an IntentMessage that wraps the transaction data. The supported signature schemes are pure Ed25519, ECDSA Secp256k1, and ECDSA Secp256r1, along with multisig, zkLogin, and passkey.
For the full signature requirements, intent format, and worked examples in Rust, TypeScript, and the Sui CLI, see Signing and Sending Transactions and Intent Signing. For offline custody workflows, see Offline Signing.
SUI staking
The Sui blockchain uses a Delegated Proof-of-Stake (DPoS) mechanism. SUI token holders stake to a validator's staking pool. When a user stakes, the network locks those tokens for the duration of the epoch in which the user adds the stake. New staking requests become active at the start of the next epoch. A user can request a withdrawal at any time. Stake withdrawals process immediately using the previous epoch's exchange rate and include the principal plus rewards accumulated through the previous epoch. The withdrawn stake stops contributing starting the next epoch.
SUI holders who stake to validators earn rewards for helping secure the Sui network. Sui determines staking rewards based on stake performance and distributes them at the end of each epoch.
The network fixes the total voting power across all validators at 10,000, similar to basis points (a voting power of 101 = 1.01%). Sui caps the voting power for a single validator at 1,000 (10%) regardless of how much stake the validator has. The quorum threshold for confirming a transaction is 6,667, which is greater than 2/3.
Staking functions
The current entry functions in the sui_system Move module for staking are listed below. These signatures are the source of truth, because they change with system package upgrades, so verify against the linked Move source before you ship.
-
request_add_stake: Add stake to a validator's staking pool. The function transfers the resultingStakedSuiobject to the sender.public entry fun request_add_stake(
wrapper: &mut SuiSystemState,
stake: Coin<SUI>,
validator_address: address,
ctx: &mut TxContext,
) -
request_add_stake_mul_coin: Add stake using multiple coins, optionally specifying a stake amount.public entry fun request_add_stake_mul_coin(
wrapper: &mut SuiSystemState,
stakes: vector<Coin<SUI>>,
stake_amount: option::Option<u64>,
validator_address: address,
ctx: &mut TxContext,
) -
request_withdraw_stake: Withdraw stake from a validator's staking pool. The function transfers the unstaked SUI coin to the sender.public entry fun request_withdraw_stake(
wrapper: &mut SuiSystemState,
staked_sui: StakedSui,
ctx: &mut TxContext,
)
Non-entry variants request_add_stake_non_entry and request_withdraw_stake_non_entry return the StakedSui object or withdrawn balance directly, so you can compose them with other PTB commands. The StakedSui type lives in the staking_pool module.
To build staking and unstaking transactions, assemble a PTB that calls one of these functions. The TypeScript SDK provides the helpers you need.
To read stake state for an address, list owned StakedSui objects through StateService.ListOwnedObjects filtered by type on gRPC, or through the address.objects(filter: { type: ... }) connection on GraphQL. The current schema exposes balance, transaction, and object access; it does not yet expose a first-class staking-state field that returns active stakes, pending stakes, and accrued rewards together. To compute accrued rewards, read the StakedSui object's stake activation epoch and principal, then compute the current value against the validator's exchange rate, or use the TypeScript SDK staking helpers if available for your use case.
Designing deposits and withdrawals
Treat deposit and withdrawal pipelines as event-driven and idempotent. The following checklist covers the design points that matter most for an exchange:
-
Use checkpoint sequence numbers as your cursor. Persist the last fully processed checkpoint, and resume from the next sequence number on restart. Checkpoints do not fork, so once you process a checkpoint, it does not change.
-
Make every credit and debit idempotent. Key your ledger entries by
(transaction digest, event sequence)for event-driven credits, or by(transaction digest, object change)for object-based credits. Replaying the same checkpoint must not produce duplicate ledger entries. -
Define a finality policy. Sui transactions are final before they are included in a checkpoint, and checkpoints themselves are final. For exchange purposes, treating inclusion in a finalized checkpoint as the point of finality is the standard choice.
-
Support reprocessing and backfill. Build the pipeline so you can replay a range of checkpoints to recover from a bug or a missed window. This depends on the idempotency keys above.
-
Reconcile against onchain balances. Periodically read
Balance.totalBalance, andBalance.coinBalanceandBalance.addressBalanceseparately, for each tracked address, and compare against your internal ledger. Investigate any drift. -
Plan for both coin objects and address balances. You can pay withdrawals from either, and a user's holdings can sit in either at any time. Build your withdrawal logic to handle both, and use PTBs rather than legacy JSON-RPC transfer methods.
-
Validate addresses on input. Reject malformed addresses early, and confirm
0xprefix handling matches your display layer.
Production considerations
-
Endpoints. Use your own full node or a contracted provider endpoint. Do not rely on the public
fullnode.<network>.sui.ioorgraphql.<network>.sui.ioURLs for production traffic. -
Observability. Configure full node logging and metrics monitoring so you can detect lag or failures quickly.
-
Snapshots. Start a new full node from a recent snapshot rather than syncing from genesis. See Sui Snapshots.
-
Custody and key management. Treat exchange custody keys and any administrative capabilities (for example, capability objects governing your deposit or withdrawal flow) as high-value assets. Separate hot, warm, and cold keys by role, so an online compromise does not expose the keys with the most privilege. Hold warm and cold keys in a multisig address or hardware custody, and sign cold-key transactions using Offline Signing. Keep Testnet and Mainnet keys strictly separate, so a test key can never sign a production transaction.
-
API stability. Pin SDK versions and verify your code against the linked references each time you upgrade. Watch the release notes for breaking changes that affect balances, events, or transaction shapes.