Skip to main content

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

VariablePurpose
@TokenPlugin.SOLNative SOL mint pseudo‑address (lamports). Use anywhere a mintAddress parameter is expected.
@TokenPlugin.USDCCanonical USDC mint on Solana (4zMMC9…JgZJDncDU).

Transactional functions

transfer

@TokenPlugin.transfer(sourceAddress, destinationAddress, mintAddress, amount)
  • amountsmallest 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)
  • amountwhole tokens (e.g., 1 → 1 USDC). The plugin automatically multiplies by 10**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

FunctionSignatureReturnsNotes
getBalance@TokenPlugin.getBalance(walletAddress, mintAddress)UIntSmallest‑unit balance of walletAddress. Works for SOL, USDC and custom mints.
getDecimals@TokenPlugin.getDecimals(mintAddress)UIntDecimal precision for any token or SOL/USDC.
getSupply@TokenPlugin.getSupply(mintAddress)UIntCurrent total supply (smallest units).
getTokenMintAddress@TokenPlugin.getTokenMintAddress(tokenId, name, symbol)AddressDeterministic 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 to transfer when precision < 1 token matters.
  • createToken and mint must match on tokenId, 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.