npm.io
0.1.9 • Published 13m ago

@eos3/connect

Licence
UNLICENSED
Version
0.1.9
Deps
2
Size
93 kB
Vulns
0
Weekly
0

@eos3/connect

Framework-neutral browser SDK for EOS Passkey Connect.

Use this package inside a Telegram Mini App to create or restore an EOS wallet, store the Bot-scoped local payment key in Telegram SecureStorage, unlock it with Telegram biometrics, sign paylimit transfers locally, and push them through the EOS Passkey API.

Install

npm install @eos3/connect

The SDK expects a browser runtime with fetch, Web Crypto, and Telegram WebApp APIs when real wallet creation or payment signing is used. It does not bundle Telegram's script into the main SDK bundle; call loadEosConnectTelegramWebAppSdk() or include Telegram's official https://telegram.org/js/telegram-web-app.js script before wallet flows.

Minimal Setup

import {
  createEosConnect,
  isEosConnectError,
  normalizeEosConnectError
} from '@eos3/connect';

const eosConnect = createEosConnect({
  network: 'testnet',
  apiBaseUrl: 'https://your-wallet-api.example.com',
  botUsername: 'your_bot',
  locale: 'zh-CN',
  defaultConnectOptions: {
    replaceWallet: true,
    assetLimits: [
      {
        tokenContract: 'core.vaulta',
        symbol: 'A',
        precision: 4,
        perTxLimit: '1',
        dailyLimit: '10',
        totalBudget: '100'
      }
    ]
  }
});

eosConnect.subscribe((state) => {
  console.log('EOS wallet state:', state);
});

await eosConnect.bootstrapTelegram();
const quickPay = await eosConnect.checkQuickPay();

if (!quickPay.enabled) {
  await eosConnect.enableQuickPay();
}

network can be testnet or mainnet. It selects browser signing RPC failover list, chain id metadata, and balance asset. The SDK does not include a hosted wallet API or a Telegram bot. If apiBaseUrl is omitted, requests use same-origin paths such as /api/tg-wallet/me. apiBaseUrl points to the EOS Passkey API or to your same-origin proxy for that API; it is not the passkey bind page URL. When botUsername is set, the SDK sends it as x-telegram-bot-username so a shared backend can choose the correct Telegram bot token for initData verification.

enableQuickPay(), startTelegramWalletFlow(), and connectTelegram() open the bindUrl returned by the API. The API should generate that URL from its WEB_BASE_URL, so users leave the Mini App and finish passkey authentication on the hosted passkey binding page.

Internationalization

Quick payment labels, Wallet ViewModel text, and the built-in payment confirmation sheet support English and Simplified Chinese. The SDK uses explicit locale, then Telegram language_code, then navigator.language, and falls back to English:

const eosConnect = createEosConnect({
  telegramWebApp,
  locale: 'zh-CN',
  messages: {
    walletSetupTitle: '开启钱包',
    paymentConfirmTitle: '确认付款',
    paymentConfirmAction: '支付'
  }
});

Quick Payment Flow

For app UIs, prefer checkQuickPay() and enableQuickPay(). They hide low-level wallet capability statuses such as needs_local_key, open pending bind URLs, rebind the current device when the local payment key is missing, and can poll until quick payment is enabled:

const quickPay = await eosConnect.checkQuickPay();

renderQuickPay({
  enabled: quickPay.enabled,
  account: quickPay.account,
  balance: quickPay.balance,
  buttonLabel: quickPay.enabled ? '快捷支付已开启' : '开启快捷支付'
});

if (!quickPay.enabled) {
  const next = await eosConnect.enableQuickPay({
    pollIntervalMs: 1500,
    timeoutMs: 120_000
  });
  renderQuickPay(next);
}

enableQuickPay() performs the common Telegram setup sequence:

  • loads Telegram's WebApp SDK when needed;
  • initializes BiometricManager and checks SecureStorage support;
  • calls checkWallet();
  • opens an existing pending bindUrl;
  • calls connectTelegram({ replaceWallet: true }) when the current device is missing the local payment key;
  • polls wallet readiness until ready, another terminal state, or timeout.

Advanced UIs can still call getWalletView() or startTelegramWalletFlow() when they need debug-level states and labels. Pass waitForReady: false if your UI should return immediately after opening the binding page.

Connect a Telegram Wallet

const state = await eosConnect.connectTelegram({
  assetLimits: [
    {
      tokenContract: 'core.vaulta',
      symbol: 'A',
      precision: 4,
      perTxLimit: '1',
      dailyLimit: '10',
      totalBudget: '100'
    }
  ]
});

if (state.status === 'pending' && state.bindUrl) {
  // The SDK opens bindUrl by default. Keep this branch for custom UI.
  console.log('Continue passkey binding:', state.bindUrl);
}

connectTelegram() generates a local EOS K1 payment key, encrypts the private key with AES-GCM, stores the encrypted envelope in Telegram SecureStorage, saves the unlock key as the Telegram biometric token, and starts the external passkey binding flow.

Do not fall back to localStorage for the private key. If Telegram SecureStorage or BiometricManager is missing, ask the user to open the Mini App in a supported Telegram mobile client.

Before showing a real connect action, prefer the async storage check. It calls BiometricManager.init() before reading Telegram's capability flags:

import { checkEosConnectTelegramPayStorage } from '@eos3/connect';

const storage = await checkEosConnectTelegramPayStorage(telegramWebApp);

if (!storage.supported) {
  console.table(storage.diagnostics);
}

Check Readiness

const capability = await eosConnect.checkWallet();

if (capability.status === 'ready') {
  console.log('Ready to pay from', capability.account);
}

if (capability.status === 'needs_local_key') {
  // The server wallet exists, but this Telegram device does not have the
  // matching encrypted local payment key. Prompt the user to rebind.
  await eosConnect.connectTelegram({ replaceWallet: true });
}

if (capability.status === 'pending' && capability.bindUrl) {
  telegramWebApp?.openLink?.(capability.bindUrl);
}

Common capability statuses:

  • unsupported: missing Telegram initData or secure Telegram APIs.
  • not_connected: no wallet exists yet.
  • pending: account creation or tgpay binding is not finished.
  • needs_local_key: wallet exists, but this device cannot sign quick payments.
  • ready: wallet and local payment key match.

Pay

try {
  const result = await eosConnect.pay({
    to: 'merchant1111',
    amount: '1.0000',
    memo: 'order-123',
    tokenContract: 'core.vaulta',
    symbol: 'A'
  });

  console.log('Pushed transaction:', result.txid);
} catch (error) {
  const normalized = normalizeEosConnectError(error);
  console.error(normalized.code, normalized.message, normalized.retryable);
}

pay() uses these API endpoints:

  • POST /api/tg-wallet/transfer/build
  • POST /api/tg-wallet/transfer/push

The default confirmation sheet can be disabled or replaced:

const eosConnect = createEosConnect({
  network: 'testnet',
  telegramWebApp,
  confirmPayment: async (details) => {
    return window.confirm(`Pay ${details.quantity} to ${details.to}?`);
  }
});

For production business actions, prefer project-specific build and push endpoints that validate contract, action, authorization, amount, memo, and any business parameters before broadcasting.

Custom Transaction Signing

Use signEosConnectTransaction() when your own backend builds a validated transaction and expects a signed payload:

import { signEosConnectTransaction } from '@eos3/connect';

const signedTransaction = await signEosConnectTransaction(transaction, {
  telegramWebApp,
  rpcUrls: ['https://jungle4.cryptolions.io:443']
});

await fetch('https://wallet.example.com/api/market/push', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    initData: telegramWebApp?.initData,
    signedTransaction
  })
});

API Summary

  • createEosConnect(options): creates the SDK client.
  • client.getProviders(): returns wallet provider metadata.
  • client.getSnapshot(): returns the current state.
  • client.subscribe(listener): subscribes to state changes.
  • client.bootstrapTelegram(): loads Telegram WebApp SDK, initializes biometrics, and checks secure storage support.
  • client.restore(): loads wallet state from the API.
  • client.refreshWallet(): refreshes wallet readiness and returns a UI-ready ViewModel.
  • client.checkWallet(): checks server wallet plus local key readiness.
  • client.checkQuickPay(): returns { enabled, account, balance, reason } for business UI.
  • client.getWalletView(): returns the current wallet ViewModel for app UIs.
  • checkEosConnectTelegramPayStorage(app): initializes Telegram biometrics and returns secure storage diagnostics.
  • client.connectTelegram(options): starts or resumes Telegram binding.
  • client.connectTokenPocket(options): starts TokenPocket binding.
  • client.startTelegramWalletFlow(options): runs the high-level Telegram wallet setup flow.
  • client.enableQuickPay(options): runs the high-level setup flow and returns quick payment readiness.
  • client.pay(options): builds, signs, confirms, and pushes a paylimit payment.
  • client.disconnect(): removes the local Telegram payment key from SecureStorage, clears the biometric token, and resets the SDK state.

Network Presets

import { EOS_CONNECT_NETWORKS } from '@eos3/connect';

console.log(EOS_CONNECT_NETWORKS.testnet.rpcUrls);
console.log(EOS_CONNECT_NETWORKS.mainnet.chainId);

Preset values:

  • testnet: Jungle4 chain id, Jungle4 RPC failover list, and default asset core.vaulta:A:4.
  • mainnet: EOS mainnet chain id, mainnet RPC failover list, and default asset core.vaulta:A:4.

Explicit options always win:

createEosConnect({
  network: 'testnet',
  apiBaseUrl: 'https://my-testnet-wallet.example.com',
  rpcUrls: ['https://my-jungle-rpc.example.com'],
  telegramWebApp
});

Error Handling

Use normalizeEosConnectError(error) at UI boundaries. It maps raw API, EOS RPC, Telegram biometric, and contract errors into stable codes:

  • DAILY_LIMIT_EXCEEDED
  • PER_TX_LIMIT_EXCEEDED
  • TOTAL_BUDGET_EXCEEDED
  • INSUFFICIENT_BALANCE
  • RAM_INSUFFICIENT
  • PAYMENT_PERMISSION_MISSING
  • SIGNATURE_REJECTED
  • SESSION_EXPIRED
  • NETWORK_ERROR
  • UNKNOWN_CHAIN_ERROR
catch (error) {
  const normalized = normalizeEosConnectError(error);
  if (normalized.retryable) {
    // Show a retry action.
  }
}

Security Notes

  • Never send the local payment private key or biometric unlock token to a server.
  • Never store the private key in localStorage, IndexedDB, cookies, or plain Telegram CloudStorage.
  • Treat missing Telegram SecureStorage or BiometricManager as unsupported.
  • Keep TELEGRAM_BOT_TOKEN, account creator keys, resource sponsor keys, and contract deployment keys on the backend only.

Keywords