Installation

Install the SDK using npm:

# Recommended for new Play Hub games
npm install @mythicalb/sdk

# Ardor-only provider
npm install @mythicalb/ardor-provider

# Core utilities are included as dependency, but can be installed separately
npm install @mythicalb/ardor-core
📦 Packages Available

@mythicalb/sdk - Unified Play Hub SDK
@mythicalb/ardor-provider - Ardor wallet bridge
@mythicalb/ardor-core - Shared utilities

Basic Setup

Create one Play Hub client for auth, profiles, sessions, wallets, leaderboards, rewards, Ardor, and Polygon.

import { createMythicalSDK } from "@mythicalb/sdk";

const mythical = createMythicalSDK({
  supabase: { url, anonKey },
  game: {
    id: "card_game",
    modeId: "casual",
    seasonId: "card_game_casual_season_1"
  },
  ardor: { hostOrigin: "https://store.mythicalbeings.io" },
  polygon: { provider: window.ethereum }
});

Create a Guest Profile

const user = await mythical.auth.signInAsGuest("Guest Player");
const profile = await mythical.profile.getOrCreate();
const session = await mythical.sessions.create();
⚠️ Origin Validation

The SDK validates that messages come from the specified origin. Always use the correct origin for your environment.

Connect Linked Wallets

Link Polygon or Ardor when the game needs wallet-specific actions:

async function connectWallet() {
  try {
    await mythical.wallets.connect("polygon");

    const session = await mythical.ardor.connect({
      appName: "My Awesome Game",
      appIconUrl: "https://mygame.com/icon.png",
      permissions: [
        "READ_ACCOUNT",      // Read account address
        "READ_BALANCES",     // Read IGNIS and asset balances
        "TX_SEND_IGNIS",     // Send IGNIS payments
        "TX_TRANSFER_ASSET"  // Transfer game assets
      ]
    });

    console.log("Connected to:", session.accountRS);
    console.log("Public key:", session.publicKey);
    
    return session;
  } catch (error) {
    if (error.code === 4001) {
      console.log("User rejected the connection");
    } else {
      console.error("Connection failed:", error);
    }
  }
}

When you call connect(), the user sees a permission modal:

Example permission modal

🎮 My Awesome Game

wants to connect to your wallet

Requested permissions:

  • ✓ Read your account address
  • ✓ Read your balances
  • ✓ Send IGNIS (requires approval)
  • ✓ Transfer assets (requires approval)

Read Ardor Balances

Once connected, you can read the user's balances:

import { formatNQTToIgnis } from "@mythicalb/ardor-core";

const provider = mythical.ardor.getProvider();
if (!provider) throw new Error("Ardor provider is not available");

// Get all balances
const balances = await provider.getBalances();

// IGNIS balance (in NQT - 8 decimals)
console.log("Raw balance:", balances.ignisNQT);
// → "1050000000"

// Convert to human-readable
const ignis = formatNQTToIgnis(balances.ignisNQT);
console.log("IGNIS:", ignis);
// → "10.5"

// Asset balances
for (const asset of balances.assets) {
  console.log(`Asset ${asset.name}: ${asset.quantityQNT}`);
}

Send a Transaction

All transactions require user approval. The user sees a confirmation modal with transaction details.

// Send IGNIS to another player
try {
  const result = await provider.sendIgnis({
    recipientRS: "ARDOR-XXXX-XXXX-XXXX-XXXXX",
    amount: { ignis: "5.0" },
    message: "Thanks for the trade!"
  });

  console.log("Transaction sent!");
  console.log("TX ID:", result.fullHash);
} catch (error) {
  if (error.code === 4001) {
    console.log("User rejected the transaction");
  } else {
    console.error("Transaction failed:", error);
  }
}

Handle Events

Listen for wallet events to keep your game in sync:

// Account changed (user switched accounts)
provider.on("accountChanged", (event) => {
  console.log("New account:", event.accountRS);
  // Reload user data
  refreshGameState();
});

// Wallet locked
provider.on("locked", () => {
  console.log("Wallet locked");
  showLoginPrompt();
});

// Wallet unlocked
provider.on("unlocked", () => {
  console.log("Wallet unlocked");
  hideLoginPrompt();
});

// Session changed (permissions updated)
provider.on("sessionChanged", (event) => {
  console.log("Session updated:", event.permissions);
});

// Network changed
provider.on("networkChanged", (event) => {
  console.log("Network:", event.isTestnet ? "Testnet" : "Mainnet");
});

Permissions

Request only the permissions your game actually needs:

Permission Description
READ_ACCOUNT Read the user's account address
READ_BALANCES Read IGNIS and asset balances
TX_SEND_IGNIS Send IGNIS payments (requires approval)
TX_TRANSFER_ASSET Transfer assets (requires approval)
TX_SEND_MESSAGE Send plain or encrypted messages
TX_MARKETPLACE Place/cancel marketplace orders
SIGN_TOKEN Sign authentication tokens

Error Handling

The SDK uses standardized error codes:

import { MythicalErrorCode } from "@mythicalb/ardor-core";

try {
  await provider.sendIgnis({ ... });
} catch (error) {
  switch (error.code) {
    case MythicalErrorCode.USER_REJECTED: // 4001
      console.log("User rejected");
      break;
    case MythicalErrorCode.WALLET_LOCKED: // 4200
      console.log("Wallet is locked");
      break;
    case MythicalErrorCode.PERMISSION_DENIED: // 4102
      console.log("Missing permission");
      break;
    case MythicalErrorCode.TX_BROADCAST_FAILED: // 4304
      console.log("Transaction failed:", error.message);
      break;
    default:
      console.error("Unknown error:", error);
  }
}

See the Error Codes guide for a complete list.

Production Checklist

Before going live, make sure you:

  • ✅ Use the production origin: https://store.mythicalbeings.io
  • ✅ Request only the permissions you need
  • ✅ Handle all error cases gracefully
  • ✅ Show loading states during transactions
  • ✅ Listen for accountChanged and locked events
  • ✅ Test on both mainnet and testnet
  • ✅ Check browser compatibility (Chrome 92+, Firefox 95+, Safari 15.4+)
🎉 You're ready!

Check out the Examples for complete working demos, or dive into the API Reference for all available methods.