Skip to main content
CCC provides a unified message signing and verification API across all supported wallet types. The same code works whether the user is connected through MetaMask, JoyID, UniSat, OKX, Nostr, or a native CKB wallet — CCC handles the chain-specific encoding internally.

How it works

When you call signer.signMessage(), CCC:
  1. Encodes the message according to the connected chain’s convention (e.g. EIP-191 for EVM, BIP-322 for BTC).
  2. Asks the wallet to sign it.
  3. Returns a Signature object containing the raw signature string, the signer’s identity, and the sign type.
The static ccc.Signer.verifyMessage() method understands all supported sign types and dispatches to the correct verification function automatically.

Supported sign types

Sign typeWallets
EvmPersonalMetaMask, OKX (EVM)
BtcEcdsaUniSat, OKX (BTC), UTXO Global
JoyIdJoyID
NostrEventNostr
CkbSecp256k1CKB native wallets
DogeEcdsaDoge wallets

Sign a message

Call signer.signMessage() with a string or byte array. The method returns a Signature object.
sign.ts
import { ccc } from "@ckb-ccc/ccc";

const message = "Hello world";

// Sign the message with the connected wallet
const signature = await signer.signMessage(message);

console.log("Signature:", signature.signature);
console.log("Identity:", signature.identity);
console.log("Sign type:", signature.signType);

The Signature object

FieldTypeDescription
signaturestringThe raw signature produced by the wallet.
identitystringThe signer’s address or public key, used to verify ownership.
signTypeSignerSignTypeIdentifies the signing algorithm so the verifier knows how to check it.

Verify a signature

Static verification

Use the static ccc.Signer.verifyMessage() method when you have a Signature object and want to check it without a signer instance. This is useful on the server side or when verifying signatures from other users.
import { ccc } from "@ckb-ccc/ccc";

const isValid = await ccc.Signer.verifyMessage(message, signature);
console.log(`Verification result: ${isValid}`); // true or false

Instance verification

Call signer.verifyMessage() on the signer instance when you want to check that the current signer produced the signature.
// Verify that the same signer produced the signature
const isValid = await signer.verifyMessage(message, signature);
Pass a raw string instead of a Signature object to verify a bare signature string using the current signer’s sign type and identity:
const isValid = await signer.verifyMessage(message, signature.signature);

Full example

sign.ts
import { ccc } from "@ckb-ccc/ccc";

async function signAndVerify(signer: ccc.Signer) {
  const message = "Hello world";

  // Sign the message
  const signature = await signer.signMessage(message);
  console.log("Signature:", signature);

  // Verify with the correct message — should be true
  const valid = await ccc.Signer.verifyMessage(message, signature);
  console.log(`Verification should pass: ${valid}`);

  // Verify with a wrong message — should be false
  const invalid = await ccc.Signer.verifyMessage("Wrong message", signature);
  console.log(`Verification should fail: ${invalid}`);
}

In a React component

sign-button.tsx
"use client";

import { useState } from "react";
import { ccc } from "@ckb-ccc/connector-react";

export function SignButton() {
  const signer = ccc.useSigner();
  const [result, setResult] = useState<string | null>(null);

  async function handleSign() {
    if (!signer) return;

    const message = "Hello from CCC!";
    const signature = await signer.signMessage(message);

    const isValid = await ccc.Signer.verifyMessage(message, signature);
    setResult(isValid ? "Signature verified" : "Verification failed");
  }

  return (
    <div>
      <button onClick={handleSign} disabled={!signer}>
        Sign message
      </button>
      {result && <p>{result}</p>}
    </div>
  );
}
The Signature object must be serialized and stored if you want to verify it later (for example in a backend or on-chain). Serialize it with JSON.stringify(signature) and restore it with JSON.parse().

Next steps

Send CKB

Move beyond signing messages and compose a full transfer transaction.

Connect Wallet

Learn how to set up the wallet connector and retrieve a signer.