Coin23 on Sui: New Controls for Creators and Merchants
Coin23
as in ‘Coin 2023’; the 2023-edition of Sui-Coin. This name is a reference to “Token22” or “Token 2022”, which is the new Token-program for Solana (which is still in development even though 2023 is now half-over). We’ve replicated all of Token22’s features*, and added a bunch more (Token22 does not, for example, have any merchant-specific functionality).
Why Coin23 exists:
- In Sui,
Coin
is hard for client-applications to work with: a person may own dozens of coins, forcing client-applications to (1) query their balances, and (2) include instructions to split / merge coins as needed to get the balance they need to pay for something. Coin
does not meet the business requirements of Circle. Circle needs to have freezable balances. On Ethereum or Solana, each person’s USDC-balance is a root-accessible account, and Circle can flip a ‘freeze’ boolean-parameter at any time. BecauseCoin
is a storable Move struct, it is trivial to render it inaccessible to Circle by wrapping it in a non-compliant struct. Circle will never be able to support native-USDC on Sui as aCoin
object.Coin
is a single-writer object, meaning that it is inaccessible to every person on the Sui blockchain other than the owner’s keypair. This means you cannot, for example (1) have an organization delegate spend-authority to an employee, (2) grant a merchant rebill authority, or (3) allow a merchant to issue a hold against an existing balance.
Coin23 fixes all of these issues. It takes the Balance
from within any Coin
and places it inside of a shared object called Coin23
. Because Coin23
and Coin
share the same Balance
it’s trivial to convert between the two; a Coin
object can be converted to a Coin23
object and vice-versa (subject to some caveats—see below).
Coin23 adds new creator controls. The current creator-control-settings for a currency are are stored inside of the CurrencyRegistry;
a global shared object. Creators of already-existing currencies can assert their control over their own currency by using their existing TreasuryCap
. Currencies do not necessarily need any creator controls in order to be used by end-users (for example, SUI will never have any creator controls). New creators of currencies can opt-in to adding creator controls to their currency using a One-Time-Witness they get in their init-function when they publish their currency-defining module for the first time.
All of the following creator controls are configurable; they can be turned on or off, as needed.
New creator controls:
- Freeze: Creators can freeze and unfreeze Coin23 objects. When frozen, users cannot withdraw from or deposit to the
available_balance
portion of their Coin23 account. This is useful for currencies like USDC, whose issuer, Circle, uses balance-freezes to comply with law-enforcement requests. Existing holds are not affected by a freeze (more on that below). - Withdraw: Creators can withdraw balances from Coin23 objects. This is useful for game-developers who might want to punish hackers who found an infinite-money glitch, or recover stolen funds. It also allows game-developers to use a server to debit a player’s virtual-currency without the owner signing a transaction. Aptos’
CoinStore
object implements this behavior calledBurnCapability
; when you submit a transaction, the network withdraws your APT balance and burns it to pay for the gas-fee. - Transfer Fees: creators can charge basis-points per transfer, giving currency-issuers a source of royalty-revenue, or of implementing a supply-reducing burn mechanism.
- Non-Transferable: Creators can prevent the transfer of balances between Coin23 accounts. Balances can still be withdrawn by the creator, or spent by creator-defined functions. This allows game-developers to create virtual currencies that cannot be transferred between players; this is useful if you only want players to be able to buy currencies from the game itself (only primary sales, no secondary sales), or if you want to prevent players from being ‘power-leveled’ by receiving tons of money gifted to them by higher-level players.
- Non-Exportable: as mentioned previously, the
Balance
of a Coin23 object can be exported back into aCoin
if the creator allows it. However, once outside of Coin23, aBalance
is free from all creator-imposed controls. As such, creators are allowed to turn off the exporting ofBalance
. - Whitelisted DeFi: unfortunately, Sui Move DeFi uses
store
. This means that, in order for you to trade coins on an orderbook for example, you must first removeBalance
from withinCoin23
and place it inside of the orderbook object. As stated above, this means the creator loses access to their own currency, hence the creator may not want to allow this. How can a creator safely compose their currency with a DeFi program, while also remaining in control of it? That’s why I created a ‘DeFi Whitelist’ feature. This allows the creator to specify programs that are allowed to export Coin23 balances which are not publicly exportable (in case the balance is publicly exportable, there is no point in having an export-program-whitelist). The idea is that the DeFi program honors creator controls, and does a Coin23 → DeFi → Coin23 swap, ensuring that the end-user is never able to use DeFi as a backdoor export to bypass creator-controls.
Merchant controls:
- Rebill: users can give merchants the ability to withdraw from their
Coin23
at regular intervals. This is useful for recurring services like Netflix. Users can specify a maximum amount per interval, and a rebill interval. Users can see upcoming rebills, and cancel them at any time. Merchants are responsible for submitting transactions themselves when a rebill is available; money is not automatically withdrawn. Merchants do not have to withdraw the maximum amount available to them; this is useful for usage-based services like utilities, where the total balance due is not known until the end of the month. - Held Balances: users can grant merchants a temporary hold on a portion of their available-balance. Held balances cannot be frozen or taken by creators; they are in the control of the merchant to either withdraw from, or release, at the merchant’s discretion. Holds expire after a specified time. After expiration, the end-user must ‘crank’ their
Coin23
account to move expired held-funds back into their available-balance. Holds are useful for merchants who want to guarantee they will be paid, but do not know the final amount, such as hotel-room stays or car-rentals. - Payment Memo: end-users can include payment-memos with their transactions. These are unique payment identifiers, which help merchants match transactions to invoices / payment requests. In other words, payments are attributable to some off-chain state (such as an invoice-system). They also help end-users link their payment-history to specific merchants, so they have a record of who they paid and for what.
Additionally, Coin23
may be easier to use than Coin
in that client-applications can simply specify a static, root-level object-id to withdraw from, and have the owner of that object sign the transaction; no need to combine and split multiple Coin
objects.
Downsides
On the downside, Coin23
does not integrate well with existing DeFi programs. If Coin23
is adopted, DeFi programs will need to be refactored to withdraw from, and deposit back into, Coin23
objects rather than using Coin
or Balance
.
Another downside is the use of a global CurrencyRegistry object. This is normally read-only, allowing parallel transactions, but modification-transactions to it will be blockers to all other Coin23
transactions, potentially causing all consensus on allCoin23
objects to be serialized until the write is processed. Unfortunately this is due to the fact that we cannot prove to the runtime that a Currency-Configuration for a given currency does not exist. I.e., if a creator creates a currency with a transfer-fee, the runtime cannot know this unless it reads that currency’s configuration file as an argument to a function. But the creator of the currency may have never created such an object, leaving the currency publicly accessible (no creator controls). As such, we must make the configuration-object input an optional parameter, but then the creator of this transaction can simply not supply a legitimate configuration object that does exist in order to bypass creator controls.
This relates to Sui’s data-access model. In Solana, account-addresses are deterministic functions of the mint-address and the owner’s public-key, meaning that if an account exists, you know where to find it. Unfortunately Sui object-ids do not have this property. Furthermore Sui lacks runtime data-access provided by Aptos’ global_borrow
except from inside of an object’s dynamic fields; the CurrencyRegistry object provides exactly this deterministic-address lookup and runtime data access, allowing the runtime to prove that a Currency-Control for a given currency in fact does _not_ exist.
Further Thoughts
Note: the only Token22 feature we’re missing in Coin23 is confidential transfers; unfortunately Sui-core had Bulletproofs and Pedersen Commitments prior to mainnet, but these were removed shortly before mainnet because they weren’t production-ready (?). Once these modules are brought back, confidential-transfers can be added to Coin23
(if people want them?). Anonymous transfers (ring signatures?) would also be interesting to explore in the future.
You can read the most up to date iteration of the module here, which will still change in the future:
Please leave your thoughts and point out any errors or how this can be improved! This is an initial draft, and can be reworked as needed to accommodate a wide set of use-cases.