Skip to content

Signing

Sign a NEAR transaction, a NEP-413 message, or an EVM-family transaction with a wallet session.

Signing

Signing calls resolve the authenticated wallet on their own; name an exact wallet or chain when your application handles more than one. The snippets below keep progress events visible so your UI can show what the signer is doing.

Prerequisites

You need a configured SeamsWebProvider and a signed-in wallet. See wallet setup and authentication if the wallet is still locked.

There is no unlock step before signing: every request opens the wallet confirmation and the user approves that transaction. unlock provisions a signing session when your product needs a burst of signatures without a prompt for each one.

ts
import type { UnlockFlowEvent } from '@seams/wallet';
import type { SeamsContextType } from '@seams/wallet/react';

export async function unlockWallet(unlock: SeamsContextType['unlock'], walletId: string) {
  const result = await unlock(walletId, {
    onEvent: (event: UnlockFlowEvent) => console.log(event.phase, event.status, event.message),
  });
  if (!result.success) {
    throw new Error(result.error);
  }

  // Read `nearAccountId` only from the NEAR branch.
  if (result.kind === 'near_wallet_unlocked') {
    console.log('NEAR account ready', result.nearAccountId);
  } else {
    console.log('EVM-family wallet ready', result.walletId);
  }
  return result;
}

Send a NEAR transaction

The example sends a set_greeting function call to a NEAR testnet account and waits for EXECUTED_OPTIMISTIC.

tsx
import { functionCall, logWalletEvents, TxExecutionStatus, useWallet } from '@seams/wallet/react';

export function SetGreetingButton() {
  // `near` is null when nobody is signed in, and when the signed-in wallet has
  // no NEAR account yet. One check covers both; read `status` to tell them apart.
  const { near } = useWallet();
  if (!near) return null;

  const onSign = async (): Promise<void> => {
    // Each request opens the wallet confirmation, where the user approves this
    // transaction with the wallet's auth method.
    await near.signAndSendTransaction({
      receiverId: 'guest-book.testnet',
      actions: [functionCall({ method: 'set_greeting', args: { greeting: 'Hello from Seams' } })],
      options: {
        waitUntil: TxExecutionStatus.EXECUTED_OPTIMISTIC,
        onEvent: logWalletEvents(),
      },
    });
  };

  return <button onClick={() => void onSign()}>Sign transaction</button>;
}

The button resolves after the configured execution status. useWallet returns near as null until the wallet has a NEAR account, so the single check before the button renders is a type guard rather than a convention.

Sign a NEP-413 message

Use NEP-413 for an off-chain, domain-bound message such as a checkout approval.

ts
import { logWalletEvents, type SeamsWeb } from '@seams/wallet';

export async function signCheckoutMessage(seams: SeamsWeb) {
  const result = await seams.near.signNEP413Message({
    // Omitting the subject targets the authenticated wallet and its NEAR
    // account; pass `walletSession` (a wallet id is enough) or `nearAccount` to
    // name an exact one.
    params: {
      message: 'Approve checkout quote #quote_123',
      recipient: 'merchant.example',
      state: 'quote_123',
    },
    options: { onEvent: logWalletEvents() },
  });

  if (!result.success) {
    throw new Error(result.error);
  }
  return result;
}

The successful result contains the signed message data. The helper throws only after the SDK returns success: false, so callers can replace the throw with an inline error state when needed.

Execute an EVM-family transaction

Create a typed EIP-1559 request and provide the chain target for the network you support.

ts
import { logWalletEvents, type SeamsWeb } from '@seams/wallet';

// EIP-1559 on any configured EVM chain. `seams.tempo` mirrors this API for
// Tempo's EIP-2718 typed transactions; the two stay separate because the
// envelopes and the signed results differ.
export async function executeEvmTransaction(seams: SeamsWeb): Promise<string> {
  const execution = await seams.evm.executeTransaction({
    // A configured network slug. The RPC endpoint comes from that chain, and
    // `tx.chainId` is filled in from it. Omitting `walletSession` targets the
    // authenticated wallet.
    chainTarget: 'ethereum-sepolia',
    request: {
      chain: 'evm',
      kind: 'eip1559',
      senderSignatureAlgorithm: 'secp256k1',
      tx: {
        maxPriorityFeePerGas: 1n,
        maxFeePerGas: 1n,
        gasLimit: 21_000n,
        to: '0x1234567890abcdef1234567890abcdef12345678',
        value: 0n,
        data: '0x',
      },
    },
    options: { onEvent: logWalletEvents() },
  });
  console.log('transaction hash', execution.txHash);
  return execution.txHash;
}

The sample targets Ethereum Sepolia and returns the transaction hash. Replace the recipient, fees, and chain target with values from your app's transaction builder before sending a real transaction. tx.chainId and the RPC endpoint both come from the chain target, so neither is repeated on the call.

For Tempo's EIP-2718 typed transactions use seams.tempo, which mirrors this API method for method.

Expected result

  • NEAR signing resolves after the requested transaction execution status.
  • NEP-413 returns a successful signed-message result.
  • EVM-family execution returns txHash after the transaction is submitted.

Progress callbacks receive SigningFlowEvent values. Use them for a status indicator and keep the final operation identity for reconciliation.

Recoverable failures

  • A cancelled approval or policy denial ends the current request. Preserve the draft intent so the person can review and retry it.
  • An expired or exhausted wallet session needs a fresh unlock before retrying.
  • A signing or RPC failure should remain attached to the operation being attempted; avoid submitting a second transaction until the first hash or nonce state is reconciled.
  • Validate chain ids, recipients, fees, and account references in your app before calling the SDK.

Read next: advanced wallet operations, events and progress, or results and errors.