Coins and Funding
Coin declaration forms, managed coins, and how account funding works.
Declare the coins your accounts hold, then fund those accounts at boot so your app starts with
balances in place. The coin namespace has three forms, one per provenance — a coin from a package
you publish, a protocol builtin, or an already-deployed on-chain type — and funding follows from
whether devstack can mint the coin: SUI from the faucet, managed package coins from their treasury
cap.
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { account, coin, defineDevstack, localPackage, sui } from '@mysten-incubation/devstack';
const HERE = dirname(fileURLToPath(import.meta.url));
const localnet = sui();
const publisher = account('publisher');
const managed = localPackage('managed_coin', {
sourcePath: resolve(HERE, 'move/managed_coin'),
publisher,
});
const studio = coin.fromPackage(managed, 'MANAGED_COIN');
const alice = account('alice', {
funding: [
{ coin: 'sui', amount: 1_000_000_000n },
{ coin: studio, amount: 1_000n },
],
});
export default defineDevstack({ members: [localnet, managed, alice], stackName: 'main' });Coin forms
coin.builtin('sui')— the protocol SUI type,0x2::sui::SUI, with known decimals (9). Pure synchronous lookup; baked as a literal into codegen.coin.fromPackage(member, witness)— a coin published by alocalPackage(...)orknownPackage(...)member, looked up by(package, witness)after the package publishes. It adds a dependency edge on the package member, so publish and coin discovery complete before any funding tries to use the coin. Generated bindings carry the discoveredCoinMetadata/coin_registry::Currencyfields.coin.known(fullCoinType)— an already-deployed on-chain type (0x…::module::WITNESS), resolved through a metadata read. Use it for live-network coins no local package publishes.
Managed coins
A managed coin is one devstack can both identify and mint for accounts. A coin is managed when:
- it's declared with
coin.fromPackage(localPackageMember, witness); - the publish output includes the coin metadata and a
TreasuryCapfor that witness; - the publisher still owns that cap (so it stays available as the funding signer).
When those hold, the coin gains a coinType:<fullCoinType> funding strategy that mints from the
treasury cap. Account funding, DeepBook pool seeding, and the dashboard fund button all mint through
that same strategy. You then fund an account with the coin directly:
const alice = account('alice', {
funding: [{ coin: studio, amount: 1_000n }],
});Account funding entries
Each entry in an account's funding array names a coin and an amount:
account('trader', {
kind: 'ephemeral',
funding: [
{ coin: 'sui', amount: 1_000_000_000_000n }, // 'sui' shorthand → the faucet
{ coin: usdc, amount: 5_000_000_000n }, // a managed coin → its treasury cap
{ coin: dbtc, amount: 100_000_000n, via: deepbook }, // via: a strategy-provider edge
],
});{ coin: 'sui', amount }is shorthand for SUI funding through the faucet — nocoin.builtin('sui')needed.{ coin: <ref>, amount }funds any resolved coin ref through itscoinType:<fullCoinType>strategy.viaadds a dependency edge on the member that provides the strategy (e.g. a DeepBook instance), so that provider resolves before funding runs. Use it when the coin's funding comes from a service rather than its own package publish.viais only valid on a coin-ref entry ({ coin: <ref> }); the{ coin: 'sui' }shorthand always funds through the faucet and takes novia.
Amounts are in the coin's smallest unit (MIST for SUI).
Which coins can be funded
You can reference more coins than you can fund. A coin is fundable when something provides a funding strategy for it:
- SUI is fundable when the active Sui network provides a faucet strategy. Explicit SUI funding throws when none exists, since default account funding depends on it.
- Managed local-package coins are fundable from their treasury cap, as above.
- Service coins like
walCoin(localWalrus)are fundable when their service provides a matchingcoinType:<fullCoinType>strategy. coin.known(fullCoinType)resolves metadata for an external coin so app code and bindings can reference it. To fund it, provide a strategy through the service that owns the mint, or passviaon the funding entry.
A missing non-SUI strategy is a no-op, so optional service funding stays ergonomic; a missing SUI strategy raises an error.
Funding runs per network: each strategy is keyed by coinType:<fullCoinType> (or
faucet:request:<chainId> for SUI) and resolved against the current network, so a stack funds only
on its own network. See Faucet and funding strategies for how
strategies are provided and dispatched.