Overview
This guide covers creating tokens on Radiant using the Glyph protocol. Whether you want to create a simple NFT, launch a fungible token, or set up a mineable token contract, this document has you covered.
Token Types
| Type | Protocol ID | Use Case | Reference Type |
| Fungible Token (FT) | 1 | Currencies, points, shares | Normal |
| Non-Fungible Token (NFT) | 2 | Art, collectibles, certificates | Singleton |
| Data Token (DAT) | 3 | Timestamps, attestations | None |
| Mineable Token (dMint) | 1 + 4 | Fair launch tokens | Normal |
| Container | 2 + 7 | NFT collections | Singleton |
Method 1: Using Photonic Wallet (Easiest)
Creating an NFT
- Open Photonic Wallet — Visit photonic.radiant4people.com
- Navigate to Mint — Click "Mint" tab → Select "NFT"
- Fill Token Details: Name, Description, Image upload
- Advanced Options (optional): Container, Royalty percentage, Custom attributes
- Mint — Review transaction, confirm and sign, wait for confirmation
Creating a Fungible Token
- Select "Fungible Token" in Mint tab
- Configure: Name, Ticker, Decimals (8 default), Total Supply
- Choose distribution: Fixed Supply (all to wallet) or dMint (proof-of-work)
- Mint and distribute
Creating a Mineable Token (dMint)
V2 Hard Fork (Block 410,000): Starting with Radiant Core 2.1, v2 dMint contracts validate proof-of-work entirely on-chain using OP_BLAKE3 and OP_K12 hash opcodes. The difficulty adjustment (DAA) is also computed on-chain via OP_LSHIFT/OP_RSHIFT. This eliminates indexer trust dependency and prevents griefing. v1 SHA256d tokens continue to work unchanged.
- Select "dMint Contract" in Mint tab
- Configure Mining Parameters:
Token Name: Mineable Coin
Ticker: MINE
Total Supply: 21,000,000
Algorithm: Blake3 (recommended)
Difficulty: 10,000 (starting)
DAA Mode: ASERT (recommended)
Target Time: 60 seconds
Reward: 100 tokens per solve
Max Height: 210,000
- Deploy Contract — creates token reference, deploys with on-chain PoW validation
Method 2: Using Photonic CLI (Batch Operations)
Setup
git clone https://github.com/Radiant-Core/Photonic-Wallet
cd Photonic-Wallet/packages/cli
pnpm install
pnpm build
Batch Mint NFT Collection
# Create wallet
node dist/cli.js wallet create --output wallet.json
# Get address and fund it
node dist/cli.js wallet address --wallet wallet.json
# Prepare batch file (tokens.json)
{
"collection": {
"name": "My Collection",
"description": "A collection of 100 NFTs"
},
"tokens": [
{ "name": "Item #1", "image": "./images/1.png", "attributes": { "rarity": "common" } },
{ "name": "Item #2", "image": "./images/2.png", "attributes": { "rarity": "rare" } }
]
}
# Mint batch
node dist/cli.js mint batch \
--wallet wallet.json \
--input tokens.json \
--output results.json
Method 3: Using radiantjs (Programmatic)
NFT Creation
const radiant = require('@radiantblockchain/radiantjs');
const CBOR = require('cbor');
const crypto = require('crypto');
async function createNFT(privateKey, utxos, metadata, fileBuffer) {
// 1. Prepare metadata
const glyphMetadata = {
v: 2, type: 'nft', p: [2],
name: metadata.name,
desc: metadata.description,
content: {
primary: {
path: 'image.png', mime: 'image/png',
size: fileBuffer.length,
hash: { algo: 'sha256', hex: crypto.createHash('sha256').update(fileBuffer).digest('hex') },
storage: 'inline'
}
}
};
// 2. Encode and hash
const encodedMetadata = CBOR.encode(glyphMetadata);
const commitHash = crypto.createHash('sha256').update(encodedMetadata).digest();
// 3. Build commit transaction
const commitTx = new radiant.Transaction()
.from(utxos[0])
.addOutput(new radiant.Transaction.Output({
script: buildCommitScript(commitHash), satoshis: 1000
}))
.change(privateKey.toAddress()).fee(500).sign(privateKey);
// 4. Broadcast commit
const commitTxId = await broadcast(commitTx.serialize());
// 5. Build reveal transaction with token reference
const tokenRef = Buffer.concat([
Buffer.from(commitTxId, 'hex').reverse(), Buffer.alloc(4)
]);
// 6. Build and broadcast reveal
const revealTx = new radiant.Transaction()
.from({ txId: commitTxId, outputIndex: 0, script: buildCommitScript(commitHash), satoshis: 1000 })
.addOutput(new radiant.Transaction.Output({
script: buildNFTScript(tokenRef, privateKey.toAddress()), satoshis: 546
}))
.addOutput(new radiant.Transaction.Output({
script: buildRevealScript(encodedMetadata, fileBuffer), satoshis: 0
}))
.change(privateKey.toAddress()).fee(500).sign(privateKey);
return { commitTxId, revealTxId: await broadcast(revealTx.serialize()) };
}
Method 4: Using RadiantScript (Smart Contracts)
Custom NFT with Royalties
// RoyaltyNFT.rxd
contract RoyaltyNFT(
bytes36 TOKEN_REF, bytes20 OWNER_PKH,
bytes20 CREATOR_PKH, int ROYALTY_BPS // 500 = 5%
)
function (sig s, pubkey pk) {
require(hash160(pk) == OWNER_PKH);
require(checkSig(s, pk));
stateSeparator;
bytes36 ref = pushInputRefSingleton(TOKEN_REF);
if (tx.outputs[1].value > 0) {
int salePrice = tx.outputs[1].value;
int royalty = salePrice * ROYALTY_BPS / 10000;
require(tx.outputs[2].value >= royalty);
bytes outScript = tx.outputs[2].lockingBytecode;
require(hash160(outScript.slice(3, 23)) == CREATOR_PKH);
}
}
Compile and Deploy
npx rxdc RoyaltyNFT.rxd -o RoyaltyNFT.json
const artifact = require('./RoyaltyNFT.json');
const lockingScript = artifact.generateLockingScript([
tokenRef, ownerPkh, creatorPkh, 500 // 5%
]);
Required Fields
{
"v": 2, // Version (always 2 for Glyph v2)
"type": "nft", // Token type
"p": [2] // Protocol IDs array
}
Common Fields
{
"name": "Token Name",
"desc": "Token description (up to 4KB)",
"created": "2026-01-27T12:00:00Z",
"creator": { "pubkey": "02abc123...", "sig": "signature_hex" }
}
Content Fields
{
"content": {
"primary": {
"path": "artwork.png", "mime": "image/png",
"size": 102400,
"hash": { "algo": "sha256", "hex": "..." },
"storage": "inline"
},
"files": [{ "path": "metadata.json", "mime": "application/json", "storage": "inline" }],
"refs": [{ "path": "video.mp4", "uri": "ipfs://QmVideo...", "mime": "video/mp4" }]
}
}
dMint-Specific Fields
{
"dmint": {
"algorithm": "blake3", // sha256d, blake3, k12
"daa": {
"mode": "asert", // fixed, epoch, asert, lwma, schedule
"baseDifficulty": 10000,
"targetMintTime": 60,
"halflife": 3600
},
"maxHeight": 210000,
"reward": 100,
"premine": 0
}
}
Storage Options
| Storage | Pros | Cons | Best For |
| inline | Permanent, censorship-resistant | Size limited, costs more | Small images, important data |
| ipfs | Unlimited size, decentralized | May become unavailable | Large media files |
| ref (URL) | Easy setup | Centralized, may break | Temporary, high-volume |
Size Limits
| Component | Limit |
| Metadata total | 256 KB |
| Single inline file | 1 MB |
| Total inline content | 10 MB |
| Name field | 256 bytes |
| Description field | 4 KB |
Best Practices
Token Creation
- Use descriptive names — Clear, searchable
- Include previews — Thumbnails load faster
- Hash all content — Verify integrity
- Set appropriate policies — Transferable, renderable flags
- Consider royalties — Protect creator rights
For Collections
- Create container first (parent token for organization)
- Use consistent metadata structure across items
- Number sequentially with
index field
- Batch mint for efficiency
Security
- Test on testnet first — never mainnet experiments
- Verify addresses — double-check recipients
- Backup keys — especially for valuable tokens
- Review transactions — before signing
Troubleshooting
| Issue | Solution |
| "Transaction rejected" | Check balance for fees; verify UTXO not spent; ensure valid CBOR |
| "Token not appearing" | Wait for confirmation; check correct network; verify ElectrumX connection |
| "Invalid metadata" | Validate CBOR encoding; check required fields; verify protocol combination |
| "High fees" | Large files increase tx size; consider IPFS for media >100KB; consolidate UTXOs |
Resources
Create responsibly. All tokens are permanent on the blockchain.