Token Plugin
Status: Stable – available on Solana devnet.
Import identifier in policy expressions:
@TokenPlugin.*
The Token Plugin provides a complete toolkit for creating, minting, transferring, burning and querying tokens directly inside Tarobase policies. It exposes two classes of functions:
- Transactional (on‑chain) functions – mutate state, revert on failure, and may only be used in
hooks.onchain.*
strings. - Read‑only functions – pure helpers that return data and may be used anywhere a rule or hook expression expects a value.
All amounts are integers; whether they represent whole tokens or smallest‑unit tokens is explained per function. Unless explicitly stated otherwise, decimals = 6 is strongly recommended for all custom tokens.
Quick‑start example
"myToken/$tokenId": {
"operationDetails": {
"read": "Public.",
"create": "Admin‑only. Creates the token and mints the full supply to escrow.",
"update": "false",
"delete": "false"
},
"onchain": true,
"fields": {
"name": "String",
"symbol": "String"
},
"rules": {
"read": "true",
"create": "@user.address == @constants.ADMIN_ADDRESS"
},
"hooks": {
"onchain": {
"create": "@TokenPlugin.createToken($tokenId, @newData.name, @newData.symbol, \"https://…\", 6) && @TokenPlugin.mint($tokenId, @newData.name, @newData.symbol, @contract.address, 1_000_000_000 * (10 ** 6))"
}
}
}
Special variables
Variable | Purpose |
---|---|
@TokenPlugin.SOL | Native SOL mint pseudo‑address (lamports). Use anywhere a mintAddress parameter is expected. |
@TokenPlugin.USDC | Canonical USDC mint on Solana (4zMMC9…JgZJDncDU ). |
Transactional functions
transfer
@TokenPlugin.transfer(sourceAddress, destinationAddress, mintAddress, amount)
- amount – smallest units (lamports, micro‑USDC, etc.).
- Use when you already operate in smallest units or need sub‑token precision.
- SOL transfers are allowed (
mintAddress = @TokenPlugin.SOL
).
transferWholeTokens
@TokenPlugin.transferWholeTokens(sourceAddress, destinationAddress, mintAddress, amount)
- amount – whole tokens (e.g.,
1
→ 1 USDC). The plugin automatically multiplies by10**decimals
under the hood. - Handy inside UI‑driven flows where users think in whole‑token numbers.
createToken
@TokenPlugin.createToken(tokenId, name, symbol, uri, decimals)
Creates a brand‑new token mint. Must be called exactly once per tokenId
. The new mint address is later derivable with getTokenMintAddress
.
Best practice: keep
decimals = 6
unless you have a compelling reason – most wallets & analytics assume 6‑decimals tokens.
mint
@TokenPlugin.mint(tokenId, name, symbol, destinationAddress, amount)
Mints additional supply to destinationAddress
.
- amount is in smallest units – multiply desired whole‑token quantity by
10**decimals
yourself or store a constant. - Parameters must exactly match those used at creation.
burn
@TokenPlugin.burn(sourceAddress, mintAddress, amount)
Irreversibly destroys amount
(smallest units) from sourceAddress
.Not available for SOL.
Read‑only functions
Function | Signature | Returns | Notes |
---|---|---|---|
getBalance | @TokenPlugin.getBalance(walletAddress, mintAddress) | UInt | Smallest‑unit balance of walletAddress . Works for SOL, USDC and custom mints. |
getDecimals | @TokenPlugin.getDecimals(mintAddress) | UInt | Decimal precision for any token or SOL/USDC. |
getSupply | @TokenPlugin.getSupply(mintAddress) | UInt | Current total supply (smallest units). |
getTokenMintAddress | @TokenPlugin.getTokenMintAddress(tokenId, name, symbol) | Address | Deterministic mint derived from tokenId , name , symbol . Use after createToken to reference the mint in later operations. |
All read‑only helpers are pure and may be used in rules.*
or hooks.*
expressions.
Usage patterns & recipes
1. Fixed‑price sale validation
"purchases/$purchaseId": {
"fields": { "tokenAmount": "UInt", "lamportsPaid": "UInt" },
"rules": {
"create": "(@newData.lamportsPaid * (10 ** 6)) == (@newData.tokenAmount * @constants.PRICE_PER_WHOLE_TOKEN)"
}
}
Use cross‑multiplication to compare lamports vs. whole‑token cost without precision loss.
2. Escrow / staking
"stakes/$userId": {
"rules": {
"create": "@newData.amount >= @constants.MIN_STAKE && @newData.owner == @user.address"
},
"hooks": {
"onchain": {
"create": "@TokenPlugin.transfer(@user.address, @contract.address, @TokenPlugin.SOL, @newData.amount)",
"delete": "@TokenPlugin.transfer(@contract.address, @user.address, @TokenPlugin.SOL, @data.amount)"
}
}
}
Best practices & gotchas
- Always hard‑code admin wallets/escrow addresses in policy rules – never store them in documents.
- Use constants (
@constants.TOKEN_DECIMALS
, etc.) to avoid magic numbers. - Prefer
transferWholeTokens
for UX simplicity; switch totransfer
when precision < 1 token matters. createToken
andmint
must match ontokenId
,name
,symbol
,decimals
or the call reverts.- You cannot burn SOL.
- Keep hooks short – no more than ~5 plugin calls.
Future roadmap
- Allowances & approvals (ERC‑20 style) for delegated spending.
- Programmatic metadata updates (name / symbol) for upgradeable mints.
- Expanded multi‑chain coverage beyond Solana.