Skip to main content
A Signer represents a connected wallet. It hides the differences between wallet implementations — browser extensions, mobile apps, hardware devices — behind a single interface. You use a signer to get addresses, check balances, sign messages, and submit transactions.

Signer types

CCC supports wallets from multiple ecosystems. The SignerType enum identifies which ecosystem a signer belongs to:
ValueEcosystem
SignerType.CKBNative CKB wallets (e.g. JoyID)
SignerType.EVMEthereum-compatible wallets (e.g. MetaMask)
SignerType.BTCBitcoin wallets (e.g. UniSat, OKX)
SignerType.NostrNostr clients
SignerType.DogeDogecoin wallets
Each signer type produces a valid CKB address using a lock script that corresponds to its native signing algorithm (secp256k1, EVM personal sign, BTC ECDSA, etc.).

Connect and disconnect

// Connect the wallet — may trigger a browser popup
await signer.connect();

// Check connection status
const connected = await signer.isConnected(); // boolean

// Disconnect when done
await signer.disconnect();
connect() is async and may throw if the user rejects the connection request. Always await it before calling any other method.

Get addresses

A signer can control more than one address (e.g. a BTC wallet with multiple account derivation paths). getRecommendedAddress returns the primary one as a string:
const address = await signer.getRecommendedAddress();
console.log(address); // "ckb1q..." or "ckt1q..."
Use getAddresses to retrieve all controlled addresses:
const addresses = await signer.getAddresses(); // string[]
Use getRecommendedAddressObj when you need the underlying Address object (which carries the lock script):
const { script: lock } = await signer.getRecommendedAddressObj();

Check balance

getBalance returns the total CKB capacity across all controlled addresses, in shannons (1 CKB = 10⁸ shannons):
const shannons = await signer.getBalance();
const ckb = Number(shannons) / 1e8;
console.log(`${ckb} CKB`);

Sign messages

Sign an arbitrary message and receive a structured Signature object:
const sig = await signer.signMessage("Hello CKB!");
// sig.signature — raw signature string
// sig.identity   — signer's identity (usually the address)
// sig.signType   — e.g. SignerSignType.CkbSecp256k1
Verify a signature without knowing which signer type was used:
const valid = await signer.verifyMessage("Hello CKB!", sig);
console.log(valid); // true
You can also verify statically:
const valid = await ccc.Signer.verifyMessage("Hello CKB!", sig);

Sign and send transactions

Build a transaction, then hand it to the signer. sendTransaction signs and broadcasts in one step:
const tx = ccc.Transaction.from({ outputs: [{ capacity: ccc.fixedPointFrom(100), lock }] });
await tx.completeInputsByCapacity(signer);
await tx.completeFeeBy(signer);

const txHash = await signer.sendTransaction(tx);
If you need the signed transaction object before broadcasting (e.g. to inspect witnesses), use signTransaction:
const signedTx = await signer.signTransaction(tx);
const txHash = await signer.client.sendTransaction(signedTx);

Find cells and transactions

A signer exposes the same search helpers as Client, but scoped to the signer’s own addresses:
// Iterate cells owned by this signer
for await (const cell of signer.findCells({})) {
  console.log(cell.cellOutput.capacity);
}

// Iterate transactions involving this signer
for await (const tx of signer.findTransactions({})) {
  console.log(tx.txHash);
}

Access the underlying client

Every signer holds a reference to the Client it was created with:
const client = signer.client;
const tip = await client.getTip();

Network preferences

When the UI needs to enforce a particular network, pass a NetworkPreference array to matchNetworkPreference. The signer returns the preferred entry when a switch is needed, or undefined when already on a compatible network:
const preference = signer.matchNetworkPreference(
  [{ addressPrefix: "ckb", signerType: ccc.SignerType.CKB, network: "mainnet" }],
  currentNetwork,
);
if (preference) {
  // prompt the user to switch to preference.network
}
In a dApp, obtain a Signer instance from a CCC connector component (React, Vue, etc.) rather than constructing one directly. The connector handles wallet discovery and network negotiation for you.