Addresses
The Address class and its EvmSigner / SvmSigner specializations — the on-chain identity carrying publicKey, vm and network that signs messages, builds/simulates/sends transactions, and sends transfers in one call with transfer().
An Address is a single on-chain identity: a public key bound to one virtual machine (vm) and one Network. A Wallet holds one Address per (vm, network), and the address is where the operations live — signing messages, building and sending transactions, and lowering chain-agnostic transfers. The sealed private key is never exposed on the address; every signing method routes through internal custody that holds the decrypted key only while the account is unlocked.
You never construct an Address directly; you read one off a wallet:
const acc = await ws.accounts.create("Desk", "wsp-pwd", MNEMONIC);
const evm = acc.wallets[0].addresses.find((a) => a.vm === "evm");
const svm = acc.wallets[0].addresses.find((a) => a.vm === "svm");Identity fields
Every Address carries the same read-only identity fields, all fixed at construction:
| Field | Type | Description |
|---|---|---|
publicKey | EvmAddress | SvmAddress | the canonical public address string |
vm | VmToken | the virtual machine — "evm", "svm", or a registered custom VM |
network | Network | the network this identity is active on |
assets | AssetCollection | the assets tracked on this address |
evm.publicKey; // "0x9858EfFD232B4033E47d90003D41EC34EcaEda94"
evm.vm; // "evm"
evm.network.chainId; // 1
String(evm); // same as evm.publicKey (toString returns it)The publicKey is canonicalized at the storage boundary (EVM checksum casing, SVM base58), so every downstream comparison — ownership checks, JSON snapshots, nonce keys — sees one byte-form regardless of how a caller typed it.
EvmSigner and SvmSigner
EvmSigner and SvmSigner are the per-chain specializations of Address that wallet.evm and wallet.svm return. They inherit Address's full surface verbatim — the subclass exists so the accessors hand back a named, per-chain type rather than the base union, giving callers a signer they can pass to chain-specific code without re-narrowing.
const signer = acc.wallets[0].evm; // EvmSigner | null
signer?.signTypedData(typedData, 1);| VM | Instance returned | Signer type |
|---|---|---|
"evm" | EvmSigner | secp256k1 |
"svm" | SvmSigner | ed25519 |
| registered custom vm | base Address | per the dialect's curve |
Per-chain behaviour is delegated to a chain dialect resolved from the VM, not hard-coded onto the class. "evm" and "svm" register dialects by default; a VM with no registered dialect throws UNSUPPORTED_OP from the operations below. Registering your own dialect is covered in Custom Chains.
Method map
The address is the single entry point for its identity's operations. The signing methods are documented on Message & Typed-Data Signing; the transaction methods on Transactions.
| Method | Returns | Documented at |
|---|---|---|
signMessage(message) | string | Signing |
signMessageEncoded(message, encoding) | { signature, messageHash } | Signing |
signTypedData(typedData, chainId) | { signature, domainSeparator, structHash } — EVM only | Signing |
signDigest(digest) | { r, s, recovery, signature } — EVM only | Signing |
signBytes(message) | { signature, signatureHex } — SVM only | Signing |
transfer(req, opts?) | TransactionTracker — one-call sign + broadcast (the common path) | Transfers |
buildTransaction(params) | EvmTransaction / SvmTransaction | Transactions |
buildTransferPayload(req) | TransferPayload | Transfers |
signTransaction(tx) | the same tx (signing runs asynchronously) | Transactions |
sendTransaction(tx) | TransactionTracker | Transactions |
simulateTransaction(tx) | Promise<SimulationResult> | Transactions |
signIn(params?) | SignInResult ({ message, signature }) | Signing |
signRawTransaction(input, opts?) | Promise<RawTx> — sign a foreign transaction | Signing |
signAll(transactions) | Promise<readonly T[]> — batch-sign your own transactions | Signing |
estimate(input, opts?) | Promise<SimulationResult> — preflight a foreign transaction | Signing |
checkDestination(req, opts?) | Promise<DestinationReport> — screen a transfer recipient | Signing |
Building a transaction
buildTransaction returns the concrete per-chain transaction (an EvmTransaction for an EVM address, an SvmTransaction for SVM) with the address already bound, so it can be signed, simulated and sent. The EVM shape, taken from the example tests:
const tx = evm.buildTransaction({
to: "0x1234567890123456789012345678901234567890",
value: 1_000_000_000_000_000n,
chainId: 1,
nonce: 0,
gasLimit: 21000n,
maxFeePerGas: 50_000_000_000n,
maxPriorityFeePerGas: 1_000_000_000n,
type: 2,
});
tx.from.toLowerCase() === evm.publicKey.toLowerCase(); // trueOwnership
signTransaction, sendTransaction and simulateTransaction all enforce that the transaction's from matches this address's publicKey; a foreign from throws a PARAMETER_ERROR synchronously. See Transactions for the tracker and simulation shapes.
refreshBalances(displayedOnly?: boolean) performs a live balance refresh: it reads each tracked asset over the read pool (with endpoint failover) and returns a Settling<readonly AssetBalance[]>. This is the only form — an Address is bound to a single network, so cross-network or single-asset refreshes are composed a layer up.