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:
| Value | Ecosystem |
|---|
SignerType.CKB | Native CKB wallets (e.g. JoyID) |
SignerType.EVM | Ethereum-compatible wallets (e.g. MetaMask) |
SignerType.BTC | Bitcoin wallets (e.g. UniSat, OKX) |
SignerType.Nostr | Nostr clients |
SignerType.Doge | Dogecoin 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.