Everything you need to build on Anonyma - SDK integration, JSON-RPC API, WebSocket subscriptions, chain architecture, and proof-of-concept validation.
Connect your dApp to Anonyma with the browser wallet extension SDK.
Users install the Anonyma Wallet Chrome extension from the Chrome Web Store. The extension injects the provider at window.anonyma.
Wait for the anonyma#initialized event or check if window.anonyma exists. The provider is ready when window.anonyma.isAnonyma === true.
Call connect() to request wallet access. Once approved, use the full SDK to send transactions, sign messages, and query balances.
// Wait for wallet extension to initialize
function getProvider() {
if ('anonyma' in window) {
return window.anonyma;
}
return new Promise(resolve => {
window.addEventListener('anonyma#initialized', () => {
resolve(window.anonyma);
}, { once: true });
});
}
// Connect to wallet
const provider = await getProvider();
const { address, publicKey } = await provider.connect();
console.log('Connected:', address);
Complete reference for the window.anonyma provider injected by the wallet extension.
isAnonyma
boolean
Always true. Use this to verify the Anonyma provider is present.
if (window.anonyma?.isAnonyma) {
// Anonyma wallet is available
}
getState()
async
→ { isLocked, hasWallet, address }
Returns the current wallet state. Use this to check if the wallet is locked, whether a wallet exists, and the current address.
| Return Field | Type | Description |
|---|---|---|
isLocked | boolean | Whether the wallet is currently locked |
hasWallet | boolean | Whether a wallet has been created |
address | string | null | Current wallet address, or null if locked |
const state = await window.anonyma.getState();
// { isLocked: false, hasWallet: true, address: "5Kd7..." }
connect()
async
→ { address, publicKey }
Requests wallet connection. Opens an approval popup for the user to confirm. Throws if the user rejects.
| Return Field | Type | Description |
|---|---|---|
address | string | Base58-encoded wallet address |
publicKey | string | Base58-encoded Ed25519 public key |
try {
const { address, publicKey } = await window.anonyma.connect();
console.log('Wallet connected:', address);
} catch (err) {
console.log('User rejected connection');
}
disconnect()
async
→ void
Disconnects the current site from the wallet. Emits the 'disconnect' event.
await window.anonyma.disconnect();
getWallet()
async
→ { address, publicKey }
Returns the connected wallet's address and public key. Use this to identify the user's account or derive encryption keys.
| Return Field | Type | Description |
|---|---|---|
address | string | Base58-encoded wallet address |
publicKey | string | Base58-encoded Ed25519 public key |
const { address, publicKey } = await window.anonyma.getWallet();
console.log('Wallet:', address);
signAndSendTransaction(tx)
async
→ { hash }
Signs a transaction with the wallet key and broadcasts it to the network. Opens an approval popup for user confirmation.
| Parameter | Type | Required | Description |
|---|---|---|---|
tx.to | string | Yes | Recipient address (Base58) |
tx.amount | number | Yes | Amount in drops (1 ANM = 1,000,000 drops) |
tx.data | string | No | Arbitrary data payload (max 524,288 bytes) |
// Send 1.5 ANM
const { hash } = await window.anonyma.signAndSendTransaction({
to: '5Kd7Rv3gmYxBaQEKbr9tcBQ5o3PdFuoCEm34fE2dajXW',
amount: 1_500_000, // 1.5 ANM in drops
});
console.log('TX sent:', hash);
// Send with data payload
const { hash: h2 } = await window.anonyma.signAndSendTransaction({
to: '5Kd7Rv3gmYxBaQEKbr9tcBQ5o3PdFuoCEm34fE2dajXW',
amount: 0,
data: 'Hello from Anonyma!',
});
signMessage(message)
async
→ { signature }
Signs an arbitrary string message with the wallet's Ed25519 private key. Useful for authentication and verification without sending a transaction.
| Parameter | Type | Description |
|---|---|---|
message | string | The message to sign |
const { signature } = await window.anonyma.signMessage('Prove wallet ownership');
console.log('Signature:', signature); // Base58-encoded Ed25519 signature
getBalance()
async
→ { balance, balanceANM }
Returns the connected wallet's current balance in drops and ANM.
| Return Field | Type | Description |
|---|---|---|
balance | number | Balance in drops (smallest unit) |
balanceANM | number | Balance in ANM (balance / 1,000,000) |
const { balance, balanceANM } = await window.anonyma.getBalance();
console.log(`Balance: ${balanceANM} ANM`);
on(event, callback)
subscribe
off(event, callback)
unsubscribe
Subscribe or unsubscribe to wallet events.
| Event | Callback Args | Description |
|---|---|---|
'connect' | { address } | Wallet connected to site |
'disconnect' | - | Wallet disconnected |
'accountChanged' | { address } | Active account changed |
// Listen for account changes
window.anonyma.on('accountChanged', ({ address }) => {
console.log('Account changed:', address);
});
// Listen for disconnect
window.anonyma.on('disconnect', () => {
console.log('Wallet disconnected');
});
Direct HTTP JSON-RPC 2.0 interface to the Anonyma chain node.
https://rpc.anonyma.network
All requests use POST with Content-Type: application/json. Body follows the JSON-RPC 2.0 specification. Failover endpoint: https://rpc2.anonyma.network (Validator 2).
// Base request format
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_chainInfo",
"params": {}
}
anm_chainInfo
GET
Returns chain metadata: height, block hash, pending transactions, account count, fee recycling stats, validators, and connected peers.
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_chainInfo"
}
{
"chainId": "anonyma-mainnet-1",
"chainName": "Anonyma",
"height": 42069,
"latestBlock": "a1b2c3...",
"baseFee": 1000000,
"dropsPerAnm": 1000000,
"pendingTxs": 0,
"accounts": 128,
"totalFeesRecycled": 5000,
"totalFeesRecycledANM": 0.005,
"validators": ["EA8sUw...", "2EJMoc..."],
"validatorCount": 2,
"peers": 1,
"peerAddresses": ["2EJMoc..."]
}
anm_getBalance
GET
Returns the balance for a given address in both drops and ANM.
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_getBalance",
"params": {
"address": "5Kd7Rv..."
}
}
{
"address": "5Kd7Rv...",
"balance": 1500000000,
"balanceANM": 1500.0
}
anm_getAccount
GET
Returns full account info including balance, nonce, and ANM balance.
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_getAccount",
"params": {
"address": "5Kd7Rv..."
}
}
{
"address": "5Kd7Rv...",
"balance": 1500000000,
"balanceANM": 1500.0,
"nonce": 42
}
anm_getNonce
GET
Returns the next nonce to use for a transaction from the given address. Includes pending (mempool) transactions.
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_getNonce",
"params": {
"address": "5Kd7Rv..."
}
}
{
"address": "5Kd7Rv...",
"nonce": 43
}
anm_sendTransaction
SEND
Submit a signed transaction to the network mempool. The transaction must be pre-signed with a valid Ed25519 signature.
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_sendTransaction",
"params": {
"transaction": {
"from": "5Kd7Rv...",
"to": "3xQ9Fm...",
"amount": 1000000,
"fee": 1,
"nonce": 0,
"timestamp": 1700000000000,
"data": "",
"hash": "abc123...",
"signature": "def456..."
}
}
}
// Success
{
"success": true,
"hash": "abc123..."
}
// Error
{
"success": false,
"error": "Insufficient balance"
}
anm_getTransaction
GET
Retrieve a transaction by its hash. Returns null if not found.
{
"jsonrpc": "2.0",
"id": 1,
"method": "anm_getTransaction",
"params": {
"hash": "abc123..."
}
}
{
"transaction": {
"from": "5Kd7Rv...",
"to": "3xQ9Fm...",
"amount": 1000000,
"fee": 1,
"hash": "abc123...",
...
},
"blockIndex": 1234
}
anm_getTransactions
GET
Get recent transactions for an address. Default limit is 50.
// Params
{ "address": "5Kd7Rv...", "limit": 20 }
anm_searchTransactions
GET
Search transactions for an address with optional data content filter. Default limit is 100.
// Params
{ "address": "5Kd7Rv...", "dataContains": "hello", "limit": 50 }
anm_getBlock
GET
Retrieve a full block by index, including all transactions.
// Params
{ "index": 1234 }
anm_getBlockCount
GET
Returns the current block height.
// Response
{ "height": 42069 }
anm_getLatestBlock
GET
Returns the latest block header (without full transaction data).
// Response
{
"index": 42069,
"timestamp": 1700000000000,
"hash": "a1b2c3...",
"previousHash": "d4e5f6...",
"validator": "5Kd7Rv...",
"txCount": 3
}
anm_getValidators
GET
Returns the list of active validators in the network and the total validator count.
// Response
{
"validators": ["EA8sUw...", "2EJMoc..."],
"count": 2
}
anm_getPeers
GET
Returns the list of connected P2P peer addresses and the total peer count. Only available when multi-validator mode is active.
// Response
{
"peers": ["2EJMoc..."],
"count": 1
}
The RPC endpoint is rate-limited to 100 requests per 10 seconds per IP address. Request body size is limited to 5 MB. Exceeding these limits returns HTTP 429 or 413.
Subscribe to live block production and address-specific transaction events.
wss://rpc.anonyma.network
Connect via WebSocket to the same RPC endpoint. Send JSON messages to subscribe/unsubscribe to event channels.
Subscribe to Blocks
Receive a notification every time a new block is produced (~400ms).
// Send
{ "action": "subscribe", "channel": "block" }
// Unsubscribe
{ "action": "unsubscribe", "channel": "block" }
{
"event": "newBlock",
"data": {
"index": 42069,
"timestamp": 1700000000000,
"hash": "a1b2c3...",
"validator": "5Kd7...",
"txCount": 3
}
}
Subscribe to Address Transactions
Receive a notification whenever a transaction involves a specific address (as sender or recipient).
// Watch incoming/outgoing txs
{
"action": "subscribe",
"channel": "tx:5Kd7Rv..."
}
{
"event": "newTransaction",
"data": {
"transaction": { ... },
"blockIndex": 42069
}
}
const ws = new WebSocket('wss://rpc.anonyma.network');
ws.addEventListener('open', () => {
// Subscribe to new blocks
ws.send(JSON.stringify({ action: 'subscribe', channel: 'block' }));
// Subscribe to txs for a specific address
ws.send(JSON.stringify({
action: 'subscribe',
channel: 'tx:5Kd7Rv3gmYxBaQEKbr9tcBQ5o3PdFuoCEm34fE2dajXW'
}));
});
ws.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
if (msg.event === 'newBlock') {
console.log('New block:', msg.data.index, 'txs:', msg.data.txCount);
}
if (msg.event === 'newTransaction') {
console.log('New tx:', msg.data.transaction.hash);
}
});
How Anonyma's Multi-Validator Proof-of-Authority consensus, P2P networking, fee recycling, and cryptography work.
Anonyma uses a distributed multi-validator Proof-of-Authority consensus. Validators connect via a P2P WebSocket network and produce blocks in a deterministic round-robin schedule (producer = blockHeight % validatorCount). Each validator signs blocks with its Ed25519 key, and all peers verify signatures before accepting blocks. This eliminates single points of failure while maintaining sub-second finality.
Transaction fees (1 ANM per TX) are recycled back to the block's validator rather than burned. This creates a sustainable economic model where no tokens are permanently removed from circulation.
Fee recycling maintains total supply at exactly 1 billion ANM. Validators are compensated for operating network infrastructure while preserving the token economy's stability.
Every transaction contains the following fields. The hash is computed from the raw fields, then signed with the sender's Ed25519 private key.
| Field | Type | Description |
|---|---|---|
from | string | Sender address (Base58) |
to | string | Recipient address (Base58) |
amount | number | Amount in drops |
fee | number | Fee in drops (must be ≥ BASE_FEE = 1,000,000 = 1 ANM) |
nonce | number | Sequential counter (prevents replay attacks) |
timestamp | number | Unix timestamp in milliseconds |
data | string | Optional arbitrary data (max 524,288 bytes) |
hash | string | SHA-256 hash of raw transaction fields |
signature | string | Ed25519 signature of the hash (Base58) |
// Transaction hash is computed as:
// SHA-256( from + to + amount + fee + nonce + timestamp + data )
// Then signed with Ed25519: sign(hash, secretKey)
| Field | Type | Description |
|---|---|---|
index | number | Block height (0 = genesis) |
timestamp | number | Block creation time (unix ms) |
previousHash | string | Hash of the previous block |
hash | string | SHA-256 of block header |
txRoot | string | Merkle-like root of included transactions |
stateRoot | string | Hash of state after applying block |
validator | string | Address of the block producer |
txCount | number | Number of transactions in block |
transactions | array | Array of signed transactions |
All keys, transaction signatures, and block signatures use Ed25519 elliptic-curve cryptography via tweetnacl. Keys are 32-byte public / 64-byte secret.
All hashing - transaction hashes, block hashes, state roots - uses SHA-256 from the Web Crypto API for performance and security.
End-to-end encrypted messaging in Palavia uses tweetnacl-js box. Messages are encrypted with the recipient's public key and can only be decrypted by the recipient. Group and channel profiles (name + avatar) are also encrypted on-chain using NaCl SecretBox with domain-separated keys.
All addresses, public keys, signatures, and hashes are encoded in Base58 (Bitcoin-style) for human-readability and URL safety.
Configure and operate a validator node in Anonyma's multi-validator PoA network.
Anonyma v2.0 introduced multi-validator consensus. 2 validators are live in production — primary at rpc.anonyma.network and backup at rpc2.anonyma.network. Validators connect to each other via a P2P WebSocket network, relay blocks and transactions, and produce blocks in a deterministic round-robin schedule. All frontend apps automatically fail over to Val 2 if Val 1 is unreachable (3-second timeout). Any node can join the network by setting the appropriate environment variables.
| Variable | Description | Example |
|---|---|---|
ANONYMA_PEERS | Comma-separated list of peer validators (host:port) | anonyma-val2.railway.internal:7779 |
ANONYMA_VALIDATORS | Comma-separated validator addresses (all known validators) | 2EJMoc...,3xLBWo... |
ANONYMA_P2P_PORT | P2P WebSocket listen port | 7779 |
PORT | HTTP JSON-RPC server port | 8080 |
ANONYMA_VALIDATOR_KEY | Validator's Ed25519 secret key (Base64) — overrides disk key | (base64 string) |
ANONYMA_DATA_DIR | Blockchain data directory (persistent volume) | /app/data |
Without ANONYMA_PEERS and ANONYMA_VALIDATORS, the node runs in solo validator mode — identical behavior to v1. No configuration changes needed for existing single-validator deployments.
Integrate ANM token swaps into your application. The Bridge API enables cross-chain swaps between ETH, SOL and ANM with constant-product AMM pricing.
https://bridge.anonyma.network
/api/pools
Returns all liquidity pools with current reserves and live USD prices.
[
{
"pair": "ETH_ANM",
"tokenA": "ETH",
"tokenB": "ANM",
"reserveA": 15.0,
"reserveB": 5000000.0,
"priceANM_USD": 0.0085,
"priceETH_USD": 2800.0,
"priceSOL_USD": 145.0
},
{
"pair": "SOL_ANM",
"tokenA": "SOL",
"tokenB": "ANM",
"reserveA": 300.0,
"reserveB": 5000000.0,
"priceANM_USD": 0.0085,
"priceETH_USD": 2800.0,
"priceSOL_USD": 145.0
}
]
/api/prices
Returns current USD prices for ANM, ETH and SOL. Prices are fetched from CoinGecko every 60 seconds.
{
"ANM": 0.0085,
"ETH": 2800.0,
"SOL": 145.0
}
/api/quote
Get a price quote for a swap. Uses constant-product AMM (x × y = k) with 0.3% fee.
| Param | Type | Description |
|---|---|---|
pair | string | ETH_ANM or SOL_ANM |
direction | string | buy (token → ANM) or sell (ANM → token) |
amount | number | Amount of input token |
// Quote: Buy ANM with 0.1 ETH
GET /api/quote?pair=ETH_ANM&direction=buy&amount=0.1
{
"amountOut": 33222.59,
"fee": 0.0003,
"feeToken": "ETH",
"priceImpact": 0.0067,
"rate": 333333.33,
"minAmountOut": 33056.48
}
/api/deposit-address
Get the bridge deposit address for a given pair and direction. Users send funds to this address before submitting a swap.
| Param | Type | Description |
|---|---|---|
pair | string | ETH_ANM or SOL_ANM |
direction | string | buy or sell |
GET /api/deposit-address?pair=ETH_ANM&direction=buy
{ "address": "0x..." }
/api/swap
Submit a swap after depositing funds to the bridge address. The bridge verifies the deposit on-chain, executes the AMM trade, and sends the output token to the receiver.
| Field | Type | Description |
|---|---|---|
pair | string | ETH_ANM or SOL_ANM |
direction | string | buy or sell |
amountIn | number | Amount sent to bridge |
senderAddress | string | Your sending address (verified against TX) |
receiverAddress | string | Address to receive output tokens |
txHash | string | Deposit transaction hash |
// Buy ANM with ETH
const res = await fetch('https://bridge.anonyma.network/api/swap', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
pair: 'ETH_ANM',
direction: 'buy',
amountIn: 0.1,
senderAddress: '0xYourEthAddress...',
receiverAddress: 'AnmReceiverAddress...',
txHash: '0xDepositTxHash...',
}),
});
const data = await res.json();
// { swapId, status, amountOut, payoutTxHash }
/api/swap/:id
Check the status of a swap by its ID.
GET /api/swap/abc123
{
"id": "abc123",
"pair": "ETH_ANM",
"direction": "buy",
"status": "completed",
"amountIn": 0.1,
"amountOut": 33222.59,
"feeAmount": 0.0003,
"depositTxHash": "0x...",
"payoutTxHash": "5abc...",
"createdAt": 1708900000000,
"completedAt": 1708900005000
}
Complete swap lifecycle for integrating into your application:
Call GET /api/quote to show the user the expected output amount, fee, and price impact before they confirm.
Call GET /api/deposit-address to get the bridge wallet address the user should send funds to.
User sends the input token (ETH, SOL, or ANM) to the bridge deposit address and obtains the transaction hash.
Call POST /api/swap with the deposit TX hash. The bridge verifies on-chain, executes the AMM trade, and sends the output token.
Optionally poll GET /api/swap/:id to track completion and get the payout transaction hash.
Anonyma Swap uses a constant-product AMM (x × y = k), the same model as Uniswap V2.
| Property | Value |
|---|---|
| Fee | 0.3% per swap |
| Formula | amountOut = (reserveOut × amountIn × 0.997) / (reserveIn + amountIn × 0.997) |
| Pairs | ETH_ANM, SOL_ANM |
| Directions | buy (token → ANM), sell (ANM → token) |
| Verification | Deposits are verified on-chain (ETH via Etherscan, SOL via Solana RPC, ANM via Anonyma RPC) |
| Sender check | The sender address in the deposit TX must match senderAddress |
| TX reuse | Each deposit TX hash can only be used once |
Top up pool reserves without resetting swap history. Requires Authorization: Bearer <ADMIN_SECRET> header.
/api/add-liquidity
Add liquidity to a pool. Provide one side for proportional add (price unchanged), or both sides for custom ratio (price may shift).
| Field | Type | Required | Description |
|---|---|---|---|
pair | string | Yes | ETH_ANM or SOL_ANM |
amountA | number | One of A/B | Amount of ETH or SOL to add |
amountB | number | One of A/B | Amount of ANM to add |
| Input | Behavior | Price Impact |
|---|---|---|
Only amountA | Auto-calculates proportional ANM | None (recommended) |
Only amountB | Auto-calculates proportional ETH/SOL | None (recommended) |
Both amountA + amountB | Adds both as-is | May shift price |
{
"ok": true,
"pair": "SOL_ANM",
"added": { "amountA": "proportional", "amountB": 100000 },
"reserves": { "tokenA": 3.5993, "ANM": 300000 },
"k": 1079775,
"priceBefore": 0.000011998,
"priceAfter": 0.000011998,
"priceANM_USD": 0.000939
}
All errors return JSON with an error field:
{ "error": "Deposit transaction not found or not confirmed..." }
| HTTP | Meaning |
|---|---|
400 | Missing or invalid parameters |
403 | Unauthorized (admin endpoints: /api/reset-pools, /api/add-liquidity) |
404 | Swap or resource not found |
409 | Deposit TX hash already used |
500 | Internal error |
Embed the full Anonyma Swap interface into your own app using an iframe. The widget auto-detects when embedded and hides redundant navigation.
<iframe
src="https://swap.anonyma.network"
title="Anonyma Swap"
width="100%"
height="680"
style="border: none; border-radius: 24px;"
allow="clipboard-write"
/>
Pass the user's ANM wallet address via the anm query parameter. The swap form will auto-fill it into the correct field based on swap direction:
<iframe
src="https://swap.anonyma.network?anm=ANM_WALLET_ADDRESS"
title="Anonyma Swap"
width="100%"
height="680"
style="border: none; border-radius: 24px;"
allow="clipboard-write"
/>
| Parameter | Type | Description |
|---|---|---|
anm | string | ANM wallet address to pre-fill in the swap form |
| Feature | Standalone | Embedded (iframe) |
|---|---|---|
| Footer links | Visible | Hidden |
| Bridge status dot | Visible | Hidden |
| Pool info | Visible | Visible |
| Vertical padding | 48px | 16px (compact) |
The swap widget allows embedding from these origins:
frame-ancestors 'self' https://anonyma.palavia.chat https://*.vercel.app http://localhost:*
To embed from a custom domain, contact us to add your origin to the allowlist.
How Anonyma ensures every transaction is valid and the chain is tamper-proof.
Every transaction includes an Ed25519 signature. The chain verifies that the signature matches the sender's public key before accepting the transaction. Invalid signatures are rejected immediately.
Transaction hashes are recomputed and compared. A transaction with a modified field will produce a different SHA-256 hash, causing signature verification to fail - making transactions tamper-proof.
Each block references the previous block's hash, forming an immutable linked chain. Altering any historical block would invalidate all subsequent block hashes.
Nonces are sequential per account, preventing replay attacks. A transaction with a duplicate or out-of-order nonce is rejected by the mempool and block validator.
Before inclusion in a block, every transaction is validated against the sender's current balance. The amount + fee must not exceed available balance. Overdrafts are impossible.
Each block includes a state root - a hash of the entire account state after applying all transactions. This allows any node to verify state consistency independently.
import nacl from 'tweetnacl';
import bs58 from 'bs58';
function verifyTransaction(tx) {
// Decode the signature and public key from Base58
const signature = bs58.decode(tx.signature);
const publicKey = bs58.decode(tx.from); // address = public key
const hashBytes = bs58.decode(tx.hash);
// Verify Ed25519 signature
const valid = nacl.sign.detached.verify(hashBytes, signature, publicKey);
return valid; // true if signature is authentic
}
// Verify a message signature
function verifyMessage(message, signature, address) {
const msgBytes = new TextEncoder().encode(message);
const sigBytes = bs58.decode(signature);
const pubKey = bs58.decode(address);
return nacl.sign.detached.verify(msgBytes, sigBytes, pubKey);
}
| Code | Constant | Description |
|---|---|---|
-32700 | PARSE_ERROR | Invalid JSON received |
-32600 | INVALID_REQUEST | Not a valid JSON-RPC 2.0 request |
-32601 | METHOD_NOT_FOUND | Unknown method name |
-32602 | INVALID_PARAMS | Missing or invalid parameters |
-32603 | INTERNAL_ERROR | Internal server error |
-32000 | TX_INVALID | Transaction validation failed |
-32001 | INSUFFICIENT_BAL | Insufficient balance for tx + fee |
-32002 | INVALID_NONCE | Nonce mismatch (too low or too high) |
-32003 | INVALID_SIG | Ed25519 signature verification failed |
-32004 | DATA_TOO_LARGE | Data payload exceeds 524,288 bytes |
Complete example: detect wallet, connect, send a transaction, and listen for confirmation.
// ── 1. Detect & Connect ──
async function initAnonyma() {
// Wait for extension to inject provider
const provider = window.anonyma ?? await new Promise(r =>
window.addEventListener('anonyma#initialized', () => r(window.anonyma), { once: true })
);
// Check wallet state
const state = await provider.getState();
if (!state.hasWallet) {
alert('Please create a wallet in the Anonyma extension');
return;
}
// Request connection
const { address } = await provider.connect();
console.log('Connected:', address);
return provider;
}
// ── 2. Send Transaction ──
async function sendPayment(provider, recipient, amountANM) {
const amountDrops = amountANM * 1_000_000;
const { hash } = await provider.signAndSendTransaction({
to: recipient,
amount: amountDrops,
});
console.log('TX submitted:', hash);
return hash;
}
// ── 3. Listen for Confirmation via WebSocket ──
function waitForConfirmation(txHash, address) {
return new Promise((resolve) => {
const ws = new WebSocket('wss://rpc.anonyma.network');
ws.addEventListener('open', () => {
ws.send(JSON.stringify({
action: 'subscribe',
channel: `tx:${address}`,
}));
});
ws.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
if (msg.data?.transaction?.hash === txHash) {
console.log('Confirmed in block', msg.data.blockIndex);
ws.close();
resolve(msg.data);
}
});
});
}
// ── 4. Usage ──
const provider = await initAnonyma();
const hash = await sendPayment(provider, 'RecipientAddress...', 10);
const confirmation = await waitForConfirmation(hash, 'SenderAddress...');
console.log('All done!', confirmation);
Install the wallet extension, connect to the RPC, and ship your first dApp.