Issue an asset
Create a new asset, such as a stablecoin or a tokenised deposit, in one transaction.
You need: a funded regtest key (Quick start). Issuing costs the network's issuance fee in ARRK (1 ARRK on regtest and testnet, 10 ARRK on mainnet), on top of the normal fee.
Decide the asset's rules first
They are fixed at issuance and public forever:
| Choice | Effect |
|---|---|
| Fixed supply | amount == max_supply; nobody can ever mint more |
MINTABLE | an authority token is created; spending it allows minting up to max_supply |
FREEZABLE | a control token is created; spending it freezes or unfreezes a holder's lock |
CLAWBACK | the control token can also recover holders' coins without their signature |
metadata_hash | commits to a ARRK-AMS-1 document; required to publish a controls_policy if the asset has controls |
Keep the authority and control tokens behind multisig or a policy lock; whoever can spend them holds the issuer's powers. Burning the control token removes the controls permanently.
What the example does
- Builds a transaction with an
issuancesentry (ticker, name, decimals, amount, max supply, flags, metadata hash), funded from the issuer's ARRK coins. - Pays the new supply and any authority/control tokens to the issuer's addresses.
- Signs and submits it, then reads the asset back with
getAsset({ idOrTicker }).
The asset id is derived from the first input's outpoint, so it is known before the transaction confirms.
/**
* Issue an asset: a mintable, freezable token with ARRK-AMS-1 metadata; pay, mint, freeze.
*
* ARREKTA_URL=http://127.0.0.1:28332 ARREKTA_ADMIN_TOKEN=... npx tsx examples/issue-asset.ts
*/
import {
createClient,
formatUnits,
freezeAsset,
fromHex,
generateSeed,
getAsset,
getChain,
getCoins,
getFrozen,
issueAsset,
keychainFromSeed,
mine,
mintAsset,
sendPayment,
unfreezeAsset,
} from 'arrekta-sdk';
const URL = process.env.ARREKTA_URL ?? 'http://127.0.0.1:28332';
const ADMIN = process.env.ARREKTA_ADMIN_TOKEN;
const SEED = fromHex(process.env.ARREKTA_SEED ?? 'a1'.repeat(32));
// 1. Connect; the issuer's wallet and a holder's.
const client = createClient({ url: URL, adminToken: ADMIN });
const { network } = await getChain(client);
const issuer = keychainFromSeed(SEED, { network });
const holder = keychainFromSeed(generateSeed(), { network });
if ((await getCoins(client, { wallet: issuer })).length === 0) await mine(client, issuer.address(0), 101);
// 2. Issue 1,000.00 units (max 5,000.00), mintable and freezable, with metadata.
const letters = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
const ticker = 'GLD' + Array.from({ length: 4 }, () => letters[Math.floor(Math.random() * letters.length)]).join('');
const metadata = {
schema: 'arrk-ams-1',
ticker,
name: 'Demo Gold',
issuer: { name: 'Demo Issuer' },
controls_policy: 'Freezes only on court order.',
};
const issued = await issueAsset(client, {
wallet: issuer,
ticker,
name: 'Demo Gold',
amount: '1000',
decimals: 2,
maxSupply: '5000',
mintable: true,
freezable: true,
metadata,
});
await mine(client, issuer.address(0), 1);
console.log(`issued ${ticker} = ${issued.asset}`);
// 3. Pay the holder 12.50 units.
await sendPayment(client, { wallet: issuer, to: holder.address(0), amount: '12.5', asset: ticker });
await mine(client, issuer.address(0), 1);
// 4. Mint 100.00 more (spends and re-creates the authority token).
await mintAsset(client, { wallet: issuer, asset: ticker, amount: '100' });
await mine(client, issuer.address(0), 1);
const asset = await getAsset(client, { idOrTicker: ticker });
console.log(`supply ${formatUnits(asset.issued, asset.decimals)} ${ticker}`);
// 5. Freeze the holder, list frozen holders, then unfreeze.
await freezeAsset(client, { wallet: issuer, asset: ticker, address: holder.address(0) });
await mine(client, issuer.address(0), 1);
console.log('frozen:', (await getFrozen(client, { asset: ticker })).frozen.map((f) => f.address));
await unfreezeAsset(client, { wallet: issuer, asset: ticker, address: holder.address(0) });
await mine(client, issuer.address(0), 1);
console.log('frozen after unfreeze:', (await getFrozen(client, { asset: ticker })).frozen);"""Issue an asset: a mintable, freezable token with ARRK-AMS-1 metadata; pay, mint, freeze.
ARREKTA_URL=http://127.0.0.1:28332 ARREKTA_ADMIN_TOKEN=... python examples/issue_asset.py
"""
import os
import secrets
from arrekta_sdk import Client, format_units, generate_seed, keychain_from_seed
URL = os.environ.get("ARREKTA_URL", "http://127.0.0.1:28332")
ADMIN = os.environ.get("ARREKTA_ADMIN_TOKEN")
SEED = bytes.fromhex(os.environ.get("ARREKTA_SEED", "a1" * 32))
def main() -> None:
# 1. Connect; the issuer's wallet and a holder's.
client = Client(URL, admin_token=ADMIN)
network = client.get_chain()["network"]
issuer = keychain_from_seed(SEED, network=network)
holder = keychain_from_seed(generate_seed(), network=network)
if not client.get_coins(issuer):
client.mine(issuer.address(0), 101)
# 2. Issue 1,000.00 units (max 5,000.00), mintable and freezable, with metadata.
ticker = "GLD" + "".join(secrets.choice("ABCDEFGHJKLMNPQRSTUVWXYZ") for _ in range(4))
metadata = {"schema": "arrk-ams-1", "ticker": ticker, "name": "Demo Gold",
"issuer": {"name": "Demo Issuer"}, "controls_policy": "Freezes only on court order."}
issued = client.issue_asset(issuer, ticker, "Demo Gold", "1000", decimals=2, max_supply="5000",
mintable=True, freezable=True, metadata=metadata)
client.mine(issuer.address(0), 1)
print(f"issued {ticker} = {issued.asset}")
# 3. Pay the holder 12.50 units.
client.send_payment(issuer, holder.address(0), "12.5", asset=ticker)
client.mine(issuer.address(0), 1)
# 4. Mint 100.00 more (spends and re-creates the authority token).
client.mint_asset(issuer, ticker, "100")
client.mine(issuer.address(0), 1)
asset = client.get_asset(ticker)
print(f"supply {format_units(asset['issued'], asset['decimals'])} {ticker}")
# 5. Freeze the holder, list frozen holders, then unfreeze.
client.freeze_asset(issuer, ticker, holder.address(0))
client.mine(issuer.address(0), 1)
print("frozen:", [f["address"] for f in client.get_frozen(ticker)["frozen"]])
client.unfreeze_asset(issuer, ticker, holder.address(0))
client.mine(issuer.address(0), 1)
print("frozen after unfreeze:", client.get_frozen(ticker)["frozen"])
if __name__ == "__main__":
main()Source: sdk/typescript/examples/issue-asset.ts (updated 2026-11-02) · sdk/python/examples/issue_asset.py (updated 2026-11-02). Runnable against a regtest node; CI runs every example.
After issuance
- Mint: spend the authority token with a
mintsentry (§7.2). - Freeze/unfreeze: spend the control token with a
freezesentry; check withgetFrozen({ asset }). - Vesting: pay holders to a vesting policy (
AND(KEY(holder), AFTER(unlock_height))). - Regulated workflows (holder registry, restricted transfers, distributions, dividends): the issuer service.
Common errors: issuance-ticker-taken and an insufficient fee
for the issuance fee.