Migrating from Coin to Address Balances
Address balances introduce a canonical balance system for fungible assets tied to Sui addresses. This supplements the Coin<T> model with direct address-owned balances, simplifying transaction construction and eliminating coin selection complexity.
For the full specification, see SIP-58: Sui Address Balances. For implementation details on sending, withdrawing, and paying gas from address balances, see Using Address Balances.
Read this first
This rollout initially has very limited impact:
- Nothing is deprecated or removed. All transactions that are currently valid continue to be valid. Coin objects are not forcibly migrated to address balances.
- No contracts need to be rewritten. Contracts can continue to accept
Coin<T>and&mut Coin<T>as before. - Coins can still be sent through
transfer::public_transferor theTransferObjectscommand.
Impact for wallets, exchanges, and custody providers
Anyone operating a wallet (custodial, non-custodial, or exchange wallets) might be impacted by this change. Users can now send funds to your address through send_funds() instead of transferring a coin object. If a wallet receives funds this way, but does not have proper support for address balances, the user cannot see or access the funds. The user might then believe the funds have been lost. The funds cannot actually be lost, but this can cause confusion for affected users.
Initially, this should not happen often because most of the ecosystem continues to transfer coin objects. However, because there is no way to prevent funds from arriving at any given wallet through an address balance transfer, wallet implementors should be prepared.
User funds can also become split across both coins and address balances. Balance queries through gRPC or GraphQL show the combined total. To send funds that include the address balance portion, you must either:
- Use
coinWithBalancefrom the TypeScript SDK (v2+), which automatically draws from both sources. - Implement manual withdrawal logic as described in Using Address Balances.
Changes to balance queries
Balance query responses now include address balance information alongside coin object totals.
JSON-RPC (legacy)
Sui Foundation disabled JSON-RPC on Mainnet full nodes. This section describes the legacy response shape so you can recognize it in code you are migrating. For new code, use the gRPC or GraphQL fields that follow.
The legacy suix_getBalance and suix_getAllBalances response carries a fundsInAddressBalance field, and its totalBalance field combines coin objects and address balance funds:
{
"coinType": "0x2::sui::SUI",
"coinObjectCount": 2,
"totalBalance": "99998990120",
"lockedBalance": {},
"fundsInAddressBalance": "5000000"
}
Getting only the coin-based balance means subtracting fundsInAddressBalance from totalBalance. The gRPC and GraphQL responses return the two amounts as separate fields, so you do not need that arithmetic.
gRPC
The GetBalance and ListBalances methods from StateService now return separate fields for coin and address balances:
coinBalance: Total held in coin objects.addressBalance: Amount held in address balance.balance: Sum of the two.
{
"balance": {
"coinType": "0x2::sui::SUI",
"balance": "99998990120",
"addressBalance": "5000000",
"coinBalance": "99993990120"
}
}
GraphQL
The balance and balances fields on address types now include addressBalance, coinBalance, and totalBalance fields. See GraphQL Reference - IAddressable.balance for the full schema.