npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

toncorp-wallet-connect-sdk

v0.1.26

Published

Wallet Connect SDK — connect TonPass, OneDollar and more wallets from any DApp

Readme

toncorp-wallet-connect-sdk

Connect TonPass, OneDollar and more wallets from any DApp or website.

Install

npm install toncorp-wallet-connect-sdk

Or via CDN:

<script src="https://cdn.jsdelivr.net/npm/toncorp-wallet-connect-sdk@latest/dist/index.umd.js"></script>

Usage

Specific wallet

import { TonPassConnect } from 'toncorp-wallet-connect-sdk';

const wallet = new TonPassConnect({
  appId: 'your_app_id',
  siteTmaUrl: 't.me/your_bot/your_app', // your DApp's TMA — the wallet reopens it after approval
});

// On page load: wait for the SDK to restore + validate the stored session first
await wallet.ready();
if (wallet.isConnected()) {
  console.log(wallet.getWallet());   // restored & still-valid session
}

// First-time connect (opens the modal, waits for approval)
const result = await wallet.connect();
console.log(result.wallet);  // { address: 'UQ...', chain: 'TON' }
console.log(result.user);    // { username: 'john', avatar: '...' }

// Access via window global
window.tonpass.isConnected()  // true
window.tonpass.getWallet()    // same result

The SDK auto-validates the stored session on init and clears it (with a "Session expired" toast) when it's no longer live. See Session lifecycle & auto-expiry.

import { OneDollarConnect } from 'toncorp-wallet-connect-sdk';

const wallet = new OneDollarConnect({
  appId: 'your_app_id',
  siteTmaUrl: 't.me/your_bot/your_app',
});
const result = await wallet.connect();

// Access via window global
window.onedollar.isConnected()
window.onedollar.getWallet()

All wallets (show picker)

import { BaseWalletConnect } from 'toncorp-wallet-connect-sdk';

const wallet = new BaseWalletConnect({
  appId: 'your_app_id',
  siteTmaUrl: 't.me/your_bot/your_app',   // required for TMA DApps (wallet reopens you)
  // walletId: ['tonpass', 'onedollar'],  // optional filter
});

const result = await wallet.connect();

siteTmaUrl matters for Telegram Mini App DApps. After the user approves in the wallet, the wallet reopens your TMA via this URL (on desktop it redirects back; on mobile it returns to your app). Omit it only for plain web widgets that stay open the whole time.

Script tag (UMD)

<script src="https://cdn.jsdelivr.net/npm/toncorp-wallet-connect-sdk@latest/dist/index.umd.js"></script>
<script>
  const wallet = new WalletConnectSDK.OneDollarConnect({
    appId: 'your_app_id',
    siteTmaUrl: 't.me/your_bot/your_app',
  });

  document.getElementById('connect-btn').onclick = async () => {
    const result = await wallet.connect();
    console.log(result);
  };

  // Available globally after instantiation
  // window.onedollar.isConnected()
  // window.onedollar.getWallet()
  // window.onedollar.disconnect()
</script>

API

Constructor options

| Option | Type | Required | Description | |--------|------|----------|-------------| | appId | string | Yes | Your registered app ID | | registryUrl | string | No | Override wallet registry URL (defaults to CDN) | | walletId | string \| string[] | No | Filter wallets (only for BaseWalletConnect) | | theme | 'light' \| 'dark' | No | Modal theme (default: dark) | | siteTmaUrl | string | No | This DApp's own TMA URL (t.me/<bot>/<app>). The wallet reopens it after the user confirms/rejects the connection. |

Methods

| Method | Returns | Description | |--------|---------|-------------| | ready() | Promise<void> | Await SDK init (resume + session-expiry check). Call before reading isConnected() / getWallet(). | | connect() | Promise<ConnectResult> | Open modal and wait for user to approve | | disconnect() | void | Disconnect, clear session and call API | | sendTransaction(params) | Promise<{ txId: string }> | Send a transaction through the connected wallet | | waitForResult(txId, options?) | Promise<{ status, msgHash?, action? }> | Poll until a transaction resolves | | resume() | Promise<{ type: 'tx'; status; result } \| null> | Resolve a pending tx after the app was closed/reopened (DApp shows its own result UI) | | isConnected() | boolean | Check connection status | | getWallet() | ConnectResult \| null | Get current connection info | | on(event, cb) | void | Listen to events | | off(event, cb) | void | Remove listener |

ConnectResult

{
  wallet: {
    address: string;   // friendly TON address
    chain: string;     // 'TON'
  } | null;
  user: {
    username?: string;
    avatar?: string;
  };
  session?: {
    sessionToken: string;
    walletId: string;
    apiUrl: string;
  };
}

sendTransaction

Send a transaction through the connected wallet. Requires an active connection.

const { txId } = await wallet.sendTransaction({
  msgBoc: 'te6cck...',         // base64-encoded BOC
  toAddress: 'UQ...',          // destination address
  amount: '1000000000',        // nano units
  wallet_address: 'UQ...',     // connected wallet address
  network: 'ton-mainnet',
  action: 'transfer',
});

console.log(txId);

Internally POSTs { ...params, source: 'widget' } to {apiUrl}/dex/sendTx.

Errors:

| Cause | Thrown message | |-------|----------------| | Not connected / 401 | Wallet not connected | | 429 | Too many pending transactions | | Network failure | Connection failed |

waitForResult

Poll {apiUrl}/dex/status/{txId} until the transaction leaves the PENDING state, then resolve with its final status.

const { txId } = await wallet.sendTransaction({ /* ... */ });

const result = await wallet.waitForResult(txId, {
  interval: 2000,    // poll every 2s (default)
  timeout: 120000,   // give up after 2min (default), throws 'Timeout'
});

console.log(result); // { status: 'CONFIRMED', msgHash: '...', action: 'transfer' }

| Option | Type | Default | Description | |--------|------|---------|-------------| | interval | number | 2000 | Delay between polls in ms | | timeout | number | 120000 | Max wait before throwing Timeout |

Emits pending on every poll while the tx is PENDING, and resolved once it settles:

wallet.on('pending', (r) => console.log('still pending', r));
wallet.on('resolved', (r) => console.log('done', r.status));

Events

| Event | Data | Description | |-------|------|-------------| | connect | ConnectResult | Connected successfully | | disconnect | - | Disconnected — manual disconnect() or an expired session cleared on init | | error | string | Transport error | | session_expired | - | Connect handshake timed out (during connect()) |

Session lifecycle & auto-expiry

A connection stays valid for a limited idle window (configured on the backend). The SDK enforces this automatically on every init — you don't call anything:

  1. On construction, after restoring the stored session, the SDK asks the backend GET /connect/status.
  2. If the connection is no longer live (expired / disconnected server-side), the SDK:
    • clears the stored session for that wallet from localStorage (scoped — other wallets untouched),
    • emits disconnect,
    • shows a lightweight "Session expired" toast (no page reload).
  3. Your app then reads isConnected() / getWallet()null → render the Connect button.

To read connection state deterministically right after construction, await ready():

const wallet = new TonPassConnect({ appId: 'your_app_id' });

await wallet.ready();               // init: resume + expiry check (clears + toasts if expired)

if (wallet.isConnected()) {
  renderConnected(wallet.getWallet());
} else {
  renderConnectButton();           // stored session was empty or just expired
}

// …or react live:
wallet.on('disconnect', renderConnectButton);

ready() also resolves after a redirect-back connect flow (wallet reopens your DApp after approval), so it's safe to gate your first render on it.

Window globals

Each wallet instance auto-registers on window:

| Class | Window global | |-------|--------------| | TonPassConnect | window.tonpass | | OneDollarConnect | window.onedollar | | BaseWalletConnect | window.walletconnect |

Integrate into TMA Wallet App (Telegram Bot)

This section is for wallet app developers who want their Telegram Mini App (TMA) to support connect requests from DApps using this SDK.

How it works

DApp (SDK)                    Your Backend              TMA (Telegram)
──────────────────────────────────────────────────────────────────────
1. SDK calls POST /connect/init
   ← { sessionToken, deeplink }

2. User clicks deeplink / scans QR
   ────────────────────────────────────────────────→ TMA opens
                                                     parse startapp param

3.                              ← POST /connect/verify   TMA sends initData
                                  verify Telegram HMAC
                                → { appId, origin }

4.                                                     TMA shows confirm UI

5. User taps Approve
                                ← POST /connect/confirm  TMA sends JWT + approved
                                  get user wallet
                                  emit WS event ──────→ SDK receives result
                                                        modal shows success

Step 1: Parse startapp param in your TMA

When a DApp initiates a connect request, the user is redirected to your TMA via deeplink. The startapp parameter contains the session token.

// In your TMA (React / vanilla JS)
const tg = window.Telegram.WebApp;
const startParam = tg.initDataUnsafe?.start_param; // "sessionToken_abc123..."

if (startParam && startParam.startsWith('sessionToken_')) {
  const sessionToken = startParam.replace('sessionToken_', '');
  // → proceed to Step 2
}

Step 2: Verify session with your backend

Call your backend to verify the session and get DApp info to show the user.

const response = await fetch('https://your-api.com/connect/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    sessionToken,
    initData: tg.initData,   // Telegram initData for HMAC verification
    botId: 'your_bot_id',
  }),
});

const { appId, appName, origin, walletId } = await response.json();
// → Show confirm UI to user

Step 3: Show confirm popup

Display the DApp info and let the user approve or reject.

// React example
function ConnectConfirm({ appName, origin, onApprove, onReject }) {
  return (
    <div className="confirm-popup">
      <h2>{appName} wants to connect</h2>
      <p>Origin: {origin}</p>
      <button onClick={onApprove}>Approve</button>
      <button onClick={onReject}>Reject</button>
    </div>
  );
}

Step 4: Confirm or reject

When the user taps Approve/Reject, call the confirm endpoint with their JWT token.

const token = 'user_jwt_token'; // from your TMA auth flow

const result = await fetch('https://your-api.com/connect/confirm', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    sessionToken,
    approved: true, // or false to reject
  }),
});

const data = await result.json();
// {
//   success: true,
//   status: 'CONFIRMED',
//   wallet: { address: 'UQ...', chain: 'TON' },
//   user: { username: 'john', avatar: '...' }
// }

// The SDK on the DApp side receives this automatically via WebSocket/polling
// → DApp modal shows "Connection Successful"

Step 5: In-app QR scanner (optional)

Allow users already in your TMA to scan a QR code from a DApp to connect.

// User scans QR → gets deeplink URL
const scannedUrl = 'https://t.me/YourBot/app?startapp=sessionToken_abc123...';

// Parse sessionToken from URL
const url = new URL(scannedUrl);
const startapp = url.searchParams.get('startapp') || '';
const sessionToken = startapp.replace('sessionToken_', '');

// → Same flow: verify → confirm popup → approve/reject

Step 6: Manage connected DApps

Let users view and disconnect DApps from your TMA.

// List connected DApps
const dapps = await fetch('https://your-api.com/connect/dapps', {
  headers: { 'Authorization': `Bearer ${token}` },
}).then(r => r.json());

// Disconnect a specific DApp
await fetch('https://your-api.com/connect/disconnect', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({
    appId: 'the_app_id',
    walletId: 'onedollar',
  }),
});

Backend API endpoints

Your backend needs these endpoints:

| Method | Path | Auth | Description | |--------|------|------|-------------| | GET | /connect/wallets | No | List supported wallets (SDK fetches this) | | POST | /connect/init | No | Create connect session (SDK calls this) | | GET | /connect/status?token= | No | Poll session status (SDK fallback) | | POST | /connect/verify | initData | Verify session + Telegram user (TMA calls) | | POST | /connect/confirm | JWT | Approve/reject session (TMA calls) | | POST | /connect/disconnect | JWT | Disconnect a DApp (TMA calls) | | POST | /connect/disconnect-by-token | No | Disconnect by session token (SDK calls) | | POST | /connect/resolve | No* | Resolve a session token → user + TON wallet (server-side verify) | | GET | /connect/dapps | JWT | List connected DApps (TMA calls) | | POST | /dex/sendTx | No | Submit a tx from the widget (SDK sendTransaction) | | GET | /dex/status/:txId | No | Poll tx status (SDK waitForResult) | | POST | /dex/confirm | JWT | Confirm/cancel a tx (TMA calls) |

* /connect/resolve is public but requires the caller to know both the sessionToken and the owning appId — call it only from your backend.

Verify a user server-side

After a user connects, your backend can verify — server-to-server — who the session belongs to instead of trusting an address sent from the client. Send the sessionToken (wallet.getWallet().session.sessionToken) from the client to your backend, then:

// on YOUR backend
const res = await fetch(`${walletApiUrl}/connect/resolve`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ sessionToken, appId: 'your_app_id' }),
});

// res.ok → authoritative identity:
// { valid: true, telegramId, userId, user: { username, avatar }, wallet: { address, chain: 'TON' } }

The returned wallet.address is the address shared at connect time (stable even if the user later switches their selected wallet) — compare it against the address you received client-side to detect spoofing.

| HTTP | Meaning | |------|---------| | 404 Session not found | wrong token or appId mismatch | | 400 Session not confirmed | user hasn't approved yet | | 400 Session expired | connection past its idle TTL / disconnected | | 404 no_wallet… | user has no TON root wallet |

Register your wallet in the registry

To make your wallet available to all DApps using the SDK, add it to registry.json:

{
  "walletId": "yourwallet",
  "name": "Your Wallet",
  "icon": "https://your-cdn.com/icon.png",
  "botUsername": "YourBot",
  "appName": "app",
  "apiUrl": "https://your-api.com",
  "description": "Your wallet description",
  "order": 0
}

License

MIT