๐ Your First Ergo Transaction โ
Quest Objective: Build and understand your first Ergo transaction Prerequisites: Node.js 18+, TypeScript basics Time Required: ~30 minutes Difficulty: โญโญ Easy
๐ฏ What You'll Build โ
By the end of this tutorial, you'll have:
- โ A working development environment
- โ Understanding of the UTXO model
- โ Your first transaction built with Fleet SDK
- โ Knowledge of fees and change handling
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ ๐ฆ Input Box โ ๐ค Output Box โ
โ (Your Wallet) (Recipient) โ
โ โ
โ โ ๐ฐ Change Box โ
โ (Back to You) โ
โ โ
โ โ โฝ Fee โ
โ (To Miners) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ๐ Prerequisites Checklist โ
Before we begin, make sure you have:
- [ ] Node.js 18+ installed (download)
- [ ] A code editor (VS Code recommended)
- [ ] Testnet ERG from the faucet
- [ ] Basic TypeScript knowledge (variables, functions, async/await)
๐บ๏ธ Understanding the UTXO Model โ
Before we write any code, let's understand how Ergo handles money.
What is UTXO? โ
UTXO stands for Unspent Transaction Output. Think of it like physical cash:
graph TD
A[๐ต You have $20 bill] -->|Buy $5 coffee| B[โ $5 to coffee shop]
A -->|Change| C[๐ต $15 back to you]
style A fill:#4CAF50
style B fill:#FF9800
style C fill:#4CAF50In Ergo:
- Boxes = Bills in your wallet (UTXOs)
- Transactions = Exchanging bills
- Inputs = Bills you're spending
- Outputs = New bills created
Key Concept: Boxes โ
On Ergo, value is stored in boxes. Each box contains:
| Property | Description | Example |
|---|---|---|
value | Amount in nanoERG | 1000000000 (1 ERG) |
ergoTree | Lock script (who can spend) | Address converted to script |
tokens | Native tokens inside | NFTs, tokens |
registers | Additional data (R4-R9) | Metadata, state |
1 ERG = 1,000,000,000 nanoERG
Always work in nanoERG when coding. The n suffix creates BigInt: 1_000_000_000n
โก Step 1: Project Setup โ
Create Project Directory โ
mkdir my-first-ergo-tx
cd my-first-ergo-tx
npm init -yInstall Dependencies โ
npm install @fleet-sdk/core @fleet-sdk/wallet @fleet-sdk/blockchain-providers
npm install -D typescript tsx @types/nodeCreate TypeScript Config โ
npx tsc --initProject Structure โ
my-first-ergo-tx/
โโโ src/
โ โโโ first-transaction.ts โ We'll create this
โโโ package.json
โโโ tsconfig.jsonโ๏ธ Step 2: Understanding the Transaction Builder โ
The TransactionBuilder is your main tool. Here's the pattern:
import { TransactionBuilder, OutputBuilder } from "@fleet-sdk/core";
const transaction = new TransactionBuilder(currentHeight)
.from(inputBoxes) // ๐ฆ What you're spending
.to(outputBoxes) // ๐ค Where it's going
.sendChangeTo(yourAddress) // ๐ฐ Leftover back to you
.payMinFee() // โฝ Network fee
.build(); // ๐จ Construct it!The Transaction Flow โ
sequenceDiagram
participant U as ๐ค User
participant TB as ๐จ TransactionBuilder
participant N as ๐ Network
U->>TB: 1. Add inputs (boxes to spend)
U->>TB: 2. Define outputs (recipients)
U->>TB: 3. Set change address
U->>TB: 4. Calculate fee
TB->>TB: 5. Build unsigned tx
U->>TB: 6. Sign transaction
TB->>N: 7. Broadcast
N->>N: 8. Confirm in block๐ป Step 3: Write Your First Transaction โ
Create src/first-transaction.ts:
/**
* โ๏ธ QUEST: Your First Ergo Transaction
*
* ๐ฏ Objective: Send ERG from one address to another
* โฑ๏ธ Time: ~10 minutes
* ๐ Reward: Understanding of UTXO transactions!
*/
import {
TransactionBuilder,
OutputBuilder,
RECOMMENDED_MIN_FEE_VALUE,
SAFE_MIN_BOX_VALUE,
type Box
} from "@fleet-sdk/core";
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ฆ CONFIGURATION
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const CONFIG = {
// ๐ฏ Recipient address (testnet)
recipientAddress: "9fRAWhdxEsTcdb8PhGNrZfwqa65zfkuYHAMmkQLcic1gdLSV5vA",
// ๐ฐ Amount to send (0.1 ERG = 100,000,000 nanoERG)
amountToSend: 100_000_000n,
// ๐ Your address for change
changeAddress: "9f4QF8AD1nQ3nJahQVkMj8hFSVVzVom77b52JU7EW71Zexg6N8v",
// ๐ Current blockchain height (fetch from explorer in production)
networkHeight: 1_200_000,
};
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ฎ MOCK DATA (Replace with real wallet data)
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
/**
* In production, you would fetch these from:
* - Your wallet (Nautilus, etc.)
* - Ergo Explorer API
* - GraphQL endpoints
*/
const mockInputBoxes: Box<bigint>[] = [
{
boxId: "abc123...",
value: 1_000_000_000n, // 1 ERG
ergoTree: "0008cd...",
creationHeight: 1_100_000,
assets: [],
additionalRegisters: {},
transactionId: "tx123...",
index: 0
}
];
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ฎ MAIN FUNCTION
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
async function buildFirstTransaction() {
console.log("โ๏ธ Starting your first transaction quest...\n");
try {
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ฆ Step 1: Prepare Inputs
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log("๐ฆ Step 1: Gathering input boxes...");
const inputs = mockInputBoxes;
const totalInput = inputs.reduce((sum, box) => sum + box.value, 0n);
console.log(` Found ${inputs.length} input box(es)`);
console.log(` Total value: ${totalInput / 1_000_000_000n} ERG\n`);
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ค Step 2: Create Output
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log("๐ค Step 2: Creating output for recipient...");
const recipientOutput = new OutputBuilder(
CONFIG.amountToSend,
CONFIG.recipientAddress
);
console.log(` Recipient: ${CONFIG.recipientAddress.slice(0, 20)}...`);
console.log(` Amount: ${CONFIG.amountToSend / 1_000_000_000n} ERG\n`);
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐จ Step 3: Build Transaction
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log("๐จ Step 3: Building transaction...");
const unsignedTx = new TransactionBuilder(CONFIG.networkHeight)
.from(inputs)
.to(recipientOutput)
.sendChangeTo(CONFIG.changeAddress)
.payFee(RECOMMENDED_MIN_FEE_VALUE)
.build();
console.log(" โ
Transaction built successfully!\n");
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ Step 4: Review Transaction
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log("๐ Step 4: Transaction Summary");
console.log("โ".repeat(50));
console.log(` Inputs: ${unsignedTx.inputs.length} box(es)`);
console.log(` Outputs: ${unsignedTx.outputs.length} box(es)`);
console.log(` Fee: ${RECOMMENDED_MIN_FEE_VALUE / 1_000_000_000n} ERG`);
// Calculate change
const outputTotal = unsignedTx.outputs.reduce(
(sum, out) => sum + out.value, 0n
);
const change = totalInput - CONFIG.amountToSend - RECOMMENDED_MIN_FEE_VALUE;
console.log(` Change: ${change / 1_000_000_000n} ERG\n`);
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ Quest Complete!
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log("๐ QUEST COMPLETE!");
console.log(" Achievement Unlocked: First Transaction Builder\n");
console.log("๐ Next Steps:");
console.log(" 1. Sign with wallet: wallet.sign(unsignedTx)");
console.log(" 2. Submit to network: await submitTx(signedTx)");
console.log(" 3. Wait for confirmation (~2 minutes)\n");
return unsignedTx;
} catch (error) {
console.error("โ Quest Failed:", error);
throw error;
}
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// ๐ฌ EXECUTE
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
buildFirstTransaction()
.then(() => {
console.log("โจ Tutorial completed successfully!");
})
.catch((err) => {
console.error("๐ Error:", err.message);
process.exit(1);
});โถ๏ธ Step 4: Run Your Code โ
npx tsx src/first-transaction.tsExpected Output:
โ๏ธ Starting your first transaction quest...
๐ฆ Step 1: Gathering input boxes...
Found 1 input box(es)
Total value: 1 ERG
๐ค Step 2: Creating output for recipient...
Recipient: 9fRAWhdxEsTcdb8Ph...
Amount: 0.1 ERG
๐จ Step 3: Building transaction...
โ
Transaction built successfully!
๐ Step 4: Transaction Summary
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Inputs: 1 box(es)
Outputs: 2 box(es)
Fee: 0.001 ERG
Change: 0.899 ERG
๐ QUEST COMPLETE!
Achievement Unlocked: First Transaction Builder
๐ Next Steps:
1. Sign with wallet: wallet.sign(unsignedTx)
2. Submit to network: await submitTx(signedTx)
3. Wait for confirmation (~2 minutes)
โจ Tutorial completed successfully!๐ Common Issues & Solutions โ
Issue 1: "Insufficient Funds" โ
Cause: Not enough ERG in input boxes to cover amount + fee
Solution:
// Check you have enough:
const required = CONFIG.amountToSend + RECOMMENDED_MIN_FEE_VALUE;
const available = inputs.reduce((sum, box) => sum + box.value, 0n);
if (available < required) {
throw new Error(`Need ${required} nanoERG, have ${available}`);
}Issue 2: "Box Value Too Small" โ
Cause: Output value below minimum (SAFE_MIN_BOX_VALUE)
Solution:
import { SAFE_MIN_BOX_VALUE } from "@fleet-sdk/core";
// Ensure output meets minimum:
const amount = Math.max(yourAmount, SAFE_MIN_BOX_VALUE);Issue 3: "Invalid Address" โ
Cause: Wrong network or malformed address
Solution:
- Testnet addresses start with
9or3 - Mainnet addresses start with
9 - Validate format before use
Issue 4: "Height Mismatch" โ
Cause: Using outdated block height
Solution:
// Fetch current height from API:
const response = await fetch('https://api.ergoplatform.com/api/v1/blocks?limit=1');
const data = await response.json();
const currentHeight = data.items[0].height;๐ What You Learned โ
- โ UTXO Model - How Ergo stores and transfers value
- โ Boxes - The fundamental unit of storage
- โ TransactionBuilder - The main API for creating transactions
- โ Outputs - Creating new boxes for recipients
- โ Change Handling - Getting leftover value back
- โ Fees - Paying miners for transaction processing
๐ Deep Dive: Transaction Anatomy โ
graph TB
subgraph "๐ฅ INPUTS"
I1[Box 1: 1 ERG]
end
subgraph "๐ค OUTPUTS"
O1[Recipient: 0.1 ERG]
O2[Change: 0.899 ERG]
O3[Fee: 0.001 ERG]
end
I1 --> O1
I1 --> O2
I1 --> O3
style I1 fill:#f96
style O1 fill:#9f6
style O2 fill:#69f
style O3 fill:#ff9๐ Next Quest โ
Ready for more? Continue to:
- Token Operations โ - Create and transfer tokens
- NFT Minting โ - Mint your first NFT
- Smart Contracts โ - Work with ErgoScript
๐ Additional Resources โ
๐ก Pro Tip
In production apps, never hardcode addresses or amounts. Use environment variables and user input instead!