Skip to content

Wallets example ​

End-to-end signature verification: create a client, list wallets, run verify(), read the result.

The address lives in a self-custodial wallet. For an address that lives on Coinbase, see Coinbase example.

This is not a Connect session. You need a public API key, not a sessionId. customerId is your id for the end user.

1. Create the client ​

ts
import {
  createWalletVerification,
  IntegrationProvider,
} from '@swapped/connect-sdk/wallet-verification'

const client = createWalletVerification({
  apiKey: 'your-public-api-key',
  environment: 'staging',
})

See Client. Call destroy() when the page tears down.

2. List wallets ​

getAvailable() is the picker catalog - signature wallets this device can use. These are not connected yet. See Availability.

ts
const wallets = await client.wallets.getAvailable({ network: 'evm' })

Each row has isInstalled, transports, supportsWalletConnect, isDeepLinkConnection, isPopupConnection, qrScanTarget, and icon.light / icon.dark.

3. Verify (signature) ​

verify() is the one-shot path. For a QR-first picker, prepareVerify() then verify({ prepared }). See Verify wallet.

QR first, then optionally the extension (one create - pick one completion, not both):

ts
const prepared = await client.wallets.prepareVerify({
  network: 'evm',
  customerId: 'user-1234',
  provider: IntegrationProvider.MetaMask,
  address: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B',
  onUri: ({ uri, deeplinkUrl }) => {
    // uri → QR / copy; deeplinkUrl → open the wallet on this device
  },
})

// phone scanned
const fromQr = await prepared.wait()

// or "Verify with extension" while the QR is up
const fromExtension = await client.wallets.verify({
  prepared,
  transport: 'injected',
  provider: IntegrationProvider.MetaMask,
  network: 'evm',
  customerId: 'user-1234',
})

Injected one-shot:

ts
const verification = await client.wallets.verify({
  network: 'evm',
  customerId: 'user-1234',
  provider: wallets[0].provider,
  transport: 'injected',
  popupIfUnavailable: true,
})

WalletConnect (QR + optional mobile link):

ts
const verification = await client.wallets.verify({
  network: 'evm',
  customerId: 'user-1234',
  provider: IntegrationProvider.Trust,
  transport: 'walletconnect',
  force: true,
  onUri: ({ uri, deeplinkUrl }) => {
    // uri → QR / copy; deeplinkUrl → open the wallet on this device
  },
})

Browse deeplink (address required):

ts
const abort = new AbortController()

const verification = await client.wallets.verify({
  address: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B',
  network: 'evm',
  customerId: 'user-1234',
  provider: IntegrationProvider.Phantom,
  signal: abort.signal,
  onDeeplinkUrl: ({ url }) => {
    // desktop: render `url` as a camera QR
  },
})

Omit address on injected / WalletConnect / popup to verify the connected account. If customerId + address is already verified, verify() returns status: 'verified' without a prompt.

4. Read the result ​

ts
if (verification.status === 'verified') {
  verification.verificationId
  verification.address
  verification.verifiedAt
}

if (verification.status === 'failed' || verification.status === 'expired') {
  // start a new verify()
}

Invalid signature: the call throws and status stays pending - call verify() again. See Result.

5. Tear down ​

ts
client.destroy()

Deep dives: Client, Availability, Verify wallet, Result, Errors.