` - The signed transaction payload. Wallet modules may narrow this return type, such as a hex string for EVM and Bitcoin transactions.
**Example:**
```typescript title="Sign Without Broadcasting"
const account = await wdk.getAccount('ethereum', 0)
const signedTransaction = await account.signTransaction({
to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
value: 1000000000000000n
})
console.log('Signed transaction:', signedTransaction)
```
## IWalletAccountWithProtocols
Extended wallet account interface that supports protocol registration and access. Extends `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 |
##### `registerProtocol(label, protocol, config)`
Registers a new protocol for this specific account.
**Type Parameters:**
* `P`: `typeof SwapProtocol | typeof BridgeProtocol | typeof LendingProtocol` - A class that extends one of the `@tetherto/wdk-wallet/protocol`'s classes
**Parameters:**
* `label` (string): Unique label for the protocol (must be unique per account and protocol type)
* `protocol` (P): The protocol class
* `config` (`ConstructorParameters[1]`): The protocol configuration
**Returns:** `IWalletAccountWithProtocols` - The account instance (supports method chaining)
**Example:**
```javascript title="Register Protocol for Account"
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
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:**
```javascript title="Get Swap Protocol"
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:**
```javascript title="Get Bridge Protocol"
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:**
```javascript title="Get Lending Protocol"
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
})
```
## Complete Example
```javascript title="Complete WDK Flow"
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
### FeeRates
```typescript title="Type: FeeRates"
interface FeeRates {
[blockchain: string]: {
normal: number;
fast: number;
};
}
```
### Middleware Function
```typescript title="Type: MiddlewareFunction"
type MiddlewareFunction = (
account: A
) => Promise ;
```
### Protocol Types
```typescript title="Types: Protocol Interfaces"
// Swap Protocol
interface ISwapProtocol {
swap(options: SwapOptions): Promise;
}
// Bridge Protocol
interface IBridgeProtocol {
bridge(options: BridgeOptions): Promise;
}
// Lending Protocol
interface ILendingProtocol {
supply(options: LendingOptions): Promise;
withdraw(options: LendingOptions): Promise;
borrow(options: LendingOptions): Promise;
repay(options: LendingOptions): Promise;
}
```
***
## Next Steps
Get started with WDK's configuration
Get started with WDK's Usage
Explore blockchain-specific wallet modules
Cross-chain USD₮0 bridges
***
### Need Help?
# WDK Core Configuration (/sdk/core-module/configuration)
# Configuration
## WDK Manager Configuration
```javascript title="Create WDK Instance"
import WDK from '@tetherto/wdk'
const wdk = new WDK(seedPhrase)
```
The WDK Manager itself only requires a seed phrase for initialization. Configuration is done through the registration of wallets and protocols.
## Wallet Registration Configuration
```javascript title="Register WDK Wallet"
import WDK from '@tetherto/wdk'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTon from '@tetherto/wdk-wallet-ton'
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'
})
```
## Protocol Registration Configuration
```javascript title="Register WDK Protocol"
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
const wdk = new WDK(seedPhrase)
.registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
apiKey: 'YOUR_velora_API_KEY'
})
```
## Configuration Options
### Wallet Configuration
Each wallet manager requires its own configuration object when registered. The configuration depends on the specific wallet module being used.
#### EVM Wallet Configuration
```javascript title="Ethereum WDK Wallet Configuration"
const ethereumWalletConfig = {
provider: 'https://eth.drpc.org', // RPC endpoint
// Additional EVM-specific configuration options
}
wdk.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
```
#### TON Wallet Configuration
```javascript title="TON WDK Wallet Configuration"
const tonWalletConfig = {
tonClient: {
secretKey: 'YOUR_TON_API_KEY',
url: 'https://toncenter.com/api/v2/jsonRPC'
}
}
wdk.registerWallet('ton', WalletManagerTon, tonWalletConfig)
```
### Protocol Configuration
Protocols also require their own configuration objects when registered.
#### Swap Protocol Configuration
```javascript title="Swap WDK Protocol Configuration"
const veloraProtocolConfig = {
apiKey: 'YOUR_velora_API_KEY',
baseUrl: 'https://apiv5.velora.io'
}
wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, veloraProtocolConfig)
```
### Middleware Configuration
Middleware functions can be registered to enhance account functionality.
```javascript title="Middleware WDK Protocol Configuration"
// Simple logging middleware
wdk.registerMiddleware('ethereum', async (account) => {
console.log('New account created:', await account.getAddress())
})
```
## Environment Variables
For production applications, consider using environment variables for sensitive configuration:
```javascript title="WDK environment variables Configuration"
const wdk = new WDK(process.env.SEED_PHRASE)
.registerWallet('ethereum', WalletManagerEvm, {
provider: process.env.ETHEREUM_RPC_URL
})
.registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
apiKey: process.env.velora_API_KEY
})
```
## Configuration Validation
The WDK Manager will validate configurations when wallets and protocols are registered:
* **Wallet Registration**: Ensures the wallet class extends the required base class
* **Protocol Registration**: Validates that protocol labels are unique per blockchain and protocol type
* **Middleware Registration**: Validates that middleware functions have the correct signature
## Error Handling
Configuration errors will be thrown during registration:
```javascript title="Configuration errors"
try {
wdk.registerWallet('ethereum', InvalidWalletClass, config)
} catch (error) {
console.error('Wallet registration failed:', error.message)
}
try {
wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, invalidConfig)
} catch (error) {
console.error('Protocol registration failed:', error.message)
}
```
***
## Next Steps
Get started with WDK's usage
Get started with WDK's API
Explore blockchain-specific wallet modules
Cross-chain USD₮0 bridges
***
### Need Help?
# WDK Core (/sdk/core-module)
This package serves as the main entry point and **orchestrator for all WDK wallet and protocol modules**, allowing you to register and manage different blockchain wallets through a single, unified interface.
## Next Steps
Get started with WDK in a Node.js environment
Get started with WDK's configuration
Get started with WDK's API
Get started with WDK's usage
***
## Need Help?
# Usage (/sdk/core-module/usage)
The WDK Core module is the central orchestrator for your wallet interactions.
Install and instantiate the WDK.
Connect specific blockchains (Ethereum, TON, etc.).
Retrieve accounts and check balances.
Transfer native tokens.
Use Swap, Bridge, and Lending protocols.
Add logging and failover protection.
Best practices for security and stability.
# Community Modules (/sdk/community-modules)
The WDK ecosystem is enriched by modules developed by our community. These modules extend WDK's capabilities to support additional blockchains, protocols, and use cases.
Community modules are developed and maintained independently by third-party contributors.
Tether and the WDK Team do not endorse or assume responsibility for their code, security, or maintenance. Use your own judgment and proceed at your own risk.
## Available Community Modules
| Module | Type | Description | Author |
| ------------------------------------------------------------------------------ | ------------- | ---------------------------------------------------- | ------------------------------------------ |
| [@utexo/wdk-wallet-rgb](https://github.com/UTEXO-Protocol/wdk-wallet-rgb) | Wallet Module | Wallet module for RGB, Bitcoin-based smart contracts | [UTEXO](https://github.com/UTEXO-Protocol) |
| [@base58-io/wdk-wallet-cosmos](https://github.com/base58-io/wdk-wallet-cosmos) | Wallet Module | Wallet module for Cosmos-compatible blockchains | [Base58](https://base58.io/) |
***
## Create Your Own Module
Want to extend WDK with your own custom module? Use the `create-wdk-module` CLI to scaffold a fully configured project in seconds:
```bash title="Scaffold a new module"
npx @tetherto/create-wdk-module@latest
```
The CLI generates source files, tests, TypeScript type definitions, and CI workflows for all five module types (wallet, swap, bridge, lending, fiat). See the [Create WDK Module documentation](../../tools/create-wdk-module) for the full guide, CLI options, and generated project structure.
You can also:
1. **Study existing modules** - Review the source code of official WDK modules on [GitHub](https://github.com/orgs/tetherto/repositories?q=wdk) to understand the patterns and interfaces
2. **Join the community** - Connect with other developers on our [Discord](https://discord.gg/arYXDhHB2w) to discuss your ideas
3. **Open an issue** - Have questions? Open an issue on the relevant repository
***
## Submit Your Module
If you've built a WDK module, we'd love to feature it here!
**To submit your module:**
1. Ensure your module follows WDK interface conventions
2. Include comprehensive documentation and a clear README
3. Make the repository publicly accessible
4. Submit through our [Community Form](https://forms.gle/wmNwc5epxaa85u8a9) or share on our **#wdk-showcase** Discord channel
Your module may be featured in our documentation and community showcases.
***
## Guidelines for Community Modules
Community modules should:
* Implement the standard WDK module interface
* Include TypeScript type definitions
* Provide clear installation and usage instructions
* Be open source or publicly accessible
* Include appropriate tests and examples
# Fiat Modules Overview (/sdk/fiat-modules)
The Wallet Development Kit (WDK) provides fiat modules that enable on-ramp and off-ramp functionality, allowing users to seamlessly convert between fiat currencies and cryptocurrencies within your application.
## Fiat Protocol Modules
On-ramp and off-ramp functionality for fiat currency integration:
| Module | Provider | Status | Documentation |
| ---------------------------------------------------------------------------------------------- | -------- | ------- | -------------------------------- |
| [`@tetherto/wdk-protocol-fiat-moonpay`](https://github.com/tetherto/wdk-protocol-fiat-moonpay) | MoonPay | ✅ Ready | [Documentation](./fiat-moonpay/) |
## Features
Fiat modules provide:
* **On-Ramp**: Allow users to purchase cryptocurrency using fiat currencies (credit card, bank transfer, etc.)
* **Off-Ramp**: Enable users to sell cryptocurrency and receive fiat currencies
* **Multiple Payment Methods**: Support for various payment options depending on the provider
* **KYC Integration**: Built-in Know Your Customer verification flows
* **Multi-Currency Support**: Support for multiple fiat and cryptocurrencies
## Next Steps
To get started with WDK fiat modules, follow these steps:
1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart)
2. Choose the fiat module that best fits your needs from the table above
3. Check specific documentation for the module you wish to use
You can also:
* Learn about key concepts in our [Concepts](../../resources/concepts) page
* Explore [wallet modules](../wallet-modules/) to manage user wallets
* Check our [examples](../../examples-and-starters/react-native-starter) for production-ready implementations
# Lending Modules Overview (/sdk/lending-modules)
The Wallet Development Kit (WDK) provides a set of modules that support connection with lending protocols on different blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations.
## Lending & Borrowing Protocol Modules
DeFi lending functionality for different lending & borrowing protocols
| Module | Route | Status | Documentation |
| ------------------------------------------------------------------------------------------------------ | ----- | ------- | ------------------------------------ |
| [`@tetherto/wdk-protocol-lending-aave-evm`](https://github.com/tetherto/wdk-protocol-lending-aave-evm) | EVM | ✅ Ready | [Documentation](./lending-aave-evm/) |
## Next Steps
To get started with WDK modules, follow these steps:
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Manage wallet and protocol modules
***
## Need Help?
# Swap Modules Overview (/sdk/swap-modules)
The Swap Development Kit (WDK) provides a set of modules that support swap on top of multiple blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations.
## Swap Protocol Modules
DeFi swap functionality for token exchanges across different DEXs:
| Module | Blockchain | Status | Documentation |
| ---------------------------------------------------------------------------------------------------- | ---------- | ----------- | ----------------------------------- |
| [`@tetherto/wdk-protocol-swap-velora-evm`](https://github.com/tetherto/wdk-protocol-swap-velora-evm) | EVM | ✅ Ready | [Documentation](./swap-velora-evm/) |
| `@tetherto/wdk-protocol-swap-stonfi-ton` | TON | In progress | Coming soon |
## Next steps
To get started with WDK modules, follow these steps:
1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart)
2. Choose the modules that best fit your needs from the tables above
3. Check specific documentation for modules you wish to use
You can also:
* Learn about key concepts like [Account Abstraction](../../resources/concepts#account-abstraction) and other important definitions
* Use one of our ready-to-use examples to be production ready
# Wallet Modules Overview (/sdk/wallet-modules)
The Wallet Development Kit (WDK) provides a set of modules that support multiple blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations.
## Supported Networks
This package works with multiple blockchain networks through wallet registration.
Bitcoin Mainnet
Ethereum, Sepolia Testnet, L2s, etc.
Tron Mainnet
TON Mainnet
Solana Mainnet
Spark Mainnet
## Classic Wallet Modules
Standard wallet implementations that use native blockchain tokens for transaction fees:
| Module | Blockchain | Status | Documentation |
| ------------------------------------------------------------------------------ | ---------- | ----------- | -------------------------------- |
| [`@tetherto/wdk-wallet-evm`](https://github.com/tetherto/wdk-wallet-evm) | EVM | ✅ Ready | [Documentation](./wallet-evm) |
| [`@tetherto/wdk-wallet-ton`](https://github.com/tetherto/wdk-wallet-ton) | TON | ✅ Ready | [Documentation](./wallet-ton) |
| [`@tetherto/wdk-wallet-btc`](https://github.com/tetherto/wdk-wallet-btc) | Bitcoin | ✅ Ready | [Documentation](./wallet-btc) |
| [`@tetherto/wdk-wallet-spark`](https://github.com/tetherto/wdk-wallet-spark) | Spark | ✅ Ready | [Documentation](./wallet-spark) |
| [`@tetherto/wdk-wallet-tron`](https://github.com/tetherto/wdk-wallet-tron) | TRON | ✅ Ready | [Documentation](./wallet-tron) |
| [`@tetherto/wdk-wallet-solana`](https://github.com/tetherto/wdk-wallet-solana) | Solana | ✅ Ready | [Documentation](./wallet-solana) |
| `@tetherto/wdk-wallet-ark` | Ark | In progress | - |
## Account Abstraction Wallet Modules
Wallet implementations that support [Account Abstraction](../../resources/concepts#account-abstraction) for gasless transactions using paymaster tokens like USD₮:
| Module | Blockchain | Status | Documentation |
| ------------------------------------------------------------------------------------------ | ---------- | ----------- | -------------------------------------- |
| [`@tetherto/wdk-wallet-evm-erc4337`](https://github.com/tetherto/wdk-wallet-evm-erc-4337) | EVM | ✅ Ready | [Documentation](./wallet-evm-erc-4337) |
| [`@tetherto/wdk-wallet-ton-gasless`](https://github.com/tetherto/wdk-wallet-ton-gasless) | TON | ✅ Ready | [Documentation](./wallet-ton-gasless) |
| [`@tetherto/wdk-wallet-tron-gasfree`](https://github.com/tetherto/wdk-wallet-tron-gasfree) | TRON | ✅ Ready | [Documentation](./wallet-tron-gasfree) |
| `@tetherto/wdk-wallet-solana-jupiterz` | Solana | In progress | - |
## Community Wallet Modules
Wallet modules developed by the community. See the [Community Modules](../community-modules/) page for more details.
Community modules are developed and maintained independently. Use your own judgment and proceed at your own risk.
| Module | Blockchain | Description | Repository |
| ----------------------- | ------------- | ----------------------------------------------------------------- | ---------------------------------------------------------- |
| `@utexo/wdk-wallet-rgb` | Bitcoin (RGB) | RGB protocol wallet integration for Bitcoin-based smart contracts | [GitHub](https://github.com/UTEXO-Protocol/wdk-wallet-rgb) |
## Next Steps
To get started with WDK modules, follow these steps:
1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart)
2. Choose the modules that best fit your needs from the tables above
3. Check specific documentation for modules you wish to use
You can also:
* Learn about key concepts like [Account Abstraction](../../resources/concepts#account-abstraction) and other important definitions
* Use one of our ready-to-use examples to be production ready
# Components List (/ui-kits/react-native-ui-kit/api-reference)
## Component List
| Component | Description |
| ------------------------------------- | -------------------------------------------------------------------- |
| [`AmountInput`](api-reference) | Numeric input with token/fiat toggle, balance helper and Max action |
| [`AssetSelector`](api-reference) | Token search & pick list with recent items and empty states |
| [`NetworkSelector`](api-reference) | Network picker with gas level indicators and colors |
| [`Balance`](api-reference) | Displays a balance value with optional masking and custom loader |
| [`CryptoAddressInput`](api-reference) | Address input with QR scan and paste helpers, validation state |
| [`QRCode`](api-reference) | QR renderer for addresses/payment requests with labeling and styling |
| [`TransactionItem`](api-reference) | Single transaction row (sent/received) with token, amounts, network |
| [`TransactionList`](api-reference) | Virtualized list of transactions using `TransactionItem` |
| [`SeedPhrase`](api-reference) | Grid of seed words with optional editing and loading states |
***
### AmountInput
Numeric input component with token/fiat toggle, balance display, and Max functionality.
AmountInput (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| ------------------- | ------------------------- | -------- | ---------------- | ---------------------------------- |
| `label` | `string` | No | `'Enter Amount'` | Field label |
| `value` | `string` | Yes | — | Amount text value |
| `onChangeText` | `(text: string) =\> void` | Yes | — | Called when text changes |
| `tokenSymbol` | `string` | Yes | — | Token code, e.g. 'ETH', 'BTC' |
| `tokenBalance` | `string` | Yes | — | Token balance (e.g. '1.23') |
| `tokenBalanceUSD` | `string` | Yes | — | Balance in fiat (e.g. '\$4200.00') |
| `inputMode` | `'token' \| 'fiat'` | Yes | — | Current input mode |
| `onToggleInputMode` | `() =\> void` | Yes | — | Switch between token/fiat modes |
| `onUseMax` | `() =\> void` | Yes | — | Fill with maximum available amount |
| `error` | `string` | No | — | Error message to display |
| `editable` | `boolean` | No | `true` | Whether input is editable |
**Example**
```tsx title="AmountInput Usage"
import { AmountInput } from '@tetherto/wdk-uikit-react-native'
function SendAmount({ amount, balance, onAmountChange }) {
return (
{/* Switch mode */}}
onUseMax={() => onAmountChange(balance.toString())}
/>
)
}
```
***
### AssetSelector
Token selection component with search functionality and recent tokens.
AssetSelector (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| --------------- | ------------------------- | -------- | ------- | ------------------------------------------ |
| `tokens` | `Token[]` | Yes | — | Full list of tokens to display/filter |
| `recentTokens` | `string[]` | Yes | — | Array of recent token names for Recent row |
| `onSelectToken` | `(token: Token) =\> void` | Yes | — | Called when user selects a token |
**Token Type**
```typescript title="Token Interface"
type Token = {
id: string
symbol: string
name: string
balance: string
balanceUSD: string
icon: ImageSourcePropType
color: string
network?: string
hasBalance: boolean
}
```
**Example**
```tsx title="AssetSelector Usage"
import { AssetSelector } from '@tetherto/wdk-uikit-react-native'
function TokenPicker({ tokens, recentTokens, onTokenSelect }) {
return (
)
}
```
***
### Balance
Display component for showing balance values with optional masking and loading states.
Balance (dark theme)
Balance amount hide (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| --------------- | --------------------- | -------- | ------- | -------------------------------------- |
| `value` | `number` | No | `0` | Balance number value |
| `isLoading` | `boolean` | No | `false` | Show loading state |
| `Loader` | `React.ComponentType` | No | — | Custom loader component |
| `showHide` | `boolean` | No | `true` | Toggle hide/show balance functionality |
| `currency` | `string` | No | `'USD'` | Currency label |
| `EyeOpenIcon` | `React.ComponentType` | No | default | Icon shown when balance is hidden |
| `EyeClosedIcon` | `React.ComponentType` | No | default | Icon shown when balance is visible |
**Example**
```tsx title="Balance Usage"
import { Balance } from '@tetherto/wdk-uikit-react-native'
function WalletBalance({ balance, currency, isLoading }) {
return (
)
}
```
***
### CryptoAddressInput
Address input component with QR scanning and paste functionality.
CryptoAddressInput (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| -------------- | ------------------------- | -------- | ------------------------------------- | ------------------------- |
| `label` | `string` | No | `'Recipient Address'` | Field label |
| `value` | `string` | Yes | — | Address text value |
| `onChangeText` | `(text: string) =\> void` | Yes | — | Called when text changes |
| `placeholder` | `string` | No | `'T08p3BGPIuh1l934IIflu....Kc2GXhKc'` | Placeholder text |
| `onPaste` | `() =\> void` | No | — | Paste action handler |
| `onQRScan` | `() =\> void` | No | — | Open QR scanner handler |
| `editable` | `boolean` | No | `true` | Whether input is editable |
| `error` | `string` | No | — | Error message to display |
**Example**
```tsx title="CryptoAddressInput Usage"
import { CryptoAddressInput } from '@tetherto/wdk-uikit-react-native'
function AddressInput({ address, onAddressChange, onQRScan }) {
return (
)
}
```
***
### QRCode
QR code renderer for addresses and payment requests.
QRCode (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| ----------------- | ----------- | -------- | --------------- | ------------------------------- |
| `value` | `string` | Yes | — | Data to encode in QR code |
| `size` | `number` | No | `200` | QR code side length in pixels |
| `color` | `string` | No | `theme.primary` | Dot color |
| `backgroundColor` | `string` | No | `'transparent'` | Background color behind QR code |
| `label` | `string` | No | — | Optional title above QR code |
| `containerStyle` | `ViewStyle` | No | — | Wrapper style |
| `labelStyle` | `any` | No | — | Style for label text |
**Example**
```tsx title="QRCode Usage"
import { QRCode } from '@tetherto/wdk-uikit-react-native'
function AddressQR({ address }) {
return (
)
}
```
***
### TransactionItem
Single transaction row component for displaying transaction details.
TransactionItem (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| ------------- | ------------- | -------- | ------- | ----------------------- |
| `transaction` | `Transaction` | Yes | — | Transaction data object |
| `onPress` | `() =\> void` | No | — | Row press handler |
**Transaction Type**
```typescript title="Transaction Interface"
type Transaction = {
id: string
token: string
amount: string
fiatAmount: string
fiatCurrency: string
network: string
type: 'sent' | 'received'
}
```
**Example**
```tsx title="TransactionItem Usage"
import { TransactionItem } from '@tetherto/wdk-uikit-react-native'
function TransactionRow({ transaction, onPress }) {
return (
)
}
```
***
### TransactionList
Virtualized list component for displaying multiple transactions.
TransactionList (dark theme)
**Props**
| Prop | Type | Required | Default | Description |
| -------------- | --------------- | -------- | ------- | ---------------------------- |
| `transactions` | `Transaction[]` | Yes | — | Array of transaction objects |
**Example**
```tsx title="TransactionList Usage"
import { TransactionList } from '@tetherto/wdk-uikit-react-native'
function TransactionHistory({ transactions }) {
return (
)
}
```
***
### NetworkSelector
Network selection component with gas level indicators.
**Props**
| Prop | Type | Required | Default | Description |
| ----------------- | ----------------------------- | -------- | ------- | ------------------------------- |
| `networks` | `Network[]` | Yes | — | Array of available networks |
| `onSelectNetwork` | `(network: Network) =\> void` | Yes | — | Called when network is selected |
**Network Type**
```typescript title="Network Interface"
type Network = {
id: string
name: string
gasLevel: 'High' | 'Normal' | 'Low'
gasColor: string
icon: string | any
color: string
}
```
**Example**
```tsx title="NetworkSelector Usage"
import { NetworkSelector } from '@tetherto/wdk-uikit-react-native'
function NetworkPicker({ networks, onNetworkSelect }) {
return (
)
}
```
***
### SeedPhrase
Grid component for displaying and editing seed phrase words.
**Props**
| Prop | Type | Required | Default | Description |
| -------------- | ---------------------------------------- | -------- | ------- | --------------------------------- |
| `words` | `string[]` | Yes | — | Array of seed words (12/24, etc.) |
| `editable` | `boolean` | No | `false` | Allow editing of word inputs |
| `onWordChange` | `(index: number, word: string) =\> void` | No | — | Called when word is edited |
| `onKeyPress` | `(index: number, key: string) =\> void` | No | — | Handle key press events |
| `isLoading` | `boolean` | No | `false` | Show loading/generating state |
**Example**
```tsx title="SeedPhrase Usage"
import { SeedPhrase } from '@tetherto/wdk-uikit-react-native'
function WalletBackup({ seedWords, editable, onWordChange }) {
return (
)
}
```
***
## Next Steps
* [Get Started](get-started) - Quick start guide and basic usage
* [Theming Guide](theming) - Deep dive into theming capabilities
* [React Native Quickstart](../../start-building/react-native-quickstart) - Complete implementation example
***
## Need Help?
# Get Started (/ui-kits/react-native-ui-kit/get-started)
The WDK React Native UI Kit provides ready-made, themeable components for building wallet applications. It's designed to work seamlessly with the SDK and offers:
* **Ready-made wallet building blocks**: amount input, asset selector, address input, QR code, balance, transaction lists, seed phrase components
* **Themeable out of the box**: light/dark modes, brand colors, `ThemeProvider` and `useTheme` API
* **Type-safe and documented**: Excellent developer experience with TypeScript support
* **Composable and unopinionated**: No business logic; wire in your own data/state from WDK
* **Mobile-first**: React Native primitives with sensible defaults and accessible touch targets
***
## Installation
Install the UI Kit package:
```bash
npm install @tetherto/wdk-uikit-react-native
```
***
## Quickstart
Wrap your app with the theme provider and render a simple component:
```tsx title="Basic Setup"
import { ThemeProvider, lightTheme, TransactionList } from '@tetherto/wdk-uikit-react-native'
export default function App() {
const transactions = [ /* your transactions */ ]
return (
)
}
```
***
## Component List
| Component | Description |
| ------------------------------------- | -------------------------------------------------------------------- |
| [`AmountInput`](api-reference) | Numeric input with token/fiat toggle, balance helper and Max action |
| [`AssetSelector`](api-reference) | Token search & pick list with recent items and empty states |
| [`NetworkSelector`](api-reference) | Network picker with gas level indicators and colors |
| [`Balance`](api-reference) | Displays a balance value with optional masking and custom loader |
| [`CryptoAddressInput`](api-reference) | Address input with QR scan and paste helpers, validation state |
| [`QRCode`](api-reference) | QR renderer for addresses/payment requests with labeling and styling |
| [`TransactionItem`](api-reference) | Single transaction row (sent/received) with token, amounts, network |
| [`TransactionList`](api-reference) | Virtualized list of transactions using `TransactionItem` |
| [`SeedPhrase`](api-reference) | Grid of seed words with optional editing and loading states |
***
## Integration with WDK
Components are designed to work seamlessly with the WDK React Native Core. Here's an example of how to wire WDK data into the UI components:
```tsx title="WDK Integration Example"
import * as React from 'react'
import { useWdkApp, useBalance, BaseAsset } from '@tetherto/wdk-react-native-core'
import {
ThemeProvider,
lightTheme,
Balance,
CryptoAddressInput,
AmountInput
} from '@tetherto/wdk-uikit-react-native'
const usdt = new BaseAsset({
id: 'usdt-ethereum',
network: 'ethereum',
symbol: 'USDT',
name: 'Tether USD',
decimals: 6,
isNative: false,
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
})
export function SendScreen() {
const { state } = useWdkApp()
const { data: usdtBalance } = useBalance(0, usdt)
const [amount, setAmount] = React.useState('')
const [address, setAddress] = React.useState('')
if (state.status !== 'READY') {
return Loading...
}
return (
{/* Handle QR scan */}}
/>
{/* Toggle fiat/token */}}
onUseMax={() => setAmount(usdtBalance?.balance ?? '0')}
/>
)
}
```
***
## Theming
The UI Kit provides a comprehensive theming system that allows you to use built-in light and dark themes, create custom brand themes from your colors and fonts, customize individual components with fine-grained control, and access theme values anywhere in your application. You can also switch themes dynamically based on user preferences.
For detailed theming documentation, including brand integration, custom themes, component customization, and advanced usage patterns, see the [Theming Guide](theming).
***
## Common Patterns
### Address Input with Validation
```tsx title="Address Input Pattern"
import { CryptoAddressInput } from '@tetherto/wdk-uikit-react-native'
export function SendScreen() {
const [address, setAddress] = React.useState('')
const [error, setError] = React.useState('')
const validateAddress = (addr: string) => {
// Add your validation logic
if (!addr.startsWith('T') && !addr.startsWith('0x')) {
setError('Invalid address format')
} else {
setError('')
}
}
return (
{
setAddress(text)
validateAddress(text)
}}
error={error}
onQRScan={() => {/* Open QR scanner */}}
/>
)
}
```
***
## Next Steps
* [Components List](./api-reference) - Complete API Reference for all components
* [Theming Guide](./theming) - Deep dive into theming capabilities
* [React Native Starter](../../start-building/react-native-quickstart) - See a complete implementation
***
## Need Help?
# React Native UI Kit (/ui-kits/react-native-ui-kit)
The WDK React Native UI Kit provides ready-made, themeable components for building wallet applications.
**[Get Started →](get-started)**
# Theming (/ui-kits/react-native-ui-kit/theming)
The WDK React Native UI Kit provides a theming system that allows you to:
* **Use built-in themes** for quick setup with light and dark modes
* **Create brand themes** from your brand colors and fonts
* **Customize individual components** with fine-grained control
* **Access theme values** anywhere in your application
* **Switch themes dynamically** based on user preferences
***
## Basic Setup
Wrap your app with the `ThemeProvider` to enable theming:
```tsx title="Basic Theme Setup"
import { ThemeProvider, lightTheme } from '@tetherto/wdk-uikit-react-native'
function App() {
return (
{/* Your app content */}
)
}
```
The UI Kit comes with two built-in themes:
```tsx
import { ThemeProvider, lightTheme, darkTheme } from '@tetherto/wdk-uikit-react-native'
// Light theme
{/* Your app */}
// Dark theme
{/* Your app */}
```
***
**Manual Theme Control**
```tsx title="Manual Theme Toggle"
import { useTheme } from '@tetherto/wdk-uikit-react-native'
function ThemeToggle() {
const { mode, setMode } = useTheme()
return (
setMode(mode === 'dark' ? 'light' : 'dark')}>
Toggle Theme
)
}
```
***
## Custom Themes
### Brand Themes
Apply your brand colors and fonts using `createThemeFromBrand`:
```tsx title="Brand Theme Creation"
import { ThemeProvider, createThemeFromBrand } from '@tetherto/wdk-uikit-react-native'
const brandTheme = createThemeFromBrand({
primaryColor: '#007AFF',
secondaryColor: '#FF3B30',
fontFamily: {
regular: 'Inter-Regular',
bold: 'Inter-Bold',
},
}, 'light')
{/* Your branded app */}
```
**BrandConfig Interface**
```typescript title="BrandConfig Type"
type BrandConfig = {
primaryColor: string
secondaryColor?: string
fontFamily?: {
regular?: string
medium?: string
semiBold?: string
bold?: string
}
}
```
### Custom Theme
Create a completely custom theme with full control over all design tokens:
```tsx title="Custom Theme"
import { ThemeProvider } from '@tetherto/wdk-uikit-react-native'
const myLightTheme = {
mode: 'light' as const,
colors: {
primary: '#007AFF',
primaryLight: '#4DA6FF',
primaryDark: '#0056CC',
onPrimary: '#FFFFFF',
secondary: '#FF3B30',
secondaryLight: '#FF6B60',
secondaryDark: '#CC2F26',
background: '#FFFFFF',
surface: '#F9FAFB',
surfaceVariant: '#F3F4F6',
surfaceElevated: '#E5E7EB',
text: '#111827',
textSecondary: '#6B7280',
textDisabled: '#9CA3AF',
border: '#E5E7EB',
borderLight: '#F3F4F6',
error: '#EF4444',
warning: '#F59E0B',
success: '#10B981',
info: '#3B82F6',
},
typography: {
fontFamily: {
regular: 'System',
medium: 'System',
semiBold: 'System',
bold: 'System'
},
fontSize: {
xs: 10, sm: 12, base: 14, md: 16, lg: 18, xl: 20, xxl: 24, xxxl: 30
},
fontWeight: {
regular: '400', medium: '500', semiBold: '600', bold: '700'
},
},
spacing: {
xs: 4, sm: 8, base: 12, md: 16, lg: 24, xl: 32, xxl: 48, xxxl: 64
},
borderRadius: {
none: 0, sm: 4, md: 8, lg: 16, xl: 24, xxl: 32, full: 9999
},
}
{/* Your app */}
```
**Theme Interface**
```typescript title="Theme Type"
type Theme = {
mode: 'light' | 'dark' | 'auto'
colors: ColorPalette
typography: Typography
spacing: Spacing
borderRadius: BorderRadius
componentVariants?: ComponentVariant
componentOverrides?: ComponentOverrides
}
```
***
## Component Customization
You can customize the components with fine-grained control.
Fine-grained style overrides for specific component parts:
```tsx title="Component Overrides"
{/* Your app */}
```
Set default visual variants per component:
```tsx title="Component Variants"
const customTheme = {
...lightTheme,
componentVariants: {
'AmountInput.default': { /* variant styles */ },
'TransactionItem.compact': { /* variant styles */ }
}
}
```
***
## Using Theme Anywhere
Access theme values anywhere in your components:
**useTheme Hook**
```tsx title="useTheme Hook"
import { useTheme } from '@tetherto/wdk-uikit-react-native'
function MyComponent() {
const { theme } = useTheme()
return (
Hello World
)
}
```
***
## Theme Structure
### Color Palette
The theming system uses semantic naming for colors:
| Token | Purpose |
| ------------------------ | -------------------------------- |
| `colors.primary` | Primary brand color |
| `colors.primaryLight` | Light variant of primary |
| `colors.primaryDark` | Dark variant of primary |
| `colors.onPrimary` | Text color on primary background |
| `colors.secondary` | Secondary brand color |
| `colors.secondaryLight` | Light variant of secondary |
| `colors.secondaryDark` | Dark variant of secondary |
| `colors.background` | Main background color |
| `colors.surface` | Card/container background |
| `colors.surfaceVariant` | Alternative surface color |
| `colors.surfaceElevated` | Elevated surface color |
| `colors.text` | Primary text color |
| `colors.textSecondary` | Secondary text color |
| `colors.textDisabled` | Disabled text color |
| `colors.border` | Border color |
| `colors.borderLight` | Light border color |
| `colors.error` | Error state color |
| `colors.warning` | Warning state color |
| `colors.success` | Success state color |
| `colors.info` | Info state color |
### Typography
| Token | Purpose |
| -------------------------------- | ----------------------------- |
| `typography.fontFamily.regular` | Regular font family |
| `typography.fontFamily.medium` | Medium font family |
| `typography.fontFamily.semiBold` | Semi-bold font family |
| `typography.fontFamily.bold` | Bold font family |
| `typography.fontSize.xs` | Extra small font size (10px) |
| `typography.fontSize.sm` | Small font size (12px) |
| `typography.fontSize.base` | Base font size (14px) |
| `typography.fontSize.md` | Medium font size (16px) |
| `typography.fontSize.lg` | Large font size (18px) |
| `typography.fontSize.xl` | Extra large font size (20px) |
| `typography.fontSize.xxl` | 2X large font size (24px) |
| `typography.fontSize.xxxl` | 3X large font size (30px) |
| `typography.fontWeight.regular` | Regular font weight ('400') |
| `typography.fontWeight.medium` | Medium font weight ('500') |
| `typography.fontWeight.semiBold` | Semi-bold font weight ('600') |
| `typography.fontWeight.bold` | Bold font weight ('700') |
### Spacing
| Token | Purpose |
| -------------- | -------------------------- |
| `spacing.xs` | Extra small spacing (4px) |
| `spacing.sm` | Small spacing (8px) |
| `spacing.base` | Base spacing (12px) |
| `spacing.md` | Medium spacing (16px) |
| `spacing.lg` | Large spacing (24px) |
| `spacing.xl` | Extra large spacing (32px) |
| `spacing.xxl` | 2X large spacing (48px) |
| `spacing.xxxl` | 3X large spacing (64px) |
### Border Radius
| Token | Purpose |
| ------------------- | -------------------------------- |
| `borderRadius.none` | No border radius (0px) |
| `borderRadius.sm` | Small border radius (4px) |
| `borderRadius.md` | Medium border radius (8px) |
| `borderRadius.lg` | Large border radius (16px) |
| `borderRadius.xl` | Extra large border radius (24px) |
| `borderRadius.xxl` | 2X large border radius (32px) |
| `borderRadius.full` | Full border radius (9999px) |
***
## Advanced Usage
**Dynamic Theme Updates**
Update themes dynamically at runtime:
```tsx title="Dynamic Theme Updates"
function Settings() {
const { setBrandConfig, setComponentOverrides } = useTheme()
const updateBrand = () => {
setBrandConfig({
primaryColor: '#FF6501',
})
}
const customizeTransactions = () => {
setComponentOverrides({
TransactionItem: {
container: {
backgroundColor: 'rgba(255, 101, 1, 0.1)',
},
},
})
}
return (
<>
Update Brand
Customize Transactions
>
)
}
```
## Next Steps
* [Get Started](get-started) - Quick start guide for the UI Kit
* [Components List](api-reference) - Complete API Reference for all components
* [React Native Quickstart](../../start-building/react-native-quickstart) - See theming in action
***
## Need Help?
# Failover Provider API Reference (/tools/failover-provider/api-reference)
# API Reference
## Package: `@tetherto/wdk-failover-provider`
### Class: `FailoverProvider\`
`FailoverProvider\` collects provider candidates of one shared shape and returns a proxied `T` that retries failed calls against the next provider.
#### Constructor
Use the constructor to set retry behavior before you add provider candidates:
```javascript title="Create A FailoverProvider Factory"
new FailoverProvider({
retries, // optional, defaults to 3
shouldRetryOn // optional, defaults to (error) => error instanceof Error
})
```
* `retries` (`number`, optional): Number of additional attempts after the first failure. Total attempts are `1 + retries`.
* `shouldRetryOn` (`(error: Error) =\> boolean`, optional): Predicate that decides whether the proxy should switch to the next provider after a failure.
#### Methods
| Method | Description | Returns |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `addProvider(provider)` | Register one provider candidate and return the same factory so you can chain more candidates. | `FailoverProvider\` |
| `initialize()` | Return a proxied provider of type `T` that reads from the active provider and retries failed calls against the next provider. | `T` |
#### `addProvider(provider)`
Register a provider candidate. Every candidate should satisfy the same `T` shape because `initialize()` returns one proxied `T`.
```javascript title="Register A Provider Candidate"
const factory = new FailoverProvider({ retries: 1 })
factory.addProvider({
name: 'primary',
async getBlockNumber () {
return 21345678
}
})
```
#### `initialize()`
Create the failover-enabled proxy after you have added at least one provider. The runtime throws if the factory is still empty.
```javascript title="Initialize The Failover Proxy"
const provider = new FailoverProvider({ retries: 1 })
.addProvider(primary)
.addProvider(secondary)
.initialize()
const blockNumber = await provider.getBlockNumber()
```
#### `FailoverProviderConfig`
The package exports the `FailoverProviderConfig` type through its top-level type surface.
| Field | Description |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| `retries?` | Additional retry attempts after the first failure. Defaults to `3`. |
| `shouldRetryOn?` | Retry predicate for thrown errors and rejected promises. Defaults to retrying any `Error` instance. |
## Runtime behavior
* `initialize()` returns a JavaScript `Proxy` over the first added provider.
* Non-function properties are forwarded from the currently active provider.
* If a property getter throws and `shouldRetryOn(error)` returns `true`, the runtime advances to the next provider before retrying the property access.
* If a synchronous method throws and `shouldRetryOn(error)` returns `true`, the runtime advances to the next provider and retries the method call.
* If an asynchronous method rejects and `shouldRetryOn(error)` returns `true`, the runtime advances to the next provider and retries the method call.
* Provider switching is round-robin. If the active provider already changed while another call was failing, the runtime keeps the newer active provider instead of advancing twice.
## Example
This example shows a transient failure on the first provider and a successful retry on the second provider:
```javascript title="Retry Across Two Providers"
import FailoverProvider from '@tetherto/wdk-failover-provider'
const primary = {
async getBlockNumber () {
throw new Error('temporary upstream outage')
}
}
const secondary = {
async getBlockNumber () {
return 21345678
}
}
const provider = new FailoverProvider({
retries: 1,
shouldRetryOn: (error) => error.message.includes('temporary')
})
.addProvider(primary)
.addProvider(secondary)
.initialize()
const blockNumber = await provider.getBlockNumber()
```
***
## Need Help?
# Failover Provider Configuration (/tools/failover-provider/configuration)
This page shows how to install `@tetherto/wdk-failover-provider`, configure `retries` and `shouldRetryOn`, and build a proxied provider with `addProvider()` and `initialize()`.
## Install the package
You can install the package from npm:
```bash title="Install @tetherto/wdk-failover-provider"
npm install @tetherto/wdk-failover-provider
```
## Create a failover provider
You can wrap any provider-like object type. This example uses plain objects so the retry behavior is easy to see:
```javascript title="Create A Failover Provider"
import FailoverProvider from '@tetherto/wdk-failover-provider'
const primary = {
name: 'primary',
async getBlockNumber () {
throw new Error('temporary upstream outage')
}
}
const secondary = {
name: 'secondary',
async getBlockNumber () {
return 21345678
}
}
const provider = new FailoverProvider({
retries: 1,
shouldRetryOn: (error) => error.message.includes('temporary')
})
.addProvider(primary)
.addProvider(secondary)
.initialize()
```
## Configuration options
### `retries`
`retries` controls how many additional attempts happen after the first failure. The published runtime defaults to `3`, which means a call can make up to `1 + retries` total attempts before the latest error is thrown.
### `shouldRetryOn`
`shouldRetryOn(error)` decides whether a thrown error or rejected promise should advance to the next provider. The published default retries on any `Error` instance.
Use a narrow predicate when you only want to retry transient failures:
```javascript title="Retry Only On Transient Errors"
const provider = new FailoverProvider({
retries: 2,
shouldRetryOn: (error) => /timeout|temporary|429/.test(error.message)
})
```
## Register provider candidates
Call `addProvider(provider)` once per candidate before you call `initialize()`. `addProvider()` returns the same `FailoverProvider` instance, so you can chain the calls.
The generic type `T` applies to every added candidate, so keep the provider shape consistent across the chain.
```javascript title="Add Multiple Provider Candidates"
const provider = new FailoverProvider({ retries: 2 })
.addProvider(primary)
.addProvider(secondary)
.addProvider({
name: 'tertiary',
async getBlockNumber () {
return 21345679
}
})
.initialize()
```
## Initialize the proxy
Call `initialize()` after you have added at least one provider. The returned value is a proxied provider of type `T`.
The runtime throws if you call `initialize()` before adding any providers:
```javascript title="Initialize Requires At Least One Provider"
const factory = new FailoverProvider()
factory.initialize()
// Error: Cannot initialize an empty provider. Call `addProvider` before this function.
```
## Runtime notes
* Non-function properties are read from the currently active provider.
* When a synchronous method throws and `shouldRetryOn(error)` returns `true`, the proxy switches to the next provider and retries.
* When an asynchronous method rejects and `shouldRetryOn(error)` returns `true`, the proxy switches to the next provider and retries.
* Provider selection advances in round-robin order. If `retries` is larger than the number of providers, the runtime loops back through the list.
***
## Need Help?
# Failover Provider (/tools/failover-provider)
Failover Provider wraps multiple provider-like objects behind one proxy so your integration can retry failed calls against the next candidate without rewriting each call site. Use this page to review the [Configuration](./configuration) and [API Reference](./api-reference) for the released `@tetherto/wdk-failover-provider` surface.
Powered by [`@tetherto/wdk-failover-provider`](https://github.com/tetherto/wdk-failover-provider).
## Features
* **Generic provider wrapper**: `FailoverProvider\` accepts any provider-like object type and returns a proxied `T` from `initialize()`.
* **Configurable retries**: Set `retries` to control how many additional attempts happen after the first failure.
* **Retry predicate**: Use `shouldRetryOn(error)` to decide which errors should advance to the next provider.
* **Sync and async failover**: The runtime retries both synchronous throws and rejected promises.
* **Zero runtime dependencies**: The published package ships a single default export with no runtime dependency tree.
## Why this matters
* You can keep one provider-shaped integration surface while rotating between browser, JSON-RPC, or custom provider implementations.
* You can narrow failover behavior to transient errors instead of retrying every exception.
* You can add redundancy to read-heavy or submission-heavy flows without building your own retry proxy.
Install the package, add provider candidates, and tune retry behavior.
Review `FailoverProvider`, its config, and the proxied runtime behavior.
***
## Need Help?
# Pear Worklet WDK API Reference (/tools/pear-wrk-wdk/api-reference)
## Package: `@tetherto/pear-wrk-wdk`
### Export: `HRPC`
#### Command Methods
| Method | Signature | Description |
| --------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `log()` | `log(args: LogRequest): void` | Sends a log payload over the HRPC stream. |
| `workletStart()` | `workletStart(args: WorkletStartRequest): Promise\` | Deprecated worklet startup request. Prefer `initializeWDK()`. |
| `initializeWDK()` | `initializeWDK(args: WdkInitializeParams): Promise\<{ status: string }\>` | Creates or reinitializes the worklet WDK instance and registers wallets and optional protocols from `config`. |
| `resetWdkWallets()` | `resetWdkWallets(args: WdkResetWalletParams): Promise\<{ status: string }\>` | Selectively disposes and re-registers only the wallets listed in `config.networks`. |
| `generateEntropyAndEncrypt()` | `generateEntropyAndEncrypt(args: WdkGenerateEntropyParams): Promise\` | Generates encrypted seed and entropy buffers inside the worklet. |
| `getMnemonicFromEntropy()` | `getMnemonicFromEntropy(args: WdkGetMnemonicParams): Promise\<{ mnemonic: string }\>` | Decrypts an encrypted entropy payload and returns the mnemonic. |
| `getSeedAndEntropyFromMnemonic()` | `getSeedAndEntropyFromMnemonic(args: { mnemonic: string }): Promise\` | Converts a mnemonic into encrypted seed and entropy buffers. |
| `dispose()` | `dispose(args: DisposeRequest): void` | Disposes the worklet WDK instance. |
| `callMethod()` | `callMethod(args: CallMethodRequest): Promise\` | Looks up the target account and invokes one wallet or protocol method by name. |
| `registerWallet()` | `registerWallet(args: { config: string }): Promise\<{ status: string, blockchains: string }\>` | Dynamically registers additional wallets from a JSON config string. |
| `registerProtocol()` | `registerProtocol(args: { config: string }): Promise\<{ status: string }\>` | Dynamically registers additional protocols from a JSON config string. |
#### Handler Registration Methods
| Method | Signature | Description |
| ----------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------- |
| `onLog()` | `onLog(responseFn): void` | Registers the server-side handler for `log()`. |
| `onWorkletStart()` | `onWorkletStart(responseFn): void` | Registers the server-side handler for `workletStart()`. |
| `onInitializeWDK()` | `onInitializeWDK(responseFn): void` | Registers the server-side handler for `initializeWDK()`. |
| `onResetWdkWallets()` | `onResetWdkWallets(responseFn): void` | Registers the server-side handler for `resetWdkWallets()`. |
| `onGenerateEntropyAndEncrypt()` | `onGenerateEntropyAndEncrypt(responseFn): void` | Registers the server-side handler for encrypted entropy generation. |
| `onGetMnemonicFromEntropy()` | `onGetMnemonicFromEntropy(responseFn): void` | Registers the server-side handler for mnemonic recovery. |
| `onGetSeedAndEntropyFromMnemonic()` | `onGetSeedAndEntropyFromMnemonic(responseFn): void` | Registers the server-side handler for mnemonic migration. |
| `onDispose()` | `onDispose(responseFn): void` | Registers the server-side handler for `dispose()`. |
| `onCallMethod()` | `onCallMethod(responseFn): void` | Registers the server-side handler for `callMethod()`. |
| `onRegisterWallet()` | `onRegisterWallet(responseFn): void` | Registers the server-side handler for `registerWallet()`. |
| `onRegisterProtocol()` | `onRegisterProtocol(responseFn): void` | Registers the server-side handler for `registerProtocol()`. |
#### `log`
* `type?` (`LogType`): Optional numeric log level.
* `data?` (`string | null`): Optional log payload.
#### `workletStart`
Deprecated startup request retained in the shipped type surface.
* `enableDebugLogs?` (`number`)
* `seedPhrase?` (`string | null`)
* `seedBuffer?` (`string | null`)
* `config` (`string`): JSON string of network configurations.
Returns:
* `status?` (`string | null`)
#### `initializeWDK`
* `encryptionKey?` (`string`): Base64-encoded decryption key for the encrypted seed buffer.
* `encryptedSeed?` (`string`): Base64-encoded encrypted seed buffer.
* `config` (`string`): JSON stringified `WdkWorkletConfig`.
The handler requires `encryptionKey` and `encryptedSeed` to be passed together or omitted together. When a seeded WDK instance already exists, the runtime disposes it before re-registering the wallets and optional protocols in `config`.
#### `resetWdkWallets`
* `config` (`string`): JSON stringified object containing a `networks` map.
The runtime validates `config.networks`, extracts each target `blockchain`, calls `wdk.dispose(targetChains)`, and re-registers only those wallet managers. This method does not re-register protocols.
#### `generateEntropyAndEncrypt`
* `wordCount` (`12 | 24`): The mnemonic word count to generate.
Returns:
* `encryptionKey` (`string`)
* `encryptedSeedBuffer` (`string`)
* `encryptedEntropyBuffer` (`string`)
#### `getMnemonicFromEntropy`
* `encryptedEntropy` (`string`): Base64-encoded encrypted entropy buffer.
* `encryptionKey` (`string`): Base64-encoded decryption key.
Returns:
* `mnemonic` (`string`)
#### `getSeedAndEntropyFromMnemonic`
* `mnemonic` (`string`): Source mnemonic to migrate into encrypted buffers.
Returns:
* `encryptionKey` (`string`)
* `encryptedSeedBuffer` (`string`)
* `encryptedEntropyBuffer` (`string`)
#### `dispose`
* `args` (`DisposeRequest`): Empty request object.
#### `callMethod`
* `methodName` (`string`): Account method to invoke.
* `network` (`string`): Target blockchain key used to resolve the account.
* `accountIndex` (`number`): Account index passed to `wdk.getAccount(network, accountIndex)`.
* `args?` (`string`): JSON string of the method arguments.
* `options?` (`string`): JSON string of `CallMethodOptions`.
`options.protocolType` may be `swap`, `bridge`, `lending`, or `fiat`. When present, the runtime resolves the protocol-specific account wrapper before invoking `methodName`.
#### `registerWallet`
* `config` (`string`): JSON string of network config entries.
Returns:
* `status` (`string`)
* `blockchains` (`string`): JSON stringified array of registered blockchain names.
#### `registerProtocol`
* `config` (`string`): JSON string of protocol config entries.
Returns:
* `status` (`string`)
#### `onLog`
Registers the server-side handler used to service `log()` requests.
#### `onWorkletStart`
Registers the server-side handler used to service the deprecated `workletStart()` request.
#### `onInitializeWDK`
Registers the server-side handler used to service `initializeWDK()` requests on the worklet side.
#### `onResetWdkWallets`
Registers the server-side handler used to service `resetWdkWallets()` requests on the worklet side.
#### `onGenerateEntropyAndEncrypt`
Registers the server-side handler used to service encrypted entropy generation requests.
#### `onGetMnemonicFromEntropy`
Registers the server-side handler used to service mnemonic recovery requests.
#### `onGetSeedAndEntropyFromMnemonic`
Registers the server-side handler used to service mnemonic migration requests.
#### `onDispose`
Registers the server-side handler used to service `dispose()` requests.
#### `onCallMethod`
Registers the server-side handler used to service `callMethod()` requests.
#### `onRegisterWallet`
Registers the server-side handler used to service `registerWallet()` requests.
#### `onRegisterProtocol`
Registers the server-side handler used to service `registerProtocol()` requests.
### Export: `registerRpcHandlers(rpc, context)`
Registers the package's server-side handlers on the provided RPC instance.
* `rpc` (`any`): RPC server instance that supports the generated handler registration methods.
* `context` (`RpcContext`): Runtime context containing `wdk`, `WDK`, `walletManagers`, `protocolManagers`, and `wdkLoadError`.
### Types
#### `WdkWorkletConfig`
```ts
interface WdkWorkletConfig {
networks: {
[blockchain: string]: {
blockchain: string
config: unknown
}
}
protocols?: {
[protocolName: string]: {
blockchain: string
protocolName: string
config: unknown
}
}
}
```
#### `WdkResetWalletParams`
```ts
interface WdkResetWalletParams {
config: string
}
```
#### `CallMethodOptions`
```ts
interface CallMethodOptions {
transformResult: Function
defaultValue: any
protocolType: 'swap' | 'bridge' | 'lending' | 'fiat'
protocolName: string
}
```
***
## Need Help?
# Pear Worklet WDK Configuration (/tools/pear-wrk-wdk/configuration)
This page explains how to [build the worklet context](#worklet-context), [shape the worklet config payload](#worklet-config-payload), [initialize-wdk](#initialize-wdk), and [reset-selected-wallets](#reset-selected-wallets).
## Worklet Context
You can bind the shipped RPC handlers to your Bare worklet using `registerRpcHandlers()`:
```javascript title="Register RPC Handlers"
const { registerRpcHandlers } = require('@tetherto/pear-wrk-wdk/worklet')
const { WDK } = require('@tetherto/wdk')
const EvmWalletManager = require('@tetherto/wdk-wallet-evm')
const SparkWalletManager = require('@tetherto/wdk-wallet-spark')
const context = {
wdk: null,
WDK,
walletManagers: {
ethereum: EvmWalletManager,
spark: SparkWalletManager
},
protocolManagers: {},
wdkLoadError: null
}
module.exports = (rpc) => {
registerRpcHandlers(rpc, context)
}
```
### Required Context Fields
* `wdk`: The current WDK instance. Set this to `null` before the first initialization.
* `WDK`: The WDK constructor used to create the seeded instance.
* `walletManagers`: A map from blockchain name to wallet manager implementation.
* `protocolManagers`: A map from protocol name to protocol manager implementation.
* `wdkLoadError`: Any startup error captured while loading WDK. Use `null` when there is no load failure.
## Worklet Config Payload
Both [`initializeWDK()`](./api-reference) and [`resetWdkWallets()`](./api-reference) expect `config` to be a JSON string. The decoded object must contain at least one entry under `networks`.
```javascript title="Minimal Worklet Config JSON"
const workletConfig = {
networks: {
ethereum: {
blockchain: 'ethereum',
config: {
provider: 'https://rpc.ankr.com/eth_sepolia'
}
}
},
protocols: {
moonpay: {
blockchain: 'ethereum',
protocolName: 'moonpay',
config: {
environment: 'sandbox'
}
}
}
}
```
### Payload Rules
* `networks` is required and must contain at least one network entry.
* Each network entry must include `blockchain` and an object `config`.
* `protocols` is optional during initialization.
* `resetWdkWallets()` reads only the `networks` portion of the decoded config.
## Initialize WDK
You can create and register the WDK instance inside the worklet using [`initializeWDK()`](./api-reference):
```javascript title="Initialize WDK"
const { HRPC } = require('@tetherto/pear-wrk-wdk')
const hrpc = new HRPC(ipcStream)
await hrpc.initializeWDK({
encryptionKey: secrets.encryptionKey,
encryptedSeed: secrets.encryptedSeedBuffer,
config: JSON.stringify(workletConfig)
})
```
### Initialization Rules
* Pass both `encryptionKey` and `encryptedSeed`, or omit both together.
* On first initialization, the worklet must receive an encrypted seed pair so it can create `context.wdk`.
* If `context.wdk` already exists, a later `initializeWDK()` call disposes the existing instance before re-registering wallets and protocols from the new config.
## Reset Selected Wallets
You can selectively dispose and re-register wallet modules using [`resetWdkWallets()`](./api-reference):
```javascript title="Reset Selected Wallet Modules"
await hrpc.resetWdkWallets({
config: JSON.stringify({
networks: {
ethereum: {
blockchain: 'ethereum',
config: {
provider: 'https://rpc.ankr.com/eth_sepolia'
}
}
}
})
})
```
### Reset Rules
* `resetWdkWallets()` requires an existing initialized `context.wdk`.
* The handler calls `wdk.dispose(targetChains)` with the blockchains extracted from `config.networks`.
* Only wallets listed in the request `networks` object are re-registered.
* The reset flow does not re-register protocols.
## Call Wallet Methods
You can execute wallet account methods through [`callMethod()`](./api-reference):
```javascript title="Call a Wallet Method"
const result = await hrpc.callMethod({
methodName: 'getAddress',
network: 'ethereum',
accountIndex: 0
})
```
### Call Method Notes
* `args` is optional and must be a JSON string when provided.
* `options` is optional and must be a JSON string when provided.
* When `args` decodes to an array, the handler spreads the values as positional method arguments.
* When `args` decodes to an object or primitive, the handler passes it as a single argument.
***
## Need Help?
# Pear Worklet WDK (/tools/pear-wrk-wdk)
Pear Worklet WDK is the low-level transport and handler layer for running WDK inside a Bare worklet. It provides the `HRPC` client, the `registerRpcHandlers()` server helper, and the typed request payloads needed to initialize WDK, call wallet methods, and reset selected wallet modules from the host app.
Powered by `@tetherto/pear-wrk-wdk`.
## Features
* **Bare worklet bridge**: Connect a host app to a worklet through the shipped `HRPC` client and generated HRPC schema
* **Typed lifecycle requests**: Initialize WDK with `initializeWDK({ config, encryptionKey, encryptedSeed })` and tear it down with `dispose()`
* **Selective wallet resets**: Re-register only the wallet modules listed in a new worklet `networks` config using `resetWdkWallets({ config })`
* **Generic wallet method calls**: Call account methods through `callMethod({ methodName, network, accountIndex, args, options })`
* **Dynamic registration hooks**: Register additional wallets or protocols with `registerWallet()` and `registerProtocol()`
## Why this matters
* You can keep WDK state and signing operations off the main thread in Bare-based apps
* You can reconfigure selected wallet modules without fully disposing the worklet
* You can use one transport layer across custom mobile, desktop, or embedded Bare integrations
Use this package when you need direct control over the worklet host and RPC layer. If you want generated worklet entry files instead, start with [`@tetherto/wdk-worklet-bundler`](https://github.com/tetherto/wdk-worklet-bundler).
Build the worklet context and pass the JSON config payloads used by initialize and reset requests
Review the exported class, server helper, and request shapes
***
## Need Help?
# API Reference (/tools/indexer-api/api-reference)
## Base URL
```text title="API Base URL"
https://wdk-api.tether.io
```
***
## Authentication
All requests require a valid API key in the `x-api-key` header:
```http title="Authentication Header"
x-api-key: your-api-key-here
```
**Don't have an API key yet?** Request one by following the steps in our [Get Started](get-started) guide.
***
## Rate Limiting
| Endpoint | Limit |
| --------------------------------------------------------- | --------------- |
| `GET /api/v1/health` | 10 req / 1 hour |
| `GET /api/v1/chains` | 60 req / 1 min |
| `GET /api/v1/:blockchain/:token/:address/token-balances` | 4 req / 10s |
| `GET /api/v1/:blockchain/:token/:address/token-transfers` | 8 req / 10s |
| `POST /api/v1/batch/token-transfers` | 8 req / 10s |
| `POST /api/v1/batch/token-balances` | 4 req / 10s |
***
## API Endpoints
### `GET /api/v1/health`
Check API server status
***
### `GET /api/v1/chains`
Get list of supported chains and tokens
***
### `GET /api/v1/{blockchain}/{token}/{address}/token-transfers`
Get token transfer history for an address
***
### `GET /api/v1/{blockchain}/{token}/{address}/token-balances`
Get current token balance for an address
***
### `POST /api/v1/batch/token-transfers`
Get batch token transfers for multiple addresses
***
### `POST /api/v1/batch/token-balances`
Get batch token balances for multiple addresses
***
## Error Handling
The API returns standard HTTP error codes:
| Status Code | Description |
| ----------- | --------------------------------------- |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid API key |
| 404 | Not Found - Resource not found |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error |
### Error Response Format
```json
{
"error": "error_type",
"message": "Detailed error message"
}
```
***
## Next Steps
* [**Get Started**](get-started) - Quick start guide with setup instructions
* [**React Native Starter**](../../examples-and-starters/react-native-starter) - See it in action
***
## Need Help?
# Get Started (/tools/indexer-api/get-started)
## Getting Started
#### Request API Key
Request your free API key to access the WDK Indexer API.
[Request API Key](https://wdk-api.tether.io/register)
#### Make Your First Request
Use your API key to query blockchain data via the REST API.
***
## Quick Example
Here's a quick example of how to query a token balance.
```bash
curl -X GET "https://wdk-api.tether.io/api/v1/ethereum/usdt/0xdac17f958d2ee523a2206206994597c13d831ec7/token-balances" \
-H "x-api-key: your-api-key-here"
```
```javascript
const axios = require('axios');
async function getTokenBalance(blockchain, token, address) {
const response = await axios.get(
`https://wdk-api.tether.io/api/v1/${blockchain}/${token}/${address}/token-balances`,
{
headers: {
'x-api-key': 'your-api-key-here'
}
}
);
return response.data.tokenBalance;
}
const balance = await getTokenBalance('ethereum', 'usdt', '0xdac17f958d2ee523a2206206994597c13d831ec7');
console.log(`Balance: ${balance.amount} ${balance.token.toUpperCase()}`);
```
**Want more info?** Check out the complete [API Reference](api-reference) for detailed method documentation, parameters, and response formats.
***
## Next Steps
* [**API Reference**](api-reference) - Complete method documentation with examples and response formats
***
## Need Help?
# Indexer API (/tools/indexer-api)
The WDK Indexer REST API provides fast, reliable access to balances, token transfers, and transaction history across multiple chains.
A blockchain indexer continuously monitors and organizes blockchain transactions, making them instantly searchable through a simple REST API.
[Get Started](./get-started)
## Supported Chains and Tokens
The WDK Indexer currently supports the following blockchain networks and tokens:
| Blockchain | Supported Tokens |
| ---------------- | ---------------- |
| Ethereum Mainnet | USD₮, XAU₮, USA₮ |
| TON | USD₮, XAU₮ |
| TRON | USD₮ |
| Arbitrum | USD₮ |
| Sepolia | USD₮ |
| Plasma | USD₮, XAU₮ |
| Polygon | USD₮ |
| Bitcoin | BTC |
| Spark | BTC |
To get the most up-to-date list of supported chains and their tokens, use the \[`/api/v1/chains`] endpoint.
**Need support for a new chain or token?** Submit a request using the form below and our team will review it.
[Request Chain / Token Support](https://forms.gle/ZsuLmGNemSVEvvoA9)
***
## Next Steps
Learn how to make your first API call
Endpoints, parameters, and responses
## Need Help?
# API Reference (/tools/price-rates/api-reference)
## Package: `@tetherto/wdk-pricing-bitfinex-http`
### Class: `BitfinexPricingClient`
Simple HTTP pricing client for Bitfinex Public REST API.
#### Constructor
```javascript title="Create Client"
new BitfinexPricingClient(options?)
```
* `options` (optional): reserved for future use
#### Methods
| Method | Description | Returns |
| ------------------------------------------------ | -------------------------------------------------------------- | ------------------- |
| `getCurrentPrice(base, quote)` | Fetch latest price for base/quote pair | `Promise\` |
| `getHistoricalPrice({ from, to, start?, end? })` | Fetch historical series (downscaled to ≤ 100 points if needed) | `Promise\` |
##### `getCurrentPrice(base, quote)`
```javascript title="Current Price"
const price = await client.getCurrentPrice('BTC', 'USD')
```
##### `getHistoricalPrice({ from, to, start?, end? })`
If the returned series exceeds 100 points, it is downscaled by powers of two until ≤ 100.
```javascript title="Historical Prices"
const series = await client.getHistoricalPrice({
from: 'BTC',
to: 'USD',
start: 1709906400000, // optional
end: 1709913600000 // optional
})
```
## Package: `@tetherto/wdk-pricing-provider`
### Class: `PricingProvider`
Cache-aware wrapper providing a unified API over a `PricingClient` implementation.
#### Constructor
```javascript title="Create Provider"
new PricingProvider({
client, // required: implements PricingClient
priceCacheDurationMs // optional: defaults to 1h
})
```
* `client`: instance implementing the `PricingClient` contract
* `priceCacheDurationMs` (number, optional): cache TTL for last price in ms (default 3,600,000)
#### Methods
| Method | Description | Returns |
| ------------------------------------------------ | ----------------------------------------------------- | ------------------- |
| `getLastPrice(base, quote)` | Returns cached last price; refreshes when TTL expires | `Promise\` |
| `getHistoricalPrice({ from, to, start?, end? })` | Delegates to client for historical data | `Promise\` |
##### `getLastPrice(base, quote)`
```javascript title="Last Price with Caching"
const provider = new PricingProvider({ client })
const last = await provider.getLastPrice('BTC', 'USD')
```
##### `getHistoricalPrice({ from, to, start?, end? })`
```javascript title="Historical via Provider"
const hist = await provider.getHistoricalPrice({ from: 'BTC', to: 'USD' })
```
### Interface: `PricingClient` (abstract)
Implement this interface to plug your data source into `PricingProvider`.
| Method | Signature | Notes |
| -------------------- | ----------------------------------------------------------------------------------------- | -------------------------- |
| `getCurrentPrice` | `(from: string, to: string) =\> Promise\` | Should return spot price |
| `getHistoricalPrice` | `(opts: { from: string, to: string, start?: number, end?: number }) =\> Promise\` | Return series for charting |
## Notes
* Uses Bitfinex Public HTTP API (`/v2/ticker` and `/v2/candles`) under the hood for the Bitfinex client
* Provider caches last price per pair using in-memory store and TTL
***
## Need Help?
# Configuration (/tools/price-rates/configuration)
## Bitfinex HTTP Client
```javascript title="Create Client"
import { BitfinexPricingClient } from '@tetherto/wdk-pricing-bitfinex-http'
// Create the client (no options needed)
const client = new BitfinexPricingClient()
```
### Current Price
```javascript title="Get Current Price"
const price = await client.getCurrentPrice('BTC', 'USD')
```
### Historical Series
Downscales long histories to ≤ 100 points.
```javascript title="Get Historical Prices"
const series = await client.getHistoricalPrice({
from: 'BTC',
to: 'USD',
start: 1709906400000, // optional (ms)
end: 1709913600000 // optional (ms)
})
```
## Provider Integration
Works with `@tetherto/wdk-pricing-provider` as a PricingClient implementation.
```javascript title="Wrap with PricingProvider"
import { PricingProvider } from '@tetherto/wdk-pricing-provider'
const provider = new PricingProvider({
client,
priceCacheDurationMs: 60 * 60 * 1000 // optional, defaults to 1h
})
const last = await provider.getLastPrice('BTC', 'USD')
const hist = await provider.getHistoricalPrice({ from: 'BTC', to: 'USD' })
```
***
## Need Help?
# Price Rates (/tools/price-rates)
Pricing utilities for WDK apps. Includes HTTP clients and providers to retrieve current and historical prices from supported services.
Powered by [`@tetherto/wdk-pricing-bitfinex-http`](https://github.com/tetherto/wdk-pricing-bitfinex-http) and compatible with [`@tetherto/wdk-pricing-provider`](https://github.com/tetherto/wdk-pricing-provider).
## Features
* **Current Prices**: Fetch latest price for a base/quote pair (e.g., BTC/USD)
* **Historical Series**: Retrieve historical price series; long histories optionally downscaled to ≤ 100 points
* **Provider Compatibility**: Works with `@tetherto/wdk-pricing-provider`
* **Lightweight HTTP Client**: Minimal dependencies; easy to integrate
## Why this matters
* Consistent pricing is required for balance valuations, charts, and quotes
* A unified client reduces integration time and data handling errors
Get started with WDK price clients
Check the API Reference and examples
***
## Need Help?
# API Reference (/tools/react-native-core/api-reference)
| Export | Type | Description |
| ----------------------------------------------- | --------- | ---------------------------------------------------- |
| [`WdkAppProvider`](#wdkappprovider) | Component | Root provider for WDK initialization |
| [`useWdkApp`](#usewdkapp) | Hook | App-level state (discriminated union) |
| [`useWalletManager`](#usewalletmanager) | Hook | Wallet lifecycle (create, restore, lock, unlock) |
| [`useAccount`](#useaccount) | Hook | Account operations (send, sign, verify, estimateFee) |
| [`useAddresses`](#useaddresses) | Hook | Load and query wallet addresses |
| [`useBalance`](#usebalance) | Hook | Single asset balance with TanStack Query |
| [`useBalancesForWallet`](#usebalancesforwallet) | Hook | Bulk balance fetch for multiple assets |
| [`useRefreshBalance`](#userefreshbalance) | Hook | Invalidate and refetch balances |
| [`BaseAsset`](#baseasset) | Class | Default `IAsset` implementation |
| [`validateMnemonic`](#validatemnemonic) | Utility | Validate BIP39 mnemonic phrases |
| [`balanceQueryKeys`](#balancequerykeys) | Utility | TanStack Query key factory |
| `WdkAppProviderProps` | Type | Props for `WdkAppProvider` |
| `WdkAppContextValue` | Type | Return type of `useWdkApp` |
| `UseAccountParams` | Type | Parameters for `useAccount` |
| `UseAccountReturn` | Type | Return type of `useAccount` |
| `UseAddressesReturn` | Type | Return type of `useAddresses` |
| `UseWalletManagerResult` | Type | Return type of `useWalletManager` |
***
## WdkAppProvider
The root provider component that orchestrates WDK initialization. Wraps your app with TanStack Query, Zustand stores, and the worklet runtime.
Must be placed at the root of your component tree. All hooks in this library require `WdkAppProvider` as an ancestor.
### Props
| Prop | Type | Default | Description |
| -------------------------------- | ------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `bundle` | [`BundleConfig`](#bundleconfig) | **required** | Worklet bundle configuration |
| `wdkConfigs` | [`WdkConfigs`](#wdkconfigs) | **required** | Network and protocol configurations |
| `enableAutoInitialization` | `boolean` | `true` | Enable automatic wallet initialization on app restart |
| `requireBiometrics` | `boolean` | `true` | Require biometric authentication for wallet operations |
| `currentUserId` | `string \| null` | `undefined` | Current user's identifier (typically email). Auto-initialization waits until this is set and matches the active wallet |
| `clearSensitiveDataOnBackground` | `boolean` | `false` | Clear sensitive data when app goes to background. When enabled, biometric auth is required on every app foreground |
| `children` | `React.ReactNode` | **required** | Child components |
### Example
```tsx
import { WdkAppProvider } from '@tetherto/wdk-react-native-core'
import { bundle } from './.wdk'
const wdkConfigs = {
networks: {
ethereum: {
blockchain: 'ethereum',
config: {
chainId: 1,
provider: 'https://eth.drpc.org',
},
},
},
}
export default function App() {
return (
)
}
```
***
## useWdkApp
Hook to access app-level state. Returns a discriminated union representing the current state of the WDK lifecycle.
Must be used within `WdkAppProvider`.
### Returns
| Property | Type | Description |
| -------- | ----------------------------- | --------------------------------------- |
| `state` | [`WdkAppState`](#wdkappstate) | Current app state (discriminated union) |
| `retry` | `() => void` | Retry initialization after an error |
### WdkAppState
The `state` property is a discriminated union on the `status` field:
| Status | Additional Fields | Description |
| ---------------- | ------------------ | --------------------------------------------------------- |
| `'INITIALIZING'` | - | Worklet is starting or wallet is loading |
| `'NO_WALLET'` | - | Worklet is ready, no wallet has been created |
| `'LOCKED'` | `walletId: string` | A wallet exists but is locked (requires biometric unlock) |
| `'READY'` | `walletId: string` | Wallet is unlocked and ready for operations |
| `'ERROR'` | `error: Error` | Initialization failed |
### Example
```tsx
import { useWdkApp, useWalletManager } from '@tetherto/wdk-react-native-core'
function AppRouter() {
const { state, retry } = useWdkApp()
const { createWallet, unlock } = useWalletManager()
switch (state.status) {
case 'INITIALIZING':
return
case 'NO_WALLET':
return createWallet('user@example.com')} />
case 'LOCKED':
return unlock(state.walletId)} />
case 'READY':
return
case 'ERROR':
return
}
}
```
***
## useWalletManager
Hook for wallet lifecycle operations: create, restore, lock, unlock, delete, and manage wallets.
### Returns
| Property | Type | Description |
| ----------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `activeWalletId` | `string \| null` | Currently active wallet identifier |
| `status` | `'LOCKED' \| 'UNLOCKED' \| 'NO_WALLET' \| 'LOADING' \| 'ERROR'` | Current wallet status |
| `wallets` | [`WalletInfo[]`](#walletinfo) | List of wallets managed by the device |
| `createWallet` | `(walletId: string) => Promise` | Create a new wallet with biometric-protected storage |
| `restoreWallet` | `(mnemonic: string, walletId: string) => Promise` | Restore a wallet from a seed phrase. Returns the wallet ID |
| `deleteWallet` | `(walletId: string) => Promise` | Delete a wallet and all associated data |
| `lock` | `() => void` | Lock the wallet - clears sensitive data from memory and stops the worklet |
| `unlock` | `(walletId?: string) => Promise` | Unlock a wallet (triggers biometric prompt) |
| `generateMnemonic` | `(wordCount?: 12 \| 24) => Promise` | Generate a new BIP39 mnemonic phrase |
| `getMnemonic` | `(walletId: string) => Promise` | Get mnemonic from wallet (requires biometric auth) |
| `createTemporaryWallet` | `(walletId: string, mnemonic?: string) => Promise` | Create an in-memory wallet for previewing addresses. Returns the temporary wallet ID |
| `clearTemporaryWallet` | `() => void` | Clear the temporary wallet session |
| `setActiveWalletId` | `(walletId: string) => void` | Set the active wallet (triggers loading) |
| `clearCache` | `() => void` | Clear cached balance data |
#### Advanced Crypto Methods
These methods provide lower-level access to wallet cryptographic operations. Most apps won't need these directly.
| Property | Type | Description |
| ------------------------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `getEncryptionKey` | `(walletId: string) => Promise` | Get encryption key (requires biometric auth) |
| `getEncryptedSeed` | `(walletId: string) => Promise` | Get encrypted seed from storage |
| `getEncryptedEntropy` | `(walletId: string) => Promise` | Get encrypted entropy from storage |
| `generateEntropyAndEncrypt` | `(wordCount?: 12 \| 24) => Promise<{ encryptionKey, encryptedSeedBuffer, encryptedEntropyBuffer }>` | Generate and encrypt entropy for wallet creation |
| `getMnemonicFromEntropy` | `(encryptedEntropy: string, encryptionKey: string) => Promise<{ mnemonic: string }>` | Derive mnemonic from encrypted entropy |
| `getSeedAndEntropyFromMnemonic` | `(mnemonic: string) => Promise<{ encryptionKey, encryptedSeedBuffer, encryptedEntropyBuffer }>` | Get encrypted seed and entropy from a mnemonic phrase |
### Example
```tsx
import { useWalletManager } from '@tetherto/wdk-react-native-core'
function OnboardingScreen() {
const { createWallet, restoreWallet, generateMnemonic } = useWalletManager()
const handleCreate = async () => {
await createWallet('user@example.com')
}
const handleRestore = async (mnemonic: string) => {
await restoreWallet(mnemonic, 'user@example.com')
}
const handlePreview = async () => {
const mnemonic = await generateMnemonic(12)
console.log('Generated mnemonic:', mnemonic)
}
return (
)
}
```
***
## useAccount
Hook to interact with a specific blockchain account. Always returns an object - check `address` or `account` for readiness.
### Parameters
| Parameter | Type | Description |
| --------------------- | -------- | -------------------------------------------------------------- |
| `params.network` | `string` | Network identifier (e.g., `'ethereum'`, `'bitcoin'`, `'tron'`) |
| `params.accountIndex` | `number` | Account index (0-based, following BIP-44 derivation) |
### Returns `UseAccountReturn`
| Property | Type | Description |
| ------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `address` | `string \| null` | The derived public address (`null` if not loaded yet) |
| `isLoading` | `boolean` | `true` if the account address is being derived |
| `error` | `Error \| null` | Error if address derivation failed |
| `account` | `{ accountIndex, network, walletId } \| null` | Account identifier (`null` if no active wallet or address not loaded) |
| `getBalance` | `(tokens: IAsset[]) => Promise` | Fetch balances directly from the network (no cache) |
| `send` | `(params: TransactionParams) => Promise` | Send a transaction (native or token transfer) |
| `sign` | `(message: string) => Promise` | Sign a UTF-8 message with the account's private key |
| `verify` | `(message: string, signature: string) => Promise` | Verify a signature |
| `estimateFee` | `(params: TransactionParams) => Promise>` | Estimate the fee for a transaction |
| `extension` | `() => T` | Access chain-specific methods not in the core API |
#### UseAccountResponse
Base response type for account operations:
```typescript
interface UseAccountResponse {
success: boolean
error?: string
}
```
#### TransactionParams
| Field | Type | Description |
| -------- | ------------------- | ---------------------------------------------------- |
| `to` | `string` | Recipient address |
| `asset` | [`IAsset`](#iasset) | Asset to send |
| `amount` | `string` | Amount in smallest denomination (e.g., wei, satoshi) |
#### TransactionResult
Extends `UseAccountResponse`:
| Field | Type | Description |
| --------- | --------- | -------------------------------------------- |
| `success` | `boolean` | Whether the transaction succeeded |
| `hash` | `string` | Transaction hash |
| `fee` | `string` | Fee paid |
| `error` | `string?` | Error message (only if `success` is `false`) |
### Example
```tsx
import { useAccount, BaseAsset } from '@tetherto/wdk-react-native-core'
const usdt = new BaseAsset({
id: 'usdt-ethereum',
network: 'ethereum',
symbol: 'USDT',
name: 'Tether USD',
decimals: 6,
isNative: false,
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
})
function SendScreen() {
const { address, isLoading, send, estimateFee } = useAccount({ network: 'ethereum', accountIndex: 0 })
if (isLoading) return Deriving address...
if (!address) return No account available
const handleSend = async () => {
const txParams = {
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
asset: usdt,
amount: '1000000', // 1 USDT (6 decimals)
}
// Estimate fee first
const estimate = await estimateFee(txParams)
console.log('Estimated fee:', estimate.fee)
// Send the transaction
const result = await send(txParams)
if (result.success) {
console.log('TX hash:', result.hash)
} else {
console.error('TX failed:', result.error)
}
}
return (
Address: {address}
)
}
```
### Extension API
Use `extension()` to access chain-specific methods that aren't part of the core interface. The returned proxy waits for wallet initialization automatically:
```tsx
// Type parameter provides type-safe access to chain-specific methods
const { extension } = useAccount<{ getTransfers: () => Promise }>({
network: 'bitcoin',
accountIndex: 0,
})
// Safe to call at any time - waits for wallet initialization internally
const btcApi = extension()
const transfers = await btcApi.getTransfers()
```
***
## useAddresses
Hook to load and query wallet addresses across all networks.
### Returns
| Property | Type | Description |
| --------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `data` | `AddressInfo[] \| undefined` | Flattened array of all loaded addresses for the active wallet |
| `isLoading` | `boolean` | `true` if any address is currently being loaded |
| `loadAddresses` | `(accountIndices: number[], networks?: string[]) => Promise` | Fetch addresses for given account indices. Returns results for each address load attempt |
| `getAddressesForNetwork` | `(network: string) => Array<{ address: string, accountIndex: number }>` | Filter addresses by network |
| `getAccountInfoFromAddress` | `(address: string) => AddressInfo \| undefined` | Reverse-lookup: resolve an address string to its account info (case-insensitive) |
#### AddressInfo
| Field | Type | Description |
| -------------- | -------- | ------------------ |
| `address` | `string` | The public address |
| `network` | `string` | Network identifier |
| `accountIndex` | `number` | Account index |
#### AddressInfoResult
Discriminated union indicating success or failure for each address load:
```typescript
type AddressInfoResult =
| { network: string; accountIndex: number; success: true; address: string }
| { network: string; accountIndex: number; success: false; reason: Error }
```
### Example
```tsx
import { useAddresses } from '@tetherto/wdk-react-native-core'
function AddressesScreen() {
const { data, isLoading, loadAddresses, getAddressesForNetwork } = useAddresses()
useEffect(() => {
loadAddresses([0]).then((results) => {
const failed = results.filter((r) => !r.success)
if (failed.length > 0) {
console.warn('Some addresses failed to load:', failed)
}
})
}, [])
const ethAddresses = getAddressesForNetwork('ethereum')
if (isLoading) return Loading addresses...
return (
{ethAddresses.map(({ address, accountIndex }) => (
Account {accountIndex}: {address}
))}
)
}
```
***
## useBalance
Hook to fetch a single asset balance using TanStack Query. The network is derived from the asset's `getNetwork()` method. Automatically reads cached data from Zustand on first render, then fetches fresh data from the network.
### Parameters
| Parameter | Type | Description |
| -------------- | --------------------------------------------- | ------------------------------------------------------------------------- |
| `accountIndex` | `number` | Account index |
| `asset` | [`IAsset`](#iasset) | Asset to fetch balance for (network is derived from `asset.getNetwork()`) |
| `options` | [`BalanceQueryOptions`](#balancequeryoptions) | Optional query configuration |
### Returns `UseBalanceResult`
A composite result combining address loading state with TanStack Query state:
```typescript
type UseBalanceResult = Omit, 'isLoading' | 'error'> & {
isLoading: boolean
error: Error | null
}
```
| Property | Type | Description |
| ------------ | --------------------------------- | --------------------------------------------------------------------- |
| `data` | `BalanceFetchResult \| undefined` | Balance result |
| `isLoading` | `boolean` | `true` while address is loading or first balance fetch is in progress |
| `isFetching` | `boolean` | Any fetch in progress (including refetch) |
| `isError` | `boolean` | Query encountered an error |
| `error` | `Error \| null` | Error from address loading or balance query |
| `refetch` | `() => Promise<...>` | Manually trigger refetch |
### Example
```tsx
import { useBalance, BaseAsset } from '@tetherto/wdk-react-native-core'
const eth = new BaseAsset({
id: 'eth',
network: 'ethereum',
symbol: 'ETH',
name: 'Ether',
decimals: 18,
isNative: true,
})
function BalanceDisplay() {
const { data: balance, isLoading } = useBalance(0, eth, {
refetchInterval: 30000, // Refresh every 30s
})
if (isLoading) return Loading...
if (balance?.success) {
return ETH Balance: {balance.balance}
}
return Failed to fetch balance
}
```
***
## useBalancesForWallet
Hook to fetch balances for multiple assets in a single query. Automatically loads addresses for all required networks before fetching balances. For non-native assets, the hook tries the wallet module's batch token balance method first, then falls back to individual token balance calls when batch fetching is not available.
### Parameters
| Parameter | Type | Description |
| -------------- | --------------------------------------------- | ------------------------------------- |
| `accountIndex` | `number` | Account index |
| `assetConfigs` | [`IAsset[]`](#iasset) | Array of assets to fetch balances for |
| `options` | [`BalanceQueryOptions`](#balancequeryoptions) | Optional query configuration |
### Returns `UseBalancesForWalletResult`
Same shape as `UseBalanceResult` but `data` is `BalanceFetchResult[]`.
```typescript
type UseBalancesForWalletResult = Omit, 'isLoading' | 'error'> & {
isLoading: boolean
error: Error | null
}
```
### Example
```tsx
import { useBalancesForWallet, BaseAsset } from '@tetherto/wdk-react-native-core'
const assets = [
new BaseAsset({ id: 'eth', network: 'ethereum', symbol: 'ETH', name: 'Ether', decimals: 18, isNative: true }),
new BaseAsset({ id: 'usdt-eth', network: 'ethereum', symbol: 'USDT', name: 'Tether USD', decimals: 6, isNative: false, address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' }),
]
function PortfolioScreen() {
const { data: balances, isLoading } = useBalancesForWallet(0, assets, {
refetchInterval: 60000,
})
if (isLoading) return Loading balances...
return (
{balances?.map((b) => (
{b.assetId}: {b.success ? b.balance : 'Error'}
))}
)
}
```
***
## useRefreshBalance
Hook that returns a TanStack Query mutation for invalidating and refetching balances.
### Returns
Standard TanStack Query mutation result (`UseMutationResult`).
Call `mutate(params)` with:
| Field | Type | Description |
| -------------- | -------------------------------------------- | ------------------------------------------------------ |
| `accountIndex` | `number` | Account index |
| `network` | `string?` | Network (required for `'token'` and `'network'` types) |
| `assetId` | `string?` | Asset ID (required for `'token'` type) |
| `type` | `'token' \| 'wallet' \| 'network' \| 'all'?` | Refresh scope (default: `'token'`) |
| `walletId` | `string?` | Wallet ID override (defaults to active wallet) |
### Example
```tsx
import { useRefreshBalance } from '@tetherto/wdk-react-native-core'
function RefreshButton() {
const { mutate: refreshBalance, isPending } = useRefreshBalance()
return (
refreshBalance({ accountIndex: 0, type: 'wallet' })}
/>
)
}
```
***
## BaseAsset
Default implementation of the [`IAsset`](#iasset) interface. Wraps an [`AssetConfig`](#assetconfig) object.
### Constructor
```typescript
new BaseAsset(config: AssetConfig)
```
### Methods
| Method | Returns | Description |
| ---------------------- | ---------------- | ------------------------------------------------- |
| `getId()` | `string` | Unique asset identifier |
| `getNetwork()` | `string` | Network this asset belongs to |
| `getSymbol()` | `string` | Ticker symbol (e.g., `'USDT'`) |
| `getName()` | `string` | Human-readable name |
| `getDecimals()` | `number` | Decimal places |
| `isNative()` | `boolean` | `true` for native chain currency (ETH, BTC, etc.) |
| `getContractAddress()` | `string \| null` | Token contract address (`null` for native assets) |
### Example
```typescript
import { BaseAsset } from '@tetherto/wdk-react-native-core'
const usdt = new BaseAsset({
id: 'usdt-ethereum',
network: 'ethereum',
symbol: 'USDT',
name: 'Tether USD',
decimals: 6,
isNative: false,
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
})
console.log(usdt.getSymbol()) // 'USDT'
console.log(usdt.isNative()) // false
console.log(usdt.getContractAddress()) // '0xdAC17F958D2ee523a2206206994597C13D831ec7'
```
***
## IAsset
Interface that all assets must implement. `BaseAsset` provides a default implementation, but you can create custom asset classes for advanced use cases.
```typescript
interface IAsset {
getId(): string
getNetwork(): string
getSymbol(): string
getName(): string
getDecimals(): number
isNative(): boolean
getContractAddress(): string | null
}
```
***
## Types
### WdkConfigs
Root configuration object passed to `WdkAppProvider`. Defines network and protocol configurations for the WDK worklet. Extends `WdkWorkletConfig` from `@tetherto/pear-wrk-wdk`.
```typescript
interface WdkConfigs, TProtocol = Record> extends WdkWorkletConfig {
networks: {
[blockchain: string]: WdkNetworkConfig
}
protocols?: {
[protocolName: string]: WdkProtocolConfig
}
}
```
#### WdkNetworkConfig
Wrapper around `NetworkConfig` with typed `config` field.
```typescript
interface WdkNetworkConfig> extends NetworkConfig {
blockchain: string
config: T
}
```
#### WdkProtocolConfig
Wrapper around `ProtocolConfig` with typed `config` field.
```typescript
interface WdkProtocolConfig> extends ProtocolConfig {
blockchain: string
protocolName: string
config: T
}
```
### AssetConfig
Raw configuration object for defining an asset. Pass this to the `BaseAsset` constructor.
```typescript
type AssetConfig> = T & {
id: string // Unique identifier
network: string // Network this asset belongs to
symbol: string // Ticker symbol
name: string // Human-readable name
decimals: number // Decimal places
isNative: boolean // true for native chain currency
address?: string | null // Token contract address (null for native)
}
```
### BalanceFetchResult
Result of a balance fetch operation.
```typescript
interface BalanceFetchResult {
success: boolean // Whether the fetch succeeded
network: string // Network name
accountIndex: number // Account index
assetId: string // Asset identifier
balance: string | null // Balance as string (null if failed)
error?: string // Error message (only if success is false)
}
```
### BundleConfig
Configuration for the worklet bundle.
```typescript
interface BundleConfig {
bundle: string // Compiled JavaScript bundle for the worklet runtime
}
```
### BalanceQueryOptions
Options for balance query hooks.
```typescript
interface BalanceQueryOptions {
enabled?: boolean // Whether the query is enabled (default: true)
refetchInterval?: number | false // Refetch interval in ms (false to disable)
staleTime?: number // Stale time in ms
}
```
### WalletInfo
Information about a wallet stored on the device.
```typescript
interface WalletInfo {
identifier: string // Wallet identifier (e.g., user email)
exists: boolean // Whether wallet exists in secure storage
}
```
### AccountInfo
Information about a wallet account.
```typescript
interface AccountInfo {
accountIndex: number // Account index (0-based)
addresses: Record // Address for each network
}
```
***
## Utilities
### validateMnemonic
Validates a BIP39 mnemonic phrase. Checks that it contains exactly 12 or 24 non-empty words.
```typescript
function validateMnemonic(mnemonic: string): boolean
```
#### Example
```typescript
import { validateMnemonic } from '@tetherto/wdk-react-native-core'
validateMnemonic('word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12')
// true
validateMnemonic('only three words')
// false
```
### balanceQueryKeys
Factory for constructing TanStack Query keys for balance queries. Useful for manual cache invalidation.
```typescript
const balanceQueryKeys = {
all: ['balances'],
byWallet: (walletId: string, accountIndex: number) => [...],
byNetwork: (network: string) => [...],
byWalletAndNetwork: (walletId: string, accountIndex: number, network: string) => [...],
byToken: (walletId: string, accountIndex: number, network: string, assetId: string) => [...],
}
```
#### Example
```typescript
import { balanceQueryKeys } from '@tetherto/wdk-react-native-core'
import { useQueryClient } from '@tanstack/react-query'
const queryClient = useQueryClient()
// Invalidate all balances for a specific wallet
queryClient.invalidateQueries({
queryKey: balanceQueryKeys.byWallet('user@example.com', 0),
})
```
***
## Need Help?
# React Native Core (/tools/react-native-core)
**React Native Core** provides a hooks-based API for wallet management, balance fetching, account operations inside any React Native app.
## Features
* **Hooks-based architecture** - `useWdkApp`, `useWalletManager`, `useAccount`, `useBalance`, and more
* **TanStack Query caching** - automatic balance fetching, per-token fallback for modules without batch balance support, cache invalidation, and optimistic updates
* **Zustand state management** - persisted wallet state with MMKV storage
* **Worklet runtime** - runs WDK in an isolated Bare worklet
* **Biometric authentication** - secure storage with device biometrics
* **Multi-wallet support** - create, restore, switch, lock, unlock, and delete wallets
* **TypeScript-first** - full type safety with exported types and interfaces
## Quick Start
### 1. Install
```bash
npm install @tetherto/wdk-react-native-core
```
### 2. Wrap Your App
```tsx
import { WdkAppProvider } from '@tetherto/wdk-react-native-core'
import { bundle } from './.wdk' // See Bundle Configuration below
export default function App() {
return (
)
}
```
### 3. Use Hooks
```tsx
import { useWdkApp, useWalletManager, useAccount } from '@tetherto/wdk-react-native-core'
function WalletScreen() {
const { state } = useWdkApp()
const { createWallet, unlock } = useWalletManager()
const { address, isLoading } = useAccount({ network: 'ethereum', accountIndex: 0 })
switch (state.status) {
case 'INITIALIZING':
return Loading...
case 'NO_WALLET':
return createWallet('my-wallet')} />
case 'LOCKED':
return unlock()} />
case 'READY':
return Address: {address}
case 'ERROR':
return Error: {state.error.message}
}
}
```
For a full integration guide, see the [React Native Quickstart](../../start-building/react-native-quickstart).
## Bundle Configuration
The WDK engine runs inside a Bare worklet. You need to provide a bundle - there are two approaches:
### Custom Bundle (Recommended)
Use the `@tetherto/wdk-worklet-bundler` CLI to generate a bundle with only the blockchain modules you need:
```bash
# 1. Install the bundler CLI
npm install -g @tetherto/wdk-worklet-bundler
# 2. Initialize configuration in your React Native project
wdk-worklet-bundler init
# 3. Edit wdk.config.js to configure your networks (see example below)
# 4. Install required WDK modules
npm install @tetherto/wdk @tetherto/wdk-wallet-evm-erc-4337
# 5. Generate the bundle
wdk-worklet-bundler generate
```
Example `wdk.config.js`:
```javascript
module.exports = {
modules: {
core: '@tetherto/wdk',
erc4337: '@tetherto/wdk-wallet-evm-erc-4337',
},
networks: {
ethereum: {
module: 'erc4337',
chainId: 1,
blockchain: 'ethereum',
provider: 'https://eth.drpc.org',
},
polygon: {
module: 'erc4337',
chainId: 137,
blockchain: 'polygon',
provider: 'https://polygon.drpc.org',
},
},
}
```
After running `wdk-worklet-bundler generate`, import and use the bundle:
```typescript
import { bundle } from './.wdk'
```
For full bundler documentation, see [wdk-worklet-bundler](https://github.com/tetherto/wdk-worklet-bundler).
### Pre-built Bundle
For quick prototyping, use the pre-built bundle from `@tetherto/pear-wrk-wdk` which includes all blockchain modules:
```typescript
import { bundle } from '@tetherto/pear-wrk-wdk'
```
The pre-built bundle includes all blockchain modules, resulting in a larger bundle size. For production apps, generate a custom bundle with only the modules you need.
## Architecture
```
WdkAppProvider
+-- QueryClientProvider (TanStack Query)
+-- Worklet Runtime (react-native-bare-kit)
| +-- WDK engine (runs in isolated Bare worklet)
+-- Zustand Stores
| +-- workletStore - worklet lifecycle, initialization state
| +-- walletStore - addresses, balances, wallet list (persisted to MMKV)
+-- Hooks (public API)
+-- useWdkApp() - app state (INITIALIZING, NO_WALLET, LOCKED, READY, ERROR)
+-- useWalletManager() - create, restore, lock, unlock, delete wallets
+-- useAccount() - address, send, sign, verify, estimateFee
+-- useAddresses() - load and query addresses
+-- useBalance() - single balance with TanStack Query
+-- useBalancesForWallet() - bulk balance fetch with per-token fallback
+-- useRefreshBalance() - invalidate and refetch balances
```
***
Complete reference for all hooks, components, types, and utilities
Step-by-step integration guide for new and existing apps
***
## Need Help?
# React Native Secure Storage API Reference (/tools/react-native-secure-storage/api-reference)
## Exports
| Export | Type | Description |
| ------------------------------------------- | --------- | ----------------------------------------------------------------- |
| `createSecureStorage` | Function | Creates a `SecureStorage` instance. |
| `SecureStorage` | Interface | Wallet credential storage contract. |
| `SecureStorageOptions` | Type | Factory options for logger, authentication, and timeout behavior. |
| `AuthenticationOptions` | Type | Biometric prompt options. |
| `SecureStorageItemOptions` | Type | Per-item storage options such as `requireBiometrics`. |
| `LogLevel`, `defaultLogger` | Value | Built-in logger controls. |
| `MAX_IDENTIFIER_LENGTH`, `MAX_VALUE_LENGTH` | Constant | Validation limits for identifiers and stored values. |
| `MIN_TIMEOUT_MS`, `MAX_TIMEOUT_MS` | Constant | Allowed timeout bounds. |
| `SecureStorageError` | Class | Base error class. |
| `KeychainWriteError`, `KeychainReadError` | Class | Keychain operation errors. |
| `AuthenticationError` | Class | Authentication failed or was unavailable. |
| `ValidationError` | Class | Input validation failed. |
| `TimeoutError` | Class | Operation timed out. |
| `DeviceSecurityNotEnabledError` | Class | Device security is not enabled when required by the app. |
## createSecureStorage
```typescript
function createSecureStorage(options?: SecureStorageOptions): SecureStorage
```
### SecureStorageOptions
```typescript
interface SecureStorageOptions {
logger?: Logger
authentication?: AuthenticationOptions
timeoutMs?: number
}
```
### AuthenticationOptions
```typescript
interface AuthenticationOptions {
promptMessage?: string
cancelLabel?: string
disableDeviceFallback?: boolean
}
```
## SecureStorage
| Method | Description | Returns |
| ---------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `isDeviceSecurityEnabled()` | Checks whether device passcode, PIN, pattern, or biometrics are enabled. | `Promise` |
| `isBiometricAvailable()` | Checks whether biometric authentication is available. | `Promise` |
| `authenticate()` | Runs the configured authentication prompt. | `Promise` |
| `setEncryptionKey(key, identifier?, options?)` | Stores the wallet encryption key. | `Promise` |
| `getEncryptionKey(identifier?, options?)` | Reads the wallet encryption key. | `Promise` |
| `setEncryptedSeed(encryptedSeed, identifier?)` | Stores an encrypted seed payload. | `Promise` |
| `getEncryptedSeed(identifier?)` | Reads an encrypted seed payload. | `Promise` |
| `setEncryptedEntropy(encryptedEntropy, identifier?)` | Stores encrypted entropy. | `Promise` |
| `getEncryptedEntropy(identifier?)` | Reads encrypted entropy. | `Promise` |
| `getAllEncrypted(identifier?)` | Reads encrypted seed, encrypted entropy, and encryption key together. | `Promise<{ encryptedSeed: string \| null; encryptedEntropy: string \| null; encryptionKey: string \| null }>` |
| `hasWallet(identifier?)` | Checks whether any wallet material exists for the identifier. | `Promise` |
| `deleteWallet(identifier?)` | Deletes wallet material for the identifier. | `Promise` |
| `cleanup()` | Releases resources associated with the storage instance. | `void` |
## SecureStorageItemOptions
```typescript
interface SecureStorageItemOptions {
requireBiometrics?: boolean
}
```
Pass `requireBiometrics: true` when reading or writing the encryption key if your app requires biometric access for that item.
## Error handling
All package-specific errors extend `SecureStorageError` and expose a `code` string. Getters return `null` when a value is missing; operational failures throw typed errors.
```typescript title="Handle Secure Storage Errors"
import {
AuthenticationError,
SecureStorageError,
TimeoutError,
ValidationError
} from '@tetherto/wdk-react-native-secure-storage'
try {
const key = await storage.getEncryptionKey('primary-wallet', {
requireBiometrics: true
})
} catch (error) {
if (error instanceof AuthenticationError) {
// Prompt the user to retry or choose another recovery path.
} else if (error instanceof TimeoutError || error instanceof ValidationError) {
// Surface a recoverable error state.
} else if (error instanceof SecureStorageError) {
// Log the machine-readable error code without sensitive values.
}
}
```
***
## Need Help?
# React Native Secure Storage Configuration (/tools/react-native-secure-storage/configuration)
This page shows how to install `@tetherto/wdk-react-native-secure-storage`, create a storage instance, and configure authentication behavior.
## Install the package
```bash title="Install React Native Secure Storage"
npm install @tetherto/wdk-react-native-secure-storage react-native-keychain expo-crypto expo-local-authentication
```
The package declares `react-native` as a peer dependency and uses native modules through `react-native-keychain`.
Use this package in a React Native app or development build with native modules available. Expo Go is not enough for all keychain-backed flows.
## Create a storage instance
Use `createSecureStorage()` once and reuse the returned object in your wallet storage layer.
```typescript title="Create Secure Storage"
import { createSecureStorage } from '@tetherto/wdk-react-native-secure-storage'
const storage = createSecureStorage({
authentication: {
promptMessage: 'Authenticate to access wallet',
cancelLabel: 'Cancel',
disableDeviceFallback: false
},
timeoutMs: 30000
})
```
## Store wallet material
Store encrypted values only. The package stores encrypted seed and entropy payloads plus the encryption key you provide.
```typescript title="Store Wallet Material"
const walletId = 'primary-wallet'
await storage.setEncryptedSeed(encryptedSeed, walletId)
await storage.setEncryptedEntropy(encryptedEntropy, walletId)
await storage.setEncryptionKey(encryptionKey, walletId, {
requireBiometrics: true
})
```
## Restore wallet material
Getters return `null` when a value has not been stored. They throw typed errors for validation, authentication, timeout, and keychain failures.
```typescript title="Restore Wallet Material"
const walletId = 'primary-wallet'
const { encryptedSeed, encryptedEntropy, encryptionKey } =
await storage.getAllEncrypted(walletId)
if (!encryptedSeed || !encryptionKey) {
throw new Error('Wallet data is incomplete')
}
```
## Check device security
Use device checks before prompting the user to create or unlock a wallet.
```typescript title="Check Device Security"
const deviceSecurityEnabled = await storage.isDeviceSecurityEnabled()
const biometricsAvailable = await storage.isBiometricAvailable()
if (!deviceSecurityEnabled) {
throw new Error('Enable device security before creating a wallet')
}
```
## Cleanup
Call `cleanup()` when the storage instance is no longer needed. Use `deleteWallet(identifier)` when you want to remove stored wallet data.
***
## Need Help?
# React Native Secure Storage (/tools/react-native-secure-storage)
React Native Secure Storage provides a typed wrapper for storing encrypted wallet seed material and encryption keys with `react-native-keychain`. It is designed for React Native wallet apps that need app-scoped encrypted storage with optional biometric access.
Powered by [`@tetherto/wdk-react-native-secure-storage`](https://www.npmjs.com/package/@tetherto/wdk-react-native-secure-storage).
## Features
* **Wallet credential helpers**: Store and retrieve encrypted seeds, encrypted entropy, and encryption keys.
* **Per-wallet identifiers**: Pass an optional `identifier` to isolate storage keys for multiple wallets.
* **Biometric access**: Require biometric authentication for encryption key reads with `requireBiometrics`.
* **Device security checks**: Check whether device passcode, PIN, pattern, or biometrics are enabled before sensitive flows.
* **Typed errors**: Catch validation, authentication, timeout, keychain read, and keychain write failures.
## When to use it
Use this package for local encrypted storage in React Native wallet apps. It does not generate wallet seeds, encrypt plaintext seed material by itself, or provide cloud backup. Pair it with WDK wallet modules and a backup provider when you need recovery across devices.
Install dependencies, configure authentication prompts, and create a storage instance.
Review `createSecureStorage`, storage methods, options, constants, and errors.
***
## Need Help?
# API Reference (/tools/secret-manager/api-reference)
## Package: `@tetherto/wdk-secret-manager`
### Class: `WdkSecretManager`
#### Constructor
```javascript title="Create Secret Manager"
new WdkSecretManager(passKey, salt, kdfParams?)
// passKey: string | Buffer | Uint8Array (min 12 chars/bytes)
// salt: Buffer (16 bytes)
// kdfParams?: { iterations?: number } // default: 100_000
```
* `passKey`: User password/device secret (string or binary). Must be at least 12 characters/bytes.
* `salt`: 16‑byte random Buffer. Store alongside encrypted payloads; salt is not secret but must be unique per user/session.
* `kdfParams.iterations`: PBKDF2 iterations (defaults to 100,000).
#### Static Methods
* `generateSalt()` → `Buffer`
* Returns a cryptographically secure, random 16‑byte salt Buffer.
```javascript title="Generate Salt"
import WdkSecretManager from '@tetherto/wdk-secret-manager'
const salt = WdkSecretManager.generateSalt()
```
#### Methods
* `generateAndEncrypt(entropyOpt?, masterKeyOpt?)` → `{ encryptedSeed: Buffer, encryptedEntropy: Buffer }`
* Generates 16‑byte entropy (or uses `entropyOpt`), converts to 12‑word mnemonic, derives 64‑byte BIP39 seed, and encrypts both.
* `masterKeyOpt` (optional): 32‑byte key (Buffer) to skip PBKDF2.
* `encrypt(data, masterKeyOpt?)` → `Buffer`
* Encrypts arbitrary data with authenticated encryption and a self‑describing header.
* Constraints: `data` must be a Buffer of length 16–64 bytes.
* `masterKeyOpt` (optional): 32‑byte key to skip PBKDF2.
* `decrypt(payload, masterKeyOpt?)` → `Buffer`
* Decrypts a payload produced by `encrypt`. Validates header and MAC.
* `generateRandomBuffer()` → `Buffer`
* Returns a 16‑byte cryptographically secure random buffer.
* `entropyToMnemonic(entropy)` → `string`
* Converts 16‑byte entropy to a 12‑word BIP39 mnemonic.
* `mnemonicToEntropy(mnemonic)` → `Buffer`
* Converts a 12‑word mnemonic back to its 16‑byte entropy buffer.
* `dispose()` → `void`
* Securely wipes internal state (passkey, salt, iterations). The instance should not be used afterwards.
#### Header & Payload (for `encrypt`)
* Header layout: `[version(1), kdf_alg(1), iterations(u32le), reserved(u32le=0), salt(16), nonce(24)]`
* Ciphertext: `secretbox([len(1) | data(16..64)], nonce, key)`
#### Examples
```javascript title="Generate, Encrypt, Decrypt"
import WdkSecretManager from '@tetherto/wdk-secret-manager'
const passkey = 'correct horse battery staple'
const salt = WdkSecretManager.generateSalt()
const sm = new WdkSecretManager(passkey, salt, { iterations: 100_000 })
// Generate and encrypt new seed + entropy
const { encryptedSeed, encryptedEntropy } = await sm.generateAndEncrypt()
// Decrypt entropy and recover mnemonic
const entropy = sm.decrypt(encryptedEntropy)
const mnemonic = sm.entropyToMnemonic(entropy)
// Wipe sensitive memory and internal state when done
sm.dispose()
```
```javascript title="Encrypt/Decrypt Arbitrary Data (16–64 bytes)"
const data = sm.generateRandomBuffer() // 16 bytes
const payload = sm.encrypt(data) // Buffer with header + ciphertext
const out = sm.decrypt(payload) // Buffer(16)
```
```javascript title="Use Pre‑Derived 32‑byte Master Key (skip PBKDF2)"
import { pbkdf2Sync } from 'crypto'
import b4a from 'b4a'
const masterKey = b4a.from(pbkdf2Sync(b4a.from(passkey), b4a.from(salt), 100_000, 32, 'sha256'))
const cipher = sm.encrypt(Buffer.from('0123456789abcdef0123456789abcdef'), masterKey)
const plain = sm.decrypt(cipher, masterKey)
```
## Security Notes
* Use strong, unique passkeys; never store them in plaintext
* Salts must be unique per user/session; store them with encrypted payloads
* No plaintext persistence; all operations are done in memory
* Call `dispose()` to zeroize internal secrets when done
***
## Need Help?
# Configuration (/tools/secret-manager/configuration)
This page shows how to configure the Secret Manager instance, what parameters matter for security, and how to use environment/runtime options.
## Constructor
```javascript title="Create Secret Manager"
import WdkSecretManager from '@tetherto/wdk-secret-manager'
const passkey = 'correct horse battery staple' // ≥ 12 chars (or Buffer/Uint8Array ≥ 12 bytes)
const salt = WdkSecretManager.generateSalt() // 16‑byte Buffer
// Optional: PBKDF2 iterations (default 100,000)
const sm = new WdkSecretManager(passkey, salt, { iterations: 100_000 })
```
### Parameters
* `passkey` (`string | Buffer | Uint8Array`): User secret used to derive the encryption key. Must be at least 12 characters/bytes. Prefer a strong, user‑specific passkey from secure storage (e.g., Keychain/Keystore).
* `salt` (`Buffer`): 16‑byte random Buffer. The salt is not secret but must be unique per user/session. Store the salt alongside the encrypted payload.
* `kdfParams.iterations` (`number`, optional): PBKDF2 iterations (default `100_000`). Increase for stronger resistance (with performance trade‑off).
## Static Utilities
### `generateSalt()`
```javascript title="Generate Salt"
const salt = WdkSecretManager.generateSalt() // Buffer(16)
```
## Recommended Settings
* Use at least `100_000` PBKDF2 iterations in mobile/desktop; consider higher values on powerful backends.
* Enforce passkeys ≥ 12 characters with mixed entropy (or binary secrets of similar strength).
* Generate a fresh 16‑byte salt per user/session; never reuse salts with the same passkey.
* Store salt with the encrypted payload; never store plaintext passkeys or mnemonics.
## Runtime Notes
* Node.js: Uses `sodium-native` and Node `crypto` (PBKDF2).
* Bare runtime: A bare build is provided; PBKDF2 is handled by the bare crypto shim.
## Examples
### Generate and Encrypt Seed + Entropy
```javascript title="Generate & Encrypt"
const { encryptedEntropy, encryptedSeed } = await sm.generateAndEncrypt()
// Decrypt later
const entropy = sm.decrypt(encryptedEntropy) // Buffer(16)
const seed = sm.decrypt(encryptedSeed) // Buffer(64)
```
### Encrypt/Decrypt Arbitrary Data (16–64 bytes)
```javascript title="Encrypt/Decrypt Data"
// Data length must be between 16 and 64 bytes
import { randomBytes } from 'crypto'
const data = randomBytes(32) // Buffer(32)
const payload = sm.encrypt(data) // Buffer(header + ciphertext)
const out = sm.decrypt(payload) // Buffer(32)
```
### Skip PBKDF2 with a Master Key
If you already have a 32‑byte key (e.g., derived via a KMS), you can skip PBKDF2:
```javascript title="Master Key Mode"
import { pbkdf2Sync } from 'crypto'
import b4a from 'b4a'
const masterKey = b4a.from(pbkdf2Sync(b4a.from(passkey), b4a.from(salt), 100_000, 32, 'sha256'))
const cipher = sm.encrypt(Buffer.from('0123456789abcdef0123456789abcdef'), masterKey)
const plain = sm.decrypt(cipher, masterKey)
```
### Mnemonic Helpers
```javascript title="Entropy ↔ Mnemonic"
const entropy16 = sm.generateRandomBuffer() // Buffer(16)
const mnemonic = sm.entropyToMnemonic(entropy16) // 12 words
const entropy2 = sm.mnemonicToEntropy(mnemonic) // Buffer(16)
```
### Memory Management
```javascript title="Dispose"
// Wipes internal passkey/salt/iteration state from memory
sm.dispose()
```
## Constraints & Validation
* `encrypt(data)` requires `data` to be a Buffer of length 16–64 bytes.
* `mnemonicToEntropy` expects a 12‑word BIP39 mnemonic; throws on invalid input.
* Constructor validates passkey length/type and salt length (16 bytes).
## Security Checklist
* Use strong, unique passkeys per user; never persist them in plaintext
* Generate a fresh 16‑byte salt per user/session
* Tune PBKDF2 iterations appropriate to your platform
* Encrypt before storing/sending secrets; keep operations in memory and call `dispose()` when done
***
## Need Help?
# Secret Manager (/tools/secret-manager)
The Secret Manager is a secure, in‑memory system for generating, encrypting, decrypting, and managing wallet seed phrases (mnemonics) and sessions. It is designed for wallet applications where user secrets must be protected and never stored in plaintext. Generates, encrypts, decrypts, and converts BIP39 mnemonics using strong, modern cryptography.
Powered by [`@tetherto/wdk-secret-manager`](https://github.com/tetherto/wdk-secret-manager).
## Features
* **Seed & Entropy Protection**: Generate and encrypt BIP39 seed (64‑byte) and entropy (16‑byte)
* **Strong Key Derivation**: PBKDF2‑SHA256 with configurable iterations (default 100,000)
* **Authenticated Encryption**: libsodium secretbox (XSalsa20‑Poly1305) with versioned, self‑describing headers
* **Mnemonic Utilities**: 16‑byte entropy ↔ 12‑word BIP39 mnemonic helpers
* **Secure Randoms**: Cryptographically secure salt and entropy generators
* **Master‑Key Mode**: Optional 32‑byte key to skip PBKDF2 when you already have a derived key
* **Memory Safety**: In‑memory operation, explicit zeroization, and `dispose()` to wipe secrets
* **Cross‑Runtime**: Works in Node and Bare environments
## Why this matters
* Seed phrases grant full control over funds and must never be exposed
* Best practice: never persist plaintext; always encrypt with a user passkey
* Memory‑only handling and prompt zeroization reduce attack surface
Get started with WDK Secret Manager
Check the API Reference and examples
***
## Need Help?
# WDK Utils API Reference (/tools/wdk-utils/api-reference)
## Package: `@tetherto/wdk-utils`
### Address Validation Helpers
| Function | Description | Returns |
| ----------------------------------- | --------------------------------------------------------------------------------- | ---------------------------------- |
| `validateBase58(address)` | Validate a Base58Check Bitcoin address payload and version byte. | See details below. |
| `validateBech32(address)` | Validate a SegWit v0 Bitcoin address. | `BtcAddressValidationResult` |
| `validateBech32m(address)` | Validate a SegWit v1+ Bitcoin address. | `BtcAddressValidationResult` |
| `validateBitcoinAddress(address)` | Validate a Bitcoin address across Base58Check, Bech32, and Bech32m formats. | `BtcAddressValidationResult` |
| `validateEVMAddress(address)` | Validate an EVM address, including EIP-55 checksum rules for mixed-case inputs. | `EvmAddressValidationResult` |
| `stripLightningPrefix(input)` | Remove a leading `lightning:` prefix before other Lightning validation steps. | `string` |
| `validateLightningInvoice(address)` | Validate a Lightning invoice string. | `LightningInvoiceValidationResult` |
| `decodeLightningInvoice(invoice)` | Decode a BOLT11 Lightning invoice into invoice metadata. | `LightningInvoiceDecodingResult` |
| `validateLnurl(address)` | Validate an LNURL string. | `LnurlValidationResult` |
| `decodeLnurl(address)` | Decode an LNURL string into its original URL. | `LnurlDecodingResult` |
| `validateLightningAddress(address)` | Validate a Lightning Address in `user@domain.tld` form. | `LightningAddressValidationResult` |
| `validateSparkAddress(address)` | Validate a Spark address or a Bitcoin L1 deposit address accepted by Spark flows. | `SparkAddressValidationResult` |
| `validateTronAddress(address)` | Validate a Tron Base58Check address and prefix byte. | `TronAddressValidationResult` |
| `validateUmaAddress(address)` | Validate a Universal Money Address. | `UmaAddressValidationResult` |
| `resolveUmaUsername(uma)` | Split a valid UMA string into `localPart`, `domain`, and `lightningAddress`. | Parsed UMA details or `null`. |
#### `validateBase58(address)`
Validate a Base58Check Bitcoin address and identify whether it matches a supported P2PKH or P2SH network version byte.
The published `beta.2` type declaration currently includes an internal `{ decoded: Uint8Array }` branch in this return type. The shipped runtime returns validation results rather than exposing that intermediate decode object.
```javascript title="Validate A Base58 Bitcoin Address"
import { validateBase58 } from '@tetherto/wdk-utils'
const result = validateBase58('18hnriom5tB5KtFb982m8f9cZz4i72PUpZ')
```
#### `validateBech32(address)`
Validate a SegWit v0 Bech32 Bitcoin address for supported network prefixes.
```javascript title="Validate A Bech32 Bitcoin Address"
import { validateBech32 } from '@tetherto/wdk-utils'
const result = validateBech32('bc1qu9yqnhc6wjj6s62s9x0shnl5l2r7gq5cudm94r7mvwv0uw4s7acq0hn9g6')
```
#### `validateBech32m(address)`
Validate a SegWit v1+ Bech32m Bitcoin address for mainnet, testnet, or regtest.
```javascript title="Validate A Bech32m Bitcoin Address"
import { validateBech32m } from '@tetherto/wdk-utils'
const result = validateBech32m('bc1pkf2alvh0q96nyf7yhw2w3x7etlw22sasn2kxu59xzzl2px7ga4asctyc2v')
```
#### `validateBitcoinAddress(address)`
Run the combined Bitcoin validator across Base58Check, Bech32, and Bech32m inputs.
```javascript title="Validate A Bitcoin Address"
import { validateBitcoinAddress } from '@tetherto/wdk-utils'
const result = validateBitcoinAddress('tb1pu9yqnhc6wjj6s62s9x0shnl5l2r7gq5cudm94r7mvwv0uw4s7acqjg9r2f')
```
`BtcAddressValidationResult` is one of these shapes:
* `{ success: true, type: 'p2pkh' | 'p2sh' | 'bech32' | 'bech32m', network: 'mainnet' | 'testnet' | 'regtest' }`
* `{ success: false, reason: string }`
#### `validateEVMAddress(address)`
Validate an EVM address. Mixed-case inputs must satisfy EIP-55 checksum casing, while all-lowercase and all-uppercase inputs remain valid.
```javascript title="Validate An EVM Address"
import { validateEVMAddress } from '@tetherto/wdk-utils'
const result = validateEVMAddress('0x742d35Cc6634C0532925a3b844Bc454e4438f44e')
```
`EvmAddressValidationResult` is one of these shapes:
* `{ success: true, type: 'evm' }`
* `{ success: false, reason: string }`
#### `stripLightningPrefix(input)`
Remove a `lightning:` URI prefix before validating or parsing Lightning inputs.
```javascript title="Strip A Lightning Prefix"
import { stripLightningPrefix } from '@tetherto/wdk-utils'
const invoice = stripLightningPrefix(
'lightning:lnbc100u1p5m3k6fpp5uk9rs7fdrvssehzthphfjvpc3t5hyacgrveskwqzwclrdsl0cjgsdqydp5scqzzsxqrrssrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqqqqqyqqqqqqqqqqqqqqqqqqqqqqjqnp4qtem70et4qm86lv449zcpqjn9nmamd6qrzm3wa3d7msnq2kx3yapwsp50c4l2z72hcmejj88en6eu2p8u2ypv87pw5pndzjjtclwaw0f7wds9qyyssqtqeqrvaaw92y7at9463vxhwkjdy7lpxet7h6g4vry8xyw4ar9yn8qq36dryntpf252v58c4hrf4g59z2pr25lhp06n7x4z7yltd022cqk7lc7e'
)
```
#### `validateLightningInvoice(address)`
Validate a Lightning invoice string after trimming input and removing any `lightning:` URI prefix.
```javascript title="Validate A Lightning Invoice"
import { validateLightningInvoice } from '@tetherto/wdk-utils'
const result = validateLightningInvoice(
'lnbc100u1p5m3k6fpp5uk9rs7fdrvssehzthphfjvpc3t5hyacgrveskwqzwclrdsl0cjgsdqydp5scqzzsxqrrssrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqqqqqyqqqqqqqqqqqqqqqqqqqqqqjqnp4qtem70et4qm86lv449zcpqjn9nmamd6qrzm3wa3d7msnq2kx3yapwsp50c4l2z72hcmejj88en6eu2p8u2ypv87pw5pndzjjtclwaw0f7wds9qyyssqtqeqrvaaw92y7at9463vxhwkjdy7lpxet7h6g4vry8xyw4ar9yn8qq36dryntpf252v58c4hrf4g59z2pr25lhp06n7x4z7yltd022cqk7lc7e'
)
```
`LightningInvoiceValidationResult` is one of these shapes:
* `{ success: true, type: 'invoice' }`
* `{ success: false, reason: string }`
#### `decodeLightningInvoice(invoice)`
Decode a BOLT11 Lightning invoice after trimming input and removing any `lightning:` URI prefix.
```javascript title="Decode A BOLT11 Invoice"
import { decodeLightningInvoice } from '@tetherto/wdk-utils'
const result = decodeLightningInvoice(
'lnbc15u1p3xnhl2pp5jptserfk3zk4qy42tlucycrfwxhydvlemu9pqr93tuzlv9cc7g3sdqsvfhkcap3xyhx7un8cqzpgxqzjcsp5f8c52y2stc300gl6s4xswtjpc37hrnnr3c9wvtgjfuvqmpm35evq9qyyssqy4lgd8tj637qcjp05rdpxxykjenthxftej7a2zzmwrmrl70fyj9hvj0rewhzj7jfyuwkwcg9g2jpwtk3wkjtwnkdks84hsnu8xps5vsq4gj5hs'
)
```
`LightningInvoiceDecodingResult` is one of these shapes:
* `{ success: true, type: 'invoice', data: DecodedLightningInvoice }`
* `{ success: false, reason: string }`
`DecodedLightningInvoice` contains decoded BOLT11 metadata such as `paymentRequest`, `network`, `satoshis`, `millisatoshis`, `timestamp`, `timeExpireDate`, `payeeNodeKey`, `signature`, and `tags` when the invoice includes those fields.
#### `validateLnurl(address)`
Validate an LNURL string that begins with `lnurl1`.
```javascript title="Validate An LNURL"
import { validateLnurl } from '@tetherto/wdk-utils'
const result = validateLnurl(
'lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhhxurj093k7mtxdae8gwfjnztwnf'
)
```
`LnurlValidationResult` is one of these shapes:
* `{ success: true, type: 'lnurl' }`
* `{ success: false, reason: string }`
#### `decodeLnurl(address)`
Decode an LNURL string into its original URL. The helper also accepts a leading `lightning:` URI prefix.
```javascript title="Decode An LNURL"
import { decodeLnurl } from '@tetherto/wdk-utils'
const result = decodeLnurl(
'lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhhxurj093k7mtxdae8gwfjnztwnf'
)
```
`LnurlDecodingResult` is one of these shapes:
* `{ success: true, type: 'lnurl', data: string }`
* `{ success: false, reason: string }`
#### `validateLightningAddress(address)`
Validate a Lightning Address in `user@domain.tld` form.
```javascript title="Validate A Lightning Address"
import { validateLightningAddress } from '@tetherto/wdk-utils'
const result = validateLightningAddress('sprycomfort92@waletofsatoshi.com')
```
`LightningAddressValidationResult` is one of these shapes:
* `{ success: true, type: 'address' }`
* `{ success: false, reason: string }`
#### `validateSparkAddress(address)`
Validate a Spark address or a Bitcoin Bech32m deposit address accepted by Spark flows.
```javascript title="Validate A Spark Address"
import { validateSparkAddress } from '@tetherto/wdk-utils'
const spark = validateSparkAddress(
'spark1pgss82uvuvyjggx72gl42qk3285yz0j6lgxw9uk2mvgajsr8w22nudv8w6hqs2'
)
const l1Deposit = validateSparkAddress(
'bc1p4lpn5nrunrjdk6teyjd2z53vmv82hlgjvv4pejkhg9wz5jq86zuqsruz85'
)
```
`SparkAddressValidationResult` is one of these shapes:
* `{ success: true, type: 'spark' | 'btc' }`
* `{ success: false, reason: string }`
#### `validateTronAddress(address)`
Validate a Tron Base58Check address. The helper checks the `T` prefix, the 34-character address length, the Tron prefix byte, and the checksum.
```javascript title="Validate A Tron Address"
import { validateTronAddress } from '@tetherto/wdk-utils'
const result = validateTronAddress('TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH')
```
`TronAddressValidationResult` is one of these shapes:
* `{ success: true, type: 'tron' }`
* `{ success: false, reason: string }`
#### `validateUmaAddress(address)`
Validate a Universal Money Address in `$user@domain.tld` form.
```javascript title="Validate A UMA Address"
import { validateUmaAddress } from '@tetherto/wdk-utils'
const result = validateUmaAddress('$you@uma.money')
```
`UmaAddressValidationResult` is one of these shapes:
* `{ success: true, type: 'uma' }`
* `{ success: false, reason: string }`
#### `resolveUmaUsername(uma)`
Resolve a valid UMA string into the local part, domain, and underlying Lightning Address.
```javascript title="Resolve A UMA Username"
import { resolveUmaUsername } from '@tetherto/wdk-utils'
const result = resolveUmaUsername('$alice@wallet.com')
```
### EIP-681 Request Parsing Helpers
| Function | Description | Returns |
| --------------------------- | ------------------------------------------------------------------------- | ------------------- |
| `isEip681Request(input)` | Detect whether a string has the shape of a supported EIP-681 request. | `boolean` |
| `parseEip681Request(input)` | Parse a supported EIP-681 transfer request into structured transfer data. | `Eip681ParseResult` |
#### `isEip681Request(input)`
Detect whether a string looks like a supported EIP-681 transfer request before you attempt a full parse.
```javascript title="Detect An EIP-681 Request"
import { isEip681Request } from '@tetherto/wdk-utils'
const looksLikeRequest = isEip681Request(
'polygon:0xc2132D05D31c914a87C6611C10748AEb04B58e8F@137/transfer?address=0xA9e338082A061d657014c08e652D96B38639F22a&value=1000000'
)
```
#### `parseEip681Request(input)`
Parse a supported EIP-681 transfer request. The published runtime supports `transfer` requests, accepts `value` as an alias for `uint256`, and normalizes scientific-notation amounts into integer `amountSmallest` strings.
```javascript title="Parse An EIP-681 Request"
import { parseEip681Request } from '@tetherto/wdk-utils'
const result = parseEip681Request(
'pol:0xc2132D05D31c914a87C6611C10748AEb04B58e8F@137/transfer?address=0xA9e338082A061d657014c08e652D96B38639F22a&uint256=0.175309000e6'
)
```
`Eip681ParseResult` is one of these shapes:
* `{ success: true, type: 'eip681-transfer', value: Eip681TransferRequest }`
* `{ success: false, reason: 'INVALID_FORMAT' | 'UNSUPPORTED_METHOD' | 'MISSING_REQUIRED_PARAM' | 'INVALID_RECIPIENT' | 'INVALID_AMOUNT' }`
`Eip681TransferRequest` contains:
* `recipient: string`
* `tokenAddress: string`
* `chainId: number`
* `amountSmallest: string`
***
## Need Help?
# WDK Utils Configuration (/tools/wdk-utils/configuration)
This package does not have constructor options or runtime configuration. This page shows how to install `@tetherto/wdk-utils`, import the helpers you need, and understand the published runtime surface.
## Install the package
You can install `@tetherto/wdk-utils` from npm:
```bash title="Install @tetherto/wdk-utils"
npm install @tetherto/wdk-utils
```
## Import address validation helpers
You can import only the validators your flow needs from the package entrypoint:
```javascript title="Import Address Validators"
import {
validateBitcoinAddress,
validateEVMAddress,
validateLightningInvoice,
decodeLightningInvoice,
validateLnurl,
decodeLnurl,
validateLightningAddress,
validateSparkAddress,
validateTronAddress,
validateUmaAddress,
resolveUmaUsername
} from '@tetherto/wdk-utils'
```
## Import EIP-681 helpers
You can detect and parse token transfer requests using the EIP-681 helpers:
```javascript title="Import EIP-681 Helpers"
import {
isEip681Request,
parseEip681Request
} from '@tetherto/wdk-utils'
```
## Runtime notes
* `@tetherto/wdk-utils` exports plain functions. There is no client object to initialize.
* The package publishes a default module entrypoint through `index.js` and a bare runtime entrypoint through `bare.js`.
* `decodeLightningInvoice()` returns decoded BOLT11 invoice data, and `decodeLnurl()` returns the decoded URL string when parsing succeeds.
* `parseEip681Request()` currently supports transfer requests for the schemes implemented in the published runtime: `ethereum`, `pol`, `matic`, `polygon`, `arbitrum`, and `plasma`.
* `parseEip681Request()` accepts both `uint256` and `value` query parameters for the amount field and normalizes the parsed amount into `amountSmallest`.
## Examples
You can validate common wallet inputs before handing them to a module:
```javascript title="Validate Common Inputs"
import {
validateBitcoinAddress,
validateLightningAddress,
validateTronAddress,
validateUmaAddress
} from '@tetherto/wdk-utils'
const btc = validateBitcoinAddress('bc1qu9yqnhc6wjj6s62s9x0shnl5l2r7gq5cudm94r7mvwv0uw4s7acq0hn9g6')
const lightning = validateLightningAddress('sprycomfort92@waletofsatoshi.com')
const tron = validateTronAddress('TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH')
const uma = validateUmaAddress('$you@uma.money')
```
You can parse a request-shaped EIP-681 transfer string into structured data:
```javascript title="Parse An EIP-681 Transfer Request"
import { parseEip681Request } from '@tetherto/wdk-utils'
const request = parseEip681Request(
'pol:0xc2132D05D31c914a87C6611C10748AEb04B58e8F@137/transfer?address=0xA9e338082A061d657014c08e652D96B38639F22a&uint256=0.175309000e6'
)
```
***
## Need Help?
# WDK Utils (/tools/wdk-utils)
WDK Utils provides validation helpers for Bitcoin, EVM, Lightning, Spark, Tron, and UMA identifiers, Lightning decoding helpers, plus EIP-681 request parsing helpers for token transfer deep links. Powered by [`@tetherto/wdk-utils`](https://github.com/tetherto/wdk-utils).
## Features
* **Address validation helpers**: Validate Bitcoin, EVM, Lightning invoice, LNURL, Lightning address, Spark, Tron, and UMA inputs before you hand them to a wallet flow.
* **Lightning decoding helpers**: Decode BOLT11 invoices and LNURL strings before you display or route payment details.
* **EIP-681 request parsing**: Detect request-shaped EIP-681 strings and parse transfer payloads into `recipient`, `tokenAddress`, `chainId`, and `amountSmallest`.
* **No runtime setup**: Import the functions you need. The package has no constructor or runtime configuration.
* **TypeScript support**: The published package ships typed exports for every validator and parser.
* **Bare runtime export**: The package publishes a bare entrypoint in addition to the default module entrypoint.
## Why this matters
* Validate user input early and return machine-readable failure reasons before you attempt a transaction or resolution flow.
* Normalize EIP-681 payment links into structured transfer data that wallet UIs can inspect before execution.
* Reuse the same helpers across Node.js and Bare-based environments without adding a larger wallet module dependency.
Install the package, import the helpers, and review runtime notes.
Review the exported validators, parsers, and result types.
***
## Need Help?
# Worklet Bundler API Reference (/tools/worklet-bundler/api-reference)
# API Reference
## Package: `@tetherto/wdk-worklet-bundler`
### Configuration Types
#### `WdkBundleConfig`
`WdkBundleConfig` is the public configuration shape for `wdk.config.js`.
```typescript title="WdkBundleConfig Shape"
interface WdkBundleConfig {
networks: Record
protocols?: Record
preloadModules?: string[]
output?: {
bundle?: string
types?: string
}
options?: {
minify?: boolean
sourceMaps?: boolean
targets?: string[]
}
}
```
#### `ResolvedConfig`
`ResolvedConfig` extends `WdkBundleConfig` with absolute filesystem paths produced by `loadConfig()`.
```typescript title="ResolvedConfig Additions"
interface ResolvedConfig extends WdkBundleConfig {
configPath: string
projectRoot: string
resolvedOutput: {
bundle: string
types: string
}
}
```
### Dependency Helpers
| Function | Description | Returns |
| -------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------ |
| `validateDependencies(modules, projectRoot)` | Resolve configured packages and report which modules are installed or missing. | `ValidationResult` |
| `detectPackageManager(projectRoot)` | Detect whether the project uses `npm`, `yarn`, or `pnpm`. | `'npm'`, `'yarn'`, or `'pnpm'` |
| `generateInstallCommand(missing, packageManager?)` | Build the command string used to install missing dependencies. | `string` |
| `installDependencies(missing, projectRoot, options?)` | Install missing dependencies with the detected or selected package manager. | `InstallResult` |
| `generateUninstallCommand(packages, packageManager?)` | Build the command string used to remove packages. | `string` |
| `uninstallDependencies(packages, projectRoot, options?)` | Remove packages with the detected or selected package manager. | `UninstallResult` |
#### `validateDependencies(modules, projectRoot)`
Use this helper to confirm that the packages listed in `wdk.config.js` are already resolvable from the host project.
```typescript title="Validate Missing Dependencies"
import { validateDependencies } from '@tetherto/wdk-worklet-bundler'
const result = validateDependencies(
['@tetherto/wdk-wallet-btc', '@tetherto/pear-wrk-wdk'],
process.cwd()
)
```
`ValidationResult` contains:
* `valid` (`boolean`)
* `installed` (`ModuleInfo[]`)
* `missing` (`string[]`)
#### `detectPackageManager(projectRoot)`
Use this helper when you need the same package-manager detection logic that the CLI uses before install or uninstall flows.
```typescript title="Detect The Package Manager"
import { detectPackageManager } from '@tetherto/wdk-worklet-bundler'
const packageManager = detectPackageManager(process.cwd())
```
#### `generateInstallCommand(missing, packageManager?)`
Build the install command string without mutating the project:
```typescript title="Generate An Install Command"
import { generateInstallCommand } from '@tetherto/wdk-worklet-bundler'
const command = generateInstallCommand(
['@tetherto/wdk-wallet-btc', '@tetherto/pear-wrk-wdk'],
'npm'
)
```
#### `installDependencies(missing, projectRoot, options?)`
Run the install flow from code when you want the same dependency installation behavior as `generate --install`.
#### `generateUninstallCommand(packages, packageManager?)`
Build the uninstall command string without mutating the project.
#### `uninstallDependencies(packages, projectRoot, options?)`
Run the uninstall flow from code and receive a structured `UninstallResult`.
### Bundle Generation
| Function | Description | Returns |
| --------------------------------------- | ----------------------------------------------------------------------- | ---------------------------------- |
| `loadConfig(configPath?)` | Load, validate, and resolve a `wdk.config.js` file into absolute paths. | `Promise\` |
| `generateBundle(config, options?)` | Generate the entrypoint, imports, bundle, and optional type output. | `Promise\` |
| `generateSourceFiles(config, options?)` | Generate the source entrypoint and related artifacts without bundling. | `Promise\<{ entryPath: string }\>` |
| `generateEntryPoint(config, outputDir)` | Generate only the Bare worklet entrypoint file. | `Promise\` |
| `generateWalletModulesCode(config)` | Generate the wallet-module section inserted into the entrypoint. | `string` |
#### `loadConfig(configPath?)`
`loadConfig()` searches for `wdk.config.js` when no explicit path is supplied, validates the public config shape, and resolves the output paths relative to the config file directory.
```typescript title="Load The Resolved Config"
import { loadConfig } from '@tetherto/wdk-worklet-bundler'
const config = await loadConfig()
```
#### `generateBundle(config, options?)`
Use `generateBundle()` when you want the same bundle workflow that powers the CLI `generate` command.
`GenerateBundleOptions` supports:
* `dryRun`
* `verbose`
* `silent`
* `skipTypes`
* `skipGeneration`
`GenerateBundleResult` contains:
* `success`
* `bundlePath`
* `typesPath`
* `bundleSize`
* `duration`
* `error?`
* `missingModule?`
```typescript title="Generate A Bundle Programmatically"
import { generateBundle, loadConfig } from '@tetherto/wdk-worklet-bundler'
const config = await loadConfig('./wdk.config.js')
const result = await generateBundle(config, { verbose: true })
```
#### `generateSourceFiles(config, options?)`
Use `generateSourceFiles()` when you want the generated entrypoint without the final `bare-pack` step.
#### `generateEntryPoint(config, outputDir)`
Use `generateEntryPoint()` when you need the exact generated Bare entrypoint string written to a chosen output directory.
In `beta.3`, the generated entrypoint suspends and resumes both the `bare-http1` and `bare-https` global agents when the Bare runtime emits `suspend` and `resume`.
#### `generateWalletModulesCode(config)`
Use `generateWalletModulesCode()` when you only need the generated wallet-module section for inspection or custom generator flows.
### CLI Commands
The published CLI exposes these commands through `wdk-worklet-bundler`:
| Command | Description | Key Options |
| -------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `generate` | Generate a WDK bundle from configuration. | `--config`, `--install`, `--keep-artifacts`, `--dry-run`, `--no-types`, `--source-only`, `--skip-generation`, `--verbose` |
| `init` | Create a new `wdk.config.js` file. | `--yes` |
| `validate` | Validate configuration without building. | `--config` |
| `list-modules` | List available WDK modules. | `--json` |
| `clean` | Remove the generated `.wdk` folder. | `--yes` |
For the end-to-end config workflow, see the Worklet Bundler configuration guide when it is available.
***
## Need Help?
# Worklet Bundler Configuration (/tools/worklet-bundler/configuration)
This page shows how to install `@tetherto/wdk-worklet-bundler`, shape `wdk.config.js`, and generate a Bare worklet bundle for your WDK modules.
## Install the package
Install the bundler as a development dependency in the host project:
```bash title="Install @tetherto/wdk-worklet-bundler"
npm install --save-dev @tetherto/wdk-worklet-bundler
```
## Create `wdk.config.js`
Use `init` to create a starter config, or write the file yourself:
```bash title="Initialize A Starter Config"
npx wdk-worklet-bundler init
```
The published config surface accepts `networks`, optional `protocols`, optional `preloadModules`, optional `output`, and optional `options`:
```javascript title="Example wdk.config.js"
module.exports = {
networks: {
ethereum: {
package: '@tetherto/wdk-wallet-evm-erc-4337'
},
bitcoin: {
package: '@tetherto/wdk-wallet-btc'
}
},
protocols: {
moonpay: {
package: '@tetherto/wdk-protocol-fiat-moonpay'
}
},
preloadModules: [
'spark-frost-bare-addon'
],
output: {
bundle: './.wdk-bundle/wdk-worklet.bundle.js',
types: './.wdk/index.d.ts'
},
options: {
minify: false,
sourceMaps: false,
targets: ['ios-arm64', 'android-arm64']
}
}
```
## Required fields
### `networks`
`networks` is required. Each key is a logical network name, and each value must provide a `package` string for the wallet module to bundle.
The loader also accepts local paths that resolve relative to the config file’s directory:
```javascript title="Use A Local Wallet Package"
module.exports = {
networks: {
local_dev: {
package: './local-packages/my-custom-wallet'
}
}
}
```
## Optional fields
### `protocols` (optional)
Use `protocols` when the worklet should preload WDK protocol packages alongside wallet modules.
### `preloadModules` (optional)
Use `preloadModules` for native addons or other modules that must be required before the generated worklet starts.
### `output` (optional)
If you omit `output.bundle`, the loader resolves the bundle path to `./.wdk-bundle/wdk-worklet.bundle.js`. If you omit `output.types`, the loader resolves the type path to `./.wdk/index.d.ts`.
### `options` (optional)
The published config type supports these build options:
* `minify` (`boolean`): Minify the generated bundle.
* `sourceMaps` (`boolean`): Request source map output.
* `targets` (`string[]`): Override the default Bare build hosts. The shipped defaults cover iOS arm64 and simulator targets plus Android arm, arm64, ia32, and x64 hosts.
## Validate and generate the bundle
Use `validate` to check the config and dependency resolution before you generate the bundle:
```bash title="Validate wdk.config.js"
npx wdk-worklet-bundler validate
```
Use `generate` to build the worklet artifact:
```bash title="Generate The Worklet Bundle"
npx wdk-worklet-bundler generate --install
```
`generate --install` can auto-install missing configured modules after the package manager is detected from the project root. Use `--source-only` when you want the generated `.wdk/wdk-worklet.generated.js` entrypoint and related artifacts without running `bare-pack`.
## Suspend and resume behavior
Generated `beta.3` worklet entrypoints register Bare lifecycle handlers for `suspend` and `resume`, then apply those handlers to both the `bare-http1` and `bare-https` global agents. No config flag is required for this behavior.
This matters when a generated worklet performs HTTPS-backed fetches. In `beta.2`, only the `bare-http1` agent was suspended and resumed. In `beta.3`, generated worklets suspend and resume both agents together.
## Troubleshooting
* If `loadConfig()` cannot find a config file, run `npx wdk-worklet-bundler init` or pass `--config \`.
* If `validate` or `generate` reports missing modules, use `generate --install` or inspect the install command from the exported helper APIs in the [API Reference](./api-reference).
* If you need to inspect generated source before bundling, use `generate --source-only` and review the files in `.wdk/`.
***
## Need Help?
# Worklet Bundler (/tools/worklet-bundler)
Worklet Bundler packages selected WDK wallet and protocol modules into a Bare runtime bundle that runs outside your main React Native application thread. Powered by [`@tetherto/wdk-worklet-bundler`](https://github.com/tetherto/wdk-worklet-bundler).
## Features
* **Config-driven bundle generation**: Map logical network names to wallet packages and optional protocol names to protocol packages in `wdk.config.js`.
* **Generated worklet artifact**: Produce a bundle for the Bare runtime plus generated TypeScript types for the host app.
* **Dependency validation helpers**: Validate configured modules, detect the active package manager, and generate install or uninstall commands when dependencies are missing.
* **CLI workflow**: Use `init`, `validate`, `generate`, `list-modules`, and `clean` without building your own wrapper.
* **Bare suspend and resume handling**: `beta.3` generated entrypoints suspend and resume both the `bare-http1` and `bare-https` global agents when the Bare thread lifecycle changes.
## Why this matters
* Bundle generation keeps wallet and protocol code in a separate Bare worklet instead of the UI thread.
* The generated type output gives the host app a stable import for the bundle surface.
* The `beta.3` runtime fix reduces the chance that HTTPS-backed worklet fetches keep running after a Bare thread suspension.
Set up `wdk.config.js`, review defaults, and understand the generated runtime behavior.
Review the exported config types, dependency helpers, and bundle-generation functions.
***
## Need Help?
# Bridge USD₮0 EVM API Reference (/sdk/bridge-modules/bridge-usdt0-evm/api-reference)
## Table of Contents
| Class | Description | Methods |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------ |
| [Usdt0ProtocolEvm](#usdt0protocolevm) | Main class for bridging USD₮0 tokens across blockchains. Extends `BridgeProtocol` from `@tetherto/wdk-wallet/protocols`. | [Constructor](#constructor), [Methods](#methods) |
## Usdt0ProtocolEvm
The main class for bridging USD₮0 tokens across different blockchains using the LayerZero protocol.
Extends `BridgeProtocol` from `@tetherto/wdk-wallet/protocols`.
### Constructor
```javascript
new Usdt0ProtocolEvm(account, config?)
```
**Parameters:**
* `account` (WalletAccountEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvm | WalletAccountReadOnlyEvmErc4337): The wallet account to use for bridge operations
* `config` (BridgeProtocolConfig, optional): Configuration object
* `bridgeMaxFee` (number | bigint, optional): Maximum total bridge cost in wei
**Example:**
```javascript
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://eth.drpc.org'
})
const bridgeProtocol = new Usdt0ProtocolEvm(account, {
bridgeMaxFee: 1000000000000000n // Maximum bridge fee in wei
})
```
### Methods
| Method | Description | Returns | Throws |
| ------------------------------- | ---------------------------------------- | ------------------------------------- | --------------------------------- |
| `bridge(options, config?)` | Bridges tokens to another blockchain | `Promise` | If no provider or fee exceeds max |
| `quoteBridge(options, config?)` | Estimates the cost of a bridge operation | `Promise>` | If no provider |
#### `bridge(options, config?)`
Bridges tokens to a different blockchain using the USD₮0 protocol.
Before calling `bridge()`, approve the token allowance for the source-chain bridge spender. If you pass `oftContractAddress`, use the same address as the approval `spender`.
**Parameters:**
* `options` (BridgeOptions): Bridge operation options
* `targetChain` (string): Destination chain name
* `recipient` (string): Address that will receive the bridged tokens (EVM hex address, Solana base58 address, TON address, or TRON address)
* `token` (string): Token contract address on source chain
* `amount` (number | bigint): Amount to bridge in token base units
* `oftContractAddress` (string, optional): Custom OFT contract address to use instead of auto-resolving from the source chain
* `dstEid` (number, optional): Custom LayerZero destination endpoint ID override
* `config` (`Pick & Pick`, optional): Override configuration for ERC-4337 accounts
* `paymasterToken` (`{ address: string }`, optional): Paymaster token configuration for gas fees
* `bridgeMaxFee` (number | bigint, optional): Override maximum bridge fee
**Returns:** `Promise` - Bridge operation result
**Throws:**
* Error if account is read-only
* Error if no provider is configured
* Error if bridge fee exceeds maximum allowed
**Example:**
```javascript
// Standard EVM account
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // ₮ contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
console.log('Bridge hash:', result.hash)
console.log('Total fee:', result.fee)
console.log('Bridge fee:', result.bridgeFee)
// ERC-4337 account
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result2 = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
}, {
paymasterToken: { address: '0x...' }, // Paymaster token configuration
bridgeMaxFee: 1000000000000000n
})
console.log('Bridge hash:', result2.hash) // Single hash for bundled operations
console.log('Total fee:', result2.fee)
console.log('Bridge fee:', result2.bridgeFee)
```
#### `quoteBridge(options, config?)`
Estimates the cost of a bridge operation without executing it.
Some providers estimate the same bridge transaction that `bridge()` sends. If that estimate fails because token allowance is missing, approve the source-chain bridge spender before calling `quoteBridge()`.
**Parameters:**
* `options` (BridgeOptions): Bridge operation options (same as bridge method)
* `config` (`Pick`, optional): Override configuration for ERC-4337 accounts
* `paymasterToken` (`{ address: string }`, optional): Paymaster token configuration for gas fees
**Returns:** `Promise>` - Bridge cost estimate
**Throws:** Error if no provider is configured
**Example:**
```javascript
const quote = await bridgeProtocol.quoteBridge({
targetChain: 'polygon',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n
})
console.log('Estimated fee:', quote.fee, 'wei')
console.log('Bridge fee:', quote.bridgeFee, 'wei')
// Check if fees are acceptable
if (quote.fee + quote.bridgeFee > 1000000000000000n) {
console.log('Bridge fees too high')
} else {
// Proceed with bridge
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'polygon',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
}
```
## Types
### BridgeOptions
```typescript
interface BridgeOptions {
targetChain: string; // Destination chain name
recipient: string; // Address that will receive bridged tokens
token: string; // Token contract address on source chain
amount: number | bigint; // Amount to bridge in token base units
oftContractAddress?: string; // Optional custom OFT contract address
dstEid?: number; // Optional destination endpoint ID override
}
```
### BridgeResult
```typescript
interface BridgeResult {
hash: string; // Main bridge transaction hash
fee: bigint; // Total gas cost in wei
bridgeFee: bigint; // Bridge protocol fee in wei
}
```
### BridgeProtocolConfig
```typescript
interface BridgeProtocolConfig {
bridgeMaxFee?: number | bigint; // Maximum total bridge cost in wei
}
```
### EvmErc4337WalletConfig
```typescript
interface EvmErc4337WalletConfig {
paymasterToken?: { // Token to use for paying gas fees
address: string;
};
}
```
### Supported Chains
The bridge protocol supports the following chains:
**Source Chains (EVM):**
* `'ethereum'` (Chain ID: 1)
* `'arbitrum'` (Chain ID: 42161) - ERC-4337 support
* `'optimism'` (Chain ID: 10)
* `'polygon'` (Chain ID: 137)
* `'berachain'` (Chain ID: 80094)
* `'ink'` (Chain ID: 57073)
* `'plasma'` (Chain ID: 9745)
* `'conflux'` (Chain ID: 1030)
* `'corn'` (Chain ID: 21000000)
* `'avalanche'` (Chain ID: 43114)
* `'celo'` (Chain ID: 42220)
* `'flare'` (Chain ID: 14)
* `'hyperevm'` (Chain ID: 999)
* `'mantle'` (Chain ID: 5000)
* `'megaeth'` (Chain ID: 4326)
* `'monad'` (Chain ID: 143)
* `'morph'` (Chain ID: 2818)
* `'rootstock'` (Chain ID: 30)
* `'sei'` (Chain ID: 1329)
* `'stable'` (Chain ID: 988)
* `'unichain'` (Chain ID: 130)
* `'xlayer'` (Chain ID: 196)
**Destination Chains:**
* **EVM destinations**: same as source-chain set above
* `'solana'` (EID: 30168)
* `'ton'` (EID: 30343)
* `'tron'` (EID: 30420)
## Error Handling
The bridge protocol throws specific errors for different failure cases:
```javascript
try {
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
} catch (error) {
if (error.message.includes('not supported')) {
console.error('Chain or token not supported')
}
if (error.message.includes('Exceeded maximum fee')) {
console.error('Bridge fee too high')
}
if (error.message.includes('must be connected to a provider')) {
console.error('Wallet not connected to blockchain')
}
if (error.message.includes('requires the protocol to be initialized with a non read-only account')) {
console.error('Cannot bridge with read-only account')
}
if (error.message.includes('cannot be equal to the source chain')) {
console.error('Cannot bridge to the same chain')
}
}
```
## Usage Examples
### Basic Bridge Operation
```javascript
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'
async function bridgeTokens() {
// Create wallet account
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://eth.drpc.org'
})
// Create bridge protocol
const bridgeProtocol = new Usdt0ProtocolEvm(account, {
bridgeMaxFee: 1000000000000000n
})
// Get quote first
const quote = await bridgeProtocol.quoteBridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n
})
console.log('Bridge quote:', quote)
// Execute bridge
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
console.log('Bridge result:', result)
return result
}
```
### Multi-Chain Bridge
```javascript
async function bridgeToMultipleChains(account, bridgeProtocol) {
const chains = ['arbitrum', 'polygon', 'ethereum']
const token = '0x...' // USDT contract address
const amount = 1000000n
const recipient = '0x...' // Recipient address
const results = []
for (const chain of chains) {
try {
// Get quote
const quote = await bridgeProtocol.quoteBridge({
targetChain: chain,
recipient,
token,
amount
})
console.log(`Bridge to ${chain}:`, quote)
// Execute bridge
await account.approve({
token,
spender: '0x...', // OFT or bridge spender address for the source route
amount
})
const result = await bridgeProtocol.bridge({
targetChain: chain,
recipient,
token,
amount,
oftContractAddress: '0x...' // Same address used as approval spender
})
results.push({ chain, result })
console.log(`Bridge to ${chain} successful:`, result.hash)
} catch (error) {
console.error(`Bridge to ${chain} failed:`, error.message)
}
}
return results
}
```
### ERC-4337 Gasless Bridge
```javascript
import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337'
async function gaslessBridge() {
// Create ERC-4337 account
const account = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", {
chainId: 42161,
provider: 'https://arb1.arbitrum.io/rpc',
bundlerUrl: 'https://api.candide.dev/public/v3/arbitrum',
entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
safeModulesVersion: '0.3.0',
paymasterUrl: 'https://api.candide.dev/public/v3/arbitrum',
paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
paymasterToken: { address: '0x...' } // Paymaster token configuration
})
// Create bridge protocol
const bridgeProtocol = new Usdt0ProtocolEvm(account, {
bridgeMaxFee: 1000000000000000n
})
// Bridge with gasless transactions
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'polygon',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
}, {
paymasterToken: { address: '0x...' } // Paymaster token configuration
})
console.log('Gasless bridge result:', result)
return result
}
```
Get started with WDK in a Node.js environment
Get started with WDK's Bridge USD₮0 EVM Protocol configuration
Get started with WDK's Bridge USD₮0 EVM Protocol usage
***
### Need Help?
# Bridge USD₮0 EVM Configuration (/sdk/bridge-modules/bridge-usdt0-evm/configuration)
## Bridge Protocol Configuration
The `Usdt0ProtocolEvm` accepts a configuration object that defines how the bridge protocol works:
```javascript
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'
// Create wallet account first
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://eth.drpc.org'
})
// Create bridge protocol with configuration
const bridgeProtocol = new Usdt0ProtocolEvm(account, {
bridgeMaxFee: 1000000000000000n // Optional: Maximum bridge fee in wei
})
```
## Account Configuration
The bridge protocol uses the wallet account's configuration for blockchain access:
```javascript
import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
// Full access account
const account = new WalletAccountEvm(
seedPhrase,
"0'/0/0", // BIP-44 derivation path
{
provider: 'https://eth.drpc.org',
transferMaxFee: 100000000000000
}
)
// Read-only account
const readOnlyAccount = new WalletAccountReadOnlyEvm(
'0x...', // Ethereum address
{
provider: 'https://eth.drpc.org'
}
)
// Create bridge protocol
const bridgeProtocol = new Usdt0ProtocolEvm(account, {
bridgeMaxFee: 1000000000000000n
})
```
## Configuration Options
### Bridge Max Fee
The `bridgeMaxFee` option sets a maximum limit for total bridge costs to prevent unexpectedly high fees.
**Type:** `number | bigint` (optional)
**Unit:** Wei (1 ETH = 1000000000000000000 Wei)
**Examples:**
```javascript
const config = {
// Set maximum bridge fee to 0.001 ETH
bridgeMaxFee: 1000000000000000n,
}
// Usage example
try {
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
} catch (error) {
if (error.message.includes('Exceeded maximum fee')) {
console.error('Bridge cancelled: Fee too high')
}
}
```
### Provider
The `provider` option comes from the wallet account configuration and specifies how to connect to the blockchain.
**Type:** `string | Eip1193Provider`
**Examples:**
```javascript
// Option 1: Using RPC URL
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://eth.drpc.org'
})
// Option 2: Using browser provider (e.g., MetaMask)
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: window.ethereum
})
// Option 3: Using custom JsonRpcProvider
import { JsonRpcProvider } from 'ethers'
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: new JsonRpcProvider('https://eth.drpc.org')
})
```
## ERC-4337 Configuration
When using ERC-4337 accounts, you can override configuration options during bridge operations:
```javascript
// Bridge with ERC-4337 account
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
}, {
paymasterToken: { address: '0x...' }, // Paymaster token for gasless transactions
bridgeMaxFee: 1000000000000000n // Override maximum bridge fee
})
```
### Paymaster Token
The `paymasterToken` option specifies which token to use for paying gas fees in ERC-4337 accounts.
**Type:** `{ address: string }` (optional)
**Format:** Object with token contract address
**Example:**
```javascript
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'arbitrum',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
}, {
paymasterToken: {
address: '0x...' // Paymaster token address
}
})
```
## Network Support
The bridge protocol uses EVM wallet providers as source chains and supports both EVM and non-EVM destinations. Change the provider URL in the wallet account configuration:
```javascript
// Ethereum Mainnet
const ethereumAccount = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://eth.drpc.org'
})
// Arbitrum
const arbitrumAccount = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://arb1.arbitrum.io/rpc'
})
// Polygon
const polygonAccount = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://polygon-rpc.com'
})
```
## Bridge Options
When calling the bridge method, you need to provide bridge options:
```javascript
const bridgeOptions = {
targetChain: 'arbitrum', // Destination chain name
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n, // Amount to bridge in base units
oftContractAddress: '0x...', // Optional custom OFT contract address
dstEid: 30110 // Optional LayerZero destination endpoint ID override
}
await account.approve({
token: bridgeOptions.token,
spender: bridgeOptions.oftContractAddress,
amount: bridgeOptions.amount
})
const result = await bridgeProtocol.bridge(bridgeOptions)
```
### Target Chain
The `targetChain` option specifies which blockchain to bridge tokens to.
**Type:** `string`
**Supported values:** `'ethereum'`, `'arbitrum'`, `'optimism'`, `'polygon'`, `'berachain'`, `'ink'`, `'plasma'`, `'conflux'`, `'corn'`, `'avalanche'`, `'celo'`, `'flare'`, `'hyperevm'`, `'mantle'`, `'megaeth'`, `'monad'`, `'morph'`, `'rootstock'`, `'sei'`, `'stable'`, `'unichain'`, `'xlayer'`, `'solana'`, `'ton'`, `'tron'`
### Recipient
The `recipient` option specifies the address that will receive the bridged tokens.
**Type:** `string`
**Format:** Valid address for the target chain
### Token
The `token` option specifies which token contract to bridge.
**Type:** `string`
**Format:** Token contract address on the source chain
### Amount
The `amount` option specifies how many tokens to bridge.
**Type:** `number | bigint`
**Unit:** Base units of the token (e.g., for USD₮: 1 USD₮ = 1000000n)
### OFT Contract Address
The optional `oftContractAddress` option lets you override auto-discovery and force a specific OFT contract.
**Type:** `string` (optional)
**Format:** Valid EVM contract address on the source chain
### Destination EID Override
The optional `dstEid` option lets you override the default LayerZero destination endpoint ID for the selected target chain.
**Type:** `number` (optional)
## Error Handling
The bridge protocol will throw errors for invalid configurations:
```javascript
try {
await account.approve({
token: '0x...', // USDT contract address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await bridgeProtocol.bridge({
targetChain: 'invalid-chain',
recipient: '0x...', // Recipient address
token: '0x...', // USDT contract address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
} catch (error) {
if (error.message.includes('not supported')) {
console.error('Chain or token not supported')
}
if (error.message.includes('Exceeded maximum fee')) {
console.error('Bridge fee too high')
}
if (error.message.includes('must be connected to a provider')) {
console.error('Wallet not connected to blockchain')
}
}
```
Get started with WDK in a Node.js environment
Get started with WDK's Bridge USD₮0 EVM Protocol API
Get started with WDK's Bridge USD₮0 EVM Protocol usage
***
### Need Help?
# Bridge USD₮0 EVM Overview (/sdk/bridge-modules/bridge-usdt0-evm)
A simple package that lets EVM wallet accounts bridge USD₮0 tokens across different blockchains. This package provides a clean API for moving tokens between chains using the LayerZero protocol and USD₮0 bridge system.
## Features
* **Cross-Chain Bridge**: Move USD₮0 tokens between supported blockchains
* **LayerZero Integration**: Uses LayerZero protocol for secure cross-chain transfers
* **Expanded Multi-Chain Support**: Bridge across 25+ networks including all major EVM chains
* **Non-EVM Destinations**: Bridge to Solana, TON, and TRON from any supported EVM chain
* **Account Abstraction**: Works with both standard EVM wallets and ERC-4337 smart accounts
* **Fee Management**: Built-in fee calculation and bridge cost estimation
* **Token Support**: Supports USD₮0 and XAU₮0 ecosystem tokens
* **Route Overrides**: Custom OFT contract addresses and destination endpoint IDs
* **TypeScript Support**: Full TypeScript definitions included
* **Memory Safety**: Secure transaction handling with proper error management
* **Provider Flexibility**: Works with JSON-RPC URLs and EIP-1193 browser providers
## Supported Networks
### Source Chains (EVM)
| Chain | Chain ID |
| -------------- | -------- |
| Ethereum | 1 |
| Arbitrum | 42161 |
| Optimism | 10 |
| Polygon | 137 |
| Berachain | 80094 |
| Ink | 57073 |
| Plasma | 9745 |
| Conflux eSpace | 1030 |
| Corn | 21000000 |
| Avalanche | 43114 |
| Celo | 42220 |
| Flare | 14 |
| HyperEVM | 999 |
| Mantle | 5000 |
| MegaETH | 4326 |
| Monad | 143 |
| Morph | 2818 |
| Rootstock | 30 |
| Sei | 1329 |
| Stable | 988 |
| Unichain | 130 |
| XLayer | 196 |
### Destination Chains
All source chains above, plus:
| Chain | Endpoint ID (EID) |
| ------ | ----------------- |
| Solana | 30168 |
| TON | 30343 |
| TRON | 30420 |
Token support is determined by the contracts deployed on each chain. The protocol checks for `oftContract`, `legacyMeshContract`, and `xautOftContract` to determine available tokens.
## Next Steps
Get started with WDK in a Node.js environment
Configure the Bridge USD₮0 EVM Protocol
Complete API documentation for the bridge protocol
Installation, quick start, and usage examples
***
## Need Help?
# Bridge USD₮0 EVM Usage (/sdk/bridge-modules/bridge-usdt0-evm/usage)
# Usage
The [@tetherto/wdk-protocol-bridge-usdt0-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-bridge-usdt0-evm) package bridges USD₮0 across EVM and selected non-EVM networks. Use the guides below for setup, standard and gasless bridging, cross-ecosystem recipients, and error handling.
Install the package, attach WalletAccountEvm, and review supported chains.
EVM-to-EVM bridges, quotes, fee caps, and optional OFT or endpoint overrides.
Gasless bridging with WalletAccountEvmErc4337 and paymaster options.
Send toward Solana, TON, or TRON recipients from EVM.
Interpret bridge failures and dispose of signing material safely.
Get started with WDK in a Node.js environment
Configure RPC, fees, and protocol options for this bridge
Constructor, methods, types, and error behavior
***
# Fiat MoonPay API Reference (/sdk/fiat-modules/fiat-moonpay/api-reference)
# API Reference
Complete API documentation for the `@tetherto/wdk-protocol-fiat-moonpay` module.
## Constructor
### `new MoonPayProtocol(account, config)`
Creates a new MoonPayProtocol instance.
**Parameters:**
| Name | Type | Description |
| --------- | ----------------------------------------------------------- | ------------------------------- |
| `account` | `IWalletAccount` \| `IWalletAccountReadOnly` \| `undefined` | Wallet account for transactions |
| `config` | `MoonPayProtocolConfig` | Configuration object |
**Config Options:**
| Name | Type | Required | Default | Description |
| ------------- | --------------------------- | -------- | ------------ | ------------------------------------------------------------------------ |
| `apiKey` | string | Yes | - | Your MoonPay publishable API key |
| `signUrl` | function | No | - | Callback used to sign buy and sell widget URLs through a trusted backend |
| `cacheTime` | number | No | `600000` | Cache duration for currencies (ms) |
| `environment` | `'production' \| 'sandbox'` | No | `production` | MoonPay widget URL endpoint set |
**Example:**
```typescript
import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay';
const moonpay = new MoonPayProtocol(walletAccount, {
apiKey: 'pk_live_xxxxx',
signUrl: async (urlForSignature) => urlForSignature,
environment: 'production',
});
```
***
## Methods
### `buy(options)`
Generates a MoonPay widget URL for purchasing cryptocurrency. If `signUrl` is configured, the URL is signed through that callback before being returned.
**Parameters:**
| Name | Type | Required | Description |
| ---------------------- | ---------------- | -------- | ----------------------------------------------------- |
| `options.cryptoAsset` | string | Yes | Cryptocurrency code (e.g., 'eth', 'btc') |
| `options.fiatCurrency` | string | Yes | Fiat currency code (e.g., 'usd', 'eur') |
| `options.cryptoAmount` | number \| bigint | No\* | Amount in smallest crypto units |
| `options.fiatAmount` | number \| bigint | No\* | Amount in smallest fiat units (cents) |
| `options.recipient` | string | No | Wallet address (uses account address if not provided) |
| `options.config` | MoonPayBuyParams | No | Widget configuration options |
\*Either `cryptoAmount` or `fiatAmount` must be provided, but not both.
**Returns:** `Promise\<{ buyUrl: string }\>`
***
### `sell(options)`
Generates a MoonPay widget URL for selling cryptocurrency. If `signUrl` is configured, the URL is signed through that callback before being returned.
**Parameters:**
| Name | Type | Required | Description |
| ----------------------- | ----------------- | -------- | ------------------------------- |
| `options.cryptoAsset` | string | Yes | Cryptocurrency code |
| `options.fiatCurrency` | string | Yes | Fiat currency code |
| `options.cryptoAmount` | number \| bigint | No\* | Amount in smallest crypto units |
| `options.fiatAmount` | number \| bigint | No\* | Amount in smallest fiat units |
| `options.refundAddress` | string | No | Refund wallet address |
| `options.config` | MoonPaySellParams | No | Widget configuration options |
**Returns:** `Promise\<{ sellUrl: string }\>`
***
### `quoteBuy(options)`
Gets a price quote for a cryptocurrency purchase.
**Parameters:**
| Name | Type | Required | Description |
| ---------------------- | --------------------- | -------- | ------------------------------- |
| `options.cryptoAsset` | string | Yes | Cryptocurrency code |
| `options.fiatCurrency` | string | Yes | Fiat currency code |
| `options.cryptoAmount` | number \| bigint | No\* | Amount in smallest crypto units |
| `options.fiatAmount` | number \| bigint | No\* | Amount in smallest fiat units |
| `options.config` | MoonPayQuoteBuyParams | No | Quote parameters |
**Returns:** `Promise\`
```typescript
{
cryptoAmount: bigint, // Crypto amount you'll receive
fiatAmount: bigint, // Fiat amount to pay
fee: bigint, // Total fee amount
rate: string, // Exchange rate
metadata: MoonPayBuyQuoteMetadata
}
```
***
### `quoteSell(options)`
Gets a price quote for selling cryptocurrency.
**Parameters:**
| Name | Type | Required | Description |
| ---------------------- | ---------------------- | -------- | ------------------------------- |
| `options.cryptoAsset` | string | Yes | Cryptocurrency code |
| `options.fiatCurrency` | string | Yes | Fiat currency code |
| `options.cryptoAmount` | number \| bigint | Yes | Amount in smallest crypto units |
| `options.config` | MoonPayQuoteSellParams | No | Quote parameters |
**Returns:** `Promise\`
```typescript
{
cryptoAmount: bigint, // Crypto amount to sell
fiatAmount: bigint, // Fiat amount you'll receive
fee: bigint, // Total fee amount
rate: string, // Exchange rate
metadata: MoonPaySellQuoteMetadata
}
```
***
### `getSupportedCryptoAssets()`
Fetches the list of supported cryptocurrencies. Results are cached.
**Returns:** `Promise\`
```typescript
{
code: string, // Currency code (e.g., 'eth')
decimals: number, // Decimal places
networkCode: string, // Network identifier
name: string, // Display name
metadata: MoonPayCryptoCurrencyDetails
}
```
***
### `getSupportedFiatCurrencies()`
Fetches the list of supported fiat currencies. Results are cached.
**Returns:** `Promise\`
```typescript
{
code: string, // Currency code (e.g., 'usd')
decimals: number, // Decimal places
name: string, // Display name
metadata: MoonPayFiatCurrencyDetails
}
```
***
### `getSupportedCountries()`
Fetches the list of supported countries.
**Returns:** `Promise\`
```typescript
{
code: string, // ISO country code
name: string, // Country name
isBuyAllowed: boolean, // Buy operations allowed
isSellAllowed: boolean,// Sell operations allowed
metadata: MoonPayCountryDetail
}
```
***
### `getTransactionDetail(txId, direction?)`
Retrieves details of a specific transaction.
**Parameters:**
| Name | Type | Required | Default | Description |
| ----------- | ----------------- | -------- | ------- | ---------------------- |
| `txId` | string | Yes | - | MoonPay transaction ID |
| `direction` | `'buy' \| 'sell'` | No | `'buy'` | Transaction type |
**Returns:** `Promise\`
```typescript
{
status: 'completed' | 'failed' | 'in_progress',
cryptoAsset: string,
fiatCurrency: string,
metadata: MoonPayBuyTransaction | MoonPaySellTransaction
}
```
***
## Types
### `MoonPayProtocolConfig`
```typescript
interface MoonPayProtocolConfig {
apiKey: string;
signUrl?: (urlForSignature: string) => Promise;
cacheTime?: number;
environment?: 'production' | 'sandbox';
}
```
### `MoonPayBuyParams`
Widget configuration options for `buy()` operations:
```typescript
interface MoonPayBuyParams {
// UI options (shared with MoonPaySellParams)
colorCode?: string;
theme?: 'dark' | 'light';
themeId?: string;
language?: string;
showAllCurrencies?: boolean;
showOnlyCurrencies?: string;
showWalletAddressForm?: boolean;
redirectURL?: string;
unsupportedRegionRedirectUrl?: string;
skipUnsupportedRegionScreen?: boolean;
// Buy-specific options
defaultCurrencyCode?: string;
walletAddress?: string;
walletAddressTag?: string;
walletAddresses?: string;
walletAddressTags?: string;
contractAddress?: string;
networkCode?: string;
lockAmount?: boolean;
email?: string;
externalTransactionId?: string;
externalCustomerId?: string;
paymentMethod?: string;
}
```
### `MoonPaySellParams`
Widget configuration options for `sell()` operations:
```typescript
interface MoonPaySellParams {
// UI options (shared with MoonPayBuyParams)
colorCode?: string;
theme?: 'dark' | 'light';
themeId?: string;
language?: string;
showAllCurrencies?: boolean;
showOnlyCurrencies?: string;
showWalletAddressForm?: boolean;
redirectURL?: string;
unsupportedRegionRedirectUrl?: string;
skipUnsupportedRegionScreen?: boolean;
// Sell-specific options
defaultBaseCurrencyCode?: string;
refundWalletAddresses?: string;
lockAmount?: boolean;
email?: string;
externalTransactionId?: string;
externalCustomerId?: string;
paymentMethod?: string;
}
```
### `MoonPayQuoteBuyParams`
```typescript
interface MoonPayQuoteBuyParams {
extraFeePercentage?: number; // 0-10%
paymentMethod?: string;
areFeesIncluded?: boolean;
walletAddress?: string;
}
```
### `MoonPayQuoteSellParams`
```typescript
interface MoonPayQuoteSellParams {
extraFeePercentage?: number; // 0-10%
payoutMethod?: string;
}
```
***
## Next Steps
* [Configuration](./configuration) - Setup and configuration options
* [Usage Guide](./usage) - Common usage patterns
# Fiat MoonPay Configuration (/sdk/fiat-modules/fiat-moonpay/configuration)
# Configuration
This page covers all configuration options for the MoonPay fiat module, including optional URL signing and environment selection.
## Prerequisites
Before using this module, you need:
1. A MoonPay developer account - [Create an account on MoonPay Dashboard](https://dashboard.moonpay.com/signup)
2. A publishable API key from your dashboard
3. If you want signed widget URLs, a trusted backend signing endpoint for the `signUrl` callback
## Installation
```bash
npm install @tetherto/wdk-protocol-fiat-moonpay
```
## Basic Configuration
```typescript
import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay';
const moonpay = new MoonPayProtocol(walletAccount, {
apiKey: 'pk_live_xxxxx', // Your MoonPay publishable API key
signUrl: async (urlForSignature) => {
const response = await fetch('/api/moonpay/sign-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ urlForSignature }),
});
if (!response.ok) {
throw new Error(`Failed to sign MoonPay URL: ${response.status} ${response.statusText}`);
}
const { signedUrl } = await response.json();
return signedUrl;
},
environment: 'sandbox',
});
```
## Configuration Options
| Option | Type | Required | Default | Description |
| ------------- | --------------------------- | -------- | ----------------- | ------------------------------------------------------------------------ |
| `apiKey` | string | Yes | - | Your MoonPay publishable API key |
| `signUrl` | function | No | - | Callback used to sign buy and sell widget URLs through a trusted backend |
| `cacheTime` | number | No | `600000` (10 min) | Duration in milliseconds to cache supported currencies |
| `environment` | `'production' \| 'sandbox'` | No | `production` | MoonPay widget URL endpoint set |
## Constructor Overloads
The `MoonPayProtocol` class supports three constructor patterns:
```typescript
// Without account (for public read operations like fetching supported currencies)
const moonpay = new MoonPayProtocol(undefined, config);
// With read-only account
const moonpay = new MoonPayProtocol(readOnlyAccount, config);
// With full wallet account (for buy/sell operations)
const moonpay = new MoonPayProtocol(walletAccount, config);
```
## Environment Configuration
### Sandbox (Testing)
Use sandbox endpoints for development and testing:
```typescript
const moonpay = new MoonPayProtocol(walletAccount, {
apiKey: 'pk_test_xxxxx',
signUrl: async (urlForSignature) => {
const response = await fetch('/api/moonpay/sign-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ urlForSignature }),
});
return (await response.json()).signedUrl;
},
environment: 'sandbox',
});
```
In sandbox mode:
* No real transactions are processed
* Use test card numbers provided by MoonPay
* KYC verification is simulated
If you do not need signed URLs, omit `signUrl` and the protocol returns unsigned widget URLs directly.
### Production
For production deployments, use live API keys and the production endpoint set:
```typescript
const moonpay = new MoonPayProtocol(walletAccount, {
apiKey: 'pk_live_xxxxx',
signUrl: async (urlForSignature) => {
const response = await fetch('/api/moonpay/sign-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ urlForSignature }),
});
return (await response.json()).signedUrl;
},
environment: 'production',
});
```
## Widget Customization
When calling `buy()` or `sell()`, you can customize the MoonPay widget appearance:
```typescript
const result = await moonpay.buy({
cryptoAsset: 'eth',
fiatCurrency: 'usd',
fiatAmount: 10000n, // $100.00 in cents
config: {
colorCode: '#3B82F6', // Your brand color (hex)
theme: 'dark', // 'dark' or 'light'
language: 'en', // ISO 639-1 language code
redirectURL: 'https://yourapp.com/callback',
},
});
```
### Available Buy Widget Options
| Option | Type | Description |
| ------------------------------ | ------------------- | ------------------------------------------------------- |
| `colorCode` | string | Hexadecimal color for widget accent |
| `theme` | `'dark' \| 'light'` | Widget appearance theme |
| `themeId` | string | ID of a custom theme |
| `language` | string | ISO 639-1 language code |
| `showAllCurrencies` | boolean | Show all supported cryptocurrencies |
| `showOnlyCurrencies` | string | Comma-separated currency codes to display |
| `showWalletAddressForm` | boolean | Show wallet address input form |
| `redirectURL` | string | URL to redirect after completion |
| `unsupportedRegionRedirectUrl` | string | URL for unsupported regions |
| `skipUnsupportedRegionScreen` | boolean | Skip unsupported region screen |
| `defaultCurrencyCode` | string | Pre-selected cryptocurrency code |
| `walletAddress` | string | Pre-filled wallet address |
| `walletAddressTag` | string | Wallet address memo/tag (for EOS, XRP, etc.) |
| `walletAddresses` | string | JSON string of wallet addresses for multiple currencies |
| `walletAddressTags` | string | JSON string of address tags for multiple currencies |
| `contractAddress` | string | Token contract address (DeFi Buy only) |
| `networkCode` | string | Network for the token contract (DeFi Buy only) |
| `lockAmount` | boolean | Prevent user from changing amount |
| `email` | string | Pre-fill customer email |
| `externalTransactionId` | string | Your transaction identifier |
| `externalCustomerId` | string | Your customer identifier |
| `paymentMethod` | string | Pre-select payment method |
### Available Sell Widget Options
For `sell()`, the widget config uses `MoonPaySellParams` with different options:
| Option | Type | Description |
| ------------------------------ | --------------------- | ------------------------------------------- |
| `colorCode` | string | Hexadecimal color for widget accent |
| `theme` | `'dark'` \| `'light'` | Widget appearance theme |
| `themeId` | string | ID of a custom theme |
| `language` | string | ISO 639-1 language code |
| `showAllCurrencies` | boolean | Show all supported cryptocurrencies |
| `showOnlyCurrencies` | string | Comma-separated currency codes to display |
| `showWalletAddressForm` | boolean | Show wallet address input form |
| `redirectURL` | string | URL to redirect after completion |
| `unsupportedRegionRedirectUrl` | string | URL for unsupported regions |
| `skipUnsupportedRegionScreen` | boolean | Skip unsupported region screen |
| `defaultBaseCurrencyCode` | string | Pre-selected cryptocurrency to sell |
| `refundWalletAddresses` | string | JSON string of wallet addresses for refunds |
| `lockAmount` | boolean | Prevent user from changing amount |
| `email` | string | Pre-fill customer email |
| `externalTransactionId` | string | Your transaction identifier |
| `externalCustomerId` | string | Your customer identifier |
| `paymentMethod` | string | Pre-select payout method |
## Next Steps
* [Usage Guide](./usage) - Learn how to integrate MoonPay
* [API Reference](./api-reference) - Complete API documentation
# Fiat MoonPay Overview (/sdk/fiat-modules/fiat-moonpay)
# @tetherto/wdk-protocol-fiat-moonpay Overview
A WDK module for integrating MoonPay's fiat on-ramp and off-ramp services. This module generates signed or unsigned widget URLs that allow users to buy and sell cryptocurrency using fiat currencies directly within your application. Provide a `signUrl` callback if you want the protocol to return signed URLs from a trusted backend, or omit it to use the unsigned widget URLs directly.
Get started by reading the [Usage](./usage) guide.
This module requires a MoonPay developer account. [Create your account here](https://dashboard.moonpay.com/signup).
If you want MoonPay to sign the widget URLs before they are returned, provide a `signUrl` callback that talks to a trusted backend signer. If you omit `signUrl`, the protocol returns unsigned widget URLs directly.
## Features
* **Fiat On-Ramp**: Generate signed or unsigned widget URLs for users to buy cryptocurrency with fiat
* **Fiat Off-Ramp**: Generate signed or unsigned widget URLs for users to sell cryptocurrency with fiat
* **Price Quotes**: Get real-time quotes for buy and sell operations
* **Transaction Tracking**: Retrieve transaction status and details
* **Currency Support**: Query supported cryptocurrencies, fiat currencies, and countries
* **Customizable Widget**: Configure colors, themes, language, and behavior
## Supported Payment Methods
* Credit and debit cards (Visa, Mastercard, etc.)
* Bank transfers (ACH, SEPA, etc.)
* Apple Pay and Google Pay
* Local payment methods (varies by region)
For the full list of supported payment methods by country, see [MoonPay's Supported Payment Methods](https://support.moonpay.com/en/articles/380823-moonpay-s-supported-payment-methods).
## Supported Cryptocurrencies
This module supports purchasing and selling cryptocurrencies on networks compatible with WDK wallet modules, including:
* Ethereum and EVM-compatible chains (ETH, USD₮, etc.)
* Bitcoin (BTC)
* TRON (TRX, USD₮)
* TON
* Solana (SOL, USD₮)
## Next Steps
Set up your MoonPay API key, optional signing callback, and environment
Learn how to integrate MoonPay in your application
Complete API documentation for the module
***
### MoonPay Resources
* [MoonPay Dashboard](https://dashboard.moonpay.com/signup) - Create your developer account
* [MoonPay Support Center](https://support.moonpay.com/) - Official MoonPay documentation and support
* [Supported Payment Methods](https://support.moonpay.com/en/articles/380823-moonpay-s-supported-payment-methods) - Full list by country
***
### Need Help?
# Fiat MoonPay Usage (/sdk/fiat-modules/fiat-moonpay/usage)
# Usage
The [@tetherto/wdk-protocol-fiat-moonpay](https://www.npmjs.com/package/@tetherto/wdk-protocol-fiat-moonpay) module builds signed MoonPay widget URLs and quotes for on-ramp and off-ramp flows. Use the guides below for setup, trading, and transaction follow-up.
Install the package and initialize MoonPayProtocol.
On-ramp, off-ramp, quotes, supported assets, widget options, recipients.
Check status and load transaction details from MoonPay.
Get started with WDK in a Node.js environment
API keys, caching, and MoonPay configuration options
Constructor, methods, and types for MoonPayProtocol
# Manage Accounts (/sdk/core-module/guides/account-management)
This guide explains how to access accounts from your registered wallets. An "Account" object in WDK is your interface for inspecting balances and sending transactions on a specific blockchain.
## Retrieve Accounts
You can retrieve an account using a simple index or a custom derivation path.
### By Index (Recommended)
The simplest way to get an account is by its index (starting at `0`). This uses the default derivation path for the specified blockchain.
```typescript title="Get Account by Index"
// Get the first account (index 0) for Ethereum and TON
const ethAccount = await wdk.getAccount('ethereum', 0)
const tonAccount = await wdk.getAccount('ton', 0)
```
### By Derivation Path (Advanced)
If you need a specific hierarchy, you can request an account by its unique derivation path.
```typescript title="Get Account by Path"
// Custom path for Ethereum
const customEthAccount = await wdk.getAccountByPath('ethereum', "0'/0/1")
```
The WDK instance caches accounts. If you call `getAccount` twice using the same index, the function will return the same `Account` object instance.
**Network Mismatch Warning**
Ensure your WDK instance configuration matches your account environment.
* If using **Testnet** keys, ensure you registered the wallet with a **Testnet RPC** (e.g., `https://sepolia.drpc.org` for ETH, `https://testnet.toncenter.com/api/v2/jsonRPC` for TON).
* If using **Mainnet** keys, ensure you registered the wallet with a **Mainnet RPC** (e.g., `https://eth.drpc.org` for ETH, `https://toncenter.com/api/v2/jsonRPC` for TON).
Using a Mainnet key on a Testnet RPC (or vice versa) will result in "Network not allowed" or zero balance errors.
## View Addresses
Once you have an account object, you can retrieve its public blockchain address using the `getAddress` function.
```typescript title="Get Addresses"
const ethAddress = await ethAccount.getAddress()
console.log('Ethereum address:', ethAddress)
```
## Check Balances
You can check the native token balance of any account (e.g., ETH on Ethereum, TON on TON) by using the `getBalance()` function.
```typescript title="Get Balance"
try {
const balance = await ethAccount.getBalance()
console.log('Balance:', balance)
} catch (error) {
console.error('Failed to fetch balance:', error)
}
```
### Multi-Chain Balance Check
Because WDK offers a unified interface, you can easily iterate through multiple chains to fetch balances.
The following example:
1. Iterates over an array of user defined chains.
2. Retrieves the first account using the respective chain's `getAccount(index)` function.
3. Retrieves the first account's balance using the `getBalance()` function.
4. Logs the balance to the console.
```typescript title="Check All Balances"
const chains = ['ethereum', 'ton', 'bitcoin']
for (const chain of chains) {
try {
const account = await wdk.getAccount(chain, 0)
const balance = await account.getBalance()
console.log(`${chain} balance:`, balance)
} catch (error) {
console.log(`${chain}: Wallet not registered or unavailable`)
}
}
```
## Next Steps
Now that you can access your accounts, learn how to [send transactions](./transactions).
# Error Handling (/sdk/core-module/guides/error-handling)
# Error Handling & Best Practices
This guide covers recommended patterns for error handling and security when using the WDK.
## Handling Common Errors
When interacting with multiple chains and protocols, various runtime issues may occur.
### Missing Registration
The most common error is attempting to access a wallet or protocol that hasn't been registered.
```typescript title="Check Registration Pattern"
try {
// This will throw if 'tron' was never registered via .registerWallet()
const tronAccount = await wdk.getAccount('tron', 0)
} catch (error) {
console.error('Tron wallet not available:', error.message)
}
```
Always use `try/catch` blocks when initializing sessions or accessing dynamic features.
## Memory Management
For security, clear sensitive data from memory when a session is complete. The WDK provides [`dispose()`](../api-reference) for this purpose.
### Disposing the Instance
You can clear every registered wallet using [`dispose()`](../api-reference):
```typescript title="Dispose WDK"
function endSession(wdk) {
// 1. Clean up sensitive data
wdk.dispose()
// 2. Modify app state to reflect logged-out status
// ...
console.log('Session ended, wallet data cleared.')
}
```
### Disposing Specific Wallets
You can dispose only the wallets you no longer need using [`dispose()`](../api-reference):
```typescript title="Dispose Specific Wallets"
// Keep the TON wallet registered, but dispose the Ethereum wallet
wdk.dispose(['ethereum'])
```
**After Disposal:** Once a wallet is disposed, any later call that depends on that wallet registration will fail until you register it again. If you call `wdk.dispose()` without arguments, you must instantiate a new WDK instance or register fresh wallets before resuming operations.
## Security Best Practices
### Environment Variables
Never hardcode API keys or seed phrases in your source code. Use environment variables (e.g., `process.env.TON_API_KEY`).
### Secure Storage
If you persist a session, never store the raw seed phrase in local storage. Use secure operating system storage (like Keychain on macOS or Keystore on Android).
# Getting Started (/sdk/core-module/guides/getting-started)
This guide explains how to install the [`@tetherto/wdk`](https://www.npmjs.com/package/@tetherto/wdk) package and create a new instance to start managing your wallets.
## 1. Installation
### Prerequisites
Before you begin, ensure you have the following installed:
* **[Node.js](https://nodejs.org/)**: version 18 or higher.
* **[npm](https://www.npmjs.com/)**: usually comes with Node.js.
### Install Package
To install the WDK Core package, run the following command in your terminal:
```bash
npm install @tetherto/wdk
```
This package allows you to manage different blockchain wallets and protocols through a single interface.
## 2. Instantiation
To use WDK, you must create an instance of the `WDK` class. This instance acts as the central manager for all your wallets and protocols.
### Import the Module
First, import the `WDK` class from the package:
```typescript title="Import WDK Core"
import WDK from '@tetherto/wdk'
```
### Initialize WDK
You can initialize `WDK` in two ways: with a [new seed phrase](#generate-a-new-wallet) or an [existing one](#restore-an-existing-wallet).
#### Generate a New Wallet
If you are creating a fresh wallet for a user, use the static `getRandomSeedPhrase()` method to generate a secure mnemonic.
```typescript title="Create new WDK Instance"
// 1. Generate a secure random seed phrase
// Generate 24-word seed phrase for higher security
const seedPhrase = WDK.getRandomSeedPhrase(24)
// Or use 12-word seed phrase (default)
// const seedPhrase = WDK.getRandomSeedPhrase()
// 2. Initialize the WDK instance with the new seed
const wdk = new WDK(seedPhrase)
```
**Secure the Seed Phrase:** You must securely store this seed phrase immediately. If it is lost, the user will permanently lose access to their funds.
#### Restore an Existing Wallet
If a user already has a seed phrase (e.g., from a previous session or another wallet), you can pass it directly to the constructor.
```typescript title="Restore WDK Instance"
// Replace this string with the user's actual seed phrase
const existingSeed = 'witch collapse practice feed shame open despair creek road again ice ...'
const wdk = new WDK(existingSeed)
```
## Next Steps
With your WDK instance ready, you can now [register wallet modules](./wallet-registration) to interact with specific blockchains like [Ethereum](../../wallet-modules/wallet-evm/), [TON](../../wallet-modules/wallet-ton/), or [Bitcoin](../../wallet-modules/wallet-btc/).
# Configure Middleware (/sdk/core-module/guides/middleware)
Middleware allows you to intercept wallet operations. You can use this to add [logging](#logging), implement retry logic, or handle [failovers for RPC providers](#failover-protection-with-provider-failover).
## Register Middleware
When registering middleware, you should reference a specific chain. The middleware function runs every time an account is instantiated or an operation is performed, depending on the implementation.
### Logging
This simple middleware logs a message whenever a new account is accessed.
```typescript title="Logging Middleware"
wdk.registerMiddleware('ethereum', async (account) => {
const address = await account.getAddress()
console.log('Accessed Ethereum account:', address)
// You can also attach custom properties or wrap methods here
})
```
## Failover Protection with Provider Failover
The [`@tetherto/wdk-provider-failover`](https://www.npmjs.com/package/@tetherto/wdk-provider-failover) package provides a resilient wrapper for wallet instances. Unlike standard middleware, you wrap your wallet class instantiation directly.
### Install `@tetherto/wdk-provider-failover`
You can install the `@tetherto/wdk-provider-failover` using npm with the following command:
```bash
npm install @tetherto/wdk-provider-failover
```
### Use `createFallbackWallet`
You can import the `createFallbackWallet` function to ensure that if your primary RPC fails, the wallet automatically retries with the fallback providers.
With this configuration, if `sendTransaction` fails due to a network error, the WDK will automatically retry using the fallback providers without throwing an error to your application.
```typescript title="Failover Wrapper Usage"
import { createFallbackWallet } from '@tetherto/wdk-provider-failover'
import { WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
const wallet = createFallbackWallet(
WalletAccountReadOnlyEvm,
['0x...'], // constructor args
{
primary: { provider: 'https://mainnet.infura.io/v3/YOUR_KEY' },
fallbacks: [
{ provider: 'https://eth.llamarpc.com' },
{ provider: 'https://ethereum.publicnode.com' }
]
}
)
// Use the wallet instance directly
const balance = await wallet.getBalance()
```
## Next Steps
Learn about [error handling and best practices](./error-handling) to ensure your application is robust and secure.
# Integrate Protocols (/sdk/core-module/guides/protocol-integration)
The WDK Core module supports registering external protocols. This allows you to extend the basic wallet functionality with advanced features like [token swapping](#swapping-tokens), [cross-chain bridging](#bridging-assets), and lending, all through a unified interface.
## Register Protocols
You can register protocols globally (for all new accounts).
### Global Registration (Recommended)
Global registration ensures that every account you retrieve already has the protocol ready to use. You can do this by chaining a call to `.registerProtocol()` on the WDK instance.
### 1. Install Protocol Modules
Install the [`@tetherto/wdk-protocol-swap-velora-evm`](https://www.npmjs.com/package/@tetherto/wdk-protocol-swap-velora-evm) and [`@tetherto/wdk-protocol-bridge-usdt0-evm`](https://www.npmjs.com/package/@tetherto/wdk-protocol-bridge-usdt0-evm) packages:
```bash
npm install @tetherto/wdk-protocol-swap-velora-evm && npm install @tetherto/wdk-protocol-bridge-usdt0-evm
```
### 2. Register in Code
Now, import the protocol modules and register them with your WDK instance. This makes the protocol methods available to any account derived from that instance.
First, import the necessary modules:
```typescript title="Import Protocols"
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
```
Then, register the protocols for the specific chains they support:
```typescript title="Register Protocols"
// Register protocols for specific chains
const wdk = new WDK(seedPhrase)
.registerWallet('ethereum', WalletManagerEvm, ethConfig)
// Register Velora Swap for Ethereum
.registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
apiKey: 'YOUR_API_KEY'
})
// Register USDT0 Bridge for Ethereum
.registerProtocol('ethereum', 'usdt0', usdt0ProtocolEvm, {
ethereumRpcUrl: 'https://eth.drpc.org' // Configuration depends on the module
})
```
## Use Protocols
Once [registered](#register-protocols), you can access the protocol instance using the specific getter methods: `getSwapProtocol`, `getBridgeProtocol`, or `getLendingProtocol`.
### Swapping Tokens
Use `getSwapProtocol` to access registered swap services on any wallet account.
```typescript title="Swap Tokens"
const ethAccount = await wdk.getAccount('ethereum', 0)
const velora = ethAccount.getSwapProtocol('velora')
const result = await velora.swap({
tokenIn: '0x...', // Address of token to sell
tokenOut: '0x...', // Address of token to buy
tokenInAmount: 1000000n // Amount to swap
})
```
### Bridging Assets
1. Use `getBridgeProtocol` to access cross-chain bridges.
2. Approve the source-chain bridge spender for the token and amount.
3. Call `bridge` from the bridge protocol to send tokens from one protocol to another.
```typescript title="Bridge Assets"
const ethAccount = await wdk.getAccount('ethereum', 0)
const usdt0 = ethAccount.getBridgeProtocol('usdt0')
await ethAccount.approve({
token: '0x...', // ERC20 Token Address
spender: '0x...', // OFT or bridge spender address
amount: 1000000n
})
const result = await usdt0.bridge({
targetChain: 'ton',
recipient: 'UQBla...', // TON address
token: '0x...', // ERC20 Token Address
amount: 1000000n,
oftContractAddress: '0x...' // Same address used as approval spender
})
```
**Protocol Availability:** If you try to access a protocol that hasn't been registered (e.g., `getSwapProtocol('uniswap')`), the SDK will throw an error. always ensure registration matches the ID you request.
## Next Steps
Learn how to [configure middleware](./middleware) to add logging or failover protection to your wallet interactions.
# Send Transactions (/sdk/core-module/guides/transactions)
You can [send native tokens](#send-native-tokens), [sign a transaction without broadcasting it](#sign-without-broadcasting), [handle transaction responses](#handling-responses), and [orchestrate multi-chain payments](#multi-chain-transactions) from WDK wallet accounts.
**Get Testnet Funds:** To test these transactions without spending real money, ensure you are on a testnet and have obtained funds. See [Testnet Funds & Faucets](../../../resources/concepts#testnet-funds--faucets) for a list of available faucets.
**BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers.
## Send Native Tokens
The `sendTransaction` method allows you to transfer value. It accepts a unified configuration object, though specific parameters (like `value` formatting) may vary slightly depending on the blockchain.
### Ethereum Example
On EVM chains, values are typically expressed in Wei (1 ETH = 10^18 Wei).
The following example will:
1. Retrieve the first Ethereum account (see [Manage Accounts](./account-management))
2. Send 0.001 ETH (1000000000000000 wei) to an account using `sendTransaction`.
```typescript title="Send ETH"
const ethAccount = await wdk.getAccount('ethereum', 0)
const result = await ethAccount.sendTransaction({
to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
value: 1000000000000000n // 0.001 ETH (in Wei)
})
console.log('Transaction sent! Hash:', result.hash)
```
### TON Example
On TON, values are expressed in Nanotons (1 TON = 10^9 Nanotons).
The following example will:
1. Retrieve the first TON account
2. Send 1 TON (1000000000 nton) to an account using `sendTransaction`.
```typescript title="Send TON"
// Send TON transaction
const tonAccount = await wdk.getAccount('ton', 0)
const tonResult = await tonAccount.sendTransaction({
to: 'UQCz5ON7jjK32HnqPushubsHxgsXgeSZDZPvh8P__oqol90r',
value: 1000000000n // 1 TON (in nanotons)
})
console.log('TON transaction:', tonResult.hash)
```
## Sign Without Broadcasting
Use [`account.signTransaction()`](../api-reference#signtransactiontx) when your app needs a signed transaction payload but does not want WDK to broadcast it immediately. Wallet modules accept their own transaction shape and may return a module-specific signed payload.
```typescript title="Sign An EVM Transaction"
const ethAccount = await wdk.getAccount('ethereum', 0)
const signedTransaction = await ethAccount.signTransaction({
to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
value: 1000000000000000n
})
console.log('Signed transaction:', signedTransaction)
```
`signTransaction()` only signs. Use `sendTransaction()` when you want WDK to sign, broadcast, and return the transaction hash.
## Handling Responses
The `sendTransaction` method returns a [transaction result object](../api-reference). The most important field is typically `hash`, which represents the transaction ID on the blockchain. You can use this hash to track the status of your payment on a block explorer.
## Multi-Chain Transactions
You can orchestrate payments across different chains in a single function by acting on multiple account objects sequentially.
The following example will:
1. Retrieve an ETH and ton account using the `getAccount()` method.
2. Send ETH and `await` the transaction.
3. Send TON and `await` the transaction.
```typescript title="Multi-Chain Payment"
async function sendCrossChainPayments(wdk) {
const ethAccount = await wdk.getAccount('ethereum', 0)
const tonAccount = await wdk.getAccount('ton', 0)
// 1. Send ETH
await ethAccount.sendTransaction({
to: '0x...',
value: 1000000000000000000n
})
// 2. Send TON
await tonAccount.sendTransaction({
to: 'EQ...',
value: 1000000000n
})
}
```
## Next Steps
For more complex interactions like swapping tokens or bridging assets, learn how to [integrate protocols](./protocol-integration).
# Register Wallets (/sdk/core-module/guides/wallet-registration)
This guide explains how to register wallet modules with your WDK instance. The WDK Core module itself doesn't contain blockchain-specific logic; instead, you register separate modules for each chain you want to support (e.g., Ethereum, TON, Bitcoin).
## How it works
The WDK uses a builder pattern, allowing you to chain `.registerWallet()` calls. Each call connects a blockchain-specific manager to your central WDK instance.
### Parameters
The `registerWallet` method (see [API Reference](../api-reference)) requires three arguments:
1. **Symbol**: A unique string identifier for the chain (e.g., `'ethereum'`, `'ton'`). You will use this ID later to retrieve accounts.
2. **Manager Class**: The wallet manager class imported from the specific module (e.g., `WalletManagerEvm`).
3. **Configuration**: An object containing the chain-specific settings (e.g., RPC providers, API keys).
## Installation
Install the [wallet managers](../../wallet-modules/) for the blockchains you want to support:
```bash
npm install @tetherto/wdk-wallet-evm @tetherto/wdk-wallet-tron @tetherto/wdk-wallet-btc
```
## Example: Registering Multiple Wallets
### Import the Wallet Manager Packages
First, import the necessary wallet manager packages:
```typescript title="Import Modules"
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTron from '@tetherto/wdk-wallet-tron'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'
```
### Register the Wallets
Then, [instantiate WDK](./getting-started#initialize-wdk) and chain the registration calls:
```typescript title="Register Wallets"
const wdk = new WDK(seedPhrase)
// 1. Register Ethereum
.registerWallet('ethereum', WalletManagerEvm, {
provider: 'https://eth.drpc.org'
})
// 2. Register TRON
.registerWallet('tron', WalletManagerTron, {
provider: 'https://api.trongrid.io'
})
// 3. Register Bitcoin
.registerWallet('bitcoin', WalletManagerBtc, {
provider: 'https://blockstream.info/api'
})
```
**RPC Providers:** The examples use public RPC endpoints for demonstration. We do not endorse any specific provider.
* **Testnets:** You can find public RPCs for Ethereum and other EVM chains on [Chainlist](https://chainlist.org).
* **Mainnet:** For production environments, we recommend using reliable, paid RPC providers to ensure stability.
**TRON Networks:** Choose the correct provider for your environment.
* **Mainnet:** `https://api.trongrid.io`
* **Shasta (Testnet):** `https://api.shasta.trongrid.io`
## Next Steps
Once your wallets are registered, you can [manage accounts and specific addresses](./account-management).
# Lending Aave EVM API Reference (/sdk/lending-modules/lending-aave-evm/api-reference)
# API Reference
## Class: AaveProtocolEvm
Main class for Aave V3 lending on EVM.
### Constructor
```javascript
new AaveProtocolEvm(account)
```
Parameters:
* `account`: `WalletAccountEvm | WalletAccountReadOnlyEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvmErc4337`
Example:
```javascript
const aave = new AaveProtocolEvm(account)
```
### Methods
| Method | Description | Returns |
| ------------------------------------------------ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `supply(options, config?)` | Add tokens to the pool | `Promise<{hash: string, fee: bigint, approveHash?: string, resetAllowanceHash?: string}>` |
| `quoteSupply(options, config?)` | Estimate cost to add tokens | `Promise<{fee: bigint}>` |
| `withdraw(options, config?)` | Remove tokens from the pool | `Promise<{hash: string, fee: bigint}>` |
| `quoteWithdraw(options, config?)` | Estimate cost to withdraw | `Promise<{fee: bigint}>` |
| `borrow(options, config?)` | Borrow tokens | `Promise<{hash: string, fee: bigint}>` |
| `quoteBorrow(options, config?)` | Estimate borrowing cost | `Promise<{fee: bigint}>` |
| `repay(options, config?)` | Repay borrowed tokens | `Promise<{hash: string, fee: bigint}>` |
| `quoteRepay(options, config?)` | Estimate repayment cost | `Promise<{fee: bigint}>` |
| `setUseReserveAsCollateral(token, use, config?)` | Toggle token as collateral | `Promise<{hash: string, fee: bigint}>` |
| `setUserEMode(categoryId, config?)` | Set user eMode | `Promise<{hash: string, fee: bigint}>` |
| `getAccountData(account?)` | Read account stats | `Promise<{ totalCollateralBase: bigint, totalDebtBase: bigint, availableBorrowsBase: bigint, currentLiquidationThreshold: bigint, ltv: bigint, healthFactor: bigint }>` |
***
When `AaveProtocolEvm` is initialized with an ERC‑4337 smart account, the optional `config` argument on mutating and quote methods accepts the same gas-payment override families documented in [`@tetherto/wdk-wallet-evm-erc-4337`](../../wallet-modules/wallet-evm-erc-4337/api-reference): paymaster token, sponsorship policy, and native coins.
### `supply(options, config?)`
Add tokens to the pool.
Options:
* `token` (`string`): token address
* `amount` (`number | bigint`): amount in base units
* `onBehalfOf` (`string`, optional)
Returns:
* May include `approveHash` and `resetAllowanceHash` for standard accounts (e.g., USD₮ allowance reset on Ethereum mainnet)
Example:
```javascript
const res = await aave.supply({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `quoteSupply(options, config?)`
Estimate fee to add tokens.
```javascript
const q = await aave.quoteSupply({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `withdraw(options, config?)`
Remove tokens from the pool.
Options:
* `token` (`string`)
* `amount` (`number | bigint`)
* `to` (`string`, optional)
```javascript
const tx = await aave.withdraw({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `quoteWithdraw(options, config?)`
Estimate fee to withdraw tokens.
```javascript
const q = await aave.quoteWithdraw({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `borrow(options, config?)`
Borrow tokens.
Options:
* `token` (`string`)
* `amount` (`number | bigint`)
* `onBehalfOf` (`string`, optional)
```javascript
const tx = await aave.borrow({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `quoteBorrow(options, config?)`
Estimate fee to borrow tokens.
```javascript
const q = await aave.quoteBorrow({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `repay(options, config?)`
Repay borrowed tokens.
Options:
* `token` (`string`)
* `amount` (`number | bigint`)
* `onBehalfOf` (`string`, optional)
```javascript
const tx = await aave.repay({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
Returns:
* For standard accounts, may include `approveHash` / `resetAllowanceHash` when applicable.
***
### `quoteRepay(options, config?)`
Estimate fee to repay borrowed tokens.
```javascript
const q = await aave.quoteRepay({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
***
### `setUseReserveAsCollateral(token, use, config?)`
Toggle token as collateral for the user.
```javascript
const tx = await aave.setUseReserveAsCollateral('TOKEN_ADDRESS', true)
```
***
### `setUserEMode(categoryId, config?)`
Set user eMode category.
```javascript
const tx = await aave.setUserEMode(1)
```
***
### `getAccountData(account?)`
Read account stats like total collateral, debt, and health.
```javascript
const data = await aave.getAccountData()
```
Returns the following structure:
```javascript
{
totalCollateralBase: bigint,
totalDebtBase: bigint,
availableBorrowsBase: bigint,
currentLiquidationThreshold: bigint,
ltv: bigint,
healthFactor: bigint
}
```
***
## ERC‑4337 Config Override (optional)
When the protocol uses `WalletAccountEvmErc4337` or `WalletAccountReadOnlyEvmErc4337`, the optional `config` argument on `supply`, `quoteSupply`, `withdraw`, `quoteWithdraw`, `borrow`, `quoteBorrow`, `repay`, `quoteRepay`, `setUseReserveAsCollateral`, and `setUserEMode` accepts the wallet module's per-call gas-payment overrides.
* **Paymaster token mode**: `paymasterUrl`, `paymasterAddress`, `paymasterToken`, `transferMaxFee`
* **Sponsorship policy mode**: `isSponsored`, `paymasterUrl`, `sponsorshipPolicyId`
* **Native coin mode**: `useNativeCoins`, `transferMaxFee`
Example:
```javascript
const res = await aave.supply(
{ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', amount: 1000000n },
{
paymasterToken: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
}
}
)
```
## Rules & Notes
* `token` must be a valid (non‑zero) address
* `amount` > 0 and in token base units (use BigInt)
* `onBehalfOf`/`to` (if set) must be valid, non‑zero addresses
* A provider is required to read/send transactions
* For USD₮ on mainnet, allowance may be reset to 0 then set again before actions
Get started with WDK in a Node.js environment
Get started with WDK's Lending Aave EVM Protocol configuration
Get started with WDK's Lending Aave EVM Protocol usage
***
### Need Help?
# Lending Aave EVM Configuration (/sdk/lending-modules/lending-aave-evm/configuration)
# Configuration
## Service Setup
```javascript
import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'
// Create wallet account first
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://ethereum-rpc.publicnode.com'
})
// Create lending service
const aave = new AaveProtocolEvm(account)
```
## Account Configuration
The service uses the wallet account configuration to connect to the target network and sign transactions.
```javascript
import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
// Full access account
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://ethereum-rpc.publicnode.com'
})
// Read-only account (quotes, reads)
const readOnly = new WalletAccountReadOnlyEvm('0xYourAddress', {
provider: 'https://ethereum-rpc.publicnode.com'
})
const aave = new AaveProtocolEvm(account)
```
## ERC‑4337 (Account Abstraction)
When using ERC‑4337 smart accounts, every mutating method and quote helper accepts an optional `config` override. In `v1.0.0-beta.4`, that override matches the three gas-payment families exposed by [`@tetherto/wdk-wallet-evm-erc-4337`](../../wallet-modules/wallet-evm-erc-4337/configuration): paymaster token, sponsorship policy, or native coins.
Use the fields that match the gas-payment mode you want for that call. For the full field-level definitions, see the [`@tetherto/wdk-wallet-evm-erc-4337` configuration docs](../../wallet-modules/wallet-evm-erc-4337/configuration) and [`Config Override`](../../wallet-modules/wallet-evm-erc-4337/api-reference) reference.
```javascript
import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337'
const aa = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", {
chainId: 1,
provider: 'https://arb1.arbitrum.io/rpc',
bundlerUrl: 'YOUR_BUNDLER_URL',
paymasterUrl: 'YOUR_PAYMASTER_URL'
})
const aaveAA = new AaveProtocolEvm(aa)
const result = await aaveAA.supply({ token: '0xdAC17F...ec7', amount: 1000000n }, {
paymasterToken: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
}
})
```
### Supported Override Families
* **Paymaster token mode**: `paymasterUrl`, `paymasterAddress`, `paymasterToken`, `transferMaxFee`
* **Sponsorship policy mode**: `isSponsored`, `paymasterUrl`, `sponsorshipPolicyId`
* **Native coin mode**: `useNativeCoins`, `transferMaxFee`
## Network Support
Aave V3 spans multiple EVM chains (Ethereum, Arbitrum, Base, Optimism, Polygon, Avalanche, BNB, Celo, Gnosis, Linea, Scroll, Soneium, Sonic, ZkSync, Metis). Ensure the correct RPC and token addresses for the target chain.
```javascript
// Ethereum Mainnet
const eth = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://ethereum-rpc.publicnode.com'
})
// Arbitrum
const arb = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://arb1.arbitrum.io/rpc'
})
```
## Operation Options
Each operation accepts a simple options object:
```javascript
// Supply
await aave.supply({ token: 'TOKEN_ADDRESS', amount: 1000000n })
// Withdraw
await aave.withdraw({ token: 'TOKEN_ADDRESS', amount: 1000000n })
// Borrow
await aave.borrow({ token: 'TOKEN_ADDRESS', amount: 1000000n })
// Repay
await aave.repay({ token: 'TOKEN_ADDRESS', amount: 1000000n })
```
### Common Parameters
* `token` (`string`): ERC‑20 token address
* `amount` (`number | bigint`): token amount in base units
* `onBehalfOf` (`string`, optional): another address to act for (supply/borrow/repay)
* `to` (`string`, optional): destination address (withdraw)
> Note: `amount` must be > 0. Addresses must be valid/non‑zero. A provider is required for any write.
Get started with WDK in a Node.js environment
Get started with WDK's Lending Aave EVM Protocol API
Get started with WDK's Lending Aave EVM Protocol usage
***
### Need Help?
# Lending Aave EVM Overview (/sdk/lending-modules/lending-aave-evm)
A lightweight package that lets EVM wallet accounts interact with Aave V3: supply, withdraw, borrow, repay, and read account data. It works with both standard EVM wallets and ERC‑4337 smart accounts.
## Features
* **Supply/Withdraw**: Add and remove supported assets from Aave pools
* **Borrow/Repay**: Borrow assets and repay debt
* **Account Data**: Read collateral, debt, health factor, and more
* **Quote System**: Estimate fees before sending transactions
* **AA Support**: Works with standard EVM and ERC‑4337 smart accounts
* **TypeScript Support**: Full TypeScript definitions
## Supported Networks
Works on Aave V3 supported EVM networks (e.g., Ethereum, Arbitrum, Base, Optimism, Polygon, Avalanche, BNB, Celo, Gnosis, Linea, Scroll, Soneium, Sonic, ZkSync, Metis). A working RPC provider and correct token addresses are required.
## Wallet Compatibility
* **Standard EVM Wallets**: `@tetherto/wdk-wallet-evm`
* **ERC‑4337 Smart Accounts**: `@tetherto/wdk-wallet-evm-erc-4337`
* **Read‑Only Accounts**: For quoting and reading account data without sending transactions
## Key Components
* **Aave V3 Integration**: Supply, withdraw, borrow, repay primitives
* **Quote Helpers**: `quoteSupply`, `quoteWithdraw`, `quoteBorrow`, `quoteRepay`
* **Collateral Controls**: Toggle collateral usage; set user eMode
## Next Steps
How to supply, withdraw, borrow and repay with Aave
Service setup, account config, ERC‑4337 options
Full API for Aave Protocol Evm methods and types
# Lending Aave EVM Guides (/sdk/lending-modules/lending-aave-evm/usage)
# Usage
The [@tetherto/wdk-protocol-lending-aave-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-lending-aave-evm) module exposes Aave V3 supply, borrow, and repayment flows for EVM accounts. Follow the guides below for setup, day-to-day operations, and error handling.
Install the package, create AaveProtocolEvm, and review prerequisites.
Supply, withdraw, borrow, repay, quotes, ERC-4337, and account data.
Handle failures and dispose wallet secrets when finished.
Get started with WDK in a Node.js environment
Networks and deployment settings for the Aave lending protocol
Methods and parameters for AaveProtocolEvm
# API Reference (/sdk/swap-modules/swap-velora-evm/api-reference)
## Class: VeloraProtocolEvm
Main class for velora token swaps on EVM.
### Constructor
```javascript
new VeloraProtocolEvm(account, config?)
```
Parameters:
* `account`: `WalletAccountEvm | WalletAccountReadOnlyEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvmErc4337`
* `config` (optional):
* `swapMaxFee` (`bigint`): maximum total gas fee allowed (wei)
Example:
```javascript
const swap = new VeloraProtocolEvm(account, { swapMaxFee: 200000000000000n })
```
### Methods
| Method | Description | Returns |
| ----------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `swap(options, config?)` | Perform a token swap | `Promise<{hash: string, fee: bigint, tokenInAmount: bigint, tokenOutAmount: bigint, approveHash?: string, resetAllowanceHash?: string}>` |
| `quoteSwap(options, config?)` | Get estimated fee and amounts | `Promise<{fee: bigint, tokenInAmount: bigint, tokenOutAmount: bigint}>` |
***
### `swap(options, config?)`
Execute a swap via velora.
Options:
* `tokenIn` (`string`): Address of the ERC‑20 token to sell
* `tokenOut` (`string`): Address of the ERC‑20 token to buy
* `tokenInAmount` (`bigint`, optional): Exact input amount (base units)
* `tokenOutAmount` (`bigint`, optional): Exact output amount (base units)
* `to` (`string`, optional): Recipient address (defaults to account address)
Config (ERC‑4337 only):
* `paymasterToken` (`string`, optional): Token symbol/address for fee sponsorship
* `swapMaxFee` (`bigint`, optional): Per‑swap fee cap (wei)
Returns:
* Standard account: `{ hash, fee, tokenInAmount, tokenOutAmount, approveHash?, resetAllowanceHash? }`
* ERC‑4337 account: `{ hash, fee, tokenInAmount, tokenOutAmount }` (approve may be bundled)
Notes:
* On Ethereum mainnet, selling USD₮ may first set allowance to 0, then approve.
* Requires a provider; requires a non read‑only account to send transactions.
Example:
```javascript
const tx = await swap.swap({
tokenIn: '0xdAC17F...ec7', // USD₮
tokenOut: '0xC02a...6Cc2', // WETH
tokenInAmount: 1000000n
})
```
***
### `quoteSwap(options, config?)`
Get estimated fee and token in/out amounts.
Options are the same as `swap`.
Returns: `{ fee, tokenInAmount, tokenOutAmount }`
Config (ERC‑4337 only):
* `paymasterToken` (`string`, optional): Token symbol/address for fee sponsorship
Works with read‑only accounts.
Example:
```javascript
const quote = await swap.quoteSwap({
tokenIn: '0xdAC17F...ec7', // USD₮
tokenOut: '0xC02a...6Cc2', // WETH
tokenOutAmount: 500000000000000000n // 0.5 WETH
})
```
***
## Errors
Common errors include:
* Insufficient liquidity / no route for pair
* Fee exceeds `swapMaxFee`
* Read‑only account cannot send swaps
* Provider/RPC errors (invalid endpoint, network mismatch)
***
## Types
* `swapMaxFee: bigint` — Upper bound for gas fees (wei)
* `tokenInAmount/tokenOutAmount: bigint` — ERC‑20 base units
* `paymasterToken: string` — token symbol or address (AA only)
Get started with WDK in a Node.js environment
Get started with WDK's Swap velora EVM Protocol configuration
Get started with WDK's Swap velora EVM Protocol usage
***
## Need Help?
# Configuration (/sdk/swap-modules/swap-velora-evm/configuration)
## Swap Service Configuration
The `VeloraProtocolEvm` accepts a configuration object that defines fee controls and behavior:
```javascript
import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm'
// Create wallet account first
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://ethereum-rpc.publicnode.com'
})
// Create swap service with configuration
const swapProtocol = new VeloraProtocolEvm(account, {
swapMaxFee: 200000000000000n // Optional: Max swap fee in wei
})
```
## Account Configuration
The swap service uses the wallet account configuration for network access and signing:
```javascript
import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
// Full access account
const account = new WalletAccountEvm(
seedPhrase,
"0'/0/0",
{
provider: 'https://ethereum-rpc.publicnode.com'
}
)
// Read-only account (quotes only)
const readOnly = new WalletAccountReadOnlyEvm(
'0xYourAddress',
{
provider: 'https://ethereum-rpc.publicnode.com'
}
)
// Create swap service
const swapProtocol = new VeloraProtocolEvm(account, {
swapMaxFee: 200000000000000n
})
```
## Configuration Options
### Swap Max Fee
The `swapMaxFee` option sets an upper bound for total gas costs to prevent excessive fees.
**Type:** `bigint` (optional)\
**Unit:** Wei
**Examples:**
```javascript
const config = {
// Cap total gas fee to 0.0002 ETH (in wei)
swapMaxFee: 200000000000000n,
}
// Usage example
try {
const result = await swapProtocol.swap({
tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USD₮ (6 decimals)
tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH (18 decimals)
tokenInAmount: 1000000n
})
} catch (error) {
if (error.message.includes('max fee')) {
console.error('Swap stopped: Fee too high')
}
}
```
## ERC‑4337 (Account Abstraction) Configuration
When using ERC‑4337 smart accounts (`@tetherto/wdk-wallet-evm-erc-4337`), you can override fee behavior per swap and specify a paymaster token:
```javascript
import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337'
const aa = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", {
chainId: 1,
provider: 'https://arb1.arbitrum.io/rpc',
bundlerUrl: 'YOUR_BUNDLER_URL',
paymasterUrl: 'YOUR_PAYMASTER_URL'
})
const swapAA = new VeloraProtocolEvm(aa, { swapMaxFee: 200000000000000n })
const result = await swapAA.swap({
tokenIn: '0xTokenIn',
tokenOut: '0xTokenOut',
tokenInAmount: 1000000n
}, {
paymasterToken: 'USDT', // Token used to pay for gas
swapMaxFee: 200000000000000n // Per‑swap override
})
```
### Paymaster Token (ERC‑4337)
The `paymasterToken` option indicates which token the paymaster should use to sponsor gas.
**Type:** `string` (optional)\
**Format:** Token symbol or address
**Example:**
```javascript
const result = await swapAA.swap({
tokenIn: '0xdAC17F...ec7',
tokenOut: '0xC02a...6Cc2', // WETH
tokenInAmount: 1000000n
}, {
paymasterToken: 'USDT'
})
```
## Network Support
velora supports multiple EVM networks (e.g., Ethereum, Polygon, Arbitrum). Ensure your account is configured with a valid provider for the target network.
```javascript
// Ethereum Mainnet
const eth = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://ethereum-rpc.publicnode.com'
})
// Polygon
const polygon = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://polygon-bor-rpc.publicnode.com'
})
```
## Swap Options
When calling `swap`, provide the swap parameters:
```javascript
const swapOptions = {
tokenIn: '0xTokenIn', // ERC‑20 to sell
tokenOut: '0xTokenOut', // ERC‑20 to buy
tokenInAmount: 1000000n, // exact input (base units)
// OR
// tokenOutAmount: 1000000n, // exact output (base units)
to: '0xRecipient' // optional recipient (defaults to your address)
}
const result = await swapProtocol.swap(swapOptions)
```
### Parameters
* `tokenIn` (`string`): ERC‑20 address to sell
* `tokenOut` (`string`): ERC‑20 address to buy
* `tokenInAmount` (`bigint`, optional): exact input amount in token base units
* `tokenOutAmount` (`bigint`, optional): exact output amount in token base units
* `to` (`string`, optional): recipient address (defaults to account address)
> Note: Use either `tokenInAmount` OR `tokenOutAmount`, not both.
Get started with WDK in a Node.js environment
Get started with WDK's velora Swap Protocol API
Get started with WDK's velora Swap Protocol usage
***
## Need Help?
# Swap velora EVM Overview (/sdk/swap-modules/swap-velora-evm)
A lightweight package that lets EVM wallet accounts swap tokens using the velora aggregator. It provides a clean SDK for token swaps on EVM chains and works with both standard wallets and ERC‑4337 smart accounts.
## Features
* **Token Swapping**: Execute token swaps through velora on supported EVM networks
* **Account Abstraction**: Compatible with standard EVM accounts and ERC‑4337 smart accounts
* **Fee Controls**: Optional `swapMaxFee` to cap gas costs
* **Allowance Safety**: Handles USD₮ mainnet pattern (reset allowance to 0 before approve)
* **Provider Flexibility**: Works with JSON‑RPC URLs and EIP‑1193 providers
* **TypeScript Support**: Full TypeScript definitions included
## Supported Networks
Works with EVM networks supported by velora (e.g., Ethereum, Polygon, Arbitrum, etc.). A working RPC provider is required.
## Wallet Compatibility
The swap service supports multiple EVM wallet types:
* **Standard EVM Wallets**: `@tetherto/wdk-wallet-evm` accounts
* **ERC‑4337 Smart Accounts**: `@tetherto/wdk-wallet-evm-erc-4337` accounts with bundler/paymaster
* **Read‑Only Accounts**: For quoting swaps without sending transactions
## Key Components
* **velora Integration**: Uses velora aggregator for routing and quotes
* **Quote System**: Pre‑transaction fee and amount estimation via `quoteSwap`
* **AA Integration**: Optional paymaster token and fee cap overrides when using ERC‑4337
* **Allowance Management**: Approve flow handled automatically when required
## Next Steps
Get started with WDK in a Node.js environment
Get started with WDK's velora Swap Protocol configuration
Get started with WDK's velora Swap Protocol API
Get started with WDK's velora Swap Protocol usage
***
## Need Help?
# Swap velora EVM Guides (/sdk/swap-modules/swap-velora-evm/usage)
# Usage
The [@tetherto/wdk-protocol-swap-velora-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-swap-velora-evm) module routes ERC-20 swaps on EVM chains through Velora. Use the guides below for setup, execution, quotes, and error handling.
Install the package, create VeloraProtocolEvm, and review supported networks.
Exact-input and exact-output swaps, including ERC-4337 smart accounts.
Quote before swapping and compare fees to your max fee cap.
Handle swap and quote failures and dispose wallet state safely.
Get started with WDK in a Node.js environment
RPC, fee limits, and environment settings for the Velora swap protocol
Methods, options, and error notes for VeloraProtocolEvm
# Wallet BTC API Reference (/sdk/wallet-modules/wallet-btc/api-reference)
## Table of Contents
| Class | Description | Methods |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [WalletManagerBtc](#walletmanagerbtc) | Main class for managing Bitcoin wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) |
| [WalletAccountBtc](#walletaccountbtc) | Individual Bitcoin wallet account implementation. Implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) |
| [WalletAccountReadOnlyBtc](#walletaccountreadonlybtc) | Read-only Bitcoin wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-2), [Methods](#methods-2) |
| [ElectrumTcp](#electrumtcp) | Standard TCP Electrum client. Implements `IBtcClient`. | [Constructor](#constructor-3) |
| [ElectrumTls](#electrumtls) | TLS Electrum client. Implements `IBtcClient`. | [Constructor](#constructor-4) |
| [ElectrumSsl](#electrumssl) | SSL Electrum client. Implements `IBtcClient`. | [Constructor](#constructor-5) |
| [ElectrumWs](#electrumws) | WebSocket Electrum client for browser environments. Implements `IBtcClient`. | [Constructor](#constructor-6), [Methods](#methods-3) |
## WalletManagerBtc
The main class for managing Bitcoin wallets.
Extends `WalletManager` from `@tetherto/wdk-wallet`.
#### Constructor
```javascript
new WalletManagerBtc(seed, config)
```
**Parameters:**
* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `config` (BtcWalletConfig, optional): Configuration object
* `client` (`IBtcClient | BtcClientDescriptor | Array`, optional): Bitcoin client, descriptor, or ordered failover list
* `network` (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")
* `bip` (number, optional): BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)
* `retries` (number, optional): Additional retry attempts when `client` is an array
### Methods
| Method | Description | Returns |
| ------------------------ | --------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `getAccount(index)` | Returns a wallet account at the specified index | `Promise` |
| `getAccountByPath(path)` | Returns a wallet account at the specified derivation path | `Promise` |
| `getFeeRates()` | Returns current fee rates for transactions | `Promise<{normal: bigint, fast: bigint}>` |
| `dispose()` | Disposes all wallet accounts, clearing private keys from memory and closing internal Electrum connections | `void` |
##### `getAccount(index)`
Returns a wallet account at the specified index using BIP-84 (default) or BIP-44 derivation.
**Parameters:**
* `index` (number, optional): The index of the account to get (default: 0)
**Returns:** `Promise` - The wallet account
**Example:**
```javascript
// Returns the account with derivation path:
// For mainnet (bitcoin): m/84'/0'/0'/0/1
// For testnet or regtest: m/84'/1'/0'/0/1
const account = await wallet.getAccount(1)
```
##### `getAccountByPath(path)`
Returns a wallet account at the specified derivation path.
**Parameters:**
* `path` (string): The derivation path (e.g., "0'/0/0")
**Returns:** `Promise` - The wallet account
**Example:**
```javascript
// Returns the account with derivation path:
// For mainnet (bitcoin): m/84'/0'/0'/0/1
// For testnet or regtest: m/84'/1'/0'/0/1
const account = await wallet.getAccountByPath("0'/0/1")
```
##### `getFeeRates()`
Returns current fee rates from mempool.space API.
**Returns:** `Promise<{normal: bigint, fast: bigint}>` - Object containing fee rates in sat/vB
* `normal`: Standard fee rate for confirmation within \~1 hour
* `fast`: Higher fee rate for faster confirmation
**Example:**
```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'sat/vB')
console.log('Fast fee rate:', feeRates.fast, 'sat/vB')
```
##### `dispose()`
Disposes all wallet accounts, clears sensitive data from memory, and closes internal Electrum connections.
**Returns:** `void`
**Example:**
```javascript
wallet.dispose()
```
## WalletAccountBtc
Represents an individual Bitcoin wallet account. Extends `WalletAccountReadOnlyBtc` and implements `IWalletAccount` from `@tetherto/wdk-wallet`.
#### Constructor
```javascript
new WalletAccountBtc(seed, path, config)
```
**Parameters:**
* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `path` (string): Derivation path suffix (e.g., "0'/0/0")
* `config` (BtcWalletConfig, optional): Configuration object
* `client` (`IBtcClient | BtcClientDescriptor | Array`, optional): Bitcoin client, descriptor, or ordered failover list
* `network` (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")
* `bip` (number, optional): BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)
* `retries` (number, optional): Additional retry attempts when `client` is an array
### Methods
| Method | Description | Returns |
| -------------------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| `getAddress()` | Returns the account's Bitcoin address | `Promise` |
| `getBalance()` | Returns the total account balance in satoshis, including unconfirmed funds when present | `Promise` |
| `sendTransaction(options, timeoutMs?)` | Sends a Bitcoin transaction and optionally polls until spent inputs disappear from unspent outputs | `Promise<{hash: string, fee: bigint}>` |
| `signTransaction(options)` | Signs a Bitcoin transaction without broadcasting it | `Promise` |
| `quoteSendTransaction(options)` | Estimates the fee for a transaction | `Promise<{fee: bigint}>` |
| `getTransfers(options?)` | Returns the account's transfer history | `Promise` |
| `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise` |
| `getMaxSpendable()` | Returns the maximum spendable amount | `Promise` |
| `sign(message)` | Signs a message with the account's private key | `Promise` |
| `verify(message, signature)` | Verifies a message signature | `Promise` |
| `toReadOnlyAccount()` | Creates a read-only version of this account | `Promise` |
| `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` |
##### `getAddress()`
Returns the account's Bitcoin address (Native SegWit bech32 by default, or legacy if using BIP-44).
**Returns:** `Promise` - The Bitcoin address
**Example:**
```javascript
const address = await account.getAddress()
console.log('Address:', address) // bc1q... (BIP-84) or 1... (BIP-44)
```
##### `getBalance()`
Returns the account's total balance in satoshis, including unconfirmed funds when present.
**Returns:** `Promise` - Balance in satoshis
**Example:**
```javascript
const balance = await account.getBalance()
console.log('Balance:', balance, 'satoshis')
```
##### `sendTransaction(options, timeoutMs?)`
Sends a Bitcoin transaction to a single recipient and optionally polls after broadcast until spent inputs disappear from the unspent-output set.
**Parameters:**
* `options` (BtcTransaction): Transaction options
* `to` (string): Recipient's Bitcoin address
* `value` (number | bigint): Amount in satoshis
* `feeRate` (number | bigint, optional): Fee rate in sat/vB. If provided, overrides the fee rate estimated from the blockchain.
* `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1)
* `timeoutMs` (number, optional): Maximum milliseconds to poll after broadcast before returning (default: 10000)
**Returns:** `Promise<{hash: string, fee: bigint}>`
* `hash`: Transaction hash
* `fee`: Transaction fee in satoshis
**Example:**
```javascript
const result = await account.sendTransaction({
to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
value: 50000n
})
console.log('Transaction hash:', result.hash)
console.log('Fee:', result.fee, 'satoshis')
```
##### `signTransaction(options)`
Signs a Bitcoin transaction and returns the signed raw transaction as a hex string. This method does not broadcast the transaction.
**Parameters:**
* `options` (BtcTransaction): Transaction options
* `to` (string): Recipient's Bitcoin address
* `value` (number | bigint): Amount in satoshis
* `feeRate` (number | bigint, optional): Fee rate in sat/vB. If provided, overrides the fee rate estimated from the blockchain.
* `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1)
**Returns:** `Promise` - Signed raw transaction hex string
**Example:**
```javascript
const signedTransaction = await account.signTransaction({
to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
value: 50000n,
feeRate: 10n
})
console.log('Signed transaction:', signedTransaction)
```
##### `quoteSendTransaction(options)`
Estimates the fee for a transaction without broadcasting it.
**Parameters:**
* `options` (BtcTransaction): Same as sendTransaction options
* `to` (string): Recipient's Bitcoin address
* `value` (number | bigint): Amount in satoshis
* `feeRate` (number | bigint, optional): Fee rate in sat/vB. If provided, overrides the fee rate estimated from the blockchain.
* `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1)
**Returns:** `Promise<{fee: bigint}>`
* `fee`: Estimated transaction fee in satoshis
**Example:**
```javascript
const quote = await account.quoteSendTransaction({
to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
value: 50000n
})
console.log('Estimated fee:', quote.fee, 'satoshis')
```
##### `getTransfers(options?)`
Returns the account's transfer history with detailed transaction information.
**Parameters:**
* `options` (object, optional): Filter options
* `direction` (string, optional): 'incoming', 'outgoing', or 'all' (default: 'all')
* `limit` (number, optional): Maximum number of transfers (default: 10)
* `skip` (number, optional): Number of transfers to skip (default: 0)
**Returns:** `Promise` - Array of transfer objects
* `txid`: Transaction ID
* `address`: Account's own address
* `vout`: Output index in the transaction
* `height`: Block height (0 if unconfirmed)
* `value`: Transfer value in satoshis (bigint)
* `direction`: 'incoming' or 'outgoing'
* `fee`: Transaction fee in satoshis (bigint, for outgoing transfers)
* `recipient`: Receiving address (for outgoing transfers)
**Example:**
```javascript
const transfers = await account.getTransfers({
direction: 'incoming',
limit: 5
})
console.log('Recent incoming transfers:', transfers)
```
##### `getTransactionReceipt(hash)`
Returns a transaction's receipt if it has been included in a block.
**Parameters:**
* `hash` (string): The transaction hash (64 hex characters)
**Returns:** `Promise` - The receipt, or null if the transaction has not been included in a block yet.
**Example:**
```javascript
const receipt = await account.getTransactionReceipt('abc123...')
if (receipt) {
console.log('Transaction confirmed')
}
```
##### `getMaxSpendable()`
Returns the maximum spendable amount that can be sent in a single transaction. The maximum spendable amount can differ from the wallet's total balance for several reasons:
* **Transaction fees**: Fees are subtracted from the total balance
* **Uneconomic UTXOs**: Small UTXOs where the fee to spend them exceeds their value are excluded
* **UTXO limit**: A transaction can include at most 200 inputs. Wallets with more UTXOs cannot spend their full balance in a single transaction.
* **Dust limit**: Outputs below the dust threshold (294 sats for SegWit, 546 sats for legacy) cannot be created
**Returns:** `Promise` - Maximum spendable result
* `amount`: Maximum spendable amount in satoshis (bigint)
* `fee`: Estimated network fee in satoshis (bigint)
* `changeValue`: Estimated change value in satoshis (bigint)
**Example:**
```javascript
const { amount, fee } = await account.getMaxSpendable()
console.log('Max spendable:', amount, 'satoshis')
console.log('Estimated fee:', fee, 'satoshis')
```
##### `sign(message)`
Signs a message using the account's private key.
**Parameters:**
* `message` (string): Message to sign
**Returns:** `Promise` - Signature as base64 string
**Example:**
```javascript
const signature = await account.sign('Hello Bitcoin!')
console.log('Signature:', signature)
```
##### `verify(message, signature)`
Verifies a message signature using the account's public key.
**Parameters:**
* `message` (string): Original message
* `signature` (string): Signature as base64 string
**Returns:** `Promise` - True if signature is valid
**Example:**
```javascript
const isValid = await account.verify('Hello Bitcoin!', signature)
console.log('Signature valid:', isValid)
```
##### `toReadOnlyAccount()`
Creates a read-only version of this account that can query balances and transactions but cannot sign or send transactions.
**Returns:** `Promise` - Read-only account instance
**Example:**
```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const balance = await readOnlyAccount.getBalance()
```
##### `dispose()`
Disposes the wallet account, securely erasing the private key from memory and closing the Electrum connection.
**Returns:** `void`
**Example:**
```javascript
account.dispose()
// Private key is now securely wiped from memory
```
#### Properties
| Property | Type | Description |
| --------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `index` | `number` | The derivation path's index of this account |
| `path` | `string` | The full derivation path of this account |
| `keyPair` | `KeyPair` | The account's public and private key pair. Treat the returned `Uint8Array` values as read-only views because mutations affect the account's internal key material. |
## WalletAccountReadOnlyBtc
Represents a read-only Bitcoin wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`.
#### Constructor
```javascript
new WalletAccountReadOnlyBtc(address, config)
```
**Parameters:**
* `address` (string): The account's Bitcoin address
* `config` (object, optional): Configuration object (same as BtcWalletConfig but without `bip`)
* `client` (`IBtcClient | BtcClientDescriptor | Array`, optional): Bitcoin client, descriptor, or ordered failover list
* `network` (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")
* `retries` (number, optional): Additional retry attempts when `client` is an array
### Methods
| Method | Description | Returns |
| ------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------- |
| `getAddress()` | Returns the account's Bitcoin address | `Promise` |
| `getBalance()` | Returns the total account balance in satoshis, including unconfirmed funds when present | `Promise` |
| `quoteSendTransaction(options)` | Estimates the fee for a transaction | `Promise<{fee: bigint}>` |
| `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise` |
| `getMaxSpendable()` | Returns the maximum spendable amount | `Promise` |
| `verify(message, signature)` | Verifies a message signature | `Promise` |
| `dispose()` | Closes any internal Electrum connection | `void` |
##### `getAddress()`
Returns the account's Bitcoin address.
**Returns:** `Promise` - The Bitcoin address
**Example:**
```javascript
const address = await readOnlyAccount.getAddress()
console.log('Address:', address)
```
##### `getBalance()`
Returns the account's confirmed balance in satoshis.
**Returns:** `Promise` - Balance in satoshis
**Example:**
```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Balance:', balance, 'satoshis')
```
##### `quoteSendTransaction(options)`
Estimates the fee for a transaction without broadcasting it.
**Parameters:**
* `options` (BtcTransaction): Transaction options
* `to` (string): Recipient's Bitcoin address
* `value` (number | bigint): Amount in satoshis
* `feeRate` (number | bigint, optional): Fee rate in sat/vB
* `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1)
**Returns:** `Promise<{fee: bigint}>` - Estimated fee in satoshis
**Example:**
```javascript
const quote = await readOnlyAccount.quoteSendTransaction({
to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
value: 50000n
})
console.log('Estimated fee:', quote.fee, 'satoshis')
```
##### `getTransactionReceipt(hash)`
Returns a transaction's receipt if it has been included in a block.
**Parameters:**
* `hash` (string): The transaction hash
**Returns:** `Promise` - The receipt, or null if not yet included
**Example:**
```javascript
const receipt = await readOnlyAccount.getTransactionReceipt('abc123...')
if (receipt) {
console.log('Transaction confirmed')
}
```
##### `getMaxSpendable()`
Returns the maximum spendable amount that can be sent in a single transaction.
**Returns:** `Promise` - Maximum spendable result
* `amount`: Maximum spendable amount in satoshis (bigint)
* `fee`: Estimated network fee in satoshis (bigint)
* `changeValue`: Estimated change value in satoshis (bigint)
**Example:**
```javascript
const { amount, fee } = await readOnlyAccount.getMaxSpendable()
console.log('Max spendable:', amount, 'satoshis')
```
##### `verify(message, signature)`
Verifies a message signature using the account's public key.
**Parameters:**
* `message` (string): Original message
* `signature` (string): Signature as base64 string
**Returns:** `Promise` - True if signature is valid
**Example:**
```javascript
const isValid = await readOnlyAccount.verify('Hello Bitcoin!', signature)
console.log('Signature valid:', isValid)
```
##### `dispose()`
Closes any internal Electrum connection owned by this account. If a [`client`](/sdk/wallet-modules/wallet-btc/configuration#client) was provided via config, the connection is left open (the caller manages its lifecycle).
**Returns:** `void`
**Example:**
```javascript
readOnlyAccount.dispose()
```
## ElectrumTcp
Electrum client using TCP transport. Standard for command-line and server-side environments.
Implements `IBtcClient`.
#### Constructor
```javascript
new ElectrumTcp(config)
```
**Parameters:**
* `config` (`Omit`): Configuration options
* `host` (string): Electrum server hostname
* `port` (number): Electrum server port
## ElectrumTls
Electrum client using TLS transport.
Implements `IBtcClient`.
#### Constructor
```javascript
new ElectrumTls(config)
```
**Parameters:**
* `config` (`Omit`): Configuration options
* `host` (string): Electrum server hostname
* `port` (number): Electrum server port
## ElectrumSsl
Electrum client using SSL transport.
Implements `IBtcClient`.
#### Constructor
```javascript
new ElectrumSsl(config)
```
**Parameters:**
* `config` (`Omit`): Configuration options
* `host` (string): Electrum server hostname
* `port` (number): Electrum server port
## ElectrumWs
Electrum client using WebSocket transport. Compatible with browser environments where TCP sockets are not available.
Implements `IBtcClient`.
#### Constructor
```javascript
new ElectrumWs(config)
```
**Parameters:**
* `config` (ElectrumWsConfig): Configuration options
* `url` (string): The WebSocket URL (e.g., 'wss\://electrum.example.com:50004')
### Methods
| Method | Description | Returns |
| ------------------------- | ------------------------------------------------------------- | -------------------------------- |
| `connect()` | Establishes connection to Electrum server | `Promise` |
| `close()` | Closes the connection | `Promise` |
| `reconnect()` | Recreates the underlying socket and reinitializes the session | `Promise` |
| `getBalance(scripthash)` | Returns balance for a script hash | `Promise` |
| `listUnspent(scripthash)` | Returns UTXOs for a script hash | `Promise` |
| `getHistory(scripthash)` | Returns transaction history | `Promise` |
| `getTransaction(txHash)` | Returns raw transaction hex | `Promise` |
| `broadcast(rawTx)` | Broadcasts raw transaction | `Promise` |
| `estimateFee(blocks)` | Returns estimated fee rate | `Promise` |
## Types
### BtcTransaction
```typescript
interface BtcTransaction {
to: string // The transaction's recipient
value: number | bigint // The amount of bitcoins to send to the recipient (in satoshis)
confirmationTarget?: number // Optional confirmation target in blocks (default: 1)
feeRate?: number | bigint // Optional fee rate in satoshis per virtual byte
}
```
### TransactionResult
```typescript
interface TransactionResult {
hash: string // Transaction hash/ID
fee: bigint // Transaction fee in satoshis
}
```
### FeeRates
```typescript
interface FeeRates {
normal: bigint // Standard fee rate (sat/vB) for ~1 hour confirmation
fast: bigint // Higher fee rate (sat/vB) for faster confirmation
}
```
### BtcTransfer
```typescript
interface BtcTransfer {
txid: string // The transaction's ID
address: string // The user's own address
vout: number // The index of the output in the transaction
height: number // The block height (if unconfirmed, 0)
value: bigint // The value of the transfer (in satoshis)
direction: 'incoming' | 'outgoing' // The direction of the transfer
fee?: bigint // The fee paid for the full transaction (in satoshis)
recipient?: string // The receiving address for outgoing transfers
}
```
### BtcMaxSpendableResult
```typescript
interface BtcMaxSpendableResult {
amount: bigint // The maximum spendable amount in satoshis
fee: bigint // The estimated network fee in satoshis
changeValue: bigint // The estimated change value in satoshis
}
```
### KeyPair
```typescript
interface KeyPair {
publicKey: Uint8Array // Public key bytes. Treat as read-only.
privateKey: Uint8Array | null // Private key bytes. Treat as read-only. Null after dispose.
}
```
### BtcWalletConfig
```typescript
interface BtcWalletConfig {
client?: IBtcClient | BtcClientDescriptor | Array // Client, descriptor, or failover list
network?: 'bitcoin' | 'testnet' | 'regtest' // Network to use (default: "bitcoin")
bip?: 44 | 84 // BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)
retries?: number // Additional retry attempts for client arrays
}
```
### BtcClientDescriptor
```typescript
type BtcClientDescriptor =
| { type: 'electrum'; clientConfig: MempoolElectrumConfig }
| { type: 'electrum-ws'; clientConfig: ElectrumWsConfig }
| { type: 'blockbook-http'; clientConfig: BlockbookClientConfig }
```
### IBtcClient
Interface for implementing custom Bitcoin network clients.
```typescript
interface IBtcClient {
connect(): Promise
close(): Promise
reconnect(): Promise
getBalance(scripthash: string): Promise
listUnspent(scripthash: string): Promise
getHistory(scripthash: string): Promise
getTransaction(txHash: string): Promise
broadcast(rawTx: string): Promise
estimateFee(blocks: number): Promise
}
```
### ElectrumBalance
```typescript
interface ElectrumBalance {
confirmed: number // Confirmed balance in satoshis
unconfirmed?: number // Unconfirmed balance in satoshis
}
```
### ElectrumUtxo
```typescript
interface ElectrumUtxo {
tx_hash: string // The transaction hash containing this UTXO
tx_pos: number // The output index within the transaction
value: number // The UTXO value in satoshis
height?: number // The block height (0 if unconfirmed)
}
```
### ElectrumHistoryItem
```typescript
interface ElectrumHistoryItem {
tx_hash: string // The transaction hash
height: number // The block height (0 or negative if unconfirmed)
}
```
### MempoolElectrumConfig
```typescript
interface MempoolElectrumConfig {
host: string // Electrum server hostname
port: number // Electrum server port
protocol?: 'tcp' | 'ssl' | 'tls' // Transport protocol (default: 'tcp')
maxRetry?: number // Maximum reconnection attempts (default: 2)
retryPeriod?: number // Delay between reconnection attempts in ms (default: 1000)
pingPeriod?: number // Delay between keep-alive pings in ms (default: 120000)
callback?: (err: Error | null) => void // Called when all retries are exhausted
}
```
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Get started with WDK's Bitcoin Wallet Usage
Get started with WDK's Bitcoin Wallet Configuration
***
### Need Help?
# Configuration (/sdk/wallet-modules/wallet-btc/configuration)
## Wallet Configuration
```javascript
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'
const wallet = new WalletManagerBtc(seedPhrase, {
client: {
type: 'electrum',
clientConfig: {
host: 'electrum.blockstream.info',
port: 50002,
protocol: 'tls'
}
},
network: 'bitcoin'
})
```
## Account Creation
```javascript
// WalletAccountBtc is created by the WalletManagerBtc
// It takes the same configuration as the manager
const account = await wallet.getAccount(0) // Get account at index 0
const customAccount = await wallet.getAccountByPath("0'/0/5") // Custom path
```
## Configuration Options
### Client
The `client` option specifies how the wallet connects to Bitcoin network data. It accepts a pre-built `IBtcClient`, a client descriptor, or an ordered array of clients and descriptors for automatic failover.
**Type:** `IBtcClient | BtcClientDescriptor | Array`
**Default:** Uses an Electrum descriptor for `electrum.blockstream.info:50001`.
**Example:**
```javascript
const config = {
client: {
type: 'electrum',
clientConfig: {
host: 'fulcrum.frznode.com',
port: 50002,
protocol: 'tls'
}
}
}
```
`BtcClientDescriptor` supports:
| Type | Description |
| ---------------- | --------------------------------------------------------------- |
| `electrum` | Creates a TCP, TLS, or SSL Electrum client from `clientConfig`. |
| `electrum-ws` | Creates a WebSocket Electrum client from `clientConfig`. |
| `blockbook-http` | Creates a stateless Blockbook HTTP client from `clientConfig`. |
#### Built-in Transport Clients
The package still exports built-in transport clients when you want to instantiate the client yourself:
```javascript
import {
ElectrumTcp, // TCP transport (default, port 50001)
ElectrumTls, // TLS transport (port 50002)
ElectrumSsl, // SSL transport (port 50002)
ElectrumWs // WebSocket transport
} from '@tetherto/wdk-wallet-btc'
// TCP (default)
const tcpClient = new ElectrumTcp({ host: 'electrum.blockstream.info', port: 50001 })
// TLS
const tlsClient = new ElectrumTls({ host: 'electrum.blockstream.info', port: 50002 })
// SSL
const sslClient = new ElectrumSsl({ host: 'electrum.blockstream.info', port: 50002 })
// WebSocket
const wsClient = new ElectrumWs({ url: 'wss://electrum.example.com:50004' })
```
#### Custom Bitcoin Client
You can implement your own client by implementing `IBtcClient`:
```typescript
import { IBtcClient } from '@tetherto/wdk-wallet-btc'
class MyCustomBitcoinClient implements IBtcClient {
// Implement the required interface methods
}
const wallet = new WalletManagerBtc(seedPhrase, {
client: new MyCustomBitcoinClient(params),
network: 'bitcoin'
})
```
#### Client Failover
Pass an ordered `client` array to retry connection failures against fallback clients. Set `retries` to control how many additional attempts can happen after the first failed call.
```javascript
const wallet = new WalletManagerBtc(seedPhrase, {
client: [
{
type: 'electrum',
clientConfig: {
host: 'primary-electrum.example',
port: 50002,
protocol: 'tls'
}
},
{
type: 'electrum',
clientConfig: {
host: 'secondary-electrum.example',
port: 50002,
protocol: 'tls'
}
}
],
retries: 1,
network: 'bitcoin'
})
```
### Host
The `host` value belongs inside an `electrum` descriptor's `clientConfig` or an `Electrum*` client constructor. It is not a top-level wallet config option.
**Type:** `string`
**Default:** `"electrum.blockstream.info"`
**Recommended:** Configure your own Electrum server for production use. Public servers can be 10-300x slower and may fail for addresses with many transactions.
**Example:**
```javascript
const config = {
client: {
type: 'electrum',
clientConfig: {
host: 'fulcrum.frznode.com',
port: 50002,
protocol: 'tls'
}
}
}
```
### Port
The `port` value belongs inside an `electrum` descriptor's `clientConfig` or an `Electrum*` client constructor. It is not a top-level wallet config option.
**Type:** `number`
**Default:** `50001`
**Common Ports:**
* `50001` - TCP (default)
* `50002` - TLS/SSL
* `50003` - WebSocket
**Example:**
```javascript
const config = {
client: {
type: 'electrum',
clientConfig: {
host: 'electrum.blockstream.info',
port: 50002,
protocol: 'tls'
}
}
}
```
### Protocol
The `protocol` value belongs inside an `electrum` descriptor's `clientConfig`. It is not a top-level wallet config option.
**Type:** `string`
**Values:**
* `"tcp"` - TCP transport (default)
* `"tls"` - TLS transport
* `"ssl"` - SSL transport
**Default:** `"tcp"`
**Example:**
```javascript
const config = {
client: {
type: 'electrum',
clientConfig: {
host: 'electrum.blockstream.info',
port: 50002,
protocol: 'tls'
}
}
}
```
### Retries
The `retries` option controls failover retry attempts when `client` is an array.
**Type:** `number` (optional)
**Example:**
```javascript
const config = {
client: [
{ type: 'electrum', clientConfig: { host: 'primary.example', port: 50002, protocol: 'tls' } },
{ type: 'electrum', clientConfig: { host: 'secondary.example', port: 50002, protocol: 'tls' } }
],
retries: 2
}
```
### Network
The `network` option specifies which Bitcoin network to use.
**Type:** `string`
**Values:**
* `"bitcoin"` - Bitcoin [mainnet](../../../resources/concepts#mainnet) (production)
* `"testnet"` - Bitcoin [testnet](../../../resources/concepts#testnet) (development)
* `"regtest"` - Bitcoin [regtest](../../../resources/concepts#regtest) (local testing)
**Default:** `"bitcoin"`
**Example:**
```javascript
const config = {
network: 'testnet' // Use testnet for development
}
```
### BIP
The `bip` option specifies the address type derivation standard to use.
**Type:** `number`
**Values:**
* `84` - [BIP-84](../../../resources/concepts#bip-84-native-segwit) (P2WPKH / Native SegWit) - addresses start with `bc1` (mainnet) or `tb1` (testnet)
* `44` - [BIP-44](../../../resources/concepts#bip-44-multi-account-hierarchy) (P2PKH / Legacy) - addresses start with `1` (mainnet) or `m`/`n` (testnet)
**Default:** `84`
**Example:**
```javascript
// Use legacy addresses
const config = {
bip: 44
}
```
## Electrum Server Configuration
**Important**: While the package defaults to `electrum.blockstream.info:50001` for convenience, **we strongly recommend configuring your own Electrum server** for production use.
### Recommended Approach
**For Production:**
* Set up your own Fulcrum server for optimal performance and reliability
* Use recent Fulcrum versions that support pagination for high-transaction addresses
**For Development/Testing:**
* `fulcrum.frznode.com:50001` - Generally faster than default
* `electrum.blockstream.info:50001` - Default fallback
### Configuration Examples
```javascript
import { ElectrumTcp, ElectrumTls } from '@tetherto/wdk-wallet-btc'
// Production with custom Fulcrum server
const productionClient = new ElectrumTls({
host: 'your-fulcrum-server.com',
port: 50002
})
const productionWallet = new WalletManagerBtc(seedPhrase, {
client: productionClient,
network: 'bitcoin'
})
// Development with alternative public server
const developmentClient = new ElectrumTcp({
host: 'fulcrum.frznode.com',
port: 50001
})
const developmentWallet = new WalletManagerBtc(seedPhrase, {
client: developmentClient,
network: 'bitcoin'
})
```
### Network-Specific Configuration
#### Bitcoin Mainnet
```javascript
import { ElectrumTcp } from '@tetherto/wdk-wallet-btc'
const client = new ElectrumTcp({
host: 'electrum.blockstream.info', // Or your own server
port: 50001
})
const wallet = new WalletManagerBtc(seedPhrase, {
client,
network: 'bitcoin'
})
```
#### Bitcoin Testnet
```javascript
import { ElectrumTcp } from '@tetherto/wdk-wallet-btc'
const client = new ElectrumTcp({
host: 'testnet.hsmiths.com', // Example testnet server
port: 53011
})
const wallet = new WalletManagerBtc(seedPhrase, {
client,
network: 'testnet'
})
```
#### Bitcoin Regtest
```javascript
import { ElectrumTcp } from '@tetherto/wdk-wallet-btc'
const client = new ElectrumTcp({
host: 'localhost', // Local regtest node
port: 50001
})
const wallet = new WalletManagerBtc(seedPhrase, {
client,
network: 'regtest'
})
```
## Derivation Paths
Bitcoin wallet addresses are derived using BIP-32 hierarchical deterministic paths:
### BIP-84 (Native SegWit) - Default
* `m/84'/0'/0'/0/0` for mainnet account 0, address 0
* `m/84'/1'/0'/0/0` for testnet/regtest account 0, address 0
Addresses start with `bc1` (mainnet) or `tb1` (testnet).
### BIP-44 (Legacy)
* `m/44'/0'/0'/0/0` for mainnet account 0, address 0
* `m/44'/1'/0'/0/0` for testnet/regtest account 0, address 0
Addresses start with `1` (mainnet) or `m`/`n` (testnet).
**Default Derivation Path Change in v1.0.0-beta.4+**
The default derivation path was updated in v1.0.0-beta.4 to use BIP-84 (Native SegWit) instead of BIP-44 (Legacy):
* **Previous path** (up to v1.0.0-beta.3): `m/44'/0'/0'/0/{index}` (Legacy addresses)
* **Current path** (v1.0.0-beta.4+): `m/84'/0'/0'/0/{index}` (Native SegWit addresses)
If you're upgrading from an earlier version, existing wallets created with the old path will generate different addresses. Make sure to migrate any existing wallets or use the old path explicitly if needed for compatibility.
Use [`getAccountByPath`](./api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
## Complete Configuration Example
```javascript
import WalletManagerBtc, { ElectrumTls } from '@tetherto/wdk-wallet-btc'
// Create Electrum client
const client = new ElectrumTls({
host: 'your-electrum-server.com', // Replace with your server
port: 50002
})
// Create wallet manager with configuration
const wallet = new WalletManagerBtc(seedPhrase, {
client,
network: 'bitcoin',
bip: 84 // Native SegWit (default)
})
// Get accounts (inherit configuration from manager)
const account0 = await wallet.getAccount(0)
const account1 = await wallet.getAccount(1)
const customAccount = await wallet.getAccountByPath("0'/0/5")
// Clean up when done
wallet.dispose()
```
## Performance Considerations
**Electrum Server Performance:**
* Public servers like Blockstream's can be significantly slower
* Addresses with many transactions may cause timeouts
* Custom Fulcrum servers provide better performance and reliability
* Consider server location and network latency
**Configuration Tips:**
* Use `fulcrum.frznode.com` for better development performance
* Set up your own Fulcrum server for production
* Monitor connection stability and implement retry logic
* Consider using multiple backup servers
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Get started with WDK's BTC Wallet Usage
Get started with WDK's BTC Wallet API
***
### Need Help?
# Wallet BTC Overview (/sdk/wallet-modules/wallet-btc)
A simple and secure package to manage BIP-84 (SegWit) and BIP-44 (Legacy) wallets for the Bitcoin blockchain. This package provides a clean API for creating, managing, and interacting with Bitcoin wallets using BIP-39 seed phrases and Bitcoin-specific derivation paths.
**Default Derivation Path Change in v1.0.0-beta.4+**
The default derivation path was updated in v1.0.0-beta.4 to use BIP-84 (Native SegWit) instead of BIP-44 (Legacy):
* **Previous path** (up to v1.0.0-beta.3): `m/44'/0'/0'/0/{index}` (Legacy addresses)
* **Current path** (v1.0.0-beta.4+): `m/84'/0'/0'/0/{index}` (Native SegWit addresses)
If you're upgrading from an earlier version, existing wallets created with the old path will generate different addresses. Make sure to migrate any existing wallets or use the old path explicitly if needed for compatibility.
Use [`getAccountByPath`](./api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
## Features
* **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases
* **Bitcoin Derivation Paths**: Support for BIP-84 (Native SegWit, default) and BIP-44 (Legacy) derivation paths
* **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
* **Address Types Support**: Generate Native SegWit (P2WPKH) addresses by default, with Legacy (P2PKH) support via configuration
* **UTXO Management**: Track and manage unspent transaction outputs
* **Offline Transaction Signing**: Sign Bitcoin transactions with `signTransaction()` without broadcasting them
* **Transaction Management**: Create, sign, and broadcast Bitcoin transactions (single recipient per transaction)
* **Fee Estimation**: Dynamic fee calculation via mempool.space API
* **Provider Failover**: Configure ordered Electrum, WebSocket, Blockbook, or custom client fallbacks
* **TypeScript Support**: Full TypeScript definitions included
* **Memory Safety**: Secure private key management with memory-safe implementation
* **Network Flexibility**: Support for mainnet, testnet, and regtest
## Supported Networks
This package works with Bitcoin networks:
* **Bitcoin Mainnet** (`"bitcoin"`)
* **Bitcoin Testnet** (`"testnet"`)
* **Bitcoin Regtest** (`"regtest"`)
### Electrum Server Configuration
**Important**: While the package defaults to `electrum.blockstream.info:50001` for convenience, **we strongly recommend configuring your own Electrum server** for production use.
#### Recommended Approach:
**For Production:**
* Set up your own Fulcrum server for optimal performance and reliability
* Use recent Fulcrum versions that support pagination for high-transaction addresses
**For Development/Testing:**
* `fulcrum.frznode.com:50001` - Generally faster than default
* `electrum.blockstream.info:50001` - Default fallback
## Next Steps
Get started with WDK in a Node.js environment
Get started with WDK's Bitcoin Wallet configuration
Get started with WDK's Bitcoin Wallet API
Get started with WDK's Bitcoin Wallet usage
***
### Need Help?
# Wallet BTC Usage (/sdk/wallet-modules/wallet-btc/usage)
# Usage
The `@tetherto/wdk-wallet-btc` module provides wallet management for the Bitcoin blockchain.
Install the package and create your first wallet.
Work with multiple accounts and custom derivation paths.
Query native BTC balances for owned and read-only accounts.
Send Bitcoin and estimate transaction fees.
Retrieve and filter transfer history.
Sign messages and verify signatures.
Handle errors, manage fees, and dispose of sensitive data.
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Get started with WDK's Bitcoin Wallet Configuration
Get started with WDK's Bitcoin Wallet API
***
### Need Help?
# Wallet EVM API Reference (/sdk/wallet-modules/wallet-evm/api-reference)
## Table of Contents
| Class | Description | Methods |
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [WalletManagerEvm](#walletmanagerevm) | Main class for managing EVM wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) |
| [WalletAccountEvm](#walletaccountevm) | Individual EVM wallet account implementation. Extends `WalletAccountReadOnlyEvm` and implements `IWalletAccount` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) |
| [WalletAccountReadOnlyEvm](#walletaccountreadonlyevm) | Read-only EVM wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-2), [Methods](#methods-2) |
## WalletManagerEvm
The main class for managing EVM wallets.
Extends `WalletManager` from `@tetherto/wdk-wallet`.
### Constructor
```javascript
new WalletManagerEvm(seed, config?)
```
**Parameters:**
* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `config` (object, optional): Configuration object
* `provider` (`string | Eip1193Provider | Array`, optional): RPC endpoint URL, EIP-1193 provider instance, or ordered failover list
* `retries` (number, optional): Additional retry attempts when `provider` is an array
* `chainId` (number, optional): Network chain ID. When provided, skips automatic chain ID detection.
* `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations (in wei)
**Example:**
```javascript
const wallet = new WalletManagerEvm(seedPhrase, {
provider: 'https://rpc.mevblocker.io/fast',
transferMaxFee: 100000000000000 // Maximum fee in wei
})
```
### Methods
| Method | Description | Returns | Throws |
| --------------------------------- | ---------------------------------------------------------------- | ----------------------------------------- | --------------------- |
| `getRandomSeedPhrase(wordCount?)` | (static) Returns a random BIP-39 seed phrase | `string` | - |
| `isValidSeedPhrase(seedPhrase)` | (static) Checks if a seed phrase is valid | `boolean` | - |
| `getAccount(index?)` | Returns a wallet account at the specified index | `Promise` | - |
| `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise` | - |
| `getFeeRates()` | Returns current fee rates for transactions | `Promise<{normal: bigint, fast: bigint}>` | If no provider is set |
| `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | - |
### Properties
| Property | Type | Description |
| -------- | ------------ | ----------------------- |
| `seed` | `Uint8Array` | The wallet's seed bytes |
#### `getRandomSeedPhrase(wordCount?)` (static)
Returns a random BIP-39 seed phrase.
**Parameters:**
* `wordCount` (12 | 24, optional): The number of words in the seed phrase (default: 12)
**Returns:** `string` - The seed phrase
**Example:**
```javascript
const seedPhrase = WalletManagerEvm.getRandomSeedPhrase()
console.log('Seed phrase:', seedPhrase) // 12 words
const longSeedPhrase = WalletManagerEvm.getRandomSeedPhrase(24)
console.log('Long seed phrase:', longSeedPhrase) // 24 words
```
#### `isValidSeedPhrase(seedPhrase)` (static)
Checks if a seed phrase is valid.
**Parameters:**
* `seedPhrase` (string): The seed phrase to validate
**Returns:** `boolean` - True if the seed phrase is valid
**Example:**
```javascript
const isValid = WalletManagerEvm.isValidSeedPhrase('abandon abandon abandon ...')
console.log('Valid:', isValid)
```
#### `getAccount(index?)`
Returns a wallet account at the specified index following BIP-44 standard.
**Parameters:**
* `index` (number, optional): The index of the account to get (default: 0)
**Returns:** `Promise` - The wallet account
**Example:**
```javascript
// Get first account (index 0)
const account = await wallet.getAccount(0)
// Get second account (index 1)
const account1 = await wallet.getAccount(1)
// Get first account (default)
const defaultAccount = await wallet.getAccount()
```
#### `getAccountByPath(path)`
Returns a wallet account at the specified BIP-44 derivation path.
**Parameters:**
* `path` (string): The derivation path (e.g., "0'/0/0")
**Returns:** `Promise` - The wallet account
**Example:**
```javascript
// Full path: m/44'/60'/0'/0/1
const account = await wallet.getAccountByPath("0'/0/1")
// Custom path: m/44'/60'/0'/0/5
const customAccount = await wallet.getAccountByPath("0'/0/5")
```
#### `getFeeRates()`
Returns current fee rates based on network conditions with predefined multipliers.
**Returns:** `Promise<{normal: bigint, fast: bigint}>` - Fee rates in wei
* `normal`: Base fee × 1.1 (10% above base)
* `fast`: Base fee × 2.0 (100% above base)
**Throws:** Error if no provider is configured
**Example:**
```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei')
console.log('Fast fee rate:', feeRates.fast, 'wei')
// Use in transaction
const result = await account.sendTransaction({
to: '0x...',
value: 1000000000000000000n,
maxFeePerGas: feeRates.fast
})
```
#### `dispose()`
Disposes all wallet accounts, clearing private keys from memory.
**Example:**
```javascript
// Clean up when done
wallet.dispose()
```
## WalletAccountEvm
Represents an individual wallet account. Extends `WalletAccountReadOnlyEvm` and implements `IWalletAccount` from `@tetherto/wdk-wallet`.
### Constructor
```javascript
new WalletAccountEvm(seed, path, config?)
```
**Parameters:**
* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `path` (string): BIP-44 derivation path (e.g., "0'/0/0")
* `config` (object, optional): Configuration object
* `provider` (`string | Eip1193Provider | Array`, optional): RPC endpoint URL, EIP-1193 provider instance, or ordered failover list
* `retries` (number, optional): Additional retry attempts when `provider` is an array
* `chainId` (number, optional): Network chain ID. When provided, skips automatic chain ID detection.
* `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations (in wei)
**Throws:**
* Error if seed phrase is invalid (BIP-39 validation fails)
**Example:**
```javascript
const account = new WalletAccountEvm(seedPhrase, "0'/0/0", {
provider: 'https://rpc.mevblocker.io/fast',
transferMaxFee: 100000000000000
})
```
### Methods
| Method | Description | Returns | Throws |
| --------------------------------------- | -------------------------------------------------------------- | ---------------------------------------- | --------------------------------- |
| `getAddress()` | Returns the account's address | `Promise` | - |
| `sign(message)` | Signs a message using the account's private key | `Promise` | - |
| `signTypedData(typedData)` | Signs typed data according to EIP-712 | `Promise` | - |
| `signTransaction(tx)` | Signs an EVM transaction without broadcasting it | `Promise` | If transaction signing fails |
| `verify(message, signature)` | Verifies a message signature | `Promise` | - |
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712) | `Promise` | - |
| `sendTransaction(tx)` | Sends an EVM transaction | `Promise<{hash: string, fee: bigint}>` | If no provider |
| `quoteSendTransaction(tx)` | Estimates the fee for an EVM transaction | `Promise<{fee: bigint}>` | If no provider |
| `transfer(options)` | Transfers ERC20 tokens to another address | `Promise<{hash: string, fee: bigint}>` | If no provider or fee exceeds max |
| `quoteTransfer(options)` | Estimates the fee for an ERC20 transfer | `Promise<{fee: bigint}>` | If no provider |
| `getBalance()` | Returns the native token balance (in wei) | `Promise` | If no provider |
| `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise` | If no provider |
| `getTokenBalances(tokenAddresses)` | Returns balances for multiple ERC20 tokens | `Promise>` | If no provider |
| `approve(options)` | Approves a spender to spend tokens | `Promise<{hash: string, fee: bigint}>` | If no provider |
| `getAllowance(token, spender)` | Returns current allowance for a spender | `Promise` | If no provider |
| `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise` | If no provider |
| `toReadOnlyAccount()` | Returns a read-only copy of the account | `Promise` | - |
| `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | - |
#### `getAddress()`
Returns the account's Ethereum address.
**Returns:** `Promise` - Checksummed Ethereum address
**Example:**
```javascript
const address = await account.getAddress()
console.log('Account address:', address) // 0x...
```
#### `sign(message)`
Signs a message using the account's private key.
**Parameters:**
* `message` (string): The message to sign
**Returns:** `Promise` - The message signature
**Example:**
```javascript
const message = 'Hello, Ethereum!'
const signature = await account.sign(message)
console.log('Signature:', signature)
```
#### `signTypedData(typedData)`
Signs typed data according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712).
**Parameters:**
* `typedData` (TypedData): The typed data to sign
* `domain` (TypedDataDomain): The domain separator (name, version, chainId, verifyingContract)
* `types` (Record\): The type definitions
* `message` (Record\): The message data
**Returns:** `Promise` - The typed data signature
**Example:**
```javascript
const typedData = {
domain: {
name: 'MyDApp',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
},
types: {
Mail: [
{ name: 'from', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'contents', type: 'string' }
]
},
message: {
from: '0xAlice...',
to: '0xBob...',
contents: 'Hello Bob!'
}
}
const signature = await account.signTypedData(typedData)
console.log('EIP-712 Signature:', signature)
```
#### `signTransaction(tx)`
Signs an EVM transaction and returns the signed raw transaction as a hex string. This method does not broadcast the transaction.
**Parameters:**
* `tx` (EvmTransaction): The transaction object
* `to` (string): Recipient address
* `value` (number | bigint): Amount in wei
* `data` (string, optional): Transaction data in hex format
* `gasLimit` (number | bigint, optional): Maximum gas units
* `gasPrice` (number | bigint, optional): Legacy gas price in wei
* `maxFeePerGas` (number | bigint, optional): EIP-1559 max fee per gas in wei
* `maxPriorityFeePerGas` (number | bigint, optional): EIP-1559 max priority fee per gas in wei
* `type` (number, optional): Transaction type, such as `4` for ERC-7702
* `nonce` (number, optional): Transaction nonce
* `chainId` (number | bigint, optional): Network chain ID
* `authorizationList` (AuthorizationLike\[], optional): ERC-7702 authorization list for type 4 transactions
**Returns:** `Promise` - Signed raw transaction hex string
**Example:**
```javascript
const signedTransaction = await account.signTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000n,
chainId: 1
})
console.log('Signed transaction:', signedTransaction)
```
#### `verify(message, signature)`
Verifies a message signature against the account's address.
**Parameters:**
* `message` (string): The original message
* `signature` (string): The signature to verify
**Returns:** `Promise` - True if signature is valid
**Example:**
```javascript
const message = 'Hello, Ethereum!'
const signature = await account.sign(message)
const isValid = await account.verify(message, signature)
console.log('Signature valid:', isValid) // true
```
#### `verifyTypedData(typedData, signature)`
Verifies a typed data signature according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712).
**Parameters:**
* `typedData` (TypedData): The typed data that was signed
* `signature` (string): The signature to verify
**Returns:** `Promise` - True if signature is valid
**Example:**
```javascript
const isValid = await account.verifyTypedData(typedData, signature)
console.log('Typed data signature valid:', isValid) // true
```
#### `sendTransaction(tx)`
Sends an EVM transaction and returns the result with hash and fee.
**Parameters:**
* `tx` (EvmTransaction): The transaction object
* `to` (string): Recipient address
* `value` (number | bigint): Amount in wei
* `data` (string, optional): Transaction data in hex format
* `gasLimit` (number | bigint, optional): Maximum gas units
* `gasPrice` (number | bigint, optional): Legacy gas price in wei
* `maxFeePerGas` (number | bigint, optional): EIP-1559 max fee per gas in wei
* `maxPriorityFeePerGas` (number | bigint, optional): EIP-1559 max priority fee per gas in wei
* `type` (number, optional): Transaction type, such as `4` for ERC-7702
* `nonce` (number, optional): Transaction nonce
* `chainId` (number | bigint, optional): Network chain ID
* `authorizationList` (AuthorizationLike\[], optional): ERC-7702 authorization list for type 4 transactions
**Returns:** `Promise<{hash: string, fee: bigint}>` - Transaction result
**Throws:** Error if no provider is configured
**Example:**
```javascript
// EIP-1559 transaction
const result = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000, // 1 ETH in wei
maxFeePerGas: 30000000000,
maxPriorityFeePerGas: 2000000000
})
// Legacy transaction
const legacyResult = await account.sendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000,
gasPrice: 20000000000,
gasLimit: 21000
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'wei')
```
#### `quoteSendTransaction(tx)`
Estimates the fee for an EVM transaction without sending it.
**Parameters:**
* `tx` (EvmTransaction): The transaction object (same format as sendTransaction)
**Returns:** `Promise<{fee: bigint}>` - Fee estimate in wei
**Throws:** Error if no provider is configured
**Example:**
```javascript
const quote = await account.quoteSendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000
})
console.log('Estimated fee:', quote.fee, 'wei')
```
#### `transfer(options)`
Transfers ERC20 tokens to another address using the standard transfer function.
**Parameters:**
* `options` (TransferOptions): Transfer options
* `token` (string): Token contract address
* `recipient` (string): Recipient address
* `amount` (number | bigint): Amount in token base units
**Returns:** `Promise<{hash: string, fee: bigint}>` - Transfer result
**Throws:**
* Error if no provider is configured
* Error if fee exceeds `transferMaxFee` (if configured)
**Example:**
```javascript
const result = await account.transfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000 // 1 USDT (6 decimals)
})
console.log('Transfer hash:', result.hash)
console.log('Transfer fee:', result.fee, 'wei')
```
#### `quoteTransfer(options)`
Estimates the fee for an ERC20 token transfer.
**Parameters:**
* `options` (TransferOptions): Transfer options (same as transfer)
**Returns:** `Promise<{fee: bigint}>` - Fee estimate in wei
**Throws:** Error if no provider is configured
**Example:**
```javascript
const quote = await account.quoteTransfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee, 'wei')
```
#### `getBalance()`
Returns the native token balance (ETH, MATIC, BNB, etc.).
**Returns:** `Promise` - Balance in wei
**Throws:** Error if no provider is configured
**Example:**
```javascript
const balance = await account.getBalance()
console.log('Balance:', balance, 'wei')
console.log('Balance in ETH:', balance / 1000000000000000000)
```
#### `getTokenBalance(tokenAddress)`
Returns the balance of a specific ERC20 token using the balanceOf function.
**Parameters:**
* `tokenAddress` (string): The ERC20 token contract address
**Returns:** `Promise` - Token balance in base units
**Throws:** Error if no provider is configured
**Example:**
```javascript
// Get USDT balance
const usdtBalance = await account.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7')
console.log('USDT balance:', usdtBalance) // In 6 decimal places
console.log('USDT balance formatted:', usdtBalance / 1000000, 'USDT')
```
#### `getTokenBalances(tokenAddresses)`
Returns balances for multiple ERC20 tokens in one call.
**Parameters:**
* `tokenAddresses` (string\[]): List of ERC20 token contract addresses
**Returns:** `Promise>` - Object mapping each token address to its balance in base units
**Throws:** Error if no provider is configured
**Example:**
```javascript
const balances = await account.getTokenBalances([
'0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
'0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT
])
console.log('USDT:', balances['0xdAC17F958D2ee523a2206206994597C13D831ec7'])
console.log('XAUT:', balances['0x68749665FF8D2d112Fa859AA293F07A622782F38'])
```
#### `approve(options)`
Approves a specific amount of tokens to a spender.
**Parameters:**
* `options` (ApproveOptions): Approve options
* `token` (string): Token contract address
* `spender` (string): Spender address
* `amount` (number | bigint): Amount to approve
**Returns:** `Promise<{hash: string, fee: bigint}>` - Transaction result
**Throws:**
* Error if no provider is configured
* Error if trying to re-approve USDT on Ethereum without resetting to 0 first
**Example:**
```javascript
const result = await account.approve({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
spender: '0xSpenderAddress...',
amount: 1000000n
})
console.log('Approve hash:', result.hash)
```
#### `getAllowance(token, spender)`
Returns the current token allowance for the given spender.
**Parameters:**
* `token` (string): ERC20 token contract address
* `spender` (string): The spender's address
**Returns:** `Promise` - The current allowance
**Throws:** Error if no provider is configured
**Example:**
```javascript
const allowance = await account.getAllowance(
'0xdAC17F958D2ee523a2206206994597C13D831ec7',
'0xSpenderContract...'
)
console.log('Current allowance:', allowance)
```
#### `getTransactionReceipt(hash)`
Returns a transaction receipt by hash.
**Parameters:**
* `hash` (string): The transaction hash
**Returns:** `Promise` - Transaction receipt or null if not mined
**Throws:** Error if no provider is configured
**Example:**
```javascript
const receipt = await account.getTransactionReceipt('0x...')
if (receipt) {
console.log('Confirmed in block:', receipt.blockNumber)
console.log('Status:', receipt.status) // 1 = success, 0 = failed
}
```
#### `toReadOnlyAccount()`
Creates a read-only copy of the account with the same configuration.
**Returns:** `Promise` - Read-only account instance
**Example:**
```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
// Can check balances but cannot send transactions
const balance = await readOnlyAccount.getBalance()
// readOnlyAccount.sendTransaction() // Would throw error
```
#### `dispose()`
Disposes the wallet account, erasing the private key from memory.
**Example:**
```javascript
// Clean up when done
account.dispose()
```
### Properties
| Property | Type | Description |
| --------- | --------------------------------------------------------- | -------------------------------------------------------------------------- |
| `index` | `number` | The derivation path's index of this account |
| `path` | `string` | The full BIP-44 derivation path of this account |
| `keyPair` | `{privateKey: Uint8Array \| null, publicKey: Uint8Array}` | The account's key pair (⚠️ Contains sensitive data) |
| `address` | `string` | The account's Ethereum address (inherited from `WalletAccountReadOnlyEvm`) |
**Example:**
```javascript
console.log('Account index:', account.index) // 0, 1, 2, etc.
console.log('Account path:', account.path) // m/44'/60'/0'/0/0
// ⚠️ SENSITIVE: Handle with care
const { privateKey, publicKey } = account.keyPair
console.log('Public key length:', publicKey.length) // 65 bytes
console.log('Private key length:', privateKey.length) // 32 bytes
```
⚠️ **Security Note**: The `keyPair` property contains sensitive cryptographic material. Never log, display, or expose the private key.
## WalletAccountReadOnlyEvm
Represents a read-only wallet account that can query balances and estimate fees but cannot send transactions.
### Constructor
```javascript
new WalletAccountReadOnlyEvm(address, config?)
```
**Parameters:**
* `address` (string): The account's Ethereum address
* `config` (`Omit`, optional): Configuration object (same as `EvmWalletConfig` but without `transferMaxFee`, since read-only accounts cannot send transactions)
* `provider` (`string | Eip1193Provider | Array`, optional): RPC endpoint URL, EIP-1193 provider instance, or ordered failover list
* `retries` (number, optional): Additional retry attempts when `provider` is an array
* `chainId` (number, optional): Network chain ID. When provided, skips automatic chain ID detection.
**Example:**
```javascript
const readOnlyAccount = new WalletAccountReadOnlyEvm('0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', {
provider: 'https://rpc.mevblocker.io/fast'
})
```
### Properties
| Property | Type | Description |
| --------- | -------- | ------------------------------ |
| `address` | `string` | The account's Ethereum address |
### Methods
| Method | Description | Returns | Throws |
| --------------------------------------- | --------------------------------------------- | ---------------------------------------- | -------------- |
| `getAddress()` | Returns the account's address | `Promise` | - |
| `getBalance()` | Returns the native token balance (in wei) | `Promise` | If no provider |
| `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise` | If no provider |
| `getTokenBalances(tokenAddresses)` | Returns balances for multiple ERC20 tokens | `Promise>` | If no provider |
| `quoteSendTransaction(tx)` | Estimates the fee for an EVM transaction | `Promise<{fee: bigint}>` | If no provider |
| `quoteTransfer(options)` | Estimates the fee for an ERC20 transfer | `Promise<{fee: bigint}>` | If no provider |
| `verify(message, signature)` | Verifies a message signature | `Promise` | - |
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712) | `Promise` | - |
| `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise` | If no provider |
| `getAllowance(token, spender)` | Returns current allowance for a spender | `Promise` | If no provider |
#### `getAddress()`
Returns the account's Ethereum address.
**Returns:** `Promise` - Checksummed Ethereum address
**Example:**
```javascript
const address = await readOnlyAccount.getAddress()
console.log('Account address:', address) // 0x...
```
#### `getBalance()`
Returns the account's native token balance.
**Returns:** `Promise` - Balance in wei
**Throws:** Error if no provider is configured
**Example:**
```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Balance:', balance, 'wei')
```
#### `getTokenBalance(tokenAddress)`
Returns the balance of a specific ERC20 token.
**Parameters:**
* `tokenAddress` (string): The ERC20 token contract address
**Returns:** `Promise` - Token balance in base units
**Throws:** Error if no provider is configured
**Example:**
```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7')
console.log('USDT balance:', tokenBalance)
```
#### `getTokenBalances(tokenAddresses)`
Returns balances for multiple ERC20 tokens.
**Parameters:**
* `tokenAddresses` (string\[]): List of ERC20 token contract addresses
**Returns:** `Promise>` - Object mapping each token address to its balance in base units
**Throws:** Error if no provider is configured
**Example:**
```javascript
const balances = await readOnlyAccount.getTokenBalances([
'0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
'0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT
])
console.log('Balances:', balances)
```
#### `quoteSendTransaction(tx)`
Estimates the fee for an EVM transaction.
**Parameters:**
* `tx` (EvmTransaction): The transaction object
**Returns:** `Promise<{fee: bigint}>` - Fee estimate in wei
**Throws:** Error if no provider is configured
**Example:**
```javascript
const quote = await readOnlyAccount.quoteSendTransaction({
to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
value: 1000000000000000000
})
console.log('Estimated fee:', quote.fee, 'wei')
```
#### `quoteTransfer(options)`
Estimates the fee for an ERC20 token transfer.
**Parameters:**
* `options` (TransferOptions): Transfer options
**Returns:** `Promise<{fee: bigint}>` - Fee estimate in wei
**Throws:** Error if no provider is configured
**Example:**
```javascript
const quote = await readOnlyAccount.quoteTransfer({
token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee, 'wei')
```
#### `verify(message, signature)`
Verifies a message signature against the account's address.
**Parameters:**
* `message` (string): The original message
* `signature` (string): The signature to verify
**Returns:** `Promise` - True if signature is valid
**Example:**
```javascript
const message = 'Hello, Ethereum!'
const signature = await account.sign(message)
const readOnlyAccount = new WalletAccountReadOnlyEvm('0x...', { provider: '...' })
const isValid = await readOnlyAccount.verify(message, signature)
console.log('Signature valid:', isValid) // true
```
#### `verifyTypedData(typedData, signature)`
Verifies a typed data signature according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712).
**Parameters:**
* `typedData` (TypedData): The typed data that was signed
* `signature` (string): The signature to verify
**Returns:** `Promise` - True if signature is valid
**Example:**
```javascript
const isValid = await readOnlyAccount.verifyTypedData(typedData, signature)
console.log('Typed data signature valid:', isValid) // true
```
#### `getTransactionReceipt(hash)`
Returns a transaction's receipt if it has been mined.
**Parameters:**
* `hash` (string): The transaction hash
**Returns:** `Promise` - Transaction receipt or null if not yet mined
**Throws:** Error if no provider is configured
**Example:**
```javascript
const receipt = await readOnlyAccount.getTransactionReceipt('0x...')
if (receipt) {
console.log('Transaction confirmed in block:', receipt.blockNumber)
console.log('Gas used:', receipt.gasUsed)
console.log('Status:', receipt.status) // 1 = success, 0 = failed
} else {
console.log('Transaction not yet mined')
}
```
#### `getAllowance(token, spender)`
Returns the current allowance for the given token and spender.
**Parameters:**
* `token` (string): The token's address
* `spender` (string): The spender's address
**Returns:** `Promise` - The allowance
**Example:**
```javascript
const allowance = await readOnlyAccount.getAllowance(
'0xdAC17F958D2ee523a2206206994597C13D831ec7',
'0xSpenderAddress...'
)
console.log('Allowance:', allowance)
```
## Types
### EvmTransaction
```typescript
interface EvmTransaction {
to: string; // The transaction's recipient address
value: number | bigint; // The amount of ethers to send (in wei)
data?: string; // The transaction's data in hex format (optional)
gasLimit?: number | bigint; // Maximum amount of gas this transaction can use (optional)
gasPrice?: number | bigint; // Legacy gas price in wei (optional)
maxFeePerGas?: number | bigint; // EIP-1559 max fee per gas in wei (optional)
maxPriorityFeePerGas?: number | bigint; // EIP-1559 priority fee in wei (optional)
type?: number; // Transaction type, such as 4 for ERC-7702 (optional)
nonce?: number; // Transaction nonce (optional)
chainId?: number | bigint; // Network chain ID (optional)
authorizationList?: AuthorizationLike[]; // ERC-7702 authorization list for type 4 transactions (optional)
}
```
### TransferOptions
```typescript
interface TransferOptions {
token: string; // ERC20 token contract address
recipient: string; // Recipient's Ethereum address
amount: number | bigint; // Amount in token's base units
}
```
### TransactionResult
```typescript
interface TransactionResult {
hash: string; // Transaction hash
fee: bigint; // Transaction fee paid in wei
}
```
### TransferResult
```typescript
interface TransferResult {
hash: string; // Transfer transaction hash
fee: bigint; // Transfer fee paid in wei
}
```
### FeeRates
```typescript
interface FeeRates {
normal: bigint; // Normal priority fee rate (base fee × 1.1)
fast: bigint; // Fast priority fee rate (base fee × 2.0)
}
```
### KeyPair
```typescript
interface KeyPair {
privateKey: Uint8Array | null; // Private key as Uint8Array (32 bytes, null after dispose)
publicKey: Uint8Array; // Public key as Uint8Array (65 bytes)
}
```
### TypedData
```typescript
interface TypedData {
domain: TypedDataDomain; // The domain separator
types: Record; // The type definitions
message: Record; // The message data
}
```
### TypedDataDomain
```typescript
interface TypedDataDomain {
name?: string; // The domain name (e.g., the DApp name)
version?: string; // The domain version
chainId?: number | bigint; // The chain ID
verifyingContract?: string; // The verifying contract address
salt?: string; // An optional salt
}
```
### TypedDataField
```typescript
interface TypedDataField {
name: string; // The field name
type: string; // The field type (e.g., 'address', 'uint256', 'string')
}
```
### EvmWalletConfig
```typescript
interface EvmWalletConfig {
provider?: string | Eip1193Provider | Array; // RPC URL, EIP-1193 provider, or ordered failover list
retries?: number; // Additional retry attempts for provider arrays
chainId?: number; // Network chain ID. Skips automatic detection when provided.
transferMaxFee?: number | bigint; // Maximum fee for transfers in wei
}
```
### ApproveOptions
```typescript
interface ApproveOptions {
token: string; // ERC20 token contract address
spender: string; // Address allowed to spend tokens
amount: number | bigint; // Amount to approve in base units
}
```
### EvmTransactionReceipt
```typescript
interface EvmTransactionReceipt {
to: string; // Recipient address
from: string; // Sender address
contractAddress: string | null; // Contract address if contract creation
transactionIndex: number; // Transaction index in block
gasUsed: bigint; // Gas actually used
logsBloom: string; // Bloom filter for logs
blockHash: string; // Block hash containing transaction
transactionHash: string; // Transaction hash
logs: Array; // Event logs
blockNumber: number; // Block number
confirmations: number; // Number of confirmations
cumulativeGasUsed: bigint; // Cumulative gas used in block
effectiveGasPrice: bigint; // Effective gas price paid
status: number; // Transaction status (1 = success, 0 = failed)
type: number; // Transaction type (0 = legacy, 2 = EIP-1559)
}
```
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Get started with WDK's EVM Wallet Usage
Get started with WDK's EVM Wallet Configuration
***
### Need Help?
# Configuration (/sdk/wallet-modules/wallet-evm/configuration)
## Wallet Configuration
The `WalletManagerEvm` accepts a configuration object that defines how the wallet interacts with the blockchain:
```javascript
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
const config = {
// Recommended: RPC endpoint URL, EIP-1193 provider, or ordered failover list
provider: 'https://eth.drpc.org',
// Optional: Skip automatic chain ID detection when the network is known
chainId: 1,
// Optional: Additional failover attempts when provider is an array
retries: 2,
// Optional: Maximum fee for transfer operations (in wei)
transferMaxFee: 100000000000000 // 0.0001 ETH
}
const wallet = new WalletManagerEvm(seedPhrase, config)
```
## Account Configuration
Both `WalletAccountEvm` and `WalletAccountReadOnlyEvm` share similar configuration options:
```javascript
import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'
// Full access account
const account = new WalletAccountEvm(
seedPhrase,
"0'/0/0", // BIP-44 derivation path
{
provider: 'https://eth.drpc.org',
transferMaxFee: 100000000000000
}
)
// Read-only account
const readOnlyAccount = new WalletAccountReadOnlyEvm(
'0x...', // Ethereum address
{
provider: 'https://eth.drpc.org'
}
)
```
## Configuration Options
### Provider
The `provider` option specifies how to connect to the blockchain. It can be a URL string, an EIP-1193 compatible provider instance, or an ordered array of URL strings and EIP-1193 providers for automatic failover.
**Type:** `string | Eip1193Provider | Array`
**Examples:**
```javascript
// Option 1: Using RPC URL
const config = {
provider: 'https://eth.drpc.org'
}
// Option 2: Using browser provider (e.g., MetaMask)
const config = {
provider: window.ethereum
}
// Option 3: Using a custom EIP-1193 provider
// Works in Node.js, Bare, and browsers - zero external dependencies
function createFetchProvider(rpcUrl) {
let requestId = 0
return {
request: async ({ method, params }) => {
const response = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: ++requestId,
method,
params: params || []
})
})
const data = await response.json()
if (data.error) throw new Error(data.error.message)
return data.result
}
}
}
const config = {
provider: createFetchProvider('https://eth.drpc.org')
}
// Option 4: Using ordered provider failover
const config = {
provider: [
'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
'https://eth.drpc.org',
createFetchProvider('https://ethereum.publicnode.com')
],
retries: 2
}
```
When `provider` is an array, the wallet uses the candidates in order and retries connection failures against the next provider. If `retries` is greater than the number of providers, the failover loop wraps around in round-robin order.
### Retries
The `retries` option controls how many additional attempts can happen after the first provider call fails. It only applies when `provider` is an array.
**Type:** `number` (optional)
**Default:** `3`
**Example:**
```javascript
const config = {
provider: [
'https://primary.example',
'https://secondary.example'
],
retries: 1
}
```
### Chain ID
The `chainId` option pins the provider to a known EVM chain ID. Use it when you already know the target network and want to skip automatic chain ID detection during provider setup.
**Type:** `number` (optional)
**Example:**
```javascript
const config = {
provider: 'https://polygon-rpc.com',
chainId: 137
}
```
### Transfer Max Fee
The `transferMaxFee` option sets a maximum limit for transaction fees to prevent unexpectedly high costs.
**Type:** `number | bigint` (optional)
**Unit:** Wei (1 ETH = 1000000000000000000 Wei)
**Examples:**
```javascript
const config = {
// Set maximum fee to 0.0001 ETH
transferMaxFee: 100000000000000n,
}
// Usage example
try {
const result = await account.transfer({
token: '0x...', // ERC20 address
recipient: '0x...',
amount: 1000000n
})
} catch (error) {
if (error.message.includes('Exceeded maximum fee')) {
console.error('Transfer cancelled: Fee too high')
}
}
```
### Fee Rate Multipliers
The wallet manager uses predefined multipliers for fee calculations:
```javascript
// Normal fee rate = base fee × 1.1
const normalFee = await wallet.getFeeRates()
console.log('Normal fee:', normalFee.normal)
// Fast fee rate = base fee × 2.0
const fastFee = await wallet.getFeeRates()
console.log('Fast fee:', fastFee.fast)
```
## Network Support
The configuration works with any EVM-compatible network. Just change the provider URL:
```javascript
// Ethereum Mainnet
const mainnetConfig = {
provider: 'https://eth.drpc.org'
}
// Polygon (Matic)
const polygonConfig = {
provider: 'https://polygon-rpc.com'
}
// Arbitrum
const arbitrumConfig = {
provider: 'https://arb1.arbitrum.io/rpc'
}
// BSC (Binance Smart Chain)
const bscConfig = {
provider: 'https://bsc-dataseed.binance.org'
}
// Avalanche C-Chain
const avalancheConfig = {
provider: 'https://avalanche-c-chain-rpc.publicnode.com',
}
// Plasma
const plasmaConfig = {
provider: 'https://plasma.drpc.org',
}
// Stable (uses USD₮ as native gas token)
// No need for ERC-4337 paymaster/bundler setup.
const stableConfig = {
provider: 'https://rpc.stable.xyz',
}
// Sepolia Testnet
const sepoliaConfig = {
provider: 'https://sepolia.drpc.org',
}
```
## Next Steps
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Get started with WDK's EVM Wallet Usage
Get started with WDK's EVM Wallet API
***
### Need Help?
# Wallet EVM Overview (/sdk/wallet-modules/wallet-evm)
A simple and secure package to manage BIP-44 wallets for EVM (Ethereum Virtual Machine) blockchains. This package provides a clean API for creating, managing, and interacting with Ethereum-compatible wallets using BIP-39 seed phrases and BIP-44 derivation paths.
## Features
* **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases
* **EVM Derivation Paths**: Support for BIP-44 standard derivation paths for Ethereum (m/44'/60')
* **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
* **EVM Address Support**: Generate and manage Ethereum-compatible addresses using ethers.js
* **Message Signing**: Sign and verify messages using EVM cryptography
* **Offline Transaction Signing**: Sign EVM transactions with `signTransaction()` without broadcasting them
* **Transaction Management**: Send transactions and get fee estimates with EIP-1559 support
* **ERC20 Support**: Query native token and ERC20 token balances using smart contract interactions
* **Batch Token Balance Queries**: Fetch balances for multiple ERC20 tokens in one call with `getTokenBalances`
* **TypeScript Support**: Full TypeScript definitions included
* **Memory Safety**: Secure private key management with memory-safe HDNodeWallet implementation
* **Provider Flexibility**: Support for JSON-RPC URLs, EIP-1193 browser providers, and ordered failover provider lists
* **Gas Optimization**: Support for EIP-1559 maxFeePerGas and maxPriorityFeePerGas
* **Fee Estimation**: Dynamic fee calculation with normal (1.1x) and fast (2.0x) multipliers
## Supported Networks
This package works with any EVM-compatible blockchain, including:
* **Ethereum**: Mainnet, Sepolia
* **Polygon**: Mainnet, Amoy
* **Binance Smart Chain (BSC)**: Mainnet, Testnet
* **Arbitrum**: One, Nova
* **Optimism**: Mainnet, Sepolia
* **Avalanche C-Chain**: Mainnet, Fuji
* **And many more...**
## Next Steps
Get started with WDK in a Node.js environment
Get started with WDK's EVM Wallet configuration
Get started with WDK's EVM Wallet API
Get started with WDK's EVM Wallet usage
***
### Need Help?
# Usage (/sdk/wallet-modules/wallet-evm/usage)
The `@tetherto/wdk-wallet-evm` module provides wallet management for Ethereum and EVM-compatible blockchains.
Install the package and create your first wallet.
Work with multiple accounts and custom derivation paths.
Query native and ERC-20 token balances.
Send native tokens with EIP-1559 or legacy gas settings.
Transfer ERC-20 tokens and estimate fees.
Sign messages and verify signatures.
Handle errors, manage fees, and dispose of sensitive data.
Get started with WDK in a Node.js environment
Build mobile wallets with React Native Expo
Get started with WDK's EVM Wallet Configuration
Get started with WDK's EVM Wallet API
***
### Need Help?
# Wallet Spark API Reference (/sdk/wallet-modules/wallet-spark/api-reference)
### Table of Contents
| Class | Description | Methods |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [WalletManagerSpark](#walletmanagerspark) | Main class for managing Spark wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) |
| [WalletAccountSpark](#walletaccountspark) | Individual Spark wallet account implementation. Implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) |
| [WalletAccountReadOnlySpark](#walletaccountreadonlyspark) | Read-only Spark wallet account. | [Constructor](#constructor-1), [Methods](#methods-2) |
## WalletManagerSpark
The main class for managing Spark wallets.
Extends `WalletManager` from `@tetherto/wdk-wallet`.
#### Constructor
```javascript
new WalletManagerSpark(seed, config)
```
**Parameters:**
* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `config` (object, optional): Configuration object
* `network` (string, optional): 'MAINNET', 'SIGNET', or 'REGTEST' (default: 'MAINNET')
* `sparkscan` (`SparkScanConfig`, optional): SparkScan configuration for balance polling
* `syncAndRetry` (boolean, optional): When true, failed sends and Lightning payments sync wallet state and retry once
### Methods
| Method | Description | Returns |
| ------------------------ | ------------------------------------------------------------------ | ----------------------------------------- |
| `getAccount(index)` | Returns a wallet account at the specified index | `Promise` |
| `getAccountByPath(path)` | Returns a wallet account at a specific BIP-44 derivation path | `Promise` |
| `getFeeRates()` | Returns current fee rates for transactions (always zero for Spark) | `Promise<{normal: bigint, fast: bigint}>` |
| `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` |
##### `getAccount(index)`
Returns a wallet account at the specified index using BIP-44 derivation path.
**Parameters:**
* `index` (number, optional): The index of the account to get (default: 0)
**Returns:** `Promise` - The wallet account
**Example:**
```javascript
const account = await wallet.getAccount(0)
const account1 = await wallet.getAccount(1)
```
**Note:** Uses derivation path pattern `m/44'/998'/{networkNumber}'/0/{index}` where 998 is the coin type for Spark and networkNumber is 0 for MAINNET, 2 for SIGNET, or 3 for REGTEST.
##### `getFeeRates()`
Returns current fee rates for transactions. On Spark network, transactions have zero fees.
**Returns:** `Promise<{normal: bigint, fast: bigint}>` - Object containing fee rates (always `{normal: 0n, fast: 0n}`)
**Example:**
```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal) // Always 0n
console.log('Fast fee rate:', feeRates.fast) // Always 0n
```
##### `dispose()`
Disposes all wallet accounts and clears sensitive data from memory.
**Returns:** `void`
**Example:**
```javascript
wallet.dispose()
```
##### `getAccountByPath(path)`
Returns a wallet account at a specific BIP-44 derivation path.
**Parameters:**
* `path` (string): The derivation path segment (e.g. `"0'/0/0"`)
**Returns:** `Promise