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 lowers transfers.
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 | SuiAddress | the canonical public address string |
vm | VmToken | the virtual machine — "evm", "svm", "sui", 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 |
"sui" | base Address | none in this build |
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 (the Sui placeholder) 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 |
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 |
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:
import { Network } from "wative-core";
const tx = await 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,
network: Network.Ethereum,
});
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(...) exists on the type but RPC-backed balance refresh is not implemented in this build. It returns an already-rejected Settling whose confirm() rejects with UNSUPPORTED_OP rather than throwing synchronously.