{
  "schema_version": "1.0.0",
  "version": "1.2.0",
  "current_sdk_version": "5.1.12",
  "generated": "2026-04-21T00:00:00.000Z",
  "description": "Decision trees for Push Chain agent routing and action selection",
  "trees": [
    {
      "id": "choose_transaction_route",
      "question": "Where should this transaction execute?",
      "branches": [
        {
          "condition": "tx.to is a plain address string (e.g., '0x...')",
          "action": "Use Route 1: Execute on Push Chain via UEA",
          "capability_ids": ["send_universal_transaction"],
          "details": {
            "execution_target": "Push Chain",
            "executor": "UEA (Universal Executor Account)",
            "sdk_call": "pushChainClient.universal.sendTransaction({ to: '0x...', data, value })"
          },
          "next": null
        },
        {
          "condition": "tx.to is an object with { address, chain } where chain is an external chain",
          "action": "Use Route 2: Execute on external chain via CEA",
          "capability_ids": ["send_multichain_transaction"],
          "details": {
            "execution_target": "External chain (e.g., Ethereum Sepolia, BNB Chain)",
            "executor": "CEA (Chain Executor Account)",
            "sdk_call": "pushChainClient.universal.sendTransaction({ to: { address: '0x...', chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA }, data })"
          },
          "next": null
        },
        {
          "condition": "tx.to is a plain address AND tx.from.chain is set to an external chain",
          "action": "Use Route 3: Execute on Push Chain with CEA as origin",
          "capability_ids": ["send_multichain_transaction"],
          "details": {
            "execution_target": "Push Chain",
            "origin": "CEA on specified external chain",
            "use_case": "When execution on Push Chain must reflect an external chain identity",
            "sdk_call": "pushChainClient.universal.sendTransaction({ from: { chain: PushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIA }, to: '0x...', data })"
          },
          "next": null
        }
      ]
    },
    {
      "id": "choose_signer_type",
      "question": "What signer library is the user or developer using?",
      "branches": [
        {
          "condition": "User has an ethers.js Wallet or Signer (v5 or v6)",
          "action": "Use PushChain.utils.signer.toUniversal(ethersSigner)",
          "capability_ids": ["create_universal_signer"],
          "details": {
            "import": "import { ethers } from 'ethers';",
            "provider_note": "RPC URL determines chain: Sepolia RPC → Ethereum Sepolia account"
          },
          "next": null
        },
        {
          "condition": "User has a viem WalletClient",
          "action": "Use PushChain.utils.signer.toUniversal(viemWalletClient)",
          "capability_ids": ["create_universal_signer"],
          "details": {
            "import": "import { createWalletClient, http } from 'viem';",
            "provider_note": "RPC URL determines chain"
          },
          "next": null
        },
        {
          "condition": "User has a Solana Keypair (@solana/web3.js)",
          "action": "Use PushChain.utils.signer.toUniversalFromKeypair(keypair, { chain, library })",
          "capability_ids": ["create_universal_signer_from_keypair"],
          "details": {
            "import": "import { Keypair } from '@solana/web3.js';",
            "chain_param": "PushChain.CONSTANTS.CHAIN.SOLANA_DEVNET",
            "library_param": "PushChain.CONSTANTS.LIBRARY.SOLANA_WEB3JS"
          },
          "next": null
        },
        {
          "condition": "User needs a custom signer implementation (no supported library)",
          "action": "Construct a UniversalSignerSkeleton and pass to toUniversal",
          "capability_ids": [
            "construct_custom_signer",
            "create_universal_signer"
          ],
          "details": {
            "method": "PushChain.utils.signer.construct(account, { signMessage, signAndSendTransaction, signTypedData })",
            "then": "PushChain.utils.signer.toUniversal(skeleton)"
          },
          "next": null
        }
      ]
    },
    {
      "id": "choose_integration_path",
      "question": "What type of application is being built?",
      "branches": [
        {
          "condition": "Building a React frontend with wallet connection UI",
          "action": "Use @pushchain/ui-kit with PushUniversalWalletProvider",
          "capability_ids": ["connect_wallet_ui", "use_wallet_provider"],
          "details": {
            "package": "@pushchain/ui-kit",
            "components": [
              "PushUniversalWalletProvider",
              "PushUniversalAccountButton"
            ],
            "hooks": [
              "usePushWalletContext",
              "usePushChainClient",
              "usePushChain"
            ],
            "benefit": "Abstracts wallet connection, signer creation, and client initialization"
          },
          "next": null
        },
        {
          "condition": "Building a backend service, bot, or script",
          "action": "Use @pushchain/core directly",
          "capability_ids": ["initialize_client", "send_universal_transaction"],
          "details": {
            "package": "@pushchain/core",
            "flow": "Create signer → PushChain.initialize() → pushChainClient.universal.sendTransaction()"
          },
          "next": "choose_signer_type"
        },
        {
          "condition": "Building a React frontend but need full control over wallet logic",
          "action": "Use @pushchain/core with custom wallet integration",
          "capability_ids": ["initialize_client", "create_universal_signer"],
          "details": {
            "package": "@pushchain/core",
            "note": "You manage wallet connection yourself, then create UniversalSigner and initialize client"
          },
          "next": null
        }
      ]
    },
    {
      "id": "handle_transaction_failure",
      "question": "What type of failure occurred?",
      "branches": [
        {
          "condition": "User rejected signature (progress event SEND-TX-104-04 / 204-04 / 304-04 depending on route)",
          "action": "Display user-friendly message and allow retry",
          "capability_ids": [],
          "mapping_note": "Diagnostic only — surface to user and prompt retry. No SDK call needed; consult errors.json + recovery-playbook.md for the wallet_connection_rejected error entry.",
          "details": {
            "message": "Transaction was declined by user",
            "recovery": "Prompt user to try again"
          },
          "next": null
        },
        {
          "condition": "Gas estimation failed",
          "action": "Check account balance and contract validity",
          "capability_ids": [],
          "mapping_note": "Diagnostic only — escalates to errors.json + recovery-playbook.md. Pre-flight balance check uses get_account_status or a direct ethers call; no routing capability executes here.",
          "details": {
            "checks": [
              "Verify target contract exists",
              "Check if user has sufficient funds",
              "Verify calldata is valid"
            ]
          },
          "next": null
        },
        {
          "condition": "Transaction reverted on-chain (progress event SEND-TX-199-02 / 299-02 / 399-02 depending on route)",
          "action": "Inspect revert reason and fix contract call",
          "capability_ids": [],
          "mapping_note": "Diagnostic only — escalates to errors.json + recovery-playbook.md. Inspect receipt from track_transaction or tx.wait(); resubmit with corrected parameters.",
          "details": {
            "debug": "Check progressHook message for revert reason",
            "common_causes": [
              "Insufficient funds in UEA",
              "Contract logic rejection",
              "Invalid function parameters"
            ]
          },
          "next": null
        },
        {
          "condition": "UEA requires upgrade (getAccountStatus shows requiresUpgrade: true)",
          "action": "Call pushChainClient.upgradeAccount() before retrying",
          "capability_ids": ["upgrade_account", "get_account_status"],
          "details": {
            "method": "await pushChainClient.upgradeAccount({ progressHook })",
            "note": "Gasless operation, handled automatically by SDK"
          },
          "next": null
        },
        {
          "condition": "Network or RPC error",
          "action": "Retry with exponential backoff or use custom RPC",
          "capability_ids": ["initialize_client", "reinitialize_client"],
          "details": {
            "custom_rpc": "Pass rpcUrls option to PushChain.initialize()"
          },
          "next": null
        }
      ]
    },
    {
      "id": "choose_tracking_method",
      "question": "How should transaction confirmation be tracked?",
      "branches": [
        {
          "condition": "Need simple confirmation wait after sendTransaction",
          "action": "Use tx.wait() on the returned transaction response",
          "capability_ids": ["track_transaction"],
          "details": {
            "method": "const receipt = await txResponse.wait();",
            "returns": "Transaction receipt with status, logs, gas used",
            "best_for": "Simple sequential flows where you wait for confirmation before proceeding"
          },
          "next": null
        },
        {
          "condition": "Need to track a transaction by hash (e.g., resuming tracking, monitoring)",
          "action": "Use pushChainClient.universal.trackTransaction(txHash)",
          "capability_ids": ["track_transaction"],
          "details": {
            "method": "const receipt = await pushChainClient.universal.trackTransaction(txHash);",
            "best_for": "Tracking transactions you didn't send, resuming after page reload"
          },
          "next": null
        },
        {
          "condition": "Building UI with real-time progress updates",
          "action": "Use progressHook callback in sendTransaction",
          "capability_ids": ["send_universal_transaction"],
          "details": {
            "method": "sendTransaction({ ..., progressHook: (progress) => updateUI(progress) })",
            "events": "Route 1: SEND-TX-1xx, Route 2: SEND-TX-2xx, Route 3: SEND-TX-3xx. Cascade: SEND-TX-001/002/999-xx prefixes wrap each hop."
          },
          "next": null
        }
      ]
    },
    {
      "id": "fee_payment_decision",
      "question": "How will gas fees be paid?",
      "branches": [
        {
          "condition": "User has native tokens on their origin chain (ETH on Ethereum, SOL on Solana)",
          "action": "SDK handles fee abstraction automatically",
          "capability_ids": ["send_universal_transaction"],
          "details": {
            "how_it_works": "User pays in native token on origin chain; SDK converts and funds UEA",
            "no_pc_required": "Users do not need to hold PC tokens for gas"
          },
          "next": null
        },
        {
          "condition": "User is on Push Chain natively",
          "action": "User pays gas directly in PC (smallest unit: uPC)",
          "capability_ids": [
            "send_universal_transaction",
            "use_utility_functions"
          ],
          "details": {
            "unit": "uPC (like wei in ETH)",
            "conversion": "PushChain.utils.helpers.parseUnits('1', 18) = 1 PC"
          },
          "next": null
        },
        {
          "condition": "User wants to move funds as part of transaction",
          "action": "Use tx.funds parameter to atomically move assets",
          "capability_ids": [
            "send_universal_transaction",
            "send_multichain_transaction"
          ],
          "details": {
            "param": "tx.funds: { amount: BigInt, token?: PushChain.CONSTANTS.MOVEABLE.TOKEN }",
            "behavior": "Asset movement and execution happen atomically"
          },
          "next": null
        }
      ]
    },
    {
      "id": "choose_cascade_vs_single",
      "question": "Does the flow require visiting multiple chains with a single user signature?",
      "branches": [
        {
          "condition": "Single chain target — user signs once and execution is complete",
          "action": "Use sendTransaction() directly",
          "capability_ids": ["send_universal_transaction"],
          "details": {
            "method": "pushChainClient.universal.sendTransaction({ to, data, value, funds, ... })",
            "returns": "UniversalTxResponse with .wait() and tx hash"
          },
          "next": "choose_transaction_route"
        },
        {
          "condition": "Multiple hops required — e.g. Push Chain then Ethereum then BNB, signed once",
          "action": "Use prepareTransaction() + executeTransactions() cascade pattern",
          "capability_ids": ["execute_transaction_cascade"],
          "details": {
            "step_1": "const hop1 = await pushChainClient.universal.prepareTransaction({ to: '0x...', data })",
            "step_2": "const hop2 = await pushChainClient.universal.prepareTransaction({ to: { address: '0x...', chain: CHAIN.ETHEREUM_SEPOLIA }, data })",
            "step_3": "const result = await pushChainClient.universal.executeTransactions([hop1, hop2])",
            "returns": "CascadedTxResponse with .wait() and .waitForAll() per hop",
            "note": "Each hop supports the same args as sendTransaction (to, data, value, funds, gasLimit, payGasWith, deadline, from, progressHook)"
          },
          "next": null
        }
      ]
    },
    {
      "id": "choose_signing_method",
      "question": "What kind of signing operation is needed?",
      "branches": [
        {
          "condition": "Sign arbitrary bytes for off-chain verification (authentication, attestation)",
          "action": "Use pushChainClient.universal.signMessage(message)",
          "capability_ids": ["sign_universal_message"],
          "details": {
            "input": "message: Uint8Array — use new TextEncoder().encode('text') for strings",
            "returns": "Uint8Array signature",
            "capability": "sign_universal_message"
          },
          "next": null
        },
        {
          "condition": "Sign EIP-712 typed data (Permit2, Uniswap v3/v4, Seaport, gasless approvals, order matching)",
          "action": "Use pushChainClient.universal.signTypedData(typedDataArgs)",
          "capability_ids": ["sign_universal_typed_data"],
          "details": {
            "input": "typedDataArgs: { domain: TypedDataDomain, types: Record<string, TypedDataField[]>, value: Record<string, unknown> }",
            "returns": "Uint8Array — EIP-712 signature bytes",
            "capability": "sign_universal_typed_data",
            "use_cases": [
              "Permit2 token approvals",
              "Uniswap v3/v4 swaps",
              "OpenSea Seaport orders",
              "Gasless meta-transactions"
            ]
          },
          "next": null
        }
      ]
    },
    {
      "id": "choose_address_derivation",
      "question": "What address-resolution operation is needed for executor accounts (UEA / CEA)?",
      "branches": [
        {
          "condition": "Need UEA address on Push Chain for a given origin wallet (pre-flight balance check, gas estimation)",
          "action": "Use PushChain.utils.account.deriveExecutorAccount(uoa, { chain: CHAIN.PUSH_TESTNET_DONUT })",
          "capability_ids": ["derive_executor_account"],
          "details": {
            "capability": "derive_executor_account",
            "returns": "{ address: string } — deterministic, no on-chain call",
            "use_cases": [
              "Check UEA balance before sending",
              "Pre-compute address for whitelisting",
              "Gas estimation UI"
            ]
          },
          "next": null
        },
        {
          "condition": "Need CEA address on an external chain (whitelist the CEA on a target contract, check CEA balance)",
          "action": "Use PushChain.utils.account.deriveExecutorAccount(uoa, { chain: CHAIN.<EXTERNAL> })",
          "capability_ids": ["derive_executor_account"],
          "details": {
            "capability": "derive_executor_account",
            "returns": "{ address: string } — same deterministic derivation, different chain",
            "skipNetworkCheck": "Pass skipNetworkCheck: true for chains not yet live to still get the address"
          },
          "next": null
        },
        {
          "condition": "Have a UEA or CEA address and need to find the origin wallet that controls it (reverse lookup, attribution, identity verification)",
          "action": "Use PushChain.utils.account.resolveControllerAccount(address, { chain? })",
          "capability_ids": ["resolve_controller_account"],
          "details": {
            "capability": "resolve_controller_account",
            "input": "UEA, CEA, or any Push Chain address as a plain string",
            "chain_param": "Required only for CEA inputs — pass the chain the CEA is on",
            "returns": "{ accounts[] } — full resolution chain; entry with role:'controller' is the root UOA",
            "direction": "Backward (executor → controller). Forward direction is deriveExecutorAccount."
          },
          "next": null
        }
      ]
    }
  ]
}
