Academy
Sign data

SignData in TON via TonConnect: A Developer Guide

When it comes to critical actions, a simple button press just doesn’t cut it. Real consent feels like your wallet standing tall and declaring: "Yes, it’s me! And I approve this!"

A signature is the real deal: cryptographic, verifiable, secure. You can sign anything — text, bytes, or cells. The signature can be verified off-chain in your dApp or passed into a smart contract for on-chain logic.

ℹ️

The signData method is implemented in the TonConnect fork by Tonkeeper (opens in a new tab) and is ready for use. You can experiment with data signing in the demo dApp (opens in a new tab). The feature will soon be merged into the main TonConnect repository.

What is SignData and Why It Matters

Any action where the user must consciously and explicitly confirm their intent – like updating public profile information, linking a new email or phone number, or accepting DAO terms – deserves something more robust than just a click.

SignData lets your dApp request a cryptographic signature – from the user's wallet – on arbitrary content. The user sees exactly what they are signing and can either approve or decline. The signature is generated using the same private key that signs TON transactions, but it provides no direct access to funds.

For a dApp, this signature is a way to secure critical actions, verify a user's real intent, and – if needed – pass validated data into a smart contract for on-chain use.

If you don’t clearly get what an Cell, TL-B, or public key is? Read the glossary below

Glossary (quick refresher)

TonConnect – The protocol connecting your dApp to the user's wallet. It handles connections, transaction requests, and data signing.
SignData – A TonConnect method that allows a dApp to request the user to sign arbitrary data (text, bytes, or Cell) with their wallet. No transaction involved – just a signature.
Cell – The atomic unit of data in TON. Holds up to 1023 bits and 4 references to other cells. Everything in TON – accounts, messages, blocks – is made of Cells. Each Cell has a hash that acts as its unique ID.
TL-B schema – Declarative definition of Cell structure. It’s required for wallets to display signing details and for smart contracts to validate the content.
Ed25519 – The signing algorithm used in TON. It powers both transactions and signData. Everything signed by the user uses Ed25519 over a SHA256 hash of a strictly formatted message.
Address – The account address in TON. Formed by a workchain (usually 0) and a hash of the contract’s code and initialization data. For standard wallets, this hash is deterministically derived from the public key.
Public Key – The public part of the user’s key pair, derived from the private key. Used to verify signatures. In TON, the public key becomes available on-chain only after the wallet is initialized (i.e., has sent at least one transaction). Until then, it’s known only to the dApp via TonConnect and the user.

Choosing the Right Format

1. Text

Use this when the data is human-readable.

Pros:

  • The user sees exactly what they are signing.
  • Simple to implement.
  • Perfect for off-chain confirmations.

Example:

{
  type: 'text',
  text: 'I confirm deletion of my account and all associated data.'
}

2. Binary

Use this when signing a hash, arbitrary bytes, or a file.

Pros:

  • Useful for generating digital receipts, hashed content references, etc.
  • Works when the content isn’t human-readable or shouldn't be shown.

Example:

{
  type: 'binary',
  bytes: '1Z/SGh+3HFMKlVHSkN91DpcCzT4C5jzHT3sA/24C5A=='
}

3. Cell

Use this if the signed data should be verifiable and restorable inside a smart contract.

Pros:

  • Smart contracts can validate the signature during execution.
  • Supports structured data via TL-B schemas.

Example:

{
  type: 'cell',
  schema: 'message#_ text:string = Message;',
  cell: 'te6ccgEBAQEAVwAAqg+KfqVUbeTvKqB4h0AcnDgIAZucsOi6TLrf...'
}

How to Request a Signature via TonConnect

const result = await tonConnectUi.signData({
  type: 'text',
  text: 'I confirm this action.',
});

TonConnect handles the request and shows the prompt in the user’s wallet. They either sign or decline.

You receive:

{
  signature: 'base64-ed25519-signature',
  address: 'EQD...',
  timestamp: 1710000000,
  domain: 'your-app.com',
  payload: {
    type: 'text',
    text: 'I confirm this action.'
  }
}

How the Signature Is Built

For text and binary

  1. The message is constructed:
0xffff ++ "ton-connect/sign-data/" ++ Address ++ AppDomain ++ Timestamp ++ Payload
  1. Components:
    • Address: wallet address (workchain + hash)
    • AppDomain: dApp domain as UTF-8 string with length
    • Timestamp: time of signing
    • Payload:
      • Prefix txt / bin
      • Length
      • Text (utf-8 encoded) or bytes
  2. Then:
Ed25519.sign(sha256(message), privateKey)

For cell

  1. A Cell is built:
beginCell()
  .storeUint(0x75569022, 32)
  .storeUint(crc32(schema), 32)
  .storeUint(timestamp, 64)
  .storeAddress(userWalletAddress)
  .storeStringRefTail(appDomain)
  .storeRef(cell)
  1. The hash of this Cell is signed:
Ed25519.sign(payload.hash(), privateKey)

🔥 Example signing in JS: https://github.com/mois-ilya/ton-sign-data-reference (opens in a new tab)

How to Verify the Signature

In JavaScript (off-chain)

For text and binary, you can reconstruct the message:

import nacl from 'tweetnacl';
  1. Rebuild the byte array exactly as described above.
  2. Retrieve the public key (from TonConnect or known in advance).
  3. Verify:
const isValid = await nacl.sign.detached.verify(hash, signature, publicKey);

Important: Always ensure that result.address matches the wallet you requested the signature from. Otherwise, an attacker could swap in a valid signature from a different wallet.


🔥 Example verification in JS: https://github.com/mois-ilya/ton-sign-data-reference (opens in a new tab)

In a Smart Contract (on-chain)

For the cell format, smart contracts can verify the signature directly.

They must validate:


🔥 On-chain example in FunC: https://github.com/p0lunin/sign-data-contract-verify-example (opens in a new tab)


TL;DR

The SignData method in TonConnect is a secure way for a dApp to request a user’s cryptographic signature on text, bytes, or TON cells – directly through their wallet. It’s not a transaction, but a confirmation that can be verified off-chain or on-chain.

  • Users see what they sign (if it's text or a proper TL-B schema).
  • Signature uses the same key as for transactions, but doesn’t send anything.
  • Verification works anywhere – on your backend or inside a smart contract.

FormatWhat’s SignedWallet UIUse Case
textHuman-readable messageDisplayed as-isAction confirmation, agreements
binaryBytes / hashes / identifiersShows warningDocument hashes, TX IDs
cellCell with TL-B schemaSchema + warning or contentSmart contract validation

If you’re building a dApp that needs real user consent and want to verify it without extra hassle – SignData gets the job done.

Useful Links