Skip to main content

3. Core Concepts

Understanding the fundamental concepts of the Amadeus Protocol SDK.

Keypairs

Amadeus Protocol uses BLS12-381 cryptography for all cryptographic operations. Each account has a public/private keypair.

Generating Keypairs

import { generateKeypair } from '@amadeus-protocol/sdk'

// Generate a new keypair
const keypair = generateKeypair()

console.log('Public Key:', keypair.publicKey) // Base58 encoded
console.log('Private Key:', keypair.privateKey) // Base58 encoded seed (64 bytes)

Keypair Structure

  • Public Key: 48-byte BLS12-381 public key, Base58-encoded
  • Private Key: 64-byte seed, Base58-encoded (also called "Seed64")

Deriving Public Keys

import { derivePublicKeyFromSeedBase58 } from '@amadeus-protocol/sdk'

// Derive public key from existing seed
const publicKey = derivePublicKeyFromSeedBase58('5Kd3N...')
console.log('Public Key:', publicKey)

Addresses

In Amadeus Protocol, public keys serve as addresses. They are Base58-encoded 48-byte BLS12-381 public keys.

Address Format

// Address is the public key
const address = keypair.publicKey
// Example: "5Kd3NvsngHeMoo884xkJ6Cyb5StvnRN6f9tYiqwqJzLpQq"

Address Characteristics

  • Length: Typically 87-88 characters (Base58 encoded)
  • Format: Base58-encoded public key
  • Uniqueness: Each keypair has a unique address
  • Public: Safe to share publicly (it's your public key)

Address Validation

import { fromBase58 } from '@amadeus-protocol/sdk'

function isValidAddress(address: string): boolean {
try {
const bytes = fromBase58(address)
return bytes.length === 48 // BLS12-381 public key is 48 bytes
} catch {
return false
}
}

Transactions

Transactions are the primary way to interact with the Amadeus blockchain. They must be:

  1. Built with proper structure
  2. Signed with the sender's private key
  3. Serialized (packed) into binary format
  4. Submitted to a node

Transaction Structure

interface UnsignedTransaction {
signer: Uint8Array // Sender's public key (48 bytes)
nonce: bigint // Transaction nonce
action: TransactionAction // Transaction action
}

interface TransactionAction {
op: 'call' // Operation type
contract: string // Contract name or address
function: string // Function to call
args: SerializableValue[] // Function arguments
}

Transaction Lifecycle

import { TransactionBuilder } from '@amadeus-protocol/sdk'

const builder = new TransactionBuilder(privateKey)

// 1. Build unsigned transaction
const unsignedTx = builder.buildTransfer({
recipient: address,
amount: 10.5,
symbol: 'AMA'
})

// 2. Sign the transaction
const { txHash, txPacked } = builder.sign(unsignedTx)

// 3. Submit to blockchain
const result = await sdk.transaction.submit(txPacked)

Transaction Nonces

Nonces are automatically generated using timestamps:

// Nonce is generated as: BigInt(Date.now()) * 1_000_000n
// This ensures uniqueness for transactions

For high-frequency transactions, ensure sufficient time between transactions to avoid nonce collisions.

Amounts

AMA tokens use 9 decimal places. Always use atomic units for transactions.

Converting Amounts

import { toAtomicAma, fromAtomicAma } from '@amadeus-protocol/sdk'

// Convert to atomic units (for transactions)
const atomic = toAtomicAma(1.5) // Returns 1500000000

// Convert from atomic units (for display)
const human = fromAtomicAma(1500000000) // Returns 1.5

Amount Precision

Always use toAtomicAma when building transactions:

// ✅ Good
const amount = toAtomicAma(1.5)

// ❌ Bad - may lose precision
const amount = 1.5 * 1000000000

Serialization

The SDK uses VecPack canonical serialization for deterministic encoding of transaction data.

Encoding

import { encode } from '@amadeus-protocol/sdk'

const data = {
foo: 'bar',
count: 42,
items: [1, 2, 3]
}

const encoded = encode(data) // Returns Uint8Array

Decoding

import { decode } from '@amadeus-protocol/sdk'

const decoded = decode(encoded) // Returns DecodedValue

Supported Types

  • null
  • boolean
  • number / bigint
  • string
  • Uint8Array
  • Arrays
  • Objects / Maps

Signing

Transactions are signed using BLS12-381 signatures over the transaction hash.

Signing Process

  1. Build transaction structure
  2. Serialize transaction (canonical encoding)
  3. Hash the serialized transaction (SHA-256)
  4. Sign the hash with private key (BLS12-381)
  5. Pack transaction with signature
// The SDK handles all of this automatically
const { txHash, txPacked } = builder.sign(unsignedTx)

Encoding Formats

Base58

Used for addresses, keys, and transaction hashes:

import { toBase58, fromBase58 } from '@amadeus-protocol/sdk'

// Encode bytes to Base58
const encoded = toBase58(new Uint8Array([1, 2, 3]))

// Decode Base58 to bytes
const decoded = fromBase58('5Kd3N...')

Base64

Used for encrypted data and binary payloads:

import { uint8ArrayToBase64, base64ToUint8Array } from '@amadeus-protocol/sdk'

// Encode to Base64
const base64 = uint8ArrayToBase64(bytes)

// Decode from Base64
const bytes = base64ToUint8Array(base64)

Encryption

The SDK provides password-based encryption for securing sensitive data.

Encrypting Data

import { encryptWithPassword } from '@amadeus-protocol/sdk'

// Encrypt private key before storage
const encrypted = await encryptWithPassword(privateKey, userPassword)
// Returns: { encryptedData, iv, salt } (all Base64 encoded)

Decrypting Data

import { decryptWithPassword } from '@amadeus-protocol/sdk'

// Decrypt when needed
const decrypted = await decryptWithPassword(encrypted, userPassword)

Security Features

  • AES-GCM encryption with 256-bit keys
  • PBKDF2 key derivation with 100,000 iterations
  • Unique salt and IV for each encryption
  • Authenticated encryption (prevents tampering)

API Client

The SDK provides a unified API client for interacting with Amadeus nodes.

Initialization

import { AmadeusSDK } from '@amadeus-protocol/sdk'

const sdk = new AmadeusSDK({
baseUrl: 'https://nodes.amadeus.bot/api',
timeout: 30000
})

API Modules

  • sdk.chain - Chain queries (tip, stats, entries)
  • sdk.wallet - Wallet operations (balances, transactions)
  • sdk.transaction - Transaction submission
  • sdk.contract - Contract interactions
  • sdk.epoch - Epoch and validator data
  • sdk.peer - Network peer information
  • sdk.proof - Validator proofs

Error Handling

All SDK errors are instances of AmadeusSDKError:

import { AmadeusSDKError } from '@amadeus-protocol/sdk'

try {
const balance = await sdk.wallet.getBalance(address, 'AMA')
} catch (error) {
if (error instanceof AmadeusSDKError) {
console.error('SDK Error:', error.message)
console.error('Status:', error.status)
console.error('Response:', error.response)
}
}

Next Steps

Now that you understand the core concepts:

  1. Transaction Building: Learn how to build and sign transactions
  2. API Modules: Explore all available API endpoints
  3. Utilities: Discover utility functions
  4. Examples: See real-world usage examples