1. Getting Started
Prerequisites
- Node.js 18+ (for JavaScript development)
- Git for version control
- Code editor (VS Code recommended)
- Basic understanding of UTXO model and Bitcoin scripting
Quick Start
# Create new project
mkdir my-radiant-app
cd my-radiant-app
npm init -y
# Install core dependencies
npm install @radiantblockchain/radiantjs
npm install @radiantblockchain/constants
# Optional: ElectrumX client
npm install ws-electrumx-client
Hello World: Send RXD
const radiant = require('@radiantblockchain/radiantjs');
// Create a new private key
const privateKey = new radiant.PrivateKey();
console.log('Address:', privateKey.toAddress().toString());
console.log('WIF:', privateKey.toWIF());
// To send RXD, you'll need:
// 1. Fund the address
// 2. Get UTXOs from ElectrumX
// 3. Build and sign transaction
// 4. Broadcast to network
2. Development Environment
Recommended Setup
# Install global tools
npm install -g typescript ts-node
# Project structure
my-radiant-app/
├── src/
│ ├── index.ts
│ ├── wallet.ts
│ ├── transactions.ts
│ └── electrum.ts
├── tests/
├── package.json
└── tsconfig.json
TypeScript Configuration
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Environment Variables
# .env
ELECTRUMX_HOST=electrumx.radiantexplorer.com
ELECTRUMX_PORT=50012
ELECTRUMX_PROTOCOL=ssl
NETWORK=mainnet
3. radiantjs SDK
Core Modules
const radiant = require('@radiantblockchain/radiantjs');
const {
PrivateKey, // Key management
PublicKey, // Public key operations
Address, // Address handling
Transaction, // Transaction building
Script, // Script construction
Opcode, // Opcode constants
crypto, // Cryptographic functions
encoding, // Data encoding utilities
Mnemonic, // BIP39 seed phrases
HDPrivateKey, // Hierarchical deterministic keys
Block, // Block parsing
Message, // Message signing
ECIES // Encryption
} = radiant;
Key Management
// Generate new key
const privateKey = new radiant.PrivateKey();
// From WIF
const keyFromWIF = radiant.PrivateKey.fromWIF('your_wif_here');
// From seed phrase (BIP39)
const mnemonic = radiant.Mnemonic.fromRandom();
console.log('Seed phrase:', mnemonic.toString());
const hdKey = mnemonic.toHDPrivateKey();
const derived = hdKey.deriveChild("m/44'/0'/0'/0/0");
const address = derived.publicKey.toAddress();
Address Operations
// Create address from public key
const address = privateKey.toAddress();
console.log('Address:', address.toString());
// Validate address
const isValid = radiant.Address.isValid('1...');
// Parse address
const parsed = new radiant.Address('1A1zP1...');
console.log('Type:', parsed.type); // 'pubkeyhash' or 'scripthash'
Glyph v2 Module
const { Glyph } = require('@radiantblockchain/radiantjs');
// Constants
console.log(Glyph.GLYPH_MAGIC); // 'gly'
console.log(Glyph.GlyphVersion.V2); // 0x02
console.log(Glyph.GlyphProtocol.GLYPH_NFT); // 2
// Encode metadata
const metadata = {
v: 2, type: 'nft', p: [2],
name: 'My NFT', desc: 'A unique token'
};
const encoded = Glyph.encodeMetadata(metadata);
// Validate protocols
const validation = Glyph.validateProtocols([1, 4]); // FT + dMint
console.log(validation.valid); // true
4. Working with Transactions
UTXO Model Basics
UTXO (Unspent Transaction Output):
┌─────────────────────────────────────┐
│ txid: abc123... │
│ vout: 0 │
│ value: 100000000 (1 RXD in photons) │
│ script: <locking script> │
└─────────────────────────────────────┘
To spend a UTXO:
1. Reference it by txid:vout
2. Provide unlocking script (signature)
3. Create new outputs
Building Transactions
const tx = new radiant.Transaction()
.from({
txId: 'previous_txid_here',
outputIndex: 0,
script: 'previous_locking_script',
satoshis: 100000000
})
.to('recipient_address', 50000000) // 0.5 RXD
.change('change_address')
.fee(1000) // Fee in photons
.sign(privateKey);
const txHex = tx.serialize();
Fee Estimation
// Radiant uses photons (1 RXD = 100,000,000 photons)
const FEE_RATE = 0.5; // photons per byte
function estimateFee(inputCount, outputCount) {
const size = inputCount * 148 + outputCount * 34 + 10;
return Math.ceil(size * FEE_RATE);
}
const fee = estimateFee(2, 2); // ~165 photons
Multi-Signature
// 2-of-3 multisig
const redeemScript = radiant.Script.buildMultisigOut([
pubKey1, pubKey2, pubKey3
], 2);
tx.from({
txId: 'txid', outputIndex: 0,
script: redeemScript.toScriptHashOut(),
satoshis: amount
}, [pubKey1, pubKey2, pubKey3], 2);
tx.sign([privateKey1, privateKey2]);
5. Glyph Tokens
Token Types
| Type | Protocol ID | Reference Type |
| Fungible (FT) | 1 | OP_PUSHINPUTREF |
| Non-Fungible (NFT) | 2 | OP_PUSHINPUTREFSINGLETON |
| Data (DAT) | 3 | None |
Creating an NFT Script
function createNFTScript(tokenRef, ownerPkh) {
return new Script()
.add(Buffer.from(tokenRef, 'hex'))
.add(Opcode.OP_PUSHINPUTREFSINGLETON)
.add(Opcode.OP_DROP)
.add(Opcode.OP_DUP)
.add(Opcode.OP_HASH160)
.add(Buffer.from(ownerPkh, 'hex'))
.add(Opcode.OP_EQUALVERIFY)
.add(Opcode.OP_CHECKSIG);
}
Glyph Metadata (CBOR)
const CBOR = require('cbor');
const metadata = {
v: 2, type: 'nft', p: [2],
name: 'My Artwork',
desc: 'A beautiful digital creation',
content: {
primary: {
path: 'artwork.png', mime: 'image/png',
size: 102400,
hash: { algo: 'sha256', hex: '...' },
storage: 'inline'
}
}
};
const encodedMetadata = CBOR.encode(metadata);
const commitHash = crypto.createHash('sha256').update(encodedMetadata).digest();
Commit-Reveal Pattern
// Phase 1: Commit Transaction
function buildCommitTx(privateKey, utxo, commitHash) {
const commitScript = new Script()
.add(Opcode.OP_RETURN)
.add(Buffer.from('gly')) // Magic bytes
.add(Buffer.from([0x02])) // Version 2
.add(Buffer.from([0x00])) // Flags
.add(commitHash); // 32-byte hash
return new Transaction()
.from(utxo)
.addOutput(new Transaction.Output({
script: commitScript, satoshis: 0
}))
.addOutput(new Transaction.Output({
script: Script.buildPublicKeyHashOut(privateKey.toAddress()),
satoshis: utxo.satoshis - 1000
}))
.sign(privateKey);
}
// Phase 2: Reveal Transaction (creates the token)
6. Smart Contracts with RadiantScript
Overview
RadiantScript is a high-level language for writing Radiant smart contracts, compiled to Bitcoin Script with Radiant opcodes.
Installation
git clone https://github.com/Radiant-Core/RadiantScript
cd RadiantScript
yarn install
# Compile contract
npx rxdc MyContract.rxd -o MyContract.json
Basic Contract
// SimpleToken.rxd
contract SimpleToken(bytes36 REF, bytes20 PKH)
function (sig s, pubkey pk) {
require(hash160(pk) == PKH);
require(checkSig(s, pk));
stateSeparator;
bytes36 ref = pushInputRef(REF);
bytes32 csh = hash256(tx.inputs[this.activeInputIndex].codeScript);
require(tx.inputs.codeScriptValueSum(csh) >=
tx.outputs.codeScriptValueSum(csh));
}
Introspection Features
// Transaction introspection
int inputCount = tx.inputCount;
int outputCount = tx.outputCount;
int myIndex = this.activeInputIndex;
int myValue = tx.inputs[myIndex].value;
// Reference tracking
int refCount = tx.outputs.refOutputCount(ref);
int refSum = tx.outputs.refValueSum(ref);
// Transaction state (OP_PUSH_TX_STATE)
bytes32 myTxId = tx.state.txId; // Current transaction's txid
int totalIn = tx.state.inputSum; // Total input value
int totalOut = tx.state.outputSum; // Total output value
Induction Proof Patterns
Radiant supports two methods for mathematical induction proofs:
- Method 1: Reference-Based —
pushInputRef creates an unbroken provenance chain from genesis. Primary method for all Glyph tokens.
- Method 2: TxId v3 Preimage — When
nVersion == 3, the txid is computed from a fixed 112-byte preimage, enabling ancestor verification.
// Code-continuity induction: verify parent had same contract code
bytes myCodeScript = tx.inputs[this.activeInputIndex].codeScript;
bytes32 myCodeHash = hash256(myCodeScript);
require(tx.outputs.codeScriptCount(myCodeHash) >= 1);
// Fee-bounded transfer using tx.state
int fee = tx.state.inputSum - tx.state.outputSum;
require(fee >= 0);
require(fee <= maxFee);
NFT with Royalties
contract NFT(
bytes36 REF, bytes20 OWNER_PKH,
bytes20 CREATOR_PKH, int ROYALTY_BPS
)
function (sig s, pubkey pk) {
require(hash160(pk) == OWNER_PKH);
require(checkSig(s, pk));
stateSeparator;
bytes36 ref = pushInputRefSingleton(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);
bytes20 royaltyRecipient = hash160(tx.outputs[2].lockingBytecode[3:23]);
require(royaltyRecipient == CREATOR_PKH);
}
}
Compile and Deploy
# Compile with debug info
npx rxdc NFT.rxd -o NFT.json --debug
# Use in JavaScript
const artifact = require('./NFT.json');
const contract = new Contract(artifact, [
tokenRef, ownerPkh, creatorPkh, 500 // 5% royalty
]);
const lockingScript = contract.lockingScript;
7. Debugging with rxdeb
Installation
git clone --recursive https://github.com/Radiant-Core/rxdeb
cd rxdeb
./autogen.sh
./configure --enable-rxd
make
sudo make install
Basic Usage
# Debug a simple script
rxdeb '[OP_1 OP_2 OP_ADD OP_3 OP_EQUAL]'
# Debug with transaction context
rxdeb --tx=<spending_tx_hex> --txin=<input_tx_hex>
# Debug RadiantScript artifact
rxdeb --artifact=MyContract.json --function=transfer --args='["<sig>", "<pk>"]'
REPL Commands
| Command | Description |
step / s | Execute one instruction |
continue / c | Run to completion |
rewind / r | Go back one step |
stack | Show main stack |
altstack | Show alt stack |
print | Show script with position |
source | Show RadiantScript source |
refs | Show reference state |
context | Show transaction context |
8. ElectrumX Integration
WebSocket Connection
class ElectrumClient {
constructor(host, port) {
this.url = `wss://${host}:${port}`;
this.requestId = 0;
this.pending = new Map();
}
async connect() {
return new Promise((resolve, reject) => {
this.ws = new WebSocket(this.url);
this.ws.on('open', () => resolve());
this.ws.on('error', reject);
this.ws.on('message', (data) => this.handleMessage(data));
});
}
async request(method, params = []) {
const id = ++this.requestId;
return new Promise((resolve, reject) => {
this.pending.set(id, { resolve, reject });
this.ws.send(JSON.stringify({ id, method, params }));
});
}
}
Common API Methods
// Get server version
await client.request('server.version', ['myapp', '1.4']);
// Get address balance
await client.request('blockchain.scripthash.get_balance', [scriptHash]);
// Get address UTXOs
await client.request('blockchain.scripthash.listunspent', [scriptHash]);
// Get transaction
await client.request('blockchain.transaction.get', [txid, true]);
// Broadcast transaction
await client.request('blockchain.transaction.broadcast', [txHex]);
// Subscribe to address
await client.request('blockchain.scripthash.subscribe', [scriptHash]);
Script Hash Calculation
function addressToScriptHash(address) {
const script = radiant.Script.buildPublicKeyHashOut(
new radiant.Address(address)
);
const hash = crypto.createHash('sha256')
.update(script.toBuffer()).digest();
return hash.reverse().toString('hex'); // Reverse for Electrum
}
9. Running a Node
Docker (Recommended)
docker run -d --name radiant-node \
-p 7332:7332 -p 7333:7333 \
-v radiant-data:/root/.radiant \
radiant-core:latest \
-rpcuser=myuser -rpcpassword=mypassword
docker exec radiant-node radiant-cli getblockchaininfo
Node Profiles
radiantd -nodeprofile=archive # Full history
radiantd -nodeprofile=agent # Minimal footprint
radiantd -nodeprofile=mining # Optimized for mining
RPC Integration
class RadiantRPC {
constructor(user, pass, host = '127.0.0.1', port = 7332) {
this.url = `http://${host}:${port}`;
this.auth = { username: user, password: pass };
}
async call(method, params = []) {
const response = await axios.post(this.url, {
jsonrpc: '2.0', id: Date.now(), method, params
}, { auth: this.auth });
if (response.data.error) throw new Error(response.data.error.message);
return response.data.result;
}
}
const rpc = new RadiantRPC('user', 'pass');
const info = await rpc.call('getblockchaininfo');
Useful RPC Commands
radiant-cli getblockchaininfo # Chain status
radiant-cli getblock <hash> # Block details
radiant-cli getrawtransaction <txid> true # TX details
radiant-cli getmempoolinfo # Mempool stats
radiant-cli getmininginfo # Mining stats
radiant-cli getnetworkinfo # Network info
10. V2 Hard Fork (Radiant Core 2.1)
Overview
Radiant Core 2.1 introduces a hard fork at block 410,000 (mainnet & testnet3) that activates 6 new and re-enabled opcodes, gated behind the SCRIPT_ENHANCED_REFERENCES flag.
New Opcodes
| Opcode | Hex | Stack Effect | Description |
OP_BLAKE3 | 0xee | data → hash | Blake3 hash (32-byte output) |
OP_K12 | 0xef | data → hash | KangarooTwelve hash (32-byte output) |
OP_LSHIFT | 0x98 | a b → (a << b) | Bitwise left shift |
OP_RSHIFT | 0x99 | a b → (a >> b) | Bitwise right shift |
OP_2MUL | 0x8d | a → (a * 2) | Multiply by 2 |
OP_2DIV | 0x8e | a → (a / 2) | Divide by 2 |
Why These Opcodes
- OP_BLAKE3 / OP_K12 — Fully on-chain PoW validation for Glyph v2 dMint tokens, eliminating indexer trust dependency
- OP_LSHIFT / OP_RSHIFT — On-chain ASERT-lite DAA via bit shifts
- OP_2MUL / OP_2DIV — Efficient numeric scaling for DAA and contract arithmetic
Using V2 Opcodes
const { Script, Opcode } = radiant;
// Blake3 hash verification
const script = new Script()
.add(Opcode.OP_BLAKE3)
.add(Opcode.OP_SIZE)
.add(Script.buildNumber(32))
.add(Opcode.OP_EQUALVERIFY);
// DAA bit-shift
const daaScript = new Script()
.add(Script.buildNumber(1000)) // target
.add(Script.buildNumber(2)) // shift amount
.add(Opcode.OP_LSHIFT); // target << 2 = 4000
Activation Heights
| Network | Height | Status |
| Mainnet | 410,000 | Pending |
| Testnet3 | 410,000 | Pending |
| Scalenet | 1,000 | Active |
| Regtest | 200 | Active |
Fee Policy Change
- Blocks < 410,000: 0.01 RXD/kB (legacy)
- Blocks 410,000 – 414,999: 0.01 RXD/kB (grace period)
- Blocks ≥ 415,000: 0.1 RXD/kB (new minimum)
Ecosystem Compatibility
| Tool | V2 Support |
| radiantjs | OP_BLAKE3/K12 (pure JS), OP_LSHIFT/RSHIFT, OP_2MUL/2DIV in interpreter |
| radiantblockchain-constants | V2 opcode values and names |
| RadiantScript | blake3(), k12() compiler globals, tx.state.* induction proof operators |
| rxdeb | Full VM execution of all V2 opcodes |
| Glyph-miner | Blake3/K12 GPU shaders for multi-algo mining |
| Photonic Wallet | Per-algorithm contract bytecodes |
| RXinDexer | Analytics-only (on-chain PoW eliminates indexer validation) |
11. AI Integration (MCP Server)
The radiant-mcp-server package makes Radiant natively accessible to AI coding assistants and any HTTP client via a REST API.
Quick Setup (MCP)
{
"mcpServers": {
"radiant": {
"command": "npx",
"args": ["radiant-mcp-server"],
"env": {
"ELECTRUMX_HOST": "electrumx.radiant4people.com",
"ELECTRUMX_PORT": "50012",
"ELECTRUMX_SSL": "true"
}
}
}
}
This gives AI agents access to 56 MCP tools across 9 categories, plus 10 MCP resources.
REST API
ELECTRUMX_HOST=electrumx.radiant4people.com \
ELECTRUMX_PORT=50012 ELECTRUMX_SSL=true \
node dist/rest.js
curl http://localhost:3080/api/chain
curl http://localhost:3080/api/address/1ADDRESS.../balance
curl http://localhost:3080/api/token/REF/metadata
See AI Integration Strategy for the full implementation reference.
12. Best Practices
Security
// ✅ Validate all inputs
function validateAddress(addr) {
if (!radiant.Address.isValid(addr)) throw new Error('Invalid address');
}
// ✅ Use secure random for keys
const privateKey = radiant.PrivateKey.fromRandom();
// ❌ DON'T: Hardcode private keys
const key = new radiant.PrivateKey('WIF_HERE'); // NEVER in code!
// ✅ Use environment variables
const key = new radiant.PrivateKey(process.env.PRIVATE_KEY_WIF);
Error Handling
async function sendTransaction(txHex) {
try {
const result = await electrum.request(
'blockchain.transaction.broadcast', [txHex]
);
return { success: true, txid: result };
} catch (error) {
if (error.message.includes('insufficient fee'))
return { success: false, error: 'FEE_TOO_LOW' };
if (error.message.includes('missing inputs'))
return { success: false, error: 'UTXO_SPENT' };
return { success: false, error: 'UNKNOWN', details: error.message };
}
}
UTXO Management
// Consolidate small UTXOs
function shouldConsolidate(utxos) {
const smallUtxos = utxos.filter(u => u.value < 10000);
return smallUtxos.length > 10;
}
// Coin selection
function selectCoins(utxos, target) {
const sorted = [...utxos].sort((a, b) => b.value - a.value);
let sum = 0;
const selected = [];
for (const utxo of sorted) {
selected.push(utxo);
sum += utxo.value;
if (sum >= target) break;
}
return { selected, sum };
}
13. Resources
Official Documentation
GitHub Repositories
Community
Tools