WDK Core API Reference
Complete API documentation for @tetherto/wdk
Table of Contents
| Class | Description | Methods |
|---|---|---|
| WDK | Main class for managing wallets across multiple blockchains. Orchestrates wallet managers, protocols, middleware, and local transaction policies. | Constructor, Methods |
| IWalletAccount | Base single-signer writable wallet account interface from @tetherto/wdk-wallet. | Methods |
| Multisig account contracts | Implementation contracts exported from @tetherto/wdk-wallet/multisig. | Interfaces and types |
| IWalletAccountWithProtocols | Protocol registration and access surface added to a wallet account. | Methods |
| WdkAccount | Consumer-facing account type returned by getAccount() and getAccountByPath(). | Type alias |
WDK
The main class for managing wallets across multiple blockchains. This class serves as an orchestrator that allows you to register different wallet managers and protocols, providing a unified interface for multi-chain operations.
Constructor
new WDK(seed, options?)Parameters:
seed(string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytesoptions(WdkOptions, optional): Instance settings.maxConditionTimeoutMsis a finite positive number that caps every policy condition timeout on this WDK instance and defaults to30000milliseconds.
Throws: Error if the seed is invalid. Throws PolicyConfigurationError if options fails the published options schema, such as an array or primitive value, or if maxConditionTimeoutMs is not a finite positive number.
Example:
import WDK from '@tetherto/wdk'
// With seed phrase
const wdk = new WDK('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about')
// With seed bytes
const seedBytes = new Uint8Array([...])
const wdk2 = new WDK(seedBytes)
// Cap every policy condition at five seconds
const policyWdk = new WDK(seedBytes, {
maxConditionTimeoutMs: 5000
})Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
registerWallet(blockchain, wallet, config) | Registers a new wallet manager for a blockchain | WDK | If a wallet is already registered for that blockchain |
registerProtocol(blockchain, label, protocol, config) | Registers a protocol globally for a blockchain | WDK | - |
registerMiddleware(blockchain, middleware) | Registers middleware for account decoration | WDK | - |
registerPolicy(policies, options?) | Registers local transaction policies for wallet account and protocol write methods | WDK | If policy configuration is invalid |
getAccount(blockchain, index?) | Returns a wallet account for a blockchain and index | Promise<WdkAccount> | If wallet not registered |
getAccountByPath(blockchain, path) | Returns a wallet account for a blockchain and derivation path | Promise<WdkAccount> | If wallet not registered |
getFeeRates(blockchain) | Returns current fee rates for a registered blockchain | Promise<FeeRates> | If wallet not registered |
dispose(blockchains?) | Disposes all registered wallets, or only the named blockchains, and clears keys and account state managed by WDK | void | - |
registerWallet(blockchain, wallet, config)
Registers a new wallet manager for a specific blockchain.
Type Parameters:
W:typeof WalletManager- A class that extends the@tetherto/wdk-wallet'sWalletManagerclass
Parameters:
blockchain(string): The name of the blockchain (e.g., "ethereum", "ton", "bitcoin")wallet(W): The wallet manager classconfig(ConstructorParameters<W>[1]): The configuration object for the wallet
Returns: WDK - The WDK instance (supports method chaining)
Throws: Error if a wallet is already registered for the same blockchain. Call dispose([blockchain]) before registering a replacement wallet for that blockchain.
Example:
import WDK from '@tetherto/wdk'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTon from '@tetherto/wdk-wallet-ton'
const wdk = new WDK(seedPhrase)
// Register EVM wallet
wdk.registerWallet('ethereum', WalletManagerEvm, {
provider: 'https://eth.drpc.org'
})
// Register TON wallet
wdk.registerWallet('ton', WalletManagerTon, {
tonApiKey: 'YOUR_TON_API_KEY',
tonApiEndpoint: 'https://tonapi.io'
})
// Method chaining
const wdk2 = new WDK(seedPhrase)
.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
.registerWallet('ton', WalletManagerTon, tonWalletConfig)registerProtocol(blockchain, label, protocol, config)
Registers a protocol globally for all accounts of a specific blockchain.
For swidge or Smart Deposit Address (SDA) integrations, pass a concrete provider class that extends the corresponding base class from @tetherto/wdk-wallet/protocols.
Type Parameters:
P:typeof SwapProtocol | typeof BridgeProtocol | typeof LendingProtocol | typeof FiatProtocol | typeof SwidgeProtocol | typeof SdaProtocol- A class that extends one of the@tetherto/wdk-wallet/protocolsclasses
Parameters:
blockchain(string): The name of the blockchainlabel(string): Registry label for the protocol. Registering the same blockchain, protocol type, and label again replaces the previous global registration.protocol(P): The protocol classconfig(ConstructorParameters<P>[1]): The protocol configuration
Returns: WDK - The WDK instance (supports method chaining)
Global registration stores the provider class and config without constructing or validating the provider. Provider-constructor errors therefore surface when an account retrieves the protocol. A global registration takes precedence over an account-scoped registration with the same type and label.
Example:
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
// Register swap protocol for Ethereum
wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
apiKey: 'YOUR_velora_API_KEY'
})
// Register bridge protocol for Ethereum
wdk.registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm)
// Register a concrete swidge provider for Ethereum
wdk.registerProtocol('ethereum', 'swidge', MySwidgeProtocol, swidgeProtocolConfig)
// Register an illustrative SDA provider for Ethereum
wdk.registerProtocol('ethereum', 'deposits', MySdaProtocol, sdaProtocolConfig)
// Method chaining
const wdk2 = new WDK(seedPhrase)
.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
.registerProtocol('ethereum', 'velora', veloraProtocolEvm, veloraProtocolConfig)registerMiddleware(blockchain, middleware)
Registers middleware for account decoration and enhanced functionality.
Parameters:
blockchain(string): The name of the blockchainmiddleware(<A extends IWalletAccount>(account: A) => Promise<A | void>): Middleware function called when deriving accounts
Returns: WDK - The WDK instance (supports method chaining)
Example:
// Simple logging middleware
wdk.registerMiddleware('ethereum', async (account) => {
console.log('New account:', await account.getAddress())
})
// Failover cascade middleware
import { getFailoverCascadeMiddleware } from '@tetherto/wdk-wrapper-failover-cascade'
wdk.registerMiddleware('ethereum', getFailoverCascadeMiddleware({
fallbackOptions: {
retries: 3,
delay: 1000
}
}))
// Method chaining
const wdk2 = new WDK(seedPhrase)
.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
.registerMiddleware('ethereum', async (account) => {
console.log('New account:', await account.getAddress())
})registerPolicy(policies, options?)
Registers one or more local transaction policies on the WDK instance.
Policies are evaluated before wrapped account and protocol write methods execute. Matching DENY rules and governed-account default-deny outcomes throw PolicyViolationError; matching ALLOW rules permit the call only when no higher-priority DENY rule applies. Governed runtime accounts also expose account.simulate.<method>(...) mirrors so you can dry-run policy evaluation without sending, signing, or broadcasting.
Evaluation order:
- Account-scoped policies run before project-scoped policies.
- Policies and rules run in registration order within their scope.
- A matching account-scoped
DENYblocks immediately. - A matching account-scoped
ALLOWwithoverride_broader_scope: trueallows immediately and skips project-scoped policies. - Project-scoped
DENYrules block after account-scoped rules unless an override allow already matched. - If no
DENYmatches and at least oneALLOWmatched, WDK allows the call. - Governed wrapped operations deny by default when no rule addresses the operation or no addressed rule matches.
For policy scoping, default-deny behavior, account-level overrides, and protocol simulation examples, see Transaction Policies.
Parameters:
policies(Policy | Policy[]): A single policy or an array of policies to register.options(RegisterPolicyOptions, optional): Settings applied only to the policies registered by this call.conditionTimeoutMsis a finite positive number and defaults to30000milliseconds. Values above the instance'smaxConditionTimeoutMsceiling are capped.
Distinct policy IDs keep their original per-registration timeouts. A repeated ID replaces the stored policy within its registry bucket and takes the timeout from the new registration call. All project-scoped policies share one bucket; account-scoped policies are bucketed by wallet.
Returns: WDK - The WDK instance (supports method chaining)
Throws: PolicyConfigurationError if a policy or option fails validation, if an account-scoped policy omits its account binding, or if a policy references a wallet identifier that has not been registered. Governed write calls also throw PolicyConfigurationError when WDK cannot snapshot a method argument safely.
Example:
import WDK, { PolicyViolationError } from '@tetherto/wdk'
const wdk = new WDK(seedPhrase)
.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
.registerPolicy({
id: 'eth-send-limit',
name: 'ETH send limit',
scope: 'project',
wallet: 'ethereum',
rules: [
{
name: 'allow-normal-operations',
operation: '*',
action: 'ALLOW',
reason: 'Default local approval',
conditions: [() => true]
},
{
name: 'block-large-send',
operation: 'sendTransaction',
action: 'DENY',
reason: 'Transaction value exceeds local policy',
conditions: [
({ args }) => {
const tx = args[0] as { value?: bigint } | undefined
const value = tx?.value
return typeof value === 'bigint' && value > 1000000000000000000n
}
]
}
]
})
const account = await wdk.getAccount('ethereum', 0)
const simulation = await (account as any).simulate.sendTransaction({
to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
value: 2000000000000000000n
})
if (simulation.decision === 'DENY') {
console.warn(simulation.reason)
}
try {
await account.sendTransaction({
to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
value: 2000000000000000000n
})
} catch (error) {
if (error instanceof PolicyViolationError) {
console.error(error.reason)
}
}Supported PolicyOperation values are sendTransaction, signTransaction, transfer, approve, sign, signTypedData, signAuthorization, delegate, revokeDelegation, swap, bridge, supply, withdraw, borrow, repay, buy, sell, swidge, createDepositAddress, renewDepositAddress, recoverDepositAddress, disableDepositAddress, and *.
Use sign for message-style signing in this release. signMessage and signHash are not valid policy operation names.
Policy-enforced calls snapshot method arguments before evaluation and forward the same approved values to the wallet method. Pass structured-cloneable values such as primitives, plain objects, arrays, bigint, and typed arrays. Non-cloneable governed arguments fail closed with PolicyConfigurationError.
getAccount(blockchain, index?)
Returns a wallet account for a specific blockchain and index using BIP-44 derivation.
Parameters:
blockchain(string): The name of the blockchain (e.g., "ethereum")index(number, optional): The index of the account to get (default: 0)
Returns: Promise<WdkAccount> - The writable wallet account with protocol support. When a registered policy targets the account, the returned runtime account is policy-enforced and exposes matching simulate helpers.
Throws: Error if no wallet has been registered for the given blockchain. Throws PolicyConfigurationError if a registered policy applies but the wallet account does not expose a read-only account view.
Example:
// Get first account (index 0)
const account = await wdk.getAccount('ethereum', 0)
// Get second account (index 1)
const account1 = await wdk.getAccount('ethereum', 1)
// Default index (0)
const defaultAccount = await wdk.getAccount('ethereum')
// This will throw an error if no wallet registered for 'tron'
try {
const tronAccount = await wdk.getAccount('tron', 0)
} catch (error) {
console.error('No wallet registered for tron blockchain')
}getAccountByPath(blockchain, path)
Returns a wallet account for a specific blockchain and BIP-44 derivation path.
Parameters:
blockchain(string): The name of the blockchain (e.g., "ethereum")path(string): The derivation path (e.g., "0'/0/0")
Returns: Promise<WdkAccount> - The writable wallet account with protocol support. When a registered policy targets the account, the returned runtime account is policy-enforced and exposes matching simulate helpers.
Throws: Error if no wallet has been registered for the given blockchain. Throws PolicyConfigurationError if a registered policy applies but the wallet account does not expose a read-only account view.
Example:
// Full path: m/44'/60'/0'/0/1
const account = await wdk.getAccountByPath('ethereum', "0'/0/1")
// Different derivation path
const customAccount = await wdk.getAccountByPath('ton', "1'/2/3")getFeeRates(blockchain)
Returns current fee rates for a registered blockchain.
Parameters:
blockchain(string): The blockchain identifier passed toregisterWallet()
Returns: Promise<FeeRates> - The fee rates in base units
Throws: Error if no wallet has been registered for the given blockchain.
Example:
const feeRates = await wdk.getFeeRates('ethereum')
console.log('Fee rates:', feeRates)dispose(blockchains?)
Disposes all registered wallets when called without arguments, or only the wallets for the named blockchains when you pass a string array.
This clears keys and account state managed by WDK, including private keys held by registered wallets. It does not mutate or zero the seed value passed to new WDK(seed). See Seed Lifecycle for the recommended cleanup pattern.
Parameters:
blockchains(string[], optional): The blockchain identifiers to dispose. Omit this parameter to dispose every registered wallet.
Example:
// Dispose all registered wallets
wdk.dispose()
// Dispose only one registered wallet
wdk.dispose(['ethereum'])Static Methods
| Method | Description | Returns |
|---|---|---|
getRandomSeedPhrase(wordCount?) | Returns a random BIP-39 seed phrase (12 or 24 words) | string |
isValidSeed(seed) | Checks if a seed phrase or seed bytes value is valid | boolean |
getRandomSeedPhrase(wordCount?)
Returns a random BIP-39 seed phrase. Supports both 12-word (128-bit entropy) and 24-word (256-bit entropy) seed phrases.
Parameters:
wordCount(12 | 24, optional): The number of words in the seed phrase. Defaults to 12.
Returns: string - The seed phrase
Example:
// Generate 12-word seed phrase (default)
const seedPhrase12 = WDK.getRandomSeedPhrase()
console.log('Generated 12-word seed:', seedPhrase12)
// Output: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
// Generate 24-word seed phrase (higher security)
const seedPhrase24 = WDK.getRandomSeedPhrase(24)
console.log('Generated 24-word seed:', seedPhrase24)
// Output: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art"isValidSeed(seed)
Checks if a seed phrase or seed bytes value is valid.
Parameters:
seed(string | Uint8Array): The seed phrase or seed bytes to validate
Returns: boolean - True if the seed is valid
Example:
const isValid = WDK.isValidSeed('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about')
console.log('Seed phrase valid:', isValid) // true
const isInvalid = WDK.isValidSeed('invalid seed phrase')
console.log('Seed phrase valid:', isInvalid) // falseIWalletAccount
Base single-signer writable wallet account interface exposed by @tetherto/wdk-wallet. Blockchain modules implement this interface and may narrow the transaction type accepted by signTransaction() and sendTransaction().
Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
getAddress() | Returns the account address | Promise<string> | - |
sign(message) | Signs a message with the account private key | Promise<string> | - |
signTransaction(tx) | Signs a transaction without broadcasting it | Promise<unknown> | If the transaction is invalid for the module |
verify(message, signature) | Verifies a message signature | Promise<boolean> | - |
getTransaction(hash) | Returns a normalized transaction receipt | Promise<TransactionReceipt> | ValueError, NoSuchElementError, ProviderRequiredError, or ProviderError |
waitForTransaction(hash, options?) | Polls until the requested finality or a stable dropped state | Promise<TransactionReceipt> | Transaction lookup errors or TimeoutError |
sendTransaction(tx) | Signs, broadcasts, and returns the transaction result | Promise<TransactionResult> | If provider access or broadcast fails |
transfer(options) | Transfers a token where supported by the module | Promise<TransferResult> | If the module does not support token transfers |
toReadOnlyAccount() | Returns a read-only account copy | Promise<IWalletAccountReadOnly> | - |
dispose() | Clears sensitive account material from memory | void | - |
signTransaction(tx)
Signs a transaction with the account private key and returns the signed transaction payload without broadcasting it. Use this when your app needs offline signing, external transaction submission, or a separate review step before broadcast.
Parameters:
tx(Transaction): Module-specific transaction object. For example, EVM accounts acceptEvmTransaction, and Bitcoin accounts acceptBtcTransaction.
Returns: Promise<unknown> - The signed transaction payload. Wallet modules may narrow this return type, such as a hex string for EVM and Bitcoin transactions.
Example:
const account = await wdk.getAccount('ethereum', 0)
const signedTransaction = await account.signTransaction({
to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
value: 1000000000000000n
})
console.log('Signed transaction:', signedTransaction)getTransaction(hash)
Returns one normalized lookup for a transaction. The common receipt includes hash, finality, and optional success, block, and fee fields; a concrete wallet module can add chain-native fields.
Parameters:
hash(string): The chain-specific transaction identifier, such as a hash, signature, orlt:hashvalue.
Returns: Promise<TransactionReceipt> - The current normalized receipt.
Throws: NoSuchElementError when the transaction has not been found. Invalid identifiers and provider failures use the corresponding base-wallet error classes.
getTransactionReceipt() is marked deprecated in the base package. Migrate after the concrete wallet module documents a getTransaction() implementation, and use that module's extended TransactionReceipt when you also need native receipt fields.
getTransaction() is a base-wallet contract, not a guarantee that current chain modules implement it. The base implementation throws NotImplementedError; for example, the currently released @tetherto/wdk-wallet-evm v1.0.0-beta.16 still exposes its legacy receipt lookup instead. Check the concrete module's release documentation before using either normalized transaction-tracking method.
waitForTransaction(hash, options?)
Calls getTransaction() until the receipt reaches the requested confirmed or final target, is reported as dropped on two consecutive polls, or times out. It returns reverted receipts too; inspect success instead of treating resolution as proof of successful execution.
Parameters:
hash(string): The transaction identifier.options(WaitForTransactionOptions, optional): Polling and finality settings.
| Option | Default | Description |
|---|---|---|
target | 'confirmed' | Finality level to wait for: 'confirmed' or 'final' |
timeout | Module default | Polling deadline checked between completed polls; the base account default is 60000 milliseconds |
interval | Module default | Poll cadence in milliseconds; the base account default is 4000 |
maxPollErrors | 3 | Consecutive ProviderError results tolerated before the next one is rethrown |
Returns: Promise<TransactionReceipt> - A receipt at the target finality, or a stable dropped receipt.
Throws: TimeoutError when the polling loop regains control and observes that the deadline has elapsed. NoSuchElementError is treated as a transient not-found while polling; other non-provider errors are rethrown immediately.
timeout is not a hard wall-clock bound and does not cancel getTransaction(). The helper awaits each provider lookup, does not shorten the final sleep to the remaining time, and checks a returned target receipt before checking the deadline again. A slow or hung lookup can therefore exceed the configured timeout, and a target receipt can resolve after it. Configure provider-level request timeouts or cancellation separately.
// `account` must come from a concrete module that implements getTransaction().
const receipt = await account.waitForTransaction(transactionHash, {
target: 'confirmed',
timeout: 120000
})
if (receipt.finality === 'dropped') {
console.error('Transaction dropped')
} else if (receipt.success === false) {
console.error('Transaction reverted')
}Base Wallet Error Exports
The root @tetherto/wdk-wallet entrypoint exports WdkError and these specialized subclasses: AssertionError, InvalidSignerError, InvalidTokenError, MaximumFeeExceededError, NoSuchElementError, NotImplementedError, ProviderError, ProviderRequiredError, TimeoutError, TransactionError, TransferError, UnsupportedOperationError, and ValueError.
ProviderError, TransactionError, and TransferError expose a reason field. Compare it with ProviderErrorReason, TransactionErrorReason, or TransferErrorReason rather than parsing the message. See Error Handling for the reason values and migration notes.
These exports do not retroactively normalize errors in a concrete wallet package built against an older base version. Check that package's release and documented error behavior before relying on instanceof WdkError.
Multisig Account Contracts
@tetherto/wdk-wallet/multisig exports contracts for chain-specific multisig wallet implementations. The package does not include a concrete multisig account or add these methods to WdkAccount. The Transaction and TransactionResult types remain type exports of the root @tetherto/wdk-wallet package.
import {
IWalletAccountReadOnlyMultisig,
IWalletAccountMultisig,
IMultisigOwnerManagement,
IMultisigMessageSigningReadOnly,
IMultisigMessageSigning
} from '@tetherto/wdk-wallet/multisig'These runtime exports are interface base classes. Their methods throw NotImplementedError until a wallet module overrides them.
IWalletAccountReadOnlyMultisig
The read-only contract shares the base address, signature-verification, balance, token-balance, and transaction-tracking methods, then adds multisig state and transaction-proposal reads:
interface IWalletAccountReadOnlyMultisig {
getMultisigInfo(): Promise<MultisigInfo>
getProposals(ids: string[]): Promise<Record<string, MultisigProposal | null>>
getProposal(id: string): Promise<MultisigProposal | null>
quoteExecuteProposal(id: string): Promise<Omit<TransactionResult, 'hash'>>
}Missing proposal IDs return null. quoteExecuteProposal() throws NoSuchElementError when the proposal does not exist.
IWalletAccountMultisig
The writable contract extends the read-only contract with signer identity, proposal actions, and execution:
interface IWalletAccountMultisig extends IWalletAccountReadOnlyMultisig {
readonly index: number
readonly path: string
readonly keyPair: KeyPair
getSignerAddress(): Promise<string>
propose(
tx: Transaction,
options?: MultisigTransactionOptions
): Promise<MultisigProposal>
approveProposal(id: string): Promise<MultisigProposal>
rejectProposal(id: string): Promise<MultisigProposal>
executeProposal(id: string): Promise<TransactionResult>
}propose() creates a proposal rather than executing the transaction directly. executeProposal() requires the approval threshold and throws ThresholdNotMetError when the proposal is not ready. Proposal quote, mutation, and execution methods can throw NoSuchElementError for an unknown ID; getter methods return null.
When autoExecute: true makes the current propose() call supply the final required approval, the returned proposal can have status: 'executed'. The current base method declarations return MultisigProposal; they do not include the transaction result.
Optional Message-Signing Contracts
Message proposals are optional capabilities in v1.0.0-beta.17. They are no longer members of IWalletAccountReadOnlyMultisig or IWalletAccountMultisig. A chain-specific module that supports them can expose these separate contracts:
interface IMultisigMessageSigningReadOnly {
getMessageProposals(ids: string[]): Promise<Record<string, MultisigMessageProposal | null>>
getMessageProposal(id: string): Promise<MultisigMessageProposal | null>
}
interface IMultisigMessageSigning extends IMultisigMessageSigningReadOnly {
proposeMessage(message: string): Promise<MultisigMessageProposal & MultisigSignature>
approveMessageProposal(id: string): Promise<MultisigMessageProposal & MultisigSignature>
}Check the concrete multisig wallet module before calling these methods. Missing message proposal IDs return null; approveMessageProposal() can throw NoSuchElementError for an unknown ID.
IMultisigOwnerManagement
Implement this separate contract when a chain-specific account supports proposal-based owner and threshold changes:
interface IMultisigOwnerManagement {
addOwner(owner: string, options?: MultisigOptions): Promise<MultisigProposal>
removeOwner(owner: string, options?: MultisigOptions): Promise<MultisigProposal>
swapOwner(oldOwner: string, newOwner: string): Promise<MultisigProposal>
changeThreshold(newThreshold: number): Promise<MultisigProposal>
}Multisig Types
interface MultisigInfo {
address: string
owners: string[]
threshold: number
}
interface MultisigProposal {
proposalId: string
confirmations: number
threshold: number
status: 'pending' | 'executed'
}
interface MultisigMessageProposal {
messageId: string
message: string
confirmations: number
threshold: number
combinedSignature: string | null
}
interface MultisigTransactionOptions {
autoExecute?: boolean
}
interface MultisigSignature {
signature: string
}
interface MultisigOptions {
threshold: number
}The subpath also re-exports the base wallet KeyPair type. MultisigAutoExecuteResult remains exported, but the current IWalletAccountMultisig methods do not use it in their return declarations.
IWalletAccountWithProtocols
Protocol registration and access surface that WDK adds to a wallet account. The consumer-facing WdkAccount type combines this interface with IWalletAccount from @tetherto/wdk-wallet.
Methods
| Method | Description | Returns | Throws |
|---|---|---|---|
registerProtocol(label, protocol, config) | Registers a protocol for this specific account | IWalletAccountWithProtocols | - |
getSwapProtocol(label) | Returns the swap protocol with the given label | ISwapProtocol | If protocol not found |
getBridgeProtocol(label) | Returns the bridge protocol with the given label | IBridgeProtocol | If protocol not found |
getLendingProtocol(label) | Returns the lending protocol with the given label | ILendingProtocol | If protocol not found |
getFiatProtocol(label) | Returns the fiat protocol with the given label | IFiatProtocol | If protocol not found |
getSwidgeProtocol(label) | Returns the swidge protocol with the given label | ISwidgeProtocol | If protocol not found |
getSdaProtocol(label) | Returns the SDA protocol with the given label | ISdaProtocol | If protocol not found |
registerProtocol(label, protocol, config)
Registers a new protocol for this specific account.
Type Parameters:
P:typeof SwapProtocol | typeof BridgeProtocol | typeof LendingProtocol | typeof FiatProtocol | typeof SwidgeProtocol | typeof SdaProtocol- A class that extends one of the@tetherto/wdk-wallet/protocolsclasses
Parameters:
label(string): Registry label for the protocol. Registering the same protocol type and label again replaces the account-scoped instance.protocol(P): The protocol classconfig(ConstructorParameters<P>[1]): The protocol configuration
Returns: IWalletAccountWithProtocols - The account instance (supports method chaining)
Example:
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
const account = await wdk.getAccount('ethereum', 0)
// Register protocol for this specific account
account.registerProtocol('usdt0', Usdt0ProtocolEvm, {
apiKey: 'YOUR_API_KEY'
})
// Method chaining on the resolved account
const account2 = (await wdk.getAccount('ethereum', 1))
.registerProtocol('usdt0', Usdt0ProtocolEvm, usdt0ProtocolConfig)getSwapProtocol(label)
Returns the swap protocol with the given label.
Parameters:
label(string): The protocol label
Returns: ISwapProtocol - The swap protocol instance
Throws: Error if no swap protocol with the given label has been registered
Example:
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
// Register swap protocol
account.registerProtocol('velora', veloraProtocolEvm, veloraProtocolConfig)
// Get swap protocol
const velora = account.getSwapProtocol('velora')
// Use the protocol
const swapResult = await velora.swap({
tokenIn: '0x...',
tokenOut: '0x...',
tokenInAmount: 1000000n
})
// This will throw an error
// try {
// const uniswap = account.getSwapProtocol('uniswap')
// } catch (error) {
// console.error('No swap protocol with label "uniswap" found')
// }getBridgeProtocol(label)
Returns the bridge protocol with the given label.
Parameters:
label(string): The protocol label
Returns: IBridgeProtocol - The bridge protocol instance
Throws: Error if no bridge protocol with the given label has been registered
Example:
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
// Register bridge protocol
account.registerProtocol('usdt0', Usdt0ProtocolEvm)
// Get bridge protocol
const usdt0 = account.getBridgeProtocol('usdt0')
// Use the protocol
await account.approve({
token: '0x...',
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const bridgeResult = await usdt0.bridge({
targetChain: 'arbitrum',
recipient: '0x...',
token: '0x...',
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})getLendingProtocol(label)
Returns the lending protocol with the given label.
Parameters:
label(string): The protocol label
Returns: ILendingProtocol - The lending protocol instance
Throws: Error if no lending protocol with the given label has been registered
Example:
import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm'
// Register lending protocol
account.registerProtocol('aave', AaveProtocolEvm, aaveProtocolConfig)
// Get lending protocol
const aave = account.getLendingProtocol('aave')
// Use the protocol
const supplyResult = await aave.supply({
token: '0x...',
amount: 1000000n
})getFiatProtocol(label)
Returns the fiat protocol with the given label.
Parameters:
label(string): The protocol label
Returns: IFiatProtocol - The fiat protocol instance
Throws: Error if no fiat protocol with the given label has been registered
Example:
import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'
// Register fiat protocol
account.registerProtocol('moonpay', MoonPayProtocol, moonpayProtocolConfig)
// Get fiat protocol
const moonpay = account.getFiatProtocol('moonpay')
const buyUrl = await moonpay.buy({
cryptoAsset: 'usdt',
fiatCurrency: 'usd',
fiatAmount: 10000n
})getSwidgeProtocol(label)
Returns the swidge protocol with the given label.
The examples below use MySwidgeProtocol as the concrete provider class supplied by your swidge provider module.
Parameters:
label(string): The protocol label
Returns: ISwidgeProtocol - The swidge protocol instance
Throws: Error if no swidge protocol with the given label has been registered
Example:
// Register a concrete provider class that extends SwidgeProtocol
account.registerProtocol('swidge', MySwidgeProtocol, swidgeProtocolConfig)
// Get swidge protocol
const swidge = account.getSwidgeProtocol('swidge')
const quote = await swidge.quoteSwidge({
fromToken: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
toToken: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
toChain: 'arbitrum',
fromTokenAmount: 1000000n
})getSdaProtocol(label)
Returns the Smart Deposit Address protocol with the given label.
The example uses MySdaProtocol as an illustrative provider class extending SdaProtocol; it does not imply that a provider package is available in the WDK documentation catalog.
Parameters:
label(string): The protocol label
Returns: ISdaProtocol - The SDA protocol instance
Throws: Error with No sda protocol registered for label: <label>. if no SDA protocol has been registered under that label
Example:
const account = await wdk.getAccount('ethereum', 0)
account.registerProtocol('deposits', MySdaProtocol, sdaProtocolConfig)
const deposits = account.getSdaProtocol('deposits')
const routes = await deposits.getSupportedRoutes({ outputAsset: 'USDT' })Global SDA registrations are constructed when retrieved. Account-scoped SDA registrations are constructed when registered. If both scopes use the same label, the global provider is returned.
Complete Example
import WDK from '@tetherto/wdk'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTon from '@tetherto/wdk-wallet-ton'
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
// Initialize WDK Manager
const wdk = new WDK(seedPhrase)
.registerWallet('ethereum', WalletManagerEvm, {
provider: 'https://eth.drpc.org'
})
.registerWallet('ton', WalletManagerTon, {
tonApiKey: 'YOUR_TON_API_KEY',
tonApiEndpoint: 'https://tonapi.io'
})
.registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
apiKey: 'YOUR_velora_API_KEY'
})
.registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm)
// Get accounts
const accountEth = await wdk.getAccount('ethereum', 3)
const accountTon = await wdk.getAccountByPath('ton', "1'/2/3")
// Use wallet account methods
const { hash, fee } = await accountEth.sendTransaction({
to: '0x...',
value: 1000000000000000000n // 1 ETH
})
// Use protocols
const velora = accountEth.getSwapProtocol('velora')
const swapResult = await velora.swap(swapOptions)
const usdt0 = accountEth.getBridgeProtocol('usdt0')
// bridgeOptions.oftContractAddress is the source-chain bridge spender.
await accountEth.approve({
token: bridgeOptions.token,
spender: bridgeOptions.oftContractAddress,
amount: bridgeOptions.amount
})
const bridgeResult = await usdt0.bridge(bridgeOptions)
// Clean up
wdk.dispose()Types
WdkAccount
WdkAccount is the exported type returned by getAccount() and getAccountByPath(). It combines the writable wallet methods with the protocol registration and lookup surface. This is a type-only export; there is no runtime WdkAccount value.
import WDK, { type WdkAccount } from '@tetherto/wdk'
async function getBitcoinAccount(wdk: WDK): Promise<WdkAccount> {
return wdk.getAccount('bitcoin')
}The published definition is IWalletAccount & IWalletAccountWithProtocols. Concrete wallet packages can expose additional methods beyond this shared shape. The declared return type of IWalletAccountWithProtocols.registerProtocol() remains IWalletAccountWithProtocols, so assigning the result of that chained call can narrow away the writable-account methods in TypeScript.
Transaction Tracking Types
type Finality = 'pending' | 'confirmed' | 'final' | 'dropped'
type WaitForTransactionTarget = 'confirmed' | 'final'
interface TransactionReceipt {
hash: string
finality: Finality
success?: boolean
block?: number
fee?: bigint
}
interface WaitForTransactionOptions {
target?: WaitForTransactionTarget
timeout?: number
interval?: number
maxPollErrors?: number
}Concrete wallet modules can extend TransactionReceipt with native chain fields. success is absent while a transaction is pending or dropped; a resolved wait can still have success: false when execution reverted.
FeeRates
interface FeeRates {
[blockchain: string]: {
normal: number;
fast: number;
};
}Middleware Function
type MiddlewareFunction = <A extends IWalletAccount>(
account: A
) => Promise<A | void>;Policy Types
interface WdkOptions {
maxConditionTimeoutMs?: number
}
type PolicyAction = 'ALLOW' | 'DENY'
type PolicyScope = 'project' | 'account'
type PolicyOperation =
| 'sendTransaction'
| 'signTransaction'
| 'transfer'
| 'approve'
| 'sign'
| 'signTypedData'
| 'signAuthorization'
| 'delegate'
| 'revokeDelegation'
| 'swap'
| 'bridge'
| 'supply'
| 'withdraw'
| 'borrow'
| 'repay'
| 'buy'
| 'sell'
| 'swidge'
| 'createDepositAddress'
| 'renewDepositAddress'
| 'recoverDepositAddress'
| 'disableDepositAddress'
| '*'
type PolicyCondition = (context: PolicyContext) => boolean | Promise<boolean>
interface PolicyContext {
operation: PolicyOperation
wallet: string
account: IWalletAccountReadOnly
args: readonly unknown[]
}
interface PolicyRule {
name: string
operation: PolicyOperation | PolicyOperation[]
action: PolicyAction
conditions: PolicyCondition[]
reason?: string
override_broader_scope?: boolean
state?: Record<string, unknown>
onSuccess?: (c: PolicyContext) => void | Promise<void>
}
interface Policy {
id: string
name: string
scope: PolicyScope
wallet?: string | string[]
accounts?: Array<string | number>
rules: PolicyRule[]
}
interface RegisterPolicyOptions {
state?: Record<string, unknown>
conditionTimeoutMs?: number
}
interface SimulationTraceEntry {
scope: PolicyScope
policy_id: string
rule_name: string
matched: boolean
error?: string
}
interface SimulationResult {
decision: 'ALLOW' | 'DENY'
policy_id: string | null
matched_rule: string | null
reason: string | null
trace: SimulationTraceEntry[]
}scope: 'project' can apply across all registered wallets or only the wallets named in wallet. scope: 'account' requires both wallet and accounts; account entries can be a derivation path string or an account index number.
override_broader_scope is valid only on account-scoped ALLOW rules. When that rule matches, WDK allows the call without evaluating project-scoped policies.
state and onSuccess are reserved for future engine-managed state and are ignored at runtime in this beta. Conditions can use app-owned state through closures or external stores, but keep that state outside rule.state; WDK does not persist or update state, run onSuccess, or provide built-in counters or cumulative spend accounting.
PolicyContext.args is a frozen array containing a snapshot of each argument in method-signature order. params was removed in v1.0.0-beta.16; use args[0] for the first argument and check optional positions before reading them.
conditionTimeoutMs belongs to the policies registered by one registerPolicy() call. Distinct policy IDs retain their earlier timeouts, while a repeated ID replaces the policy within its registry bucket and takes the new registration's timeout. All project-scoped policies share one bucket; account-scoped policies are bucketed by wallet. maxConditionTimeoutMs is the instance-wide ceiling set by new WDK(seed, options). Both timeout settings default to 30000 milliseconds, and a per-policy request above the ceiling is capped.
Simulation results returned by the runtime account.simulate.<method>(...) mirrors include decision, policy_id, matched_rule, reason, and a trace array that records evaluated rules. reason can include a rule reason or one of the engine outcomes: matched, override, no-applicable-rule, or governed-but-unmatched.
Protocol Types
// Swap Protocol
interface ISwapProtocol {
swap(options: SwapOptions): Promise<SwapResult>;
}
// Bridge Protocol
interface IBridgeProtocol {
bridge(options: BridgeOptions): Promise<BridgeResult>;
}
// Lending Protocol
interface ILendingProtocol {
supply(options: LendingOptions): Promise<LendingResult>;
withdraw(options: LendingOptions): Promise<LendingResult>;
borrow(options: LendingOptions): Promise<LendingResult>;
repay(options: LendingOptions): Promise<LendingResult>;
}
// Swidge Protocol (unified swap + bridge + route)
interface ISwidgeProtocol extends ISwapProtocol, IBridgeProtocol {
quoteSwidge(options: SwidgeOptions): Promise<SwidgeQuote>;
swidge(options: SwidgeOptions, config?: SwidgeProtocolConfig): Promise<SwidgeResult>;
getSwidgeStatus(id: string, options?: SwidgeStatusOptions): Promise<SwidgeStatusResult>;
getSupportedChains(): Promise<SwidgeSupportedChain[]>;
getSupportedTokens(options?: SwidgeSupportedTokensOptions): Promise<SwidgeSupportedToken[]>;
}
// Smart Deposit Address Protocol
interface ISdaProtocol {
getSupportedRoutes(options?: SdaRoutesOptions): Promise<SdaRoute[]>;
createDepositAddress(options: SdaCreateDepositAddressOptions): Promise<SdaDepositAddress[]>;
quoteDeposit(options: SdaDepositOptions): Promise<SdaDepositQuote>;
deriveDepositAddress(options: SdaCreateDepositAddressOptions): Promise<string>;
getDepositAddress(id: string): Promise<SdaDepositAddress>;
renewDepositAddress(id: string): Promise<SdaDepositAddress>;
getTransfers(address: string, options?: SdaTransfersOptions): Promise<SdaTransfer[]>;
getTransfersByRecipient(destinationChain: string | number, recipient: string, options?: SdaTransfersOptions): Promise<SdaTransfer[]>;
getTransfer(id: string): Promise<SdaTransfer>;
recoverDepositAddress(options: SdaRecoveryOptions): Promise<SdaRecoveryResult>;
disableDepositAddress(id: string): Promise<void>;
}SdaProtocol requires provider subclasses to implement getSupportedRoutes() and createDepositAddress(). The remaining methods are optional in the base class and throw UnsupportedOperationError unless the provider implements them. Output assets are provider- and route-specific; USDT is a common example, not a base-interface guarantee.
Swidge Protocol
SwidgeProtocol is an abstract base class exported from @tetherto/wdk-wallet/protocols for provider packages that implement a single, route-aware surface for same-chain swaps and cross-chain bridges. It implements ISwidgeProtocol, which extends both ISwapProtocol and IBridgeProtocol, so the base class derives swap(), quoteSwap(), bridge(), and quoteBridge() by delegating to swidge() and quoteSwidge(). Provider subclasses implement the abstract methods below.
| Method | Description | Returns |
|---|---|---|
quoteSwidge(options) | Returns a non-binding quote for a swap/bridge operation | Promise<SwidgeQuote> |
swidge(options, config?) | Executes a swap/bridge operation | Promise<SwidgeResult> |
getSwidgeStatus(id, options?) | Returns the current status of an in-flight operation | Promise<SwidgeStatusResult> |
getSupportedChains() | Returns the chains the provider supports | Promise<SwidgeSupportedChain[]> |
getSupportedTokens(options?) | Returns the tokens the provider supports, optionally route-scoped | Promise<SwidgeSupportedToken[]> |
The SwidgeOptions input combines common fields (fromToken, toToken, optional toChain, recipient, refundAddress, slippage) with either an exact-in (fromTokenAmount) or exact-out (toTokenAmount) amount. The optional SwidgeProtocolConfig accepts maxNetworkFeeBps and maxProtocolFeeBps to cap acceptable fees.
See the provider catalog in Swidge modules, then use the selected provider's API reference for its released discovery, quote, execution, status, fee, and result behavior.
type SwidgeProtocolConfig = {
maxNetworkFeeBps?: number | bigint;
maxProtocolFeeBps?: number | bigint;
};
type SwidgeOptions = {
fromToken: string;
toToken: string;
toChain?: string | number; // defaults to the source chain (same-chain swap)
recipient?: string;
refundAddress?: string;
slippage?: number; // decimal, e.g. 0.01 for 1%
minAmountOut?: number | bigint; // destination-token base units; provider-defined enforcement
} & (
| { fromTokenAmount: number | bigint } // exact-in
| { toTokenAmount: number | bigint } // exact-out
);
type SwidgeStatus =
| 'pending' | 'action-required' | 'completed' | 'failed'
| 'refund-pending' | 'refunded' | 'cancelled' | 'expired' | 'partial';Next Steps
WDK Core Configuration
Get started with WDK's configuration
WDK Core Usage
Get started with WDK's Usage
Wallet Modules
Explore blockchain-specific wallet modules
Bridge Modules
Cross-chain USDâ‚®0 bridges