# Welcome

Build secure, multi-chain, self-custodial wallets for any device with minimal effort and infinite scalability

The **Wallet Development Kit&#x20;*****by Tether*****&#x20;(WDK)** is Tether's open-source toolkit that empowers humans, machines and AI agents alike to build, deploy and use secure, multi-chain, self-custodial wallets that can be integrated anywhere from the smallest embedded device to any mobile, desktop and server operating system. WDK enables trillions of self-custodial wallets.

WDK provides a set of core libraries that give you the highest level of control and a wide range of user-interface templates and widgets to maximize your development and deployment speed.

{% embed url="<https://www.youtube.com/embed/15IRw2mAFR0?si=6lEdGgHlHgRcwnN6>" %}

***

### Discover WDK

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>About WDK</strong></td><td>Understand WDK core features and design principles</td><td><a href="about">about</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-29bfa0bd41c25b02c93e8420327380536fe6f59d%2Fabout.png?alt=media">about.png</a></td></tr><tr><td><strong>Our Vision</strong></td><td>Discover our philosophy and idea for the future wallets</td><td><a href="vision">vision</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-957ceb74edb97ac7f8d281ef3d8d0e01c21b7f9d%2Fvision.png?alt=media">vision.png</a></td></tr><tr><td><strong>Key Concepts</strong></td><td>Learn foundational concepts and terminology</td><td><a href="../resources-and-guides/concepts">concepts</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-c2bf984026ded131c959fa8319e5d6aff0d60fe3%2Fconcepts.png?alt=media">concepts.png</a></td></tr></tbody></table>

***

### Start Building

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-microchip">:microchip:</i></td><td><strong>Bare Runtime Quickstart</strong></td><td>Deploy WDK in lightweight environments</td><td><a href="../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-puzzle-piece">:puzzle-piece:</i></td><td><strong>UI Kit</strong></td><td>Explore our React Native UI Kit with pre-built components</td><td><a href="../ui-kits/react-native-ui-kit">react-native-ui-kit</a></td></tr></tbody></table>

***

### Get Involved

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-flask">:flask:</i></td><td><strong>Partner with us</strong></td><td>Driving impact? Register your project for direct team access</td><td><a href="https://wkf.ms/4hd40JK" class="button primary">Get in touch</a></td><td><a href="https://wkf.ms/4hd40JK">https://wkf.ms/4hd40JK</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Repos</strong></td><td>View source code, report issues, and contribute on GitHub</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">View Repo</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-question-circle">:question-circle:</i></td><td><strong>Get Support</strong></td><td>Need help? Our community can help troupleshoot</td><td><a href="https://discord.gg/arYXDhHB2w" class="button secondary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr></tbody></table>


# About WDK

Learn about the Wallet Development Kit and its capabilities

The **Wallet Development Kit&#x20;*****by Tether*****&#x20;(WDK)** is Tether's open-source toolkit that empowers humans, machines and AI agents alike to build, deploy and use secure, multi-chain, self-custodial wallets that can be integrated anywhere from the smallest embedded device to any mobile, desktop and server operating system.

A developer-first framework designed for maximum flexibility and scalability, powering anything from consumer wallets to wallet-enabled apps, DeFi integrations (lending, swaps, ...), IoT use cases, and AI agents.

Unlike closed solutions or SaaS-based wallet infrastructure providers, WDK offers zero lock-in and is designed for maximum flexibility and extensibility. It is modular, runs on Bare, Node.js and React-Native, thus can be embedded in a wide variety of environments.

***

## What Problems Does WDK Solve?

The current blockchain ecosystem is highly fragmented, with each blockchain requiring different SDKs, APIs, and integration approaches. This fragmentation creates significant barriers for developers who want to build truly seamless user-experiences that span across any blockchain, environment and use-case.

Traditional wallet development requires months of integration work. Developers must learn different standards, implement contrasting security practices, or rely on closed-source paid solutions which act as gatekeepers.

### **The Missing AI Foundation**

As we move toward a world where humans, machines and AI Agents need to manage digital assets safely, existing solutions fall short. AI agents will require wallets to interact in the financial infrastructure, and WDK wants to lay secure foundation that works for human, AI and IoT use cases. WDK enables trillions of self-custodial wallets.

***

## Why WDK is Different

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>Runs Anywhere</strong></td><td>Works with Node.js, Bare runtime, mobile (React Native), and future embedded environments</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-94c04e7f9a43526520416f845ae21c5d7f30fb81%2Fruns-anywhere.png?alt=media">runs-anywhere.png</a></td></tr><tr><td><strong>Modular &#x26; Extensible</strong></td><td>Pick only the modules you need; extend functionality with custom modules</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-79b3944a629aab98b8dd8c6fac6aa27352d6ca66%2Fmodular.png?alt=media">modular.png</a></td></tr><tr><td><strong>Developer-Centric</strong></td><td>Clear SDK design, strong TypeScript typing, extensive docs, and ready-to-use starters</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-1ae5bedaee5410ff3e93c12358f889eb33805d0e%2Fdeveloper-centric.png?alt=media">developer-centric.png</a></td></tr><tr><td><strong>Secure by Design</strong></td><td>Stateless and self-custodial architecture ensures keys never leave user control</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-2e12a05b566ea12fc2f159d18ccabda97571c72e%2Fsecure.png?alt=media">secure.png</a></td></tr><tr><td><strong>Zero Lock-In</strong></td><td>Transparent, community-driven, and free to adopt with no vendor lock-in</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-35b5d631ad2922dd9f60f63a0a92a674af891935%2Fzero-lock-in.png?alt=media">zero-lock-in.png</a></td></tr><tr><td><strong>Ecosystem-Backed</strong></td><td>Maintained and supported by Tether with strong community involvement</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-354918b42252b8e52e9debee8024d1efdc187b06%2Fecosystem.png?alt=media">ecosystem.png</a></td></tr></tbody></table>

***

## What WDK Provides

WDK combines four core components to deliver a complete wallet development solution:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>Modular SDK</strong></td><td>Unified APIs for wallet and protocol operations across multiple blockchains</td><td><a href="../sdk/get-started">get-started</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-d034131752538000760ce8a277522ef7e843591a%2Fproduct-sdk.png?alt=media">product-sdk.png</a></td></tr><tr><td><strong>Indexer API</strong></td><td>Reliable blockchain data access for balances, transactions, and historical data</td><td><a href="../tools/indexer-api">indexer-api</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-6016e51bab6ce5ec935076eac0a365416142b660%2Fproduct-indexer.png?alt=media">product-indexer.png</a></td></tr><tr><td><strong>UI Kits</strong></td><td>Reusable React Native components for building wallet interfaces</td><td><a href="../ui-kits/react-native-ui-kit">react-native-ui-kit</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-caf234ebfcfc731585bd79bffa42fb171c796d21%2Fproduct-ui-kit.png?alt=media">product-ui-kit.png</a></td></tr><tr><td><strong>Examples &#x26; Starters</strong></td><td>Production-ready wallet templates and reference implementations</td><td><a href="../examples-and-starters/react-native-starter">react-native-starter</a></td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-1776503a78bf24c5e00dec4fe3c895a6185ba2e7%2Fproduct-starters.png?alt=media">product-starters.png</a></td></tr></tbody></table>

***

## Supported Blockchains & Protocols

WDK natively supports a broad set of blockchains and standards out of the box:

{% tabs %}
{% tab title="Wallet Modules" %}

| Blockchain/Module                                                                      | Support |
| -------------------------------------------------------------------------------------- | ------- |
| [Bitcoin](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc)                    | ✅       |
| [Ethereum & EVM](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm)             | ✅       |
| [Ethereum ERC-4337](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337) | ✅       |
| [TON](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton)                        | ✅       |
| [TON Gasless](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless)        | ✅       |
| [TRON](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron)                      | ✅       |
| [TRON Gasfree](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron-gasfree)      | ✅       |
| [Solana](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana)                  | ✅       |
| [Spark/Lightning](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark)          | ✅       |
| {% endtab %}                                                                           |         |

{% tab title="DeFi Modules" %}

| Protocol/Module                                                                       | Support |
| ------------------------------------------------------------------------------------- | ------- |
| [velora (EVM)](https://docs.wdk.tether.io/sdk/swap-modules/swap-velora-evm)           | ✅       |
| [USD₮0 Bridge (EVM)](https://docs.wdk.tether.io/sdk/bridge-modules/bridge-usdt0-evm)  | ✅       |
| [Aave Lending (EVM)](https://docs.wdk.tether.io/sdk/lending-modules/lending-aave-evm) | ✅       |
| {% endtab %}                                                                          |         |
| {% endtabs %}                                                                         |         |

The modular architecture allows new chains, tokens, or protocols to be added by implementing dedicated modules.

Ready to start building? Explore our [getting started guide](https://docs.wdk.tether.io/start-building/nodejs-bare-quickstart) or dive into our [SDK documentation](https://docs.wdk.tether.io/sdk/get-started).


# Our Vision

Our philosophy and vision for the future of wallet development and asset management

Imagine a world where humans, machines, and AI agents have the freedom to control their own finances. WDK is a fully open-source, self-custodial toolkit designed to be modular, independent, resilient and infinitely scalable, enabling trillions of wallets.

***

### **Universal Unstoppable Access**

Anyone should be able to build, deploy or use a wallet and manage assets without friction or gatekeepers. Whether you're an independent developer, a startup, a corporation, an AI, or even a nation-state, WDK provides the open technology to create hyper-secure self-custodial wallets without barriers.

### **Ubiquitous Deployment**

Wallets need to run everywhere. Through Bare runtime compatibility, WDK can live and evolve on any embedded device, mobile apps, desktop applications, IoT devices, servers, and even autonomous systems. From smartphones to smart fridges, from trading bots to spaceships — WDK enables financial sovereignty across all environments.

### **AI-Native Architecture**

In a world where AI agents and robots are becoming autonomous and will permeate every single part of our lives, the machines need to have access and self-manage their own resources. WDK is the preferred choice for the digital entities of tomorrow, ensuring direct custody of funds, highly scalable transactions, and empowering the infinite AI economy of the future.

***

## A world of opportunities

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><strong>Millions of Wallets</strong></td><td>WDK enables a future with millions of wallets built on top of it, each tailored to specific needs and use cases</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-f8778938c89e4bd7bf112f84f96aa593e28a568a%2Fmillions-of-wallets.png?alt=media">millions-of-wallets.png</a></td></tr><tr><td><strong>Trillions of AI Agents</strong></td><td>WDK enables trillions of AI agents to have their own wallet, managing resources autonomously in the digital economy</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-8b1ffc21cc3a71977d299e319fa76ef060767639%2Ftrillions-of-agents.png?alt=media">trillions-of-agents.png</a></td></tr><tr><td><strong>Global Financial Sovereignty</strong></td><td>Any developer, company, organization, or country can build their own white-label wallet and manage their assets independently</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-99ef5b1463421d545503fadb3512c1b270d63bbf%2Ffinancial-sovereignty.png?alt=media">financial-sovereignty.png</a></td></tr><tr><td><strong>Ubiquitous Computing</strong></td><td>From IoT devices to autonomous vehicles, every connected device can have its own wallet and financial identity</td><td><a href="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-7963877d592e6c7a5e7bdc57b0f662b98bcd7ca6%2Fubiquitous-computing.png?alt=media">ubiquitous-computing.png</a></td></tr></tbody></table>

***

## Let's build this future together

WDK is more than a development kit—it's the foundation for a new era of financial sovereignty. By making wallet technology accessible, ubiquitous, and AI-native, we're enabling a world where:

* **Developers** can focus on innovation rather than infrastructure
* **Users** maintain complete control over their digital assets
* **AI Agents** can operate autonomously in the digital economy
* **Organizations** can build custom financial solutions without compromise
* **Society** benefits from more secure, efficient, and accessible financial infrastructure

Join us in building this future. The tools are open-source, the vision is clear, and the possibilities are limitless.

***

Ready to start building? Explore our [getting started guide](https://docs.wdk.tether.io/start-building/nodejs-bare-quickstart) or dive into our [SDK documentation](https://docs.wdk.tether.io/sdk/get-started).


# Partner with WDK

Build with WDK alongside Tether through our partnership tracks

Build with WDK alongside Tether. Whether you're integrating WDK into your product or extending the ecosystem with new capabilities, we have a partnership track designed for you.

WDK is built to be open and extensible, but we know that building great products often takes more than just great documentation. We offer a selected group of partners a direct connection with Tether's engineering and product teams so you can ship faster, with confidence. We offer 3 partnership tracks depending on how you plan to work with WDK.

* [Project Partners](#project-partners)
* [WDK Tech Contributors](#wdk-tech-contributors)
* [Consulting & Implementation Partners (Alpha)](#consulting-and-implementation-partners-alpha)

***

## Project Partners

Integrate WDK more confidently, with direct access to Tether's engineering team and WDK solutions architects. Project Partners approved for Tether-supported implementations will benefit from:

* Access to a WDK Solutions Architect to discuss product-specific implementation strategies
* Custom integration assistance
* Privileged support channel
* WDK roadmap visibility
* Early access to APIs and SDKs
* Direct access to WDK product and engineering core team

### Is it for you?

Project Partners are companies and teams building end-user products powered by WDK. You're a good fit for this track if you are:

* A **fintech or neobank** building a wallet, payments app, or asset management platform and looking to leverage WDK as your underlying wallet infrastructure.
* An **exchange or trading platform** adding self-custodial wallet features for your users.
* A **messaging or social platform** integrating peer-to-peer payments or tipping functionality.
* A **remittance or cross-border payments provider** looking to use stablecoins and multi-chain support to serve your customers.
* An **enterprise or institutional player** that needs WDK integrated into internal treasury, compliance, or operations tooling.
* Any team that plans to **ship a product to end users** where WDK handles key management, transaction signing, or blockchain interactions under the hood.

As a Project Partner, you get hands-on integration support from the team that builds WDK. We'll help you navigate architecture decisions, troubleshoot implementation challenges, and make sure your product launches on solid foundations.

<a href="https://forms.monday.com/forms/6d484c4b34949e3a238988c47bf0a1b6?r=euc1" class="button primary">Become a Project Partner</a>

***

## WDK Tech Contributors

Tap into the network of WDK adopters by developing modules and extensions for the WDK ecosystem. Technology partners approved as WDK Tech Contributors will benefit from:

* Build and publish WDK modules
* Visibility across WDK community and in WDK documentation
* Co-marketing opportunities
* Early access to APIs and SDKs
* Technical documentation collaboration

### Is it for you?

Tech Contributors are protocol teams, service providers, and developer organizations building modules, plugins, or integrations that extend what WDK can do. You're a good fit for this track if you are:

* A **swap or DEX protocol** looking to provide liquidity and trading capabilities to WDK-powered wallets.
* A **bridge protocol** enabling cross-chain asset transfers that WDK wallets can access natively.
* An **on/off-ramp provider** connecting fiat currencies to the WDK ecosystem.
* A **lending or DeFi protocol** looking to make your services available directly within WDK wallets.
* A **hardware wallet or signing solution provider** building signer integrations for WDK.
* A **blockchain or L2 network** that wants first-class WDK wallet support for your chain.
* An **open-source developer or team** contributing new wallet modules, protocol integrations, or developer tooling to the WDK ecosystem.

As a Tech Contributor, you'll work closely with our SDK team to build, test, and publish modules that reach every WDK-powered wallet. You'll get early access to unreleased APIs, architecture guidance, co-marketing exposure through our documentation and community channels, and the opportunity to shape how your protocol integrates across the ecosystem.

<a href="https://forms.monday.com/forms/f6c509ea32fabfa63f719ac8eed9f934?r=euc1" class="button primary">Become a Technology Partner</a>

***

## Consulting & Implementation Partners (Alpha)

Consulting companies, agencies, and systems integrators building wallet solutions with WDK for their clients. Approved Consulting & Implementation Partners will benefit from:

* **Being part of Tether's partner ecosystem**
* Access to a WDK Solutions Architect to discuss product-specific implementation strategies for your clients
* Custom integration assistance
* Direct access to WDK product and engineering core team
* Privileged support channel
* WDK roadmap visibility
* Early access to APIs and SDKs
* Co-marketing support

### Is it for you?

Consulting & Implementation Partners are agencies, system integrators, and software houses that would like to deliver WDK-powered solutions on behalf of their clients. You're a good fit for this track if you are:

* A **system integrator** helping enterprise clients adopt blockchain and digital asset infrastructure.
* A **software development agency** building custom wallet or payment applications.
* A **blockchain consultancy** advising companies on self-custodial wallet strategy and architecture.
* A **digital transformation firm** integrating stablecoin payments into existing client platforms.
* A **managed services provider** offering ongoing support and maintenance for WDK-based deployments.

As a Consulting & Implementation Partner, you'll gain access to Tether's referral network, dedicated technical support for your client engagements. We'll equip your team with the training, documentation, and direct engineering access needed to deliver successful WDK implementations at scale.

{% hint style="info" %}
**Alpha Program** - This partnership track is currently in alpha. We're onboarding a limited number of partners as we shape the program and cannot guarantee acceptance, specific benefits, or program terms at this stage. Apply to express your interest and help shape the program as it evolves.
{% endhint %}

<a href="https://forms.monday.com/forms/d4603bc6e37b0c0a9c591764bcfb9380?r=euc1" class="button primary">Become a Consulting & Implementation Partner</a>


# Get Support

Need help with WDK? We've got you covered

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>

We're here to help you succeed with WDK. Don't hesitate to reach out.


# Changelog

Updates and improvements to the Wallet Development Kit (WDK) modules and tools.

Stay up to date with the latest improvements, new features, and bug fixes across all WDK modules.

***

### April 3, 2026

**Changes**

* **wallet-spark** ([v1.0.0-beta.12](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.12)): [`WalletAccountReadOnlySpark`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#walletaccountreadonlyspark) gained [`getTransfers()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#gettransfers-options), [`getUnusedDepositAddresses()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#getunuseddepositaddresses-options) (paginated return type), [`getStaticDepositAddresses()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#getstaticdepositaddresses), [`getUtxosForDepositAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#getutxosfordepositaddress-options), and [`getSparkInvoices()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#getsparkinvoices-params) (new parameter type). Removed `sparkScanApiKey` config option and `SparkTransactionReceipt` type after dropping the `@sparkscan/api-node-sdk-client` dependency. [`getTransactionReceipt()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#gettransactionreceipt-hash) now returns `SparkTransfer` instead. Added [`getAccountByPath()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#getaccountbypath-path) to [`WalletManagerSpark`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#walletmanagerspark). SIGNET network support documented. Dependency upgrades: `@buildonspark/spark-sdk` 0.7.3, `@buildonspark/bare` 0.0.53.

***

### April 2, 2026

**Changes**

* **react-native-core** ([v1.0.0-beta.7](https://www.npmjs.com/package/@tetherto/wdk-react-native-core/v/1.0.0-beta.7)): Added missing type exports: `WdkAppState`, `TransactionParams`, `TransactionResult`, `UseAccountResponse`, `AddressInfo`, `AddressInfoResult`, `BalanceQueryOptions`, `UseWdkAppResult`. Removed `indexer` as a top-level config prop.

***

### March 24, 2026

**What's New**

* [**React Native Core**](https://docs.wdk.tether.io/tools/react-native-core): Added documentation for `@tetherto/wdk-react-native-core` ([v1.0.0-beta.6](https://github.com/tetherto/wdk-core-react-native/releases/tag/v1.0.0-beta.6)), the hooks-based React Native integration layer for WDK. Includes [API Reference](https://docs.wdk.tether.io/tools/react-native-core/api-reference) covering `WdkAppProvider`, `useWdkApp`, `useWalletManager`, `useAccount`, `useBalance`, and more. Updated [React Native Quickstart](https://docs.wdk.tether.io/start-building/react-native-quickstart) with step-by-step integration guide.

***

### March 12, 2026

**Changes**

* **wallet-btc** ([v1.0.0-beta.6](https://github.com/tetherto/wdk-wallet-btc/releases/tag/v1.0.0-beta.6)): Added `dispose()` method to [`WalletAccountReadOnlyBtc`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/api-reference#walletaccountreadonlybtc) for closing internal Electrum connections. Security dependency updates.

***

### March 6, 2026

**Changes**

* **wallet-tron**: Fixed case-sensitive address check in `verify`, upgraded TonWeb to v6.2.0 ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-tron/releases/tag/v1.0.0-beta.5))
* **lending-aave-evm**: Security dependency updates ([v1.0.0-beta.4](https://github.com/tetherto/wdk-protocol-lending-aave-evm/releases/tag/v1.0.0-beta.4))
* **wdk**: Security dependency updates ([v1.0.0-beta.6](https://github.com/tetherto/wdk/releases/tag/v1.0.0-beta.6))

***

### March 5, 2026

**What's New**

* **create-wdk-module**: Added documentation for the [`create-wdk-module`](https://docs.wdk.tether.io/tools/create-wdk-module) CLI scaffolding tool. Updated [Community Modules](https://docs.wdk.tether.io/sdk/community-modules) and [SDK Get Started](https://docs.wdk.tether.io/sdk/get-started) pages with references to the new tool.

***

### February 26, 2026

**Changes**

* **wdk-protocol-bridge-usdt0-evm** ([v1.0.0-beta.3](https://github.com/tetherto/wdk-protocol-bridge-usdt0-evm/releases/tag/v1.0.0-beta.3)): Added per-call `BridgeOptions` overrides (`oftContractAddress`, `dstEid`) and expanded routing from EVM source chains to EVM plus non-EVM destinations (Solana, TON, TRON).

***

### February 25, 2026

**Changes**

* **wallet-evm** ([v1.0.0-beta.8](https://github.com/tetherto/wdk-wallet-evm/releases/tag/v1.0.0-beta.8)): Added [`getTokenBalances(tokenAddresses)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#gettokenbalancestokenaddresses) to [`WalletAccountReadOnlyEvm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#walletaccountreadonlyevm), also available on [`WalletAccountEvm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#walletaccountevm) through inheritance.
* **wallet-evm-erc-4337** ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-evm-erc-4337/releases/tag/v1.0.0-beta.5)): Added EIP-712 typed data methods [`signTypedData(typedData)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/api-reference#signtypeddatatypeddata) and [`verifyTypedData(typedData, signature)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/api-reference#verifytypeddatatypeddata-signature), plus multicall token balance method [`getTokenBalances(tokenAddresses)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/api-reference#gettokenbalancestokenaddresses).

***

### February 24, 2026

**Changes**

* **wallet-spark** ([v1.0.0-beta.11](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.11)): Added Pear runtime entrypoint support (`pear.js`), removed static import causing runtime issues, and bumped spark bare SDK (`@buildonspark/bare`) to `0.0.47`.

***

### February 20, 2026

**What's New**

* [**Showcase**](https://docs.wdk.tether.io/overview/showcase): More visibility for our showcase page, we value contributions! Added 4 featured community projects: [wdk-mcp](https://github.com/dieselftw/wdk-mcp), [wdk-starter-browser-extension](https://github.com/base58-io/wdk-starter-browser-extension), [wdk-wallet-evm-x402-facilitator](https://github.com/SemanticPay/wdk-wallet-evm-x402-facilitator), and [x402-usdt0](https://github.com/baghdadgherras/x402-usdt0).
* [**Community Modules**](https://docs.wdk.tether.io/sdk/community-modules): Added [`@base58-io/wdk-wallet-cosmos`](https://github.com/base58-io/wdk-wallet-cosmos) — wallet module for Cosmos-compatible blockchains by [Base58](https://base58.io/).

***

### February 18, 2026

**What's New**

* [**x402 Payments**](https://docs.wdk.tether.io/ai/x402): New guide for accepting and making instant USD₮ payments over HTTP using WDK self-custodial wallets. Covers the x402 protocol, buyer integration with `@tetherto/wdk-wallet-evm`, seller setup with hosted and self-hosted facilitators, and bridging USD₮ to Plasma and Stable chains.

***

### February 15, 2026

**Changes**

* **wallet-spark**: Added [`getIdentityKey()`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#getidentitykey) method to [`WalletAccountReadOnlySpark`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#walletaccountreadonlyspark) for retrieving the account's identity public key ([v1.0.0-beta.10](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.10))

***

### February 14, 2026

**Changes**

* **wallet-spark**: Upgrade spark-sdk from `0.6.1` to `0.6.4` and spark bare SDK to `0.0.43` ([v1.0.0-beta.9](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.9))

***

### February 12, 2026

**What's New**

* [**Agent Skills**](https://docs.wdk.tether.io/ai/agent-skills): New page covering WDK's agent skill capabilities, self-custodial vs hosted comparison, and platform compatibility with OpenClaw, Claude, Cursor, and other agent platforms.
* [**OpenClaw Integration**](https://docs.wdk.tether.io/ai/openclaw): New page for installing and configuring the WDK skill in OpenClaw via ClawHub, including security precautions for running agents locally.

**Changes**

* **wallet-evm** ([v1.0.0-beta.7](https://github.com/tetherto/wdk-wallet-evm/releases/tag/v1.0.0-beta.7)): Added [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data support:
  * Added [`signTypedData(typedData)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#signtypeddatatypeddata) method to [`WalletAccountEvm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#walletaccountevm) for signing structured data
  * Added [`verifyTypedData(typedData, signature)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#verifytypeddatatypeddata-signature) method to [`WalletAccountEvm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#walletaccountevm) and [`WalletAccountReadOnlyEvm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#walletaccountreadonlyevm) for verifying typed data signatures
* **wallet-evm-erc-4337** ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-evm-erc-4337/releases/tag/v1.0.0-beta.4)):
  * Added 2 new gas payment modes: [Sponsorship Policy](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/configuration#gas-payment-mode-flags) and [Native Coins](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/configuration#gas-payment-mode-flags), alongside the existing Paymaster Token mode
  * Added per-call [config override](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/api-reference#config-override) parameter to `sendTransaction`, `transfer`, `quoteSendTransaction`, and `quoteTransfer`
  * Added [`getUserOperationReceipt(hash)`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/api-reference#getuseroperationreceipthash) method for retrieving ERC-4337 UserOperation receipts
  * Added [`ConfigurationError`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/api-reference#configurationerror) error type for invalid configuration validation

***

### February 10, 2026

**What's New**

* [**Build with AI**](https://docs.wdk.tether.io/start-building/build-with-ai): New guide for using AI coding assistants with WDK. Includes MCP server setup, Markdown context endpoints, project rules, and example prompts. Supports Cursor, Claude Code, GitHub Copilot, Windsurf, Cline, and Continue.
* [**MCP Toolkit**](https://docs.wdk.tether.io/ai/mcp-toolkit): New documentation for `@tetherto/wdk-mcp-toolkit` (`v1.0.0-beta.1`). Covers the `WdkMcpServer` class, 35 built-in MCP tools across 7 categories (wallet, pricing, indexer, swap, bridge, lending, fiat), setup wizard, multi-tool configuration, and full API reference.

***

### February 08, 2026

**Changes**

* **wallet-spark**: Fixed import causing wallet init failure. Upgrade spark-sdk from `0.5.7` to `0.6.1` ([v1.0.0-beta.8](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.8))

***

### February 02, 2026

**Changes**

* **wallet-ton-gasless**: Added `verify` method to [`WalletAccountReadOnlyTonGasless`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless/api-reference#walletaccountreadonlytongasless) ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-ton-gasless/releases/tag/v1.0.0-beta.4))
* **wallet-tron-gasfree**: Added `verify` method to [`WalletAccountReadOnlyTronGasfree`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron-gasfree/api-reference#walletaccountreadonlytrongasfree) ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-tron-gasfree/releases/tag/v1.0.0-beta.4))

***

### January 29, 2026

**What's New**

* **wdk-indexer**
  * Updated Ethereum indexer supported tokens list to add USA₮.

**Changes**

* **wdk-indexer docs**
  * Fixed the USD₮, XAU₮ token names.

***

### January 26, 2026

**Changes**

* **wallet-btc** ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-btc/releases/tag/v1.0.0-beta.5)):
  * Added `verify` method to [`WalletAccountReadOnlyBtc`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/api-reference#walletaccountreadonlybtc)
  * Added Pluggable Transport classes: [`ElectrumTcp`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/api-reference#electrumtcp), [`ElectrumTls`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/api-reference#electrumtls), [`ElectrumSsl`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/api-reference#electrumssl), [`ElectrumWs`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/api-reference#electrumws)
* **wallet-evm**: Added `verify` method to [`WalletAccountReadOnlyEvm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/api-reference#walletaccountreadonlyevm) ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-evm/releases/tag/v1.0.0-beta.5))
* **wallet-solana**: Added `verify` method to [`WalletAccountReadOnlySolana`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/api-reference#walletaccountreadonlysolana) ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-solana/releases/tag/v1.0.0-beta.5))
* **wallet-ton**: Added `verify` method to [`WalletAccountReadOnlyTon`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/api-reference#walletaccountreadonlyton) ([v1.0.0-beta.7](https://github.com/tetherto/wdk-wallet-ton/releases/tag/v1.0.0-beta.7))
* **wallet-tron**: Added `verify` method to [`WalletAccountReadOnlyTron`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron/api-reference#walletaccountreadonlytron) ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-tron/releases/tag/v1.0.0-beta.4))
* **wallet-spark**: Added `verify` method to [`WalletAccountReadOnlySpark`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference#walletaccountreadonlyspark) ([v1.0.0-beta.7](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.7))

***

### January 23, 2026

**What's New**

* **wdk-core docs**: Added comprehensive [Core Module Guides](https://docs.wdk.tether.io/sdk/core-module/usage/getting-started) covering:
  * [Getting Started](https://docs.wdk.tether.io/sdk/core-module/usage/getting-started) - Installation and instantiation
  * [Wallet Registration](https://docs.wdk.tether.io/sdk/core-module/usage/wallet-registration) - Registering wallet modules for different blockchains
  * [Account Management](https://docs.wdk.tether.io/sdk/core-module/usage/account-management) - Working with accounts and addresses
  * [Transactions](https://docs.wdk.tether.io/sdk/core-module/usage/transactions) - Sending native tokens
  * [Protocol Integration](https://docs.wdk.tether.io/sdk/core-module/usage/protocol-integration) - Using swaps, bridges, and lending protocols
  * [Middleware](https://docs.wdk.tether.io/sdk/core-module/usage/middleware) - Configuring logging and failover protection
  * [Error Handling](https://docs.wdk.tether.io/sdk/core-module/usage/error-handling) - Best practices and memory management
* **wdk-core**: Added support for 24-word seed phrases via `WDK.getRandomSeedPhrase(24)`
* **indexer-api**:
  * Added new `/api/v1/chains` endpoint to list supported blockchains and tokens
  * Added XAU₮ support for Plasma network

**Changes**

* **wallet-btc docs**:
  * Updated documentation with BIP-84 (Native SegWit) and BIP-44 (Legacy) support
  * Improved API reference and configuration documentation
* **wallet-spark docs**:
  * Removed testnet support (now only mainnet and regtest)
  * Added [Lightspark Regtest Faucet](https://app.lightspark.com/regtest-faucet) link for test funds
* **wallet-tron-gasfree docs**:
  * Updated testnet from Shasta to Nile
  * Updated GasFree service URLs and configuration examples
* **wallet-evm-erc-4337 docs**: Added paymaster token configuration documentation
* **docs**:
  * Updated token symbols to USD₮ and XAU₮ throughout documentation
  * Various documentation improvements with better cross-linking and examples

**Fixes**

* **wallet-tron-gasfree docs**: Fixed typo "Gras-Free" to "Gas-Free"
* Fixed GitBook callout syntax and formatting issues across documentation

***

### December 23, 2025

**What's New**

* Added [MoonPay Fiat Module](https://docs.wdk.tether.io/sdk/fiat-modules/fiat-moonpay) for on-ramp and off-ramp functionality
* Added [Community Modules](https://docs.wdk.tether.io/sdk/community-modules) section to highlight community-built modules

**Changes**

* Added this changelog page in the docs!
* **wallet-spark**: Updated Spark SDK to latest version ([v1.0.0-beta.6](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.6))
* Introduced [All Modules](https://docs.wdk.tether.io/sdk/all-modules) page in docs for comprehensive module listings
* Reorganized documentation structure for better navigation

***

### December 17, 2025

**What's New**

* **wdk-core**: Added fiat protocol support for on-ramp integrations ([v1.0.0-beta.5](https://github.com/tetherto/wdk-core/releases/tag/v1.0.0-beta.5))
* **wdk-wallet**: Added fiat protocol integration ([v1.0.0-beta.6](https://github.com/tetherto/wdk-wallet/releases/tag/v1.0.0-beta.6))

***

### December 3, 2025

**What's New**

* **wallet-ton**: Added integration tests ([v1.0.0-beta.6](https://github.com/tetherto/wdk-wallet-ton/releases/tag/v1.0.0-beta.6))
* **wallet-btc**: Added support for custom `feeRate` and `confirmationTarget` parameters ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-btc/releases/tag/v1.0.0-beta.4))

**Changes**

* **wallet-ton**: Updated default derivation path, fixed transaction receipt LT and from address
* **wallet-solana**: Updated default derivation path for better compatibility ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-solana/releases/tag/v1.0.0-beta.4))
* **wallet-btc**: Multiple improvements:
  * Automatic dust limit inference based on wallet type
  * Performance improvements with bounded concurrency and caching for `getTransfers`
  * Switched to `bitcoinjs-message` for standard message signing
  * Updated default BIP to 84 (Native SegWit)
  * Fixed testnet derivation path (now uses `1'`)

***

### November 14, 2025

**Changes**

* **wdk-wallet**: Runtime updates and dependency synchronization ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet/releases/tag/v1.0.0-beta.5))

***

### November 12, 2025

**What's New**

* **wallet-solana**: Added `sendTransaction` support with unit tests ([v1.0.0-beta.3](https://github.com/tetherto/wdk-wallet-solana/releases/tag/v1.0.0-beta.3))

**Changes**

* **wallet-solana**: Fixed `punycode` module resolution issue
* **lending-aave-evm**: Runtime compatibility updates ([v1.0.0-beta.3](https://github.com/tetherto/wdk-protocol-lending-aave-evm/releases/tag/v1.0.0-beta.3))

***

### November 11, 2025

**Changes**

* **swap-velora-evm**: Runtime compatibility updates ([v1.0.0-beta.4](https://github.com/tetherto/wdk-protocol-swap-velora-evm/releases/tag/v1.0.0-beta.4))

***

### November 9-10, 2025

**What's New**

* **wallet-ton-gasless**: Added unit tests ([v1.0.0-beta.3](https://github.com/tetherto/wdk-wallet-ton-gasless/releases/tag/v1.0.0-beta.3))
* **pear-wrk-wdk**: Added seed buffer support in `workletStart` ([v1.0.0-beta.5](https://github.com/tetherto/pear-wrk-wdk/releases/tag/v1.0.0-beta.5))

**Changes**

* **wallet-tron-gasfree**: Fixed bug interacting with Gasfree API ([v1.0.0-beta.3](https://github.com/tetherto/wdk-wallet-tron-gasfree/releases/tag/v1.0.0-beta.3))
* **wallet-ton-gasless**: Updated TON query-id and transaction hash handling
* **wallet-evm**: Runtime updates ([v1.0.0-beta.4](https://github.com/tetherto/wdk-wallet-evm/releases/tag/v1.0.0-beta.4))
* **wallet-tron**: Dependency and runtime updates ([v1.0.0-beta.3](https://github.com/tetherto/wdk-wallet-tron/releases/tag/v1.0.0-beta.3))

***

### November 8, 2025

**Changes**

* **wdk-core**: Updated `bare-node-runtime` for improved compatibility ([v1.0.0-beta.4](https://github.com/tetherto/wdk-core/releases/tag/v1.0.0-beta.4))
* **wallet-spark**: Updated Spark dependencies and improved `dispose` method ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.5))

***

### November 7, 2025

**Changes**

* **wallet-evm-erc-4337**: Fixed destructuring of user operation in `getTransactionReceipt()` ([v1.0.0-beta.3](https://github.com/tetherto/wdk-wallet-evm-erc-4337/releases/tag/v1.0.0-beta.3))
* **wallet-ton**: Replaced UUID-based message body with seqno/queryId for TON transfers, downgraded `@ton/ton` to 15.1.0 for stability ([v1.0.0-beta.5](https://github.com/tetherto/wdk-wallet-ton/releases/tag/v1.0.0-beta.5))

***

## How to Stay Updated

* Check this page for the latest updates
* Join our [Discord community](https://discord.gg/arYXDhHB2w) for real-time announcements
* Star and follow the [GitHub repositories](https://github.com/orgs/tetherto/repositories?q=wdk) for detailed release notes


# Showcase

Explore the projects built by the WDK community showcasing real-world use cases, integrations, and creative implementations using the Wallet Development Kit.

{% hint style="warning" %}
Showcase projects 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.
{% endhint %}

{% hint style="info" %}
Looking for community-built WDK modules you can install and use in your project? Check out the [Community Modules](https://docs.wdk.tether.io/sdk/community-modules) page instead.
{% endhint %}

## Featured Projects

***

### wdk-starter-browser-extension

> Self-custodial browser extension wallet starter built on WDK.

**Author:** Base58 ([Website](https://base58.io/), [GitHub](https://github.com/base58-io)) / alexszolowicz ([GitHub](https://github.com/alexszolowicz-blockether)) **Repository:** [github.com/base58-io/wdk-starter-browser-extension](https://github.com/base58-io/wdk-starter-browser-extension)

A browser extension starter kit that demonstrates how to build a self-custodial wallet using WDK. Provides a ready-made template for creating Chrome-compatible extension wallets with secure key management and transaction signing.

<figure><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-dfef50503adbb34b996a33432226334473c51fe9%2Fwdk-starter-browser-extension.gif?alt=media" alt="wdk-starter-browser-extension demo"><figcaption></figcaption></figure>

***

### wdk-wallet-evm-x402-facilitator

> x402 payment facilitator adapter for WDK EVM wallets.

**Author:** SemanticPay ([Website](https://www.semanticpay.io/), [GitHub](https://github.com/SemanticPay)) **Repository:** [github.com/SemanticPay/wdk-wallet-evm-x402-facilitator](https://github.com/SemanticPay/wdk-wallet-evm-x402-facilitator)

An adapter that enables WDK EVM wallets to act as x402 payment facilitators. Bridges the WDK wallet interface with the x402 HTTP payment protocol, allowing servers to charge for API access using on-chain payments.

***

### x402-usdt0

> End-to-end x402 reference implementation on Plasma with USDT0 and WDK.

**Author:** baghdadgherras ([GitHub](https://github.com/baghdadgherras)) **Repository:** [github.com/baghdadgherras/x402-usdt0](https://github.com/baghdadgherras/x402-usdt0)

A complete reference implementation demonstrating the x402 HTTP payment protocol using USDT0 on the Plasma network. Includes both client and server components, showcasing how WDK wallets can facilitate machine-to-machine payments in a real-world setup.

***

### wdk-mcp

> AI-powered blockchain operations via Model Context Protocol.

**Author:** Seven ([GitHub](https://github.com/dieselftw)) **Repository:** [github.com/dieselftw/wdk-mcp](https://github.com/dieselftw/wdk-mcp)

Integrates WDK capabilities within the MCP (Model Context Protocol) ecosystem, allowing AI Agents to perform blockchain operations such as signing, transactions, and wallet interactions securely and locally. This project expands the reach of WDK to autonomous systems and AI-driven workflows.

## Submit Your Project

If you've built something using WDK, we'd love to showcase it.

Projects listed here should:

* Use one or more WDK modules or SDKs
* Be open source or publicly accessible
* Include a clear README and installation instructions

Your work may be featured in future updates, social posts, or documentation spotlights.

Submit your project through our [Community Form](https://forms.gle/wmNwc5epxaa85u8a9) below or share it on our [**#wdk-showcase** Discord channel](https://discordapp.com/channels/1425125849346216029/1427975123406688267).

<a href="https://forms.gle/wmNwc5epxaa85u8a9" class="button primary">Submit your project</a>


# Node.js & Bare Quickstart

Get started with WDK in Node.js or Bare runtime environments in 3 minutes

## What You'll Build

In this quickstart, you'll create a simple application that:

* [ ] Sets up WDK with multiple blockchain wallets (EVM, Bitcoin, TRON)
* [ ] Generates a new secret phrase (seed phrase)
* [ ] Resolves addresses across different chains
* [ ] Checks balances and estimates transaction costs
* [ ] Sends transactions on multiple blockchains

{% hint style="info" %}
**Want to build faster?** Connect your AI coding assistant to WDK docs for context-aware help. [Learn how →](https://docs.wdk.tether.io/start-building/build-with-ai)
{% endhint %}

***

## Prerequisites

Before we start, make sure you have:

{% tabs %}
{% tab title="Node.js" %}

| Tool            | Version | Why You Need It        |
| --------------- | ------- | ---------------------- |
| **Node.js**     | 20+     | To run JavaScript code |
| **npm**         | Latest  | To install packages    |
| **Code Editor** | Any     | To write code          |
| {% endtab %}    |         |                        |

{% tab title="Bare Runtime" %}

| Tool             | Version   | Why You Need It     |
| ---------------- | --------- | ------------------- |
| **Bare Runtime** | >= 1.23.5 | To run JavaScript   |
| **npm**          | Latest    | To install packages |
| **Code Editor**  | Any       | To write code       |

To install Bare runtime first include to the `package.json`:

```
"type": "module"
```

and run the command `npm i -g bare`
{% endtab %}
{% endtabs %}

{% hint style="info" %}
You can try all features without real funds required. You can use the Pimlico or Candide faucets to get some Sepolia USD₮.

<a href="https://dashboard.pimlico.io/test-erc20-faucet" class="button primary">Get mock/test USD₮ on Pimlico </a><a href="https://dashboard.candide.dev/faucet" class="button primary">Get mock/test USD₮ on Candide</a>

See the [configuration](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/configuration) for quick setup and Sepolia testnet configuration.
{% endhint %}

***

## Step 1: Set Up Your Project

First, we need to create a folder and initialize the project

```bash
mkdir wdk-quickstart && cd wdk-quickstart && npm init -y && npm pkg set type=module
```

Then install necessary WDK modules

```bash
npm install @tetherto/wdk @tetherto/wdk-wallet-evm @tetherto/wdk-wallet-tron @tetherto/wdk-wallet-btc
```

{% hint style="info" %}
Learn more about WDK modules:

* [**@tetherto/wdk**](https://docs.wdk.tether.io/sdk/core-module) - The main SDK module
* [**@tetherto/wdk-wallet-evm**](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm) - Ethereum and EVM-compatible chains support
* [**@tetherto/wdk-wallet-tron**](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron) - TRON blockchain support
* [**@tetherto/wdk-wallet-btc**](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc) - Bitcoin blockchain support
  {% endhint %}

***

## Step 2: Create Your First Wallet

Create a file called `app.js`:

{% code title="app.js" lineNumbers="true" %}

```javascript
import WDK from '@tetherto/wdk'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTron from '@tetherto/wdk-wallet-tron'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'

console.log('Starting WDK App...')

try {
  // Your code will go here
} catch (error) {
  console.error('Application error:', error.message)
  process.exit(1)
}
```

{% endcode %}

Now, add the following code to generate a seed phrase:

{% code title="app.js" lineNumbers="true" %}

```typescript
try {
  const seedPhrase = WDK.getRandomSeedPhrase()
  console.log('Generated seed phrase:', seedPhrase)
} catch (error) {
  console.error('Application error:', error.message)
  process.exit(1)
}
```

{% endcode %}

Now, let's register wallets for different blockchains:

{% code title="app.js" lineNumbers="true" %}

```typescript
// Add this code after the seed phrase generation
console.log('Registering wallets...')

const wdkWithWallets = new WDK(seedPhrase)
  .registerWallet('ethereum', WalletManagerEvm, {
    provider: 'https://eth.drpc.org'
  })
  .registerWallet('tron', WalletManagerTron, {
    provider: 'https://api.trongrid.io'
  })
  .registerWallet('bitcoin', WalletManagerBtc, {
    network: 'mainnet',
    host: 'electrum.blockstream.info',
    port: 50001
  })

console.log('Wallets registered for Ethereum, TRON, and Bitcoin')
```

{% endcode %}

{% hint style="info" %}
To learn more about configuring the wallet modules:

* [Configuring @tetherto/wdk-wallet-evm](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/configuration)
* [Configuring @tetherto/wdk-wallet-tron](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron/configuration)
* [Configuring @tetherto/wdk-wallet-btc](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/configuration)
  {% endhint %}

***

## Step 3: Check Balances

To check balances, we first need to get accounts and addresses. Let's get accounts and addresses for all blockchains:

{% code title="app.js" lineNumbers="true" %}

```typescript
// Add this code after the wallet registration
console.log('Retrieving accounts...')

const accounts = {
  ethereum: await wdkWithWallets.getAccount('ethereum', 0),
  tron: await wdkWithWallets.getAccount('tron', 0),
  bitcoin: await wdkWithWallets.getAccount('bitcoin', 0)
}

console.log('Resolving addresses:')

for (const [chain, account] of Object.entries(accounts)) {
  const address = await account.getAddress()
  console.log(`   ${chain.toUpperCase()}: ${address}`)
}
```

{% endcode %}

Now, let's check balances across all chains:

```typescript
// Add this code after the address resolution
console.log('Checking balances...')

for (const [chain, account] of Object.entries(accounts)) {
    const balance = await account.getBalance()
    console.log(`   ${chain.toUpperCase()}: ${balance.toString()} units`)
}
```

Here is the complete `app.js` file:

{% code title="app.js" lineNumbers="true" %}

```javascript
import WDK from '@tetherto/wdk'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTron from '@tetherto/wdk-wallet-tron'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'

console.log('Starting WDK App...')

try {
  const seedPhrase = WDK.getRandomSeedPhrase()
  console.log('Generated seed phrase:', seedPhrase)

  console.log('Registering wallets...')

  const wdkWithWallets = new WDK(seedPhrase)
    .registerWallet('ethereum', WalletManagerEvm, {
      provider: 'https://eth.drpc.org'
    })
    .registerWallet('tron', WalletManagerTron, {
      provider: 'https://api.trongrid.io'
    })
    .registerWallet('bitcoin', WalletManagerBtc, {
      network: 'mainnet',
      host: 'electrum.blockstream.info',
      port: 50001
    })

  console.log('Wallets registered for Ethereum, TRON, and Bitcoin')

  const accounts = {
    ethereum: await wdkWithWallets.getAccount('ethereum', 0),
    tron: await wdkWithWallets.getAccount('tron', 0),
    bitcoin: await wdkWithWallets.getAccount('bitcoin', 0)
  }

  console.log('Resolving addresses:')

  for (const [chain, account] of Object.entries(accounts)) {
    const address = await account.getAddress()
    console.log(`   ${chain.toUpperCase()}: ${address}`)
  }

  console.log('Checking balances...')

  for (const [chain, account] of Object.entries(accounts)) {
    const balance = await account.getBalance()
    console.log(`   ${chain.toUpperCase()}: ${balance.toString()} units`)
  }

  console.log('Application completed successfully!')
  process.exit(0)
} catch (error) {
  console.error('Application error:', error.message)
  process.exit(1)
}
```

{% endcode %}

***

## Step 4: Run Your App

Execute your app:

{% tabs %}
{% tab title="Node.js" %}

```bash
node app.js
```

{% endtab %}

{% tab title="Bare Runtime" %}

```bash
bare app.js
```

{% endtab %}
{% endtabs %}

You should see an output similar to this:

```
Starting WDK App...
Generated seed phrase: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
Registering wallets...
Wallets registered for Ethereum, TRON, and Bitcoin
Resolving addresses:
   ETHEREUM: 0x742d35Cc6634C0532925a3b8D9C5c8b7b6e5f6e5
   TRON: TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH
   BITCOIN: 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
Checking balances...
   ETHEREUM: 0 units
   TRON: 0 units
   BITCOIN: 0 units
Application completed successfully!
```

***

## What Just Happened?

**Congratulations!** You've successfully created your first multi-chain WDK application that works in both Node.js and Bare runtime environments. Here's what happened:

* [x] You generated a single seed phrase that works across all blockchains
* [x] You registered wallets for Ethereum, TRON, and Bitcoin
* [x] You created accounts derived from the same seed phrase using BIP-44
* [x] You used the same API to interact with different blockchains
* [x] You checked balances across multiple chains with consistent methods

***

## Next Steps

Now that you have a basic multi-chain wallet running, here's what you can explore:

### Add More Blockchains

For example, to add Solana support:

```bash
npm install @tetherto/wdk-wallet-solana
```

{% code lineNumbers="true" %}

```typescript
import WalletManagerSolana from '@tetherto/wdk-wallet-solana'

// New or existing WDK instance
const wdk = new WDK(seedPhrase)

wdk.registerWallet('solana', WalletManagerSolana, {
  rpcUrl: 'https://api.mainnet-beta.solana.com',
  wsUrl: 'wss://api.mainnet-beta.solana.com'
})

```

{% endcode %}

### Estimate Transaction Costs

{% code lineNumbers="true" %}

```typescript
for (const [chain, account] of Object.entries(accounts)) {
  try {
    const quote = await account.quoteSendTransaction({
      to: await account.getAddress(),
      value: chain === 'bitcoin' ? 100000000n : chain === 'tron' ? 1000000n : 1000000000000000000n
    })
    console.log(`   ${chain.toUpperCase()}: ${quote.fee.toString()} units`)
  } catch (error) {
    console.log(`   ${chain.toUpperCase()}: Unable to estimate`)
  }
}
```

{% endcode %}

### **Send Transactions**

{% code lineNumbers="true" %}

```typescript
const result = await ethAccount.sendTransaction({
  to: '0x742d35Cc6634C05...a3b8D9C5c8b7b6e5f6e5',
  value: 1000000000000000000n // 1 ETH
})

console.log('Transaction hash:', result.hash)
```

{% endcode %}

### **Use DeFi Protocols**

```bash
npm install @tetherto/wdk-protocol-swap-velora-evm
```

{% code lineNumbers="true" %}

```typescript
import VeloraProtocolEvm  from '@tetherto/wdk-protocol-swap-velora-evm'

wdk.registerProtocol('ethereum', 'swap-velora-evm', VeloraProtocolEvm, {
  provider: 'https://eth.drpc.org'
})
```

{% endcode %}

***

## Troubleshooting

### **Common Issues**

**"Provider not connected"**

* Check your API keys and network connections
* Ensure you're using the correct provider URLs

**"Insufficient balance"**

* This is normal for new addresses
* Use testnet faucets to get test tokens

**"Module not found"**

* Make sure you've installed all required packages
* Check your import statements

### **Need more help?**

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# React Native Quickstart

Get started with WDK in React Native in under 3 minutes

## What You'll Build

In this quickstart, you'll integrate WDK into a React Native app to create a multi-chain wallet that:

* [ ] Supports multiple blockchains (Bitcoin, Ethereum, Polygon, Arbitrum, TON, Tron)
* [ ] Manages multiple tokens (BTC, USD₮, XAU₮, and more)
* [ ] Provides secure seed generation and encrypted storage
* [ ] Shows real-time balances and transaction history
* [ ] Includes wallet creation, import, and unlock flows

{% hint style="info" %}
You can try all features without real funds required. You can use the Pimlico or Candide faucets to get some Sepolia USD₮.

<a href="https://dashboard.pimlico.io/test-erc20-faucet" class="button primary">Get mock/test USD₮ on Pimlico </a><a href="https://dashboard.candide.dev/faucet" class="button primary">Get mock/test USD₮ on Candide</a>

See the [configuration.md](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/configuration) for quick setup and Sepolia testnet configuration.
{% endhint %}

{% hint style="info" %}
**Want to build faster?** Connect your AI coding assistant to WDK docs for context-aware help. [Learn how →](https://docs.wdk.tether.io/start-building/build-with-ai)
{% endhint %}

## Prerequisites

Before we start, make sure you have:

| Tool             | Version | Why You Need It             |
| ---------------- | ------- | --------------------------- |
| **Node.js**      | 22+     | To run JavaScript code      |
| **npm**          | Latest  | To install packages         |
| **React Native** | 0.81.0+ | Framework version           |
| **Android SDK**  | API 29+ | Android minimum SDK version |
| **iOS**          | 15.1+   | iOS deployment target       |

***

## Quick Start Paths

You have 2 options for using WDK in a React Native. Choose your preferred starting point:

{% tabs %}
{% tab title="Use Starter Template (Fastest)" %}
Get up and running in 3 minutes with our pre-configured starter template.

[**→ Jump to Starter Template Setup**](#option-1-starter-template)
{% endtab %}

{% tab title="Add to Existing App" %}
Integrate WDK into your existing React Native or Expo app.

[**→ Jump to Library Integration**](#option-2-add-to-existing-app)
{% endtab %}
{% endtabs %}

***

## Option 1: Starter Template

The fastest way to get started is with our starter template. Note: this is still in alpha, and may be subject to breaking changes.

### Step 1: Clone the Starter

```bash
git clone https://github.com/tetherto/wdk-starter-react-native.git
cd wdk-starter-react-native
```

### Step 2: Install Dependencies

```bash
npm install
```

### Step 3: Configure Environment

Create an environment file for the WDK Indexer API:

```bash
cp .env.example .env
```

Edit `.env` and add your WDK Indexer API key:

```bash
EXPO_PUBLIC_WDK_INDEXER_BASE_URL=https://wdk-api.tether.io
EXPO_PUBLIC_WDK_INDEXER_API_KEY=your_actual_api_key_here
# Optional: For Tron network support
EXPO_PUBLIC_TRON_API_KEY=your_tron_api_key
EXPO_PUBLIC_TRON_API_SECRET=your_tron_api_secret
```

{% hint style="info" %}
**Where do I get an Indexer API key?** The WDK Indexer is required for transaction history and balance indexing. Get your free API key from the [Indexer API setup guide](https://docs.wdk.tether.io/tools/indexer-api/get-started).
{% endhint %}

### Step 4: Run Your App

{% tabs %}
{% tab title="iOS Simulator" %}

```bash
npm run ios
```

{% endtab %}

{% tab title="Android Emulator" %}

```bash
npm run android
```

{% endtab %}
{% endtabs %}

**Congratulations!** You now have a multi-chain wallet running.

[**→ Skip to What's Next**](#whats-next)

***

## Option 2: Add to Existing App

Integrate WDK into your existing React Native or Expo project using `@tetherto/wdk-react-native-core`.

### Step 1: Install

```bash
npm install @tetherto/wdk-react-native-core
```

### Step 2: Configure Android minSdkVersion

The library requires **Android API 29** or higher to support `react-native-bare-kit`.

{% tabs %}
{% tab title="Expo Projects" %}
Add to your `app.json` or `app.config.js`:

```json
{
  "expo": {
    "plugins": [
      [
        "expo-build-properties",
        {
          "android": {
            "minSdkVersion": 29
          }
        }
      ]
    ]
  }
}
```

If you haven't installed `expo-build-properties`:

```bash
npx expo install expo-build-properties
```

{% endtab %}

{% tab title="Bare React Native" %}
Update `android/build.gradle`:

```gradle
buildscript {
    ext {
        minSdkVersion = 29
        // ... other config
    }
}
```

{% endtab %}
{% endtabs %}

### Step 3: Configure the Bundle

The WDK engine runs inside a Bare worklet. You need to provide a bundle - choose one of two approaches:

{% tabs %}
{% tab title="Custom Bundle (Recommended)" %}
Use the `@tetherto/wdk-worklet-bundler` CLI to generate a bundle with only the 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 (pick the ones you need)
npm install @tetherto/wdk @tetherto/wdk-wallet-evm-erc-4337

# 5. Generate the bundle
wdk-worklet-bundler generate
```

This generates a `.wdk/` directory in your project. Import it:

```typescript
import { bundle } from './.wdk'
```

{% hint style="info" %}
**Which WDK modules do I need?** Each blockchain requires its own wallet module (e.g., `wdk-wallet-evm-erc-4337` for Ethereum/Polygon, `wdk-wallet-btc` for Bitcoin). See the full list of available modules in the [wdk-worklet-bundler documentation](https://github.com/tetherto/wdk-worklet-bundler).
{% endhint %}
{% endtab %}

{% tab title="Pre-built Bundle" %}
For quick prototyping, install and import the ready-made bundle from `@tetherto/pear-wrk-wdk`:

```bash
npm install @tetherto/pear-wrk-wdk
```

```typescript
import { bundle } from '@tetherto/pear-wrk-wdk'
```

{% hint style="info" %}
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.
{% endhint %}
{% endtab %}
{% endtabs %}

### Step 4: Configure WDK Settings

Create a configuration file for your WDK setup (e.g., `src/config/wdk.ts`):

```typescript
// src/config/wdk.ts
import type { WdkConfigs } from '@tetherto/wdk-react-native-core'

export const wdkConfigs: WdkConfigs = {
  networks: {
    ethereum: {
      blockchain: 'ethereum',
      config: {
        chainId: 11155111, // Sepolia testnet
        provider: 'https://rpc.sepolia.org',
        bundlerUrl: 'https://api.candide.dev/public/v3/sepolia',
        paymasterUrl: 'https://api.candide.dev/public/v3/sepolia',
        paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
        entrypointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
        transferMaxFee: 5000000,
        paymasterToken: {
          address: '0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0', // USDT on Sepolia
        },
      },
    },
    // Add more networks as needed
  },
}
```

{% hint style="info" %}
This example uses **Sepolia testnet** with a free public RPC so you can start immediately without API keys. For production or mainnet configuration, see the [Chain Configuration Guide](https://docs.wdk.tether.io/sdk/core-module/configuration).
{% endhint %}

### Step 5: Add WdkAppProvider

Wrap your app with `WdkAppProvider` to enable wallet functionality throughout your app.

{% tabs %}
{% tab title="Expo Router" %}
Add to your `app/_layout.tsx`:

```tsx
// app/_layout.tsx
import { WdkAppProvider } from '@tetherto/wdk-react-native-core'
import { bundle } from './.wdk'
import { Stack } from 'expo-router'
import { wdkConfigs } from '../config/wdk'

export default function RootLayout() {
  return (
    <WdkAppProvider bundle={{ bundle }} wdkConfigs={wdkConfigs}>
      <Stack />
    </WdkAppProvider>
  )
}
```

{% endtab %}

{% tab title="Standard React Native" %}
Update your `App.tsx`:

```tsx
// App.tsx
import React from 'react'
import { WdkAppProvider } from '@tetherto/wdk-react-native-core'
import { bundle } from './.wdk'
import { NavigationContainer } from '@react-navigation/native'
import { MainNavigator } from './src/navigation'
import { wdkConfigs } from './src/config/wdk'

export default function App() {
  return (
    <WdkAppProvider bundle={{ bundle }} wdkConfigs={wdkConfigs}>
      <NavigationContainer>
        <MainNavigator />
      </NavigationContainer>
    </WdkAppProvider>
  )
}
```

{% endtab %}
{% endtabs %}

### Step 6: Use Hooks

Now you can use the WDK hooks in any component inside `WdkAppProvider`:

```tsx
import { useWdkApp, useWalletManager, useAccount } from '@tetherto/wdk-react-native-core'

function WalletScreen() {
  const { state } = useWdkApp()
  const { createWallet, unlock } = useWalletManager()
  const { address } = useAccount({ network: 'ethereum', accountIndex: 0 })

  switch (state.status) {
    case 'INITIALIZING':
      return <Text>Loading...</Text>
    case 'NO_WALLET':
      return <Button title="Create Wallet" onPress={() => createWallet('my-wallet')} />
    case 'LOCKED':
      return <Button title="Unlock" onPress={() => unlock()} />
    case 'READY':
      return <Text>Address: {address}</Text>
    case 'ERROR':
      return <Text>Error: {state.error.message}</Text>
  }
}
```

For the full list of available hooks and their parameters, see the [React Native Core API Reference](https://docs.wdk.tether.io/tools/react-native-core/api-reference).

### Step 7: Rebuild and Run

{% tabs %}
{% tab title="Expo" %}
For Expo projects, run prebuild to apply native changes:

```bash
npx expo prebuild --clean
npx expo run:ios
# or
npx expo run:android
```

{% endtab %}

{% tab title="Bare React Native" %}
Rebuild your native apps:

```bash
npx react-native run-ios
# or
npx react-native run-android
```

{% endtab %}
{% endtabs %}

**Congratulations!** You've successfully integrated WDK into your React Native app!

***

## What's Next?

Now that you have WDK integrated, here's what you can explore:

### Send Transactions

Use the `useAccount()` hook to send transactions:

```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, send } = useAccount({ network: 'ethereum', accountIndex: 0 })

  const handleSend = async () => {
    if (!address) return

    const result = await send({
      to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
      asset: usdt,
      amount: '1000000', // 1 USDT (6 decimals)
    })

    if (result.success) {
      console.log('TX hash:', result.hash, 'Fee:', result.fee)
    } else {
      console.error('TX failed:', result.error)
    }
  }

  return <Button title="Send 1 USDT" onPress={handleSend} />
}
```

### Lock the Wallet

Use `lock()` to clear sensitive data from memory:

```tsx
const { lock } = useWalletManager()

// Lock wallet and clear all sensitive data
lock()
```

### Refresh Balances

```tsx
import { useRefreshBalance } from '@tetherto/wdk-react-native-core'

const { mutate: refreshBalance } = useRefreshBalance()

// Refresh all balances for account 0
refreshBalance({ accountIndex: 0, type: 'wallet' })
```

***

## Troubleshooting

**Android build fails with "Execution failed for task ':app:checkDebugAarMetadata'"**

This means your minSdkVersion is too low. Make sure you've set it to 29:

```json
{
  "expo": {
    "plugins": [
      ["expo-build-properties", { "android": { "minSdkVersion": 29 } }]
    ]
  }
}
```

Then rebuild:

```bash
npx expo prebuild --clean
npx expo run:android
```

**"useWdkApp must be used within WdkAppProvider"**

Ensure your component is rendered inside `WdkAppProvider`. The provider must be at the root of your component tree:

```tsx
// Correct
<WdkAppProvider bundle={{ bundle }} wdkConfigs={configs}>
  <MyComponent />  {/* Can use useWdkApp() here */}
</WdkAppProvider>

// Wrong - hook used outside provider
<MyComponent />  {/* Cannot use useWdkApp() here */}
<WdkAppProvider bundle={{ bundle }} wdkConfigs={configs}>
  ...
</WdkAppProvider>
```

**Biometric prompt not appearing on simulator**

Biometric authentication is required by default. On iOS Simulator, enable Face ID via `Features > Face ID > Enrolled`. On Android Emulator, set up a fingerprint in `Settings > Security`. To disable biometrics during development, pass `requireBiometrics={false}` to `WdkAppProvider`.

**Metro cache issues**

If you see stale module errors after upgrading, clear the Metro cache:

```bash
npx expo start --clear
# or
npx react-native start --reset-cache
```

**TypeScript errors about missing types**

Some native dependencies may lack type definitions. Add to your `tsconfig.json`:

```json
{
  "compilerOptions": {
    "skipLibCheck": true
  }
}
```

### Complete Setup Checklist

**For Expo projects:**

* Install `@tetherto/wdk-react-native-core`
* Configure Android minSdkVersion to 29 in `app.json`
* Set up bundle (custom or pre-built)
* Create `WdkConfigs` configuration
* Add `WdkAppProvider` to `app/_layout.tsx`
* Use hooks (`useWdkApp`, `useWalletManager`, `useAccount`, `useBalance`)
* Run `npx expo prebuild --clean` before building

**For bare React Native:**

* Install package
* Set minSdkVersion to 29 in `android/build.gradle`
* Set up bundle (custom or pre-built)
* Create `WdkConfigs` configuration
* Wrap root component with `WdkAppProvider`
* Rebuild native code

***

## Learn More

Ready to dive deeper? Check out these resources:

### Core Concepts

* [**React Native Core Docs**](https://docs.wdk.tether.io/tools/react-native-core) - Full documentation for `@tetherto/wdk-react-native-core`
* [**API Reference**](https://docs.wdk.tether.io/tools/react-native-core/api-reference) - Complete hook and type reference
* [**Chain Configuration**](https://docs.wdk.tether.io/sdk/core-module/configuration#wallet-configuration) - Configure blockchain networks

### Examples & Starters

* [**React Native Starter**](https://docs.wdk.tether.io/examples-and-starters/react-native-starter) - Full-featured starter app
* [**React Native UI Kit**](https://docs.wdk.tether.io/ui-kits/react-native-ui-kit) - Pre-built wallet components

### **Need Help?**

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Build with AI

Connect your AI coding assistant to WDK documentation for context-aware code generation, architecture guidance, and debugging help.

WDK documentation is optimized for AI coding assistants. Give your AI tool context about WDK to get accurate code generation, architecture guidance, and debugging help.

There are two ways to provide WDK context to your AI:

1. [**Connect via MCP Server**](#connect-wdk-docs-via-mcp-server) - Best experience. Your AI tool can search and query WDK docs in real time.
2. [**Connect via Markdown**](#connect-wdk-docs-via-markdown) - Works with any AI tool. Feed documentation directly into the context window.

{% hint style="info" %}
**Want to give AI agents wallet access?** The [MCP Toolkit](https://docs.wdk.tether.io/ai/mcp-toolkit) creates an MCP server that exposes WDK wallets as tools - letting AI agents check balances, send transactions, swap tokens, and more.
{% endhint %}

{% hint style="info" %}
**Want agents to pay for resources?** The [x402 guide](https://docs.wdk.tether.io/ai/x402) shows how to use WDK wallets with the x402 protocol for instant, programmatic USD₮ payments over HTTP.
{% endhint %}

***

## Connect WDK Docs via MCP Server

The WDK documentation is available as an MCP server, giving your AI tool searchable access to all modules, API references, quickstarts, and guides. This works with any tool that supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/).

**MCP Server URL:**

```
https://docs.wallet.tether.io/~gitbook/mcp
```

Add this server to your AI tool's MCP configuration:

{% tabs %}
{% tab title="Cursor" %}
**Config path:** `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project-level)

```json
{
  "mcpServers": {
    "wdk-docs": {
      "url": "https://docs.wallet.tether.io/~gitbook/mcp"
    }
  }
}
```

→ [Cursor MCP documentation](https://cursor.com/docs/context/mcp)
{% endtab %}

{% tab title="Claude Code" %}
Run this command in your terminal:

```bash
claude mcp add wdk-docs --transport sse https://docs.wallet.tether.io/~gitbook/mcp
```

→ [Claude Code MCP documentation](https://docs.anthropic.com/en/docs/claude-code/tutorials#set-up-model-context-protocol-mcp)
{% endtab %}

{% tab title="Windsurf" %}
**Config path:** `~/.codeium/windsurf/mcp_config.json`

```json
{
  "mcpServers": {
    "wdk-docs": {
      "url": "https://docs.wallet.tether.io/~gitbook/mcp"
    }
  }
}
```

→ [Windsurf MCP documentation](https://docs.windsurf.com/windsurf/cascade/mcp)
{% endtab %}

{% tab title="GitHub Copilot" %}
**Config path:** `.vscode/mcp.json` (project-level)

```json
{
  "servers": {
    "wdk-docs": {
      "url": "https://docs.wallet.tether.io/~gitbook/mcp"
    }
  }
}
```

→ [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
{% endtab %}

{% tab title="Cline" %}
Add via Cline's MCP settings panel in VS Code, or edit the config file directly.

**Server URL:** `https://docs.wallet.tether.io/~gitbook/mcp`

→ [Cline MCP documentation](https://github.com/cline/cline#add-context)
{% endtab %}

{% tab title="Continue" %}
**Config path:** `~/.continue/config.yaml`

Add to the `mcpServers` section:

**Server URL:** `https://docs.wallet.tether.io/~gitbook/mcp`

→ [Continue MCP documentation](https://docs.continue.dev/customize/mcp-tools)
{% endtab %}
{% endtabs %}

{% hint style="info" %}
The MCP server provides access to published documentation only. If your tool is not listed above, add the MCP server URL (`https://docs.wallet.tether.io/~gitbook/mcp`) to your tool's MCP configuration - most MCP-compatible tools follow a similar JSON format.
{% endhint %}

{% hint style="warning" %}
**No MCP support?** You can feed WDK documentation directly into any AI tool as Markdown. See [Connect WDK Docs via Markdown](#connect-wdk-docs-via-markdown) below.
{% endhint %}

### Add WDK Project Rules (Optional)

Project rules give your AI assistant persistent context about WDK conventions, package naming, and common patterns. This is optional but recommended for teams working extensively with WDK.

Copy the rules content below and save it at the file path for your tool.

#### Rules Content

```markdown
# WDK Development Rules

## Package Structure
- All WDK packages are published under the `@tetherto` scope on npm
- Core module: `@tetherto/wdk`
- Wallet modules follow the pattern: `@tetherto/wdk-wallet-<chain>`
  - Examples: `@tetherto/wdk-wallet-evm`, `@tetherto/wdk-wallet-btc`, `@tetherto/wdk-wallet-solana`, `@tetherto/wdk-wallet-ton`, `@tetherto/wdk-wallet-tron`, `@tetherto/wdk-wallet-spark`
- Specialized wallet modules: `@tetherto/wdk-wallet-evm-erc4337`, `@tetherto/wdk-wallet-ton-gasless`, `@tetherto/wdk-wallet-tron-gasfree`
- Protocol modules follow the pattern: `@tetherto/wdk-protocol-<type>-<name>-<chain>`
  - Examples: `@tetherto/wdk-protocol-swap-velora-evm`, `@tetherto/wdk-protocol-bridge-usdt0-evm`, `@tetherto/wdk-protocol-lending-aave-evm`

## Platform Notes
- For Node.js or Bare runtime: Use `@tetherto/wdk` as the orchestrator, then register individual wallet modules
- For React Native: You have two options:
  - Use the React Native provider package for convenience (provides hooks and managed lifecycle)
  - Or use WDK packages directly in the Hermes runtime - this works the same as Node.js integration

## Architecture
- WDK is modular - each blockchain and protocol is a separate npm package
- Wallet modules expose `WalletManager`, `WalletAccount`, and `WalletAccountReadOnly` classes
- `WalletAccount` extends `WalletAccountReadOnly` - it has all read-only methods plus write methods (sign, send)
- All modules follow a consistent pattern: configuration → initialization → usage

## Documentation
- Official docs: https://docs.wallet.tether.io
- For any WDK question, consult the official documentation before making assumptions
- API references, configuration guides, and usage examples are available for every module
```

#### Where to Save

| AI Coding Assistant | File Path                         | Notes                        |
| ------------------- | --------------------------------- | ---------------------------- |
| Cursor              | `.cursor/rules/wdk.mdc`           | Project-level, auto-attached |
| Claude Code         | `CLAUDE.md`                       | Place in project root        |
| Windsurf            | `.windsurf/rules/wdk.md`          | Project-level rules          |
| GitHub Copilot      | `.github/copilot-instructions.md` | Project-level instructions   |
| Cline               | `.clinerules`                     | Place in project root        |
| Continue            | `.continuerules`                  | Place in project root        |

***

## Connect WDK Docs via Markdown

If your AI tool doesn't support MCP, you can feed WDK documentation directly into the context window using these endpoints:

| Endpoint   | URL                                                                                | Description                        |
| ---------- | ---------------------------------------------------------------------------------- | ---------------------------------- |
| Page index | [docs.wallet.tether.io/llms.txt](https://docs.wallet.tether.io/llms.txt)           | Index of all page URLs and titles  |
| Full docs  | [docs.wallet.tether.io/llms-full.txt](https://docs.wallet.tether.io/llms-full.txt) | Complete documentation in one file |

You can also append `.md` to any documentation page URL to get the raw Markdown, ready to paste into a chat context window.

***

## Agent Guidelines in WDK Repos

Each WDK package repository includes an `AGENTS.md` file in its root. This file provides AI agents with context about the project structure, coding conventions, testing patterns, and linting rules.

If your AI tool has access to the WDK source repositories (e.g., via a local clone), it will automatically ingest `AGENTS.md` for additional context beyond the documentation.

***

## Example Prompt

Here's an example prompt you can use to generate a multichain wallet with WDK. Try it with MCP connected or paste the relevant quickstart docs for best results:

```
Create a Node.js app using WDK (@tetherto/wdk) that:
1. Creates a multichain wallet supporting Bitcoin and Polygon
2. Use @tetherto/wdk-wallet-btc for Bitcoin and @tetherto/wdk-wallet-evm for Polygon
3. Generates wallet addresses for both chains
4. Retrieves the balance for each address
5. Use a mnemonic from environment variables

Check the WDK documentation for the correct configuration and initialization pattern.
```

***

## Tips for Effective AI-Assisted Development

* **Be specific about the chain.** Tell the AI which blockchain you're targeting (e.g., "I'm building on Ethereum using `@tetherto/wdk-wallet-evm`") so it picks the right module.
* **Reference the exact package name.** Mention the full `@tetherto/wdk-*` package name in your prompt for more accurate code generation.
* **Ask the AI to check docs first.** Prompt with "Check the WDK documentation before answering" to ensure it uses the MCP-connected docs rather than outdated training data.
* **Start with a quickstart.** Point the AI at the [Node.js Quickstart](https://docs.wdk.tether.io/start-building/nodejs-bare-quickstart) or [React Native Quickstart](https://docs.wdk.tether.io/start-building/react-native-quickstart) as a working reference before building custom features.
* **Iterate in steps.** Use the AI to scaffold your WDK integration first, then refine module configuration and error handling in follow-up prompts.


# MCP Toolkit

Build MCP servers that give AI agents self-custodial WDK wallets

The MCP Toolkit lets AI agents interact with self-custodial WDK wallets. It creates an [MCP server](https://modelcontextprotocol.io/) that exposes wallet operations (checking balances, sending transactions, swapping tokens, bridging assets, and more) as structured tools that any MCP-compatible AI client can call.

Powered by [`@tetherto/wdk-mcp-toolkit`](https://github.com/tetherto/wdk-mcp-toolkit).

{% hint style="warning" %}
**Beta** - This package is in active development (`v1.0.0-beta.1`). APIs may change between releases.
{% endhint %}

{% embed url="<https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRwT8I8B1DP5OZiLSjSCW%2Fuploads%2F4bLqUGsw5krkbnRiAEmx%2F543206805-9fc1aa65-b76b-4569-bac0-42f75ccdc1ce.mp4?alt=media&token=25181754-0e5d-4497-b59c-ebc8c955675e>" %}

## Features

* **MCP Server Extension** - Extends the official `@modelcontextprotocol/sdk` McpServer with WDK-specific capabilities
* **Multi-Chain** - Support for 13 blockchains out of the box, including EVM chains, Bitcoin, Solana, Spark, TON, and Tron
* **35 Built-in Tools** - Ready-to-use tools for wallets, pricing, indexer queries, swaps, bridges, lending, and fiat on/off-ramps
* **Human Confirmation** - All write operations use MCP elicitations to require explicit user approval before broadcasting transactions
* **Extensible** - Register custom tools alongside built-in ones using standard MCP SDK patterns
* **Secure by Design** - Seed phrases stay local, `close()` wipes keys from memory, and read/write tool separation lets you control access

## Supported Chains

| Chain     | Identifier  |
| --------- | ----------- |
| Ethereum  | `ethereum`  |
| Polygon   | `polygon`   |
| Arbitrum  | `arbitrum`  |
| Optimism  | `optimism`  |
| Base      | `base`      |
| Avalanche | `avalanche` |
| BNB Chain | `bnb`       |
| Plasma    | `plasma`    |
| Bitcoin   | `bitcoin`   |
| Solana    | `solana`    |
| Spark     | `spark`     |
| TON       | `ton`       |
| Tron      | `tron`      |

{% hint style="info" %}
You can register **any** blockchain name - the `CHAINS` constants are for convenience only. For custom chains, register tokens manually with `registerToken()`.
{% endhint %}

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Get Started</strong></td><td>Install and run your first MCP server in minutes</td><td><a href="mcp-toolkit/get-started">get-started</a></td></tr><tr><td><i class="fa-wrench">:wrench:</i></td><td><strong>Configuration</strong></td><td>Wallets, capabilities, tokens, protocols, and custom tools</td><td><a href="mcp-toolkit/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>API Reference</strong></td><td>All 35 built-in MCP tools and the WdkMcpServer class</td><td><a href="mcp-toolkit/api-reference">api-reference</a></td></tr><tr><td><i class="fa-link">:link:</i></td><td><strong>LangChain Integration</strong></td><td>Use WDK tools in LangChain agents via the serve CLI</td><td><a href="mcp-toolkit/langchain">langchain</a></td></tr></tbody></table>

{% hint style="info" %}
**Already using an AI coding assistant?** See [Build with AI](https://docs.wdk.tether.io/start-building/build-with-ai) for how to connect WDK docs as context via MCP or Markdown.
{% endhint %}

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Get Started

Install the MCP Toolkit and run your first AI-powered wallet server

{% hint style="info" %}
**Building a LangChain agent?** The `serve` command provides zero-config MCP server startup -- no server script needed. See [LangChain Integration](https://docs.wdk.tether.io/ai/mcp-toolkit/langchain).
{% endhint %}

## Setup Wizard

The fastest way to get running. Clone the repository and let the wizard configure everything:

{% code title="Terminal" %}

```bash
git clone https://github.com/tetherto/wdk-mcp-toolkit.git
cd wdk-mcp-toolkit
npm install
npm run setup
```

{% endcode %}

The wizard will:

1. Prompt for your seed phrase (required)
2. Ask for optional API keys (WDK Indexer, MoonPay)
3. Generate `.vscode/mcp.json` with your credentials
4. Install required dependencies automatically

Once complete, open the project in VS Code, start the MCP server from `.vscode/mcp.json`, and open the chatbot with **Cmd + Shift + I** (or run **Chat: Open Agent** from the Command Palette on non-Mac).

{% hint style="warning" %}
**Security** - Your seed phrase is stored locally in `.vscode/mcp.json`, which is gitignored. Always use a **dedicated development wallet** with limited funds.
{% endhint %}

***

## Manual Setup

If you prefer to set things up yourself or want to integrate the toolkit into an existing project:

{% stepper %}
{% step %}
**Install the toolkit**

Install the MCP Toolkit and the wallet modules you need:

{% code title="Terminal" %}

```bash
npm install @tetherto/wdk-mcp-toolkit @modelcontextprotocol/sdk

# Wallet modules (add any combination)
npm install @tetherto/wdk-wallet-evm    # Ethereum, Polygon, Arbitrum, etc.
npm install @tetherto/wdk-wallet-btc    # Bitcoin
```

{% endcode %}
{% endstep %}

{% step %}
**Create your MCP server**

Create `index.js` with a basic multi-chain server:

{% code title="index.js" lineNumbers="true" %}

```javascript
import { WdkMcpServer, CHAINS, WALLET_TOOLS, PRICING_TOOLS } from '@tetherto/wdk-mcp-toolkit'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'

const server = new WdkMcpServer('my-wallet-server', '1.0.0')

// 1. Enable WDK with your seed phrase
server.useWdk({ seed: process.env.WDK_SEED })

// 2. Register wallet modules
server.registerWallet('ethereum', WalletManagerEvm, {
  provider: 'https://eth.drpc.org'
})

server.registerWallet('bitcoin', WalletManagerBtc, {
  network: 'bitcoin',
  host: 'electrum.blockstream.info',
  port: 50001
})

// 3. Enable pricing
server.usePricing()

// 4. Register tools and start
server.registerTools([...WALLET_TOOLS, ...PRICING_TOOLS])
```

{% endcode %}
{% endstep %}

{% step %}
**Connect your AI client**

Add the MCP server to your AI tool's configuration:

{% tabs %}
{% tab title="GitHub Copilot" %}
**Config path:** `.vscode/mcp.json` (project-level)

{% code title=".vscode/mcp.json" %}

```json
{
  "servers": {
    "wdk": {
      "type": "stdio",
      "command": "node",
      "args": ["index.js"],
      "env": {
        "WDK_SEED": "your twelve word seed phrase here"
      }
    }
  }
}
```

{% endcode %}

Then in VS Code:

1. Open `.vscode/mcp.json` and click **Start** above the server config
2. Open GitHub Copilot Chat and select **Agent mode**
3. Click **Tools** to verify the MCP tools are available

→ [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
{% endtab %}

{% tab title="Cursor" %}
**Config path:** `.cursor/mcp.json` (project-level)

```json
{
  "mcpServers": {
    "wdk": {
      "command": "node",
      "args": ["index.js"],
      "env": {
        "WDK_SEED": "your twelve word seed phrase here"
      }
    }
  }
}
```

→ [Cursor MCP documentation](https://cursor.com/docs/context/mcp)
{% endtab %}

{% tab title="Claude Code" %}
Run this command from your project directory:

```bash
claude mcp add wdk -- node index.js
```

Set the environment variable separately:

```bash
export WDK_SEED="your twelve word seed phrase here"
```

→ [Claude Code MCP documentation](https://docs.anthropic.com/en/docs/claude-code/tutorials#set-up-model-context-protocol-mcp)
{% endtab %}

{% tab title="Windsurf" %}
**Config path:** `~/.codeium/windsurf/mcp_config.json`

```json
{
  "mcpServers": {
    "wdk": {
      "command": "node",
      "args": ["index.js"],
      "env": {
        "WDK_SEED": "your twelve word seed phrase here"
      }
    }
  }
}
```

→ [Windsurf MCP documentation](https://docs.windsurf.com/windsurf/cascade/mcp)
{% endtab %}

{% tab title="Cline" %}
Add via Cline's MCP settings panel in VS Code, or create the config file directly:

```json
{
  "mcpServers": {
    "wdk": {
      "command": "node",
      "args": ["index.js"],
      "env": {
        "WDK_SEED": "your twelve word seed phrase here"
      }
    }
  }
}
```

→ [Cline MCP documentation](https://github.com/cline/cline#add-context)
{% endtab %}

{% tab title="Continue" %}
**Config path:** `~/.continue/config.yaml`

Add to the `mcpServers` section with the command and arguments for your server:

```
command: node
args: ["index.js"]
env:
  WDK_SEED: "your twelve word seed phrase here"
```

→ [Continue MCP documentation](https://docs.continue.dev/customize/mcp-tools)
{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}
**Try it out**

Ask your AI assistant:

```
What's my ethereum address?
```

```
Check my BTC balance
```

```
What's the current price of ETH in USD?
```

```
Send 10 USDT to 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb7 on ethereum
```

{% hint style="info" %}
Write operations (sending, swapping, bridging) will show a **confirmation dialog** before executing. You must explicitly approve each transaction.
{% endhint %}
{% endstep %}
{% endstepper %}

***

## Optional Capabilities

Add more capabilities by installing additional packages and enabling them on the server:

{% code title="Additional capabilities" lineNumbers="true" %}

```javascript
import { INDEXER_TOOLS, SWAP_TOOLS, BRIDGE_TOOLS, LENDING_TOOLS, FIAT_TOOLS } from '@tetherto/wdk-mcp-toolkit'
import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm'
import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'

// Indexer - transaction history
server.useIndexer({ apiKey: process.env.WDK_INDEXER_API_KEY })

// DeFi protocols
server.registerProtocol('ethereum', 'velora', VeloraProtocolEvm)
server.registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm)
server.registerProtocol('ethereum', 'aave', AaveProtocolEvm)
server.registerProtocol('ethereum', 'moonpay', MoonPayProtocol, {
  secretKey: process.env.MOONPAY_SECRET_KEY,
  apiKey: process.env.MOONPAY_API_KEY
})

// Register the corresponding tools
server.registerTools([
  ...INDEXER_TOOLS,
  ...SWAP_TOOLS,
  ...BRIDGE_TOOLS,
  ...LENDING_TOOLS,
  ...FIAT_TOOLS
])
```

{% endcode %}

***

## Environment Variables

| Variable              | Required | Description                                                                |
| --------------------- | -------- | -------------------------------------------------------------------------- |
| `WDK_SEED`            | Yes      | BIP-39 seed phrase for wallet derivation                                   |
| `WDK_INDEXER_API_KEY` | No       | Enables `INDEXER_TOOLS` - [get a key](https://wdk-api.tether.io/register)  |
| `MOONPAY_API_KEY`     | No       | Enables `FIAT_TOOLS` - [MoonPay Dashboard](https://dashboard.moonpay.com/) |
| `MOONPAY_SECRET_KEY`  | No       | Required with `MOONPAY_API_KEY`                                            |

***

## Next Steps

* [**Configuration**](https://docs.wdk.tether.io/ai/mcp-toolkit/configuration) - Wallets, tokens, protocols, custom tools, and security
* [**API Reference**](https://docs.wdk.tether.io/ai/mcp-toolkit/api-reference) - All 35 built-in MCP tools with parameters and schemas

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Configuration

Configure wallets, capabilities, tokens, protocols, and custom tools

## Server Setup

Create a server with a name and version:

```javascript
import { WdkMcpServer } from '@tetherto/wdk-mcp-toolkit'

const server = new WdkMcpServer('my-server', '1.0.0')
```

The `WdkMcpServer` extends `McpServer` from the official [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) with WDK-specific capabilities. All standard MCP server features are available.

***

## Wallet Configuration

### Enable WDK

```javascript
server.useWdk({ seed: process.env.WDK_SEED })
```

The `seed` is a BIP-39 mnemonic phrase used for key derivation across all registered blockchains.

{% hint style="danger" %}
**Never hardcode seed phrases in source code.** Use environment variables or a secrets manager. The setup wizard generates a gitignored `.vscode/mcp.json` for local development.
{% endhint %}

### Register Wallets

Register a wallet module for each blockchain you want to support:

```javascript
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'
import WalletManagerSolana from '@tetherto/wdk-wallet-solana'

// EVM chains - one module handles all EVM networks
server.registerWallet('ethereum', WalletManagerEvm, {
  provider: 'https://eth.drpc.org'
})
server.registerWallet('polygon', WalletManagerEvm, {
  provider: 'https://polygon-rpc.com'
})

// Bitcoin
server.registerWallet('bitcoin', WalletManagerBtc, {
  network: 'bitcoin',
  host: 'electrum.blockstream.info',
  port: 50001
})

// Solana
server.registerWallet('solana', WalletManagerSolana, {
  provider: 'https://api.mainnet-beta.solana.com'
})
```

Each `registerWallet()` call registers the chain name and makes it available to all wallet tools. For configuration details of each wallet module, see the [Wallet Modules](https://docs.wdk.tether.io/sdk/wallet-modules) documentation.

***

## Capabilities

Enable optional capabilities before registering their tools:

| Capability  | Method                                                        | Requirement                                       | Unlocks                   |
| ----------- | ------------------------------------------------------------- | ------------------------------------------------- | ------------------------- |
| **Pricing** | `server.usePricing()`                                         | None                                              | `PRICING_TOOLS` (2 tools) |
| **Indexer** | `server.useIndexer({ apiKey })`                               | [WDK API key](https://wdk-api.tether.io/register) | `INDEXER_TOOLS` (2 tools) |
| **Swap**    | `server.registerProtocol(chain, label, SwapProtocol)`         | Swap module installed                             | `SWAP_TOOLS` (2 tools)    |
| **Bridge**  | `server.registerProtocol(chain, label, BridgeProtocol)`       | Bridge module installed                           | `BRIDGE_TOOLS` (2 tools)  |
| **Lending** | `server.registerProtocol(chain, label, LendingProtocol)`      | Lending module installed                          | `LENDING_TOOLS` (8 tools) |
| **Fiat**    | `server.registerProtocol(chain, label, FiatProtocol, config)` | Fiat module installed                             | `FIAT_TOOLS` (8 tools)    |

### Pricing

Fetches live prices from Bitfinex. No API key needed.

```javascript
server.usePricing()
```

### Indexer

Enables querying token balances and transfer history for **any** address. Requires an API key.

```javascript
server.useIndexer({ apiKey: process.env.WDK_INDEXER_API_KEY })
```

### Protocols

DeFi protocols are registered per-chain:

```javascript
import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm'
import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'

server.registerProtocol('ethereum', 'velora', VeloraProtocolEvm)
server.registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm)
server.registerProtocol('ethereum', 'aave', AaveProtocolEvm)
server.registerProtocol('ethereum', 'moonpay', MoonPayProtocol, {
  apiKey: process.env.MOONPAY_API_KEY,
  secretKey: process.env.MOONPAY_SECRET_KEY
})
```

***

## Token Management

### Default Tokens

USDT is auto-registered for supported chains via `DEFAULT_TOKENS`. You can query what's available:

```javascript
server.getRegisteredTokens('ethereum')  // ['USDT']
```

### Custom Tokens

Register additional tokens with `registerToken()`:

```javascript
server.registerToken('ethereum', 'DAI', {
  address: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
  decimals: 18
})
```

Registered tokens are available to all tools that accept a `token` parameter (`getTokenBalance`, `transfer`, `quoteTransfer`, `swap`, etc.).

***

## Tool Registration

### Built-in Tool Arrays

Each category exports three arrays for fine-grained control:

| Export                | Contents                          |
| --------------------- | --------------------------------- |
| `WALLET_TOOLS`        | All 11 wallet tools               |
| `WALLET_READ_TOOLS`   | 7 read-only wallet tools          |
| `WALLET_WRITE_TOOLS`  | 4 wallet tools that modify state  |
| `PRICING_TOOLS`       | All 2 pricing tools               |
| `INDEXER_TOOLS`       | All 2 indexer tools               |
| `SWAP_TOOLS`          | All 2 swap tools                  |
| `SWAP_READ_TOOLS`     | 1 read-only swap tool             |
| `SWAP_WRITE_TOOLS`    | 1 swap tool that modifies state   |
| `BRIDGE_TOOLS`        | All 2 bridge tools                |
| `BRIDGE_READ_TOOLS`   | 1 read-only bridge tool           |
| `BRIDGE_WRITE_TOOLS`  | 1 bridge tool that modifies state |
| `LENDING_TOOLS`       | All 8 lending tools               |
| `LENDING_READ_TOOLS`  | 4 read-only lending tools         |
| `LENDING_WRITE_TOOLS` | 4 lending tools that modify state |
| `FIAT_TOOLS`          | All 8 fiat tools                  |
| `FIAT_READ_TOOLS`     | 6 read-only fiat tools            |
| `FIAT_WRITE_TOOLS`    | 2 fiat tools that modify state    |

### Read-Only Mode

To allow an AI agent to query data without the ability to make transactions:

```javascript
import {
  WALLET_READ_TOOLS,
  PRICING_TOOLS,
  INDEXER_TOOLS,
  SWAP_READ_TOOLS
} from '@tetherto/wdk-mcp-toolkit'

server.registerTools([
  ...WALLET_READ_TOOLS,
  ...PRICING_TOOLS,
  ...INDEXER_TOOLS,
  ...SWAP_READ_TOOLS
])
```

### Individual Tool Registration

You can also import and register tools individually:

```javascript
import { getAddress, getBalance, getCurrentPrice } from '@tetherto/wdk-mcp-toolkit'

server.registerTools([getAddress, getBalance, getCurrentPrice])
```

### Custom Tools

Add your own MCP tools alongside the built-in ones using the standard `registerTool()` method (inherited from `McpServer`). See the [MCP SDK tools documentation](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server.md#tools) for full details.

```javascript
server.registerTool(
  'myCustomTool',
  {
    title: 'My Custom Tool',
    description: 'Description of what this tool does',
    inputSchema: z.object({
      param: z.string().describe('A required parameter')
    }),
    outputSchema: z.object({
      result: z.string()
    }),
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      idempotentHint: true,
      openWorldHint: false
    }
  },
  async ({ param }) => {
    return {
      content: [{ type: 'text', text: `Result: ${param}` }],
      structuredContent: { result: param }
    }
  }
)
```

***

## Environment Variables

| Variable              | Required | Description                               |
| --------------------- | -------- | ----------------------------------------- |
| `WDK_SEED`            | Yes      | BIP-39 mnemonic for wallet key derivation |
| `WDK_INDEXER_API_KEY` | No       | API key for WDK Indexer                   |
| `MOONPAY_API_KEY`     | No       | API key for MoonPay fiat on/off-ramp      |
| `MOONPAY_SECRET_KEY`  | No       | Secret key for MoonPay                    |

***

## Security Checklist

{% hint style="danger" %}
**Self-custodial wallets require careful key management.** Follow these guidelines to protect user funds.
{% endhint %}

* [ ] **Use a dedicated development wallet** - Never use production wallets with real funds for testing
* [ ] **Never hardcode seed phrases** - Always use environment variables or `.vscode/mcp.json` (gitignored)
* [ ] **Use `WALLET_READ_TOOLS` for untrusted agents** - Only register write tools when user confirmation is available
* [ ] **Call `server.close()` on shutdown** - This disposes the WDK instance and wipes keys from memory
* [ ] **Use `stdio` transport** - The default transport communicates only with the local AI client process
* [ ] **Review MCP annotations** - Tools declare `readOnlyHint` and `destructiveHint` so clients can warn users appropriately
* [ ] **Keep `.vscode/mcp.json` gitignored** - The setup wizard handles this automatically

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

WdkMcpServer class and all 35 built-in MCP tools

## WdkMcpServer

The `WdkMcpServer` class extends `McpServer` from `@modelcontextprotocol/sdk` with WDK-specific wallet, pricing, indexer, and protocol capabilities.

### Constructor

```javascript
const server = new WdkMcpServer(name: string, version: string)
```

| Parameter | Type     | Description                       |
| --------- | -------- | --------------------------------- |
| `name`    | `string` | Server name (shown to AI clients) |
| `version` | `string` | Server version string             |

### Core Methods

#### `useWdk(config)`

Initializes the WDK wallet engine. Must be called before `registerWallet()` or `registerProtocol()`.

```typescript
server.useWdk(config: WdkConfig): WdkMcpServer
```

| Parameter     | Type     | Required | Description                 |
| ------------- | -------- | -------- | --------------------------- |
| `config.seed` | `string` | Yes      | BIP-39 mnemonic seed phrase |

**Returns:** `WdkMcpServer` (for chaining)

***

#### `registerWallet(blockchain, WalletManager, config)`

Registers a wallet module for a specific blockchain.

```typescript
server.registerWallet<W extends typeof WalletManager>(
  blockchain: string,
  WalletManager: W,
  config: ConstructorParameters<W>[1]
): WdkMcpServer
```

| Parameter       | Type     | Required | Description                                            |
| --------------- | -------- | -------- | ------------------------------------------------------ |
| `blockchain`    | `string` | Yes      | Chain name (e.g., `'ethereum'`, `'bitcoin'`)           |
| `WalletManager` | `class`  | Yes      | Wallet module class (e.g., `WalletManagerEvm`)         |
| `config`        | `object` | Yes      | Module-specific config (see each wallet module's docs) |

**Requires:** `useWdk()` called first

***

#### `registerProtocol(chain, label, Protocol, config?)`

Registers a DeFi protocol (swap, bridge, lending, or fiat) for a chain.

```typescript
server.registerProtocol<P extends typeof SwapProtocol | typeof BridgeProtocol | typeof LendingProtocol | typeof FiatProtocol>(
  chain: string,
  label: string,
  Protocol: P,
  config?: ConstructorParameters<P>[1]
): WdkMcpServer
```

| Parameter  | Type     | Required | Description                                      |
| ---------- | -------- | -------- | ------------------------------------------------ |
| `chain`    | `string` | Yes      | Chain name (must have a wallet registered)       |
| `label`    | `string` | Yes      | Protocol identifier (e.g., `'velora'`, `'aave'`) |
| `Protocol` | `class`  | Yes      | Protocol module class                            |
| `config`   | `object` | No       | Protocol-specific config                         |

**Requires:** `useWdk()` called first

***

#### `useIndexer(config)`

Enables the WDK Indexer client for querying token balances and transfer history.

```typescript
server.useIndexer(config: { apiKey: string }): WdkMcpServer
```

| Parameter       | Type     | Required | Description         |
| --------------- | -------- | -------- | ------------------- |
| `config.apiKey` | `string` | Yes      | WDK Indexer API key |

***

#### `usePricing()`

Enables the Bitfinex pricing client for current and historical prices.

```typescript
server.usePricing(): WdkMcpServer
```

***

#### `registerTools(tools)`

Registers multiple MCP tools at once.

```typescript
server.registerTools(tools: ToolFunction[]): WdkMcpServer
```

***

#### `registerToken(chain, symbol, token)`

Registers a custom token for a chain.

```typescript
server.registerToken(chain: string, symbol: string, token: TokenInfo): WdkMcpServer
```

| Parameter        | Type     | Description                   |
| ---------------- | -------- | ----------------------------- |
| `chain`          | `string` | Chain name                    |
| `symbol`         | `string` | Token symbol (e.g., `'USDT'`) |
| `token.address`  | `string` | Token contract address        |
| `token.decimals` | `number` | Token decimal places          |

***

#### `close()`

Disposes the WDK instance and clears seed material from memory. Call this when shutting down the server.

```typescript
server.close(): void
```

### Query Methods

| Method                        | Returns                  | Description                          |
| ----------------------------- | ------------------------ | ------------------------------------ |
| `getChains()`                 | `string[]`               | Registered blockchain names          |
| `getTokenInfo(chain, symbol)` | `TokenInfo \| undefined` | Token address and decimals           |
| `getRegisteredTokens(chain)`  | `string[]`               | Registered token symbols for a chain |
| `getSwapChains()`             | `string[]`               | Chains with swap protocols           |
| `getSwapProtocols(chain)`     | `string[]`               | Swap protocol labels for a chain     |
| `getBridgeChains()`           | `string[]`               | Chains with bridge protocols         |
| `getBridgeProtocols(chain)`   | `string[]`               | Bridge protocol labels for a chain   |
| `getLendingChains()`          | `string[]`               | Chains with lending protocols        |
| `getLendingProtocols(chain)`  | `string[]`               | Lending protocol labels for a chain  |
| `getFiatChains()`             | `string[]`               | Chains with fiat protocols           |
| `getFiatProtocols(chain)`     | `string[]`               | Fiat protocol labels for a chain     |

### Getters

| Getter                 | Type               | Description                           |
| ---------------------- | ------------------ | ------------------------------------- |
| `server.wdk`           | `WalletKit`        | WDK instance (after `useWdk()`)       |
| `server.indexerClient` | `WdkIndexerClient` | Indexer client (after `useIndexer()`) |
| `server.pricingClient` | `WdkPricingClient` | Pricing client (after `usePricing()`) |

***

## Types

```typescript
type WdkConfig = {
  seed?: string
}

type TokenInfo = {
  address: string
  decimals: number
}

type ToolFunction = (server: WdkMcpServer) => void
```

***

## Built-in MCP Tools

All tools use [Zod](https://zod.dev/) for input/output validation and include [MCP tool annotations](https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations) that describe their behavior to AI clients.

### MCP Annotations

Every tool declares these annotations:

| Annotation        | Type      | Meaning                                           |
| ----------------- | --------- | ------------------------------------------------- |
| `readOnlyHint`    | `boolean` | Tool does not modify state                        |
| `destructiveHint` | `boolean` | Tool may spend funds or make irreversible changes |
| `idempotentHint`  | `boolean` | Calling multiple times produces the same result   |
| `openWorldHint`   | `boolean` | Tool interacts with external systems              |

{% hint style="info" %}
**Human Confirmation** - All tools where `destructiveHint: true` use MCP [elicitations](https://modelcontextprotocol.io/docs/concepts/elicitation) to show a confirmation dialog before broadcasting. The user must explicitly approve each transaction.
{% endhint %}

***

## Wallet Tools

*Requires: `useWdk()` + `registerWallet()`*

### `getAddress`

Get the wallet address for a blockchain. **Read-only.**

**Input:**

| Parameter | Type   | Required | Description                           |
| --------- | ------ | -------- | ------------------------------------- |
| `chain`   | `enum` | Yes      | The blockchain to get the address for |

**Output:**

| Field     | Type     | Description        |
| --------- | -------- | ------------------ |
| `address` | `string` | The wallet address |

***

### `getBalance`

Get the native token balance for a blockchain (ETH, BTC, SOL, etc.). **Read-only.**

**Input:**

| Parameter | Type   | Required | Description             |
| --------- | ------ | -------- | ----------------------- |
| `chain`   | `enum` | Yes      | The blockchain to query |

**Output:**

| Field     | Type     | Description                                 |
| --------- | -------- | ------------------------------------------- |
| `balance` | `string` | Balance in base units (wei, satoshis, etc.) |

***

### `getTokenBalance`

Get the balance of a registered token (USDT, XAU₮, etc.). **Read-only.**

**Input:**

| Parameter | Type     | Required | Description                   |
| --------- | -------- | -------- | ----------------------------- |
| `chain`   | `enum`   | Yes      | The blockchain to query       |
| `token`   | `string` | Yes      | Token symbol (e.g., `"USDT"`) |

**Output:**

| Field              | Type     | Description                  |
| ------------------ | -------- | ---------------------------- |
| `balance`          | `string` | Human-readable token balance |
| `balanceBaseUnits` | `string` | Balance in smallest unit     |

***

### `getFeeRates`

Get current network fee rates. **Read-only.**

**Input:**

| Parameter | Type   | Required | Description             |
| --------- | ------ | -------- | ----------------------- |
| `chain`   | `enum` | Yes      | The blockchain to query |

**Output:**

| Field    | Type     | Description                                      |
| -------- | -------- | ------------------------------------------------ |
| `normal` | `string` | Normal fee rate (balanced speed)                 |
| `fast`   | `string` | Fast fee rate (higher cost, faster confirmation) |

Fee units vary by chain: satoshis/byte (Bitcoin), wei (Ethereum), or chain-specific units.

***

### `getMaxSpendableBtc`

Get the maximum spendable Bitcoin amount after fees. **Read-only.** Bitcoin-only.

**Input:** None

**Output:**

| Field         | Type     | Description                          |
| ------------- | -------- | ------------------------------------ |
| `amount`      | `string` | Maximum spendable amount (satoshis)  |
| `fee`         | `string` | Estimated transaction fee (satoshis) |
| `changeValue` | `string` | Expected change output (satoshis)    |

***

### `quoteSendTransaction`

Estimate the fee for sending native currency. **Read-only.** Does not broadcast.

**Input:**

| Parameter | Type     | Required | Description                              |
| --------- | -------- | -------- | ---------------------------------------- |
| `chain`   | `enum`   | Yes      | The blockchain                           |
| `to`      | `string` | Yes      | Recipient address                        |
| `value`   | `string` | Yes      | Amount in **base units** (wei, satoshis) |

**Output:**

| Field | Type     | Description                             |
| ----- | -------- | --------------------------------------- |
| `fee` | `string` | Estimated transaction fee in base units |

***

### `quoteTransfer`

Estimate the fee for transferring a token. **Read-only.** Does not broadcast.

**Input:**

| Parameter   | Type     | Required | Description                                        |
| ----------- | -------- | -------- | -------------------------------------------------- |
| `chain`     | `enum`   | Yes      | The blockchain                                     |
| `token`     | `string` | Yes      | Token symbol (e.g., `"USDT"`)                      |
| `recipient` | `string` | Yes      | Recipient address                                  |
| `amount`    | `string` | Yes      | Amount in **human-readable** format (e.g., `"10"`) |

**Output:**

| Field | Type     | Description                             |
| ----- | -------- | --------------------------------------- |
| `fee` | `string` | Estimated transaction fee in base units |

***

### `sendTransaction`

Send native currency (ETH, BTC, etc.). **Destructive** - requires user confirmation.

**Input:**

| Parameter | Type     | Required | Description                              |
| --------- | -------- | -------- | ---------------------------------------- |
| `chain`   | `enum`   | Yes      | The blockchain                           |
| `to`      | `string` | Yes      | Recipient address                        |
| `value`   | `string` | Yes      | Amount in **base units** (wei, satoshis) |

**Output:**

| Field  | Type     | Description      |
| ------ | -------- | ---------------- |
| `hash` | `string` | Transaction hash |
| `fee`  | `string` | Actual fee paid  |

{% hint style="warning" %}
This tool shows a confirmation dialog with transaction details before broadcasting. The user must approve the transaction explicitly.
{% endhint %}

***

### `transfer`

Transfer a registered token. **Destructive** - requires user confirmation.

**Input:**

| Parameter | Type     | Required | Description                                         |
| --------- | -------- | -------- | --------------------------------------------------- |
| `chain`   | `enum`   | Yes      | The blockchain                                      |
| `token`   | `string` | Yes      | Token symbol (e.g., `"USDT"`)                       |
| `to`      | `string` | Yes      | Recipient address                                   |
| `amount`  | `string` | Yes      | Amount in **human-readable** format (e.g., `"100"`) |

**Output:**

| Field  | Type     | Description      |
| ------ | -------- | ---------------- |
| `hash` | `string` | Transaction hash |
| `fee`  | `string` | Actual fee paid  |

{% hint style="warning" %}
This tool shows a confirmation dialog with transaction details before broadcasting. The user must approve the transaction explicitly.
{% endhint %}

***

### `sign`

Sign an arbitrary message with the wallet's private key. **Does not reveal the private key.**

**Input:**

| Parameter | Type     | Required | Description     |
| --------- | -------- | -------- | --------------- |
| `chain`   | `enum`   | Yes      | The blockchain  |
| `message` | `string` | Yes      | Message to sign |

**Output:**

| Field       | Type     | Description             |
| ----------- | -------- | ----------------------- |
| `signature` | `string` | Cryptographic signature |

***

### `verify`

Verify that a signature is valid for a given message. **Read-only.**

**Input:**

| Parameter   | Type     | Required | Description         |
| ----------- | -------- | -------- | ------------------- |
| `chain`     | `enum`   | Yes      | The blockchain      |
| `message`   | `string` | Yes      | Original message    |
| `signature` | `string` | Yes      | Signature to verify |

**Output:**

| Field   | Type      | Description                    |
| ------- | --------- | ------------------------------ |
| `valid` | `boolean` | Whether the signature is valid |

***

## Pricing Tools

*Requires: `usePricing()`*

### `getCurrentPrice`

Get the current spot price from Bitfinex. **Read-only.**

**Input:**

| Parameter | Type     | Required | Description                              |
| --------- | -------- | -------- | ---------------------------------------- |
| `base`    | `string` | Yes      | Base currency (e.g., `"BTC"`, `"ETH"`)   |
| `quote`   | `string` | Yes      | Quote currency (e.g., `"USD"`, `"USDT"`) |

**Output:**

| Field   | Type     | Description        |
| ------- | -------- | ------------------ |
| `base`  | `string` | Base currency      |
| `quote` | `string` | Quote currency     |
| `price` | `number` | Current spot price |

***

### `getHistoricalPrice`

Get historical price data (OHLCV candles) from Bitfinex. **Read-only.**

**Input:**

| Parameter | Type     | Required | Description                      |
| --------- | -------- | -------- | -------------------------------- |
| `from`    | `string` | Yes      | Base currency (e.g., `"BTC"`)    |
| `to`      | `string` | Yes      | Quote currency (e.g., `"USD"`)   |
| `start`   | `number` | No       | Start timestamp (ms, unix epoch) |
| `end`     | `number` | No       | End timestamp (ms, unix epoch)   |

**Output:**

| Field    | Type         | Description                                            |
| -------- | ------------ | ------------------------------------------------------ |
| `from`   | `string`     | Base currency                                          |
| `to`     | `string`     | Quote currency                                         |
| `start`  | `number`     | Start timestamp (if provided)                          |
| `end`    | `number`     | End timestamp (if provided)                            |
| `points` | `number[][]` | Array of `[timestamp, open, close, high, low, volume]` |

{% hint style="info" %}
Long time ranges are automatically downscaled to ≤100 data points.
{% endhint %}

***

## Indexer Tools

*Requires: `useIndexer()`*

### `getIndexerTokenBalance`

Get token balance for **any** address via the WDK Indexer API. **Read-only.**

**Input:**

| Parameter    | Type     | Required | Description                               |
| ------------ | -------- | -------- | ----------------------------------------- |
| `blockchain` | `enum`   | Yes      | Blockchain to query                       |
| `token`      | `enum`   | Yes      | Token (e.g., `"usdt"`, `"xaut"`, `"btc"`) |
| `address`    | `string` | Yes      | Wallet address                            |

**Output:**

| Field                     | Type     | Description     |
| ------------------------- | -------- | --------------- |
| `tokenBalance.blockchain` | `string` | Blockchain name |
| `tokenBalance.token`      | `string` | Token name      |
| `tokenBalance.amount`     | `string` | Token balance   |

{% hint style="info" %}
This queries the **indexed** balance, which may have slight delay compared to real-time blockchain state. For your own wallet's balance, use `getBalance` or `getTokenBalance` instead.
{% endhint %}

***

### `getTokenTransfers`

Get token transfer history for an address. **Read-only.**

**Input:**

| Parameter    | Type     | Required | Description                               |
| ------------ | -------- | -------- | ----------------------------------------- |
| `blockchain` | `enum`   | Yes      | Blockchain to query                       |
| `token`      | `enum`   | Yes      | Token (e.g., `"usdt"`, `"xaut"`, `"btc"`) |
| `address`    | `string` | Yes      | Wallet address                            |
| `limit`      | `number` | No       | Results per page (1–1000, default: 10)    |
| `fromTs`     | `number` | No       | Start timestamp (unix seconds)            |
| `toTs`       | `number` | No       | End timestamp (unix seconds)              |
| `sort`       | `enum`   | No       | `"asc"` or `"desc"` (default: `"desc"`)   |

**Output:**

| Field                         | Type       | Description               |
| ----------------------------- | ---------- | ------------------------- |
| `transfers`                   | `object[]` | Array of transfer records |
| `transfers[].blockchain`      | `string`   | Blockchain                |
| `transfers[].blockNumber`     | `number`   | Block number              |
| `transfers[].transactionHash` | `string`   | Transaction hash          |
| `transfers[].token`           | `string`   | Token                     |
| `transfers[].amount`          | `string`   | Transfer amount           |
| `transfers[].timestamp`       | `number`   | Unix timestamp            |
| `transfers[].from`            | `string`   | Sender address            |
| `transfers[].to`              | `string`   | Recipient address         |

***

## Swap Tools

*Requires: `registerProtocol()` with a swap protocol*

### `quoteSwap`

Get a swap quote without executing. **Read-only.**

**Input:**

| Parameter  | Type     | Required | Description                    |
| ---------- | -------- | -------- | ------------------------------ |
| `chain`    | `enum`   | Yes      | Blockchain with swap protocol  |
| `tokenIn`  | `string` | Yes      | Token to sell (e.g., `"USDT"`) |
| `tokenOut` | `string` | Yes      | Token to buy (e.g., `"WETH"`)  |
| `amount`   | `string` | Yes      | Amount in human-readable units |
| `side`     | `enum`   | Yes      | `"sell"` or `"buy"`            |

**Output:**

| Field            | Type     | Description                    |
| ---------------- | -------- | ------------------------------ |
| `protocol`       | `string` | DEX protocol used              |
| `tokenIn`        | `string` | Input token symbol             |
| `tokenOut`       | `string` | Output token symbol            |
| `tokenInAmount`  | `string` | Input amount (human-readable)  |
| `tokenOutAmount` | `string` | Output amount (human-readable) |
| `fee`            | `string` | Estimated fee                  |

***

### `swap`

Execute a token swap. **Destructive** - requires user confirmation.

**Input:**

| Parameter  | Type     | Required | Description                            |
| ---------- | -------- | -------- | -------------------------------------- |
| `chain`    | `enum`   | Yes      | Blockchain with swap protocol          |
| `tokenIn`  | `string` | Yes      | Token to sell                          |
| `tokenOut` | `string` | Yes      | Token to buy                           |
| `amount`   | `string` | Yes      | Amount in human-readable units         |
| `side`     | `enum`   | Yes      | `"sell"` or `"buy"`                    |
| `to`       | `string` | No       | Recipient address (defaults to wallet) |

**Output:**

| Field            | Type      | Description                |
| ---------------- | --------- | -------------------------- |
| `success`        | `boolean` | Whether the swap succeeded |
| `protocol`       | `string`  | DEX protocol used          |
| `hash`           | `string`  | Transaction hash           |
| `tokenIn`        | `string`  | Input token symbol         |
| `tokenOut`       | `string`  | Output token symbol        |
| `tokenInAmount`  | `string`  | Actual input amount        |
| `tokenOutAmount` | `string`  | Actual output amount       |
| `fee`            | `string`  | Fee paid                   |

{% hint style="warning" %}
This tool quotes the swap first, then shows a confirmation dialog before broadcasting.
{% endhint %}

***

## Bridge Tools

*Requires: `registerProtocol()` with a bridge protocol*

### `quoteBridge`

Get a bridge quote without executing. **Read-only.**

**Input:**

| Parameter     | Type     | Required | Description                                    |
| ------------- | -------- | -------- | ---------------------------------------------- |
| `chain`       | `enum`   | Yes      | Source blockchain                              |
| `targetChain` | `string` | Yes      | Destination blockchain                         |
| `token`       | `string` | Yes      | Token to bridge (e.g., `"USDT"`)               |
| `amount`      | `string` | Yes      | Amount in human-readable units                 |
| `recipient`   | `string` | No       | Recipient on target chain (defaults to wallet) |

**Output:**

| Field         | Type     | Description            |
| ------------- | -------- | ---------------------- |
| `protocol`    | `string` | Bridge protocol used   |
| `sourceChain` | `string` | Source blockchain      |
| `targetChain` | `string` | Destination blockchain |
| `token`       | `string` | Token symbol           |
| `amount`      | `string` | Amount to bridge       |
| `fee`         | `string` | Estimated gas fee      |
| `bridgeFee`   | `string` | Bridge protocol fee    |

***

### `bridge`

Execute a cross-chain bridge. **Destructive** - requires user confirmation.

**Input:**

| Parameter     | Type     | Required | Description                                    |
| ------------- | -------- | -------- | ---------------------------------------------- |
| `chain`       | `enum`   | Yes      | Source blockchain                              |
| `targetChain` | `string` | Yes      | Destination blockchain                         |
| `token`       | `string` | Yes      | Token to bridge                                |
| `amount`      | `string` | Yes      | Amount in human-readable units                 |
| `recipient`   | `string` | No       | Recipient on target chain (defaults to wallet) |

**Output:**

| Field         | Type      | Description                  |
| ------------- | --------- | ---------------------------- |
| `success`     | `boolean` | Whether the bridge succeeded |
| `protocol`    | `string`  | Bridge protocol used         |
| `hash`        | `string`  | Transaction hash             |
| `sourceChain` | `string`  | Source blockchain            |
| `targetChain` | `string`  | Destination blockchain       |
| `token`       | `string`  | Token symbol                 |
| `amount`      | `string`  | Amount bridged               |
| `fee`         | `string`  | Gas fee paid                 |
| `bridgeFee`   | `string`  | Bridge protocol fee paid     |

{% hint style="warning" %}
Bridge finality varies by target chain - tokens may take minutes to hours to arrive.
{% endhint %}

***

## Lending Tools

*Requires: `registerProtocol()` with a lending protocol*

### `quoteSupply`

Get a fee estimate for supplying tokens to a lending pool. **Read-only.**

**Input:**

| Parameter    | Type     | Required | Description                                     |
| ------------ | -------- | -------- | ----------------------------------------------- |
| `chain`      | `enum`   | Yes      | Blockchain with lending protocol                |
| `token`      | `string` | Yes      | Token to supply                                 |
| `amount`     | `string` | Yes      | Amount in human-readable units                  |
| `onBehalfOf` | `string` | No       | Address to receive aTokens (defaults to wallet) |

**Output:**

| Field      | Type     | Description           |
| ---------- | -------- | --------------------- |
| `protocol` | `string` | Lending protocol used |
| `chain`    | `string` | Blockchain            |
| `token`    | `string` | Token symbol          |
| `amount`   | `string` | Amount to supply      |
| `fee`      | `string` | Estimated gas fee     |

***

### `supply`

Supply tokens to a lending pool. **Destructive** - requires user confirmation.

Same input as `quoteSupply`. Output includes `success`, `protocol`, `hash`, `token`, `amount`, and `fee`.

***

### `quoteWithdraw`

Estimate fee for withdrawing from a lending pool. **Read-only.**

**Input:**

| Parameter | Type     | Required | Description                    |
| --------- | -------- | -------- | ------------------------------ |
| `chain`   | `enum`   | Yes      | Blockchain                     |
| `token`   | `string` | Yes      | Token to withdraw              |
| `amount`  | `string` | Yes      | Amount in human-readable units |

**Output:** Same structure as `quoteSupply`.

***

### `withdraw`

Withdraw tokens from a lending pool. **Destructive** - requires user confirmation.

Same input as `quoteWithdraw`. Output includes `success`, `protocol`, `hash`, `token`, `amount`, and `fee`.

***

### `quoteBorrow`

Estimate fee for borrowing from a lending pool. **Read-only.**

**Input:**

| Parameter | Type     | Required | Description                    |
| --------- | -------- | -------- | ------------------------------ |
| `chain`   | `enum`   | Yes      | Blockchain                     |
| `token`   | `string` | Yes      | Token to borrow                |
| `amount`  | `string` | Yes      | Amount in human-readable units |

**Output:** Same structure as `quoteSupply`.

***

### `borrow`

Borrow tokens from a lending pool. **Destructive** - requires user confirmation.

Same input as `quoteBorrow`. Output includes `success`, `protocol`, `hash`, `token`, `amount`, and `fee`.

***

### `quoteRepay`

Estimate fee for repaying a loan. **Read-only.**

**Input:**

| Parameter | Type     | Required | Description                    |
| --------- | -------- | -------- | ------------------------------ |
| `chain`   | `enum`   | Yes      | Blockchain                     |
| `token`   | `string` | Yes      | Token to repay                 |
| `amount`  | `string` | Yes      | Amount in human-readable units |

**Output:** Same structure as `quoteSupply`.

***

### `repay`

Repay borrowed tokens. **Destructive** - requires user confirmation.

Same input as `quoteRepay`. Output includes `success`, `protocol`, `hash`, `token`, `amount`, and `fee`.

***

## Fiat Tools

*Requires: `registerProtocol()` with a fiat protocol*

### `quoteBuy`

Get a quote for purchasing crypto with fiat. **Read-only.**

**Input:**

| Parameter      | Type     | Required | Description                                 |
| -------------- | -------- | -------- | ------------------------------------------- |
| `chain`        | `enum`   | Yes      | Blockchain for the fiat protocol            |
| `cryptoAsset`  | `string` | Yes      | Crypto asset code (e.g., `"eth"`, `"btc"`)  |
| `fiatCurrency` | `string` | Yes      | Fiat currency code (e.g., `"USD"`, `"EUR"`) |
| `amount`       | `string` | Yes      | Amount to quote                             |
| `amountType`   | `enum`   | Yes      | `"crypto"` or `"fiat"`                      |

**Output:**

| Field          | Type     | Description                               |
| -------------- | -------- | ----------------------------------------- |
| `protocol`     | `string` | Fiat protocol used                        |
| `cryptoAsset`  | `string` | Crypto asset code                         |
| `fiatCurrency` | `string` | Fiat currency code                        |
| `cryptoAmount` | `string` | Crypto amount (base units)                |
| `fiatAmount`   | `string` | Fiat amount (smallest units, e.g., cents) |
| `fee`          | `string` | Total fee (fiat smallest units)           |
| `rate`         | `string` | Exchange rate                             |

***

### `buy`

Execute a fiat-to-crypto purchase. **Destructive** - requires user confirmation.

Same input as `quoteBuy`. Output includes `success`, `protocol`, redirect URL or transaction details.

***

### `quoteSell`

Get a quote for selling crypto to fiat. **Read-only.**

Same input structure as `quoteBuy`. Same output structure.

***

### `sell`

Execute a crypto-to-fiat sale. **Destructive** - requires user confirmation.

Same input as `quoteSell`. Output includes `success`, `protocol`, and transaction details.

***

### `getTransactionDetail`

Get details of a fiat transaction by ID. **Read-only.**

**Input:**

| Parameter       | Type     | Required | Description                           |
| --------------- | -------- | -------- | ------------------------------------- |
| `chain`         | `enum`   | Yes      | Blockchain                            |
| `transactionId` | `string` | Yes      | Transaction ID from the fiat provider |

***

### `getSupportedCryptoAssets`

List crypto assets supported by the fiat provider. **Read-only.**

**Input:**

| Parameter | Type   | Required | Description |
| --------- | ------ | -------- | ----------- |
| `chain`   | `enum` | Yes      | Blockchain  |

***

### `getSupportedFiatCurrencies`

List fiat currencies supported by the fiat provider. **Read-only.**

**Input:**

| Parameter | Type   | Required | Description |
| --------- | ------ | -------- | ----------- |
| `chain`   | `enum` | Yes      | Blockchain  |

***

### `getSupportedCountries`

List countries supported by the fiat provider. **Read-only.**

**Input:**

| Parameter | Type   | Required | Description |
| --------- | ------ | -------- | ----------- |
| `chain`   | `enum` | Yes      | Blockchain  |

***

## Utility Exports

Utility functions for converting between human-readable amounts and blockchain base units:

```javascript
import {
  parseAmountToBaseUnits,
  formatBaseUnitsToAmount,
  AmountParseError,
  AMOUNT_ERROR_CODES
} from '@tetherto/wdk-mcp-toolkit'
```

### `parseAmountToBaseUnits(amount, decimals)`

Converts a human-readable amount string to `BigInt` base units without floating-point errors.

```javascript
parseAmountToBaseUnits('2.01', 6)   // → 2010000n
parseAmountToBaseUnits('100', 18)   // → 100000000000000000000n
parseAmountToBaseUnits('1,000.50', 6) // → 1000500000n
```

### `formatBaseUnitsToAmount(baseUnits, decimals)`

Converts `BigInt` base units to a human-readable string.

```javascript
formatBaseUnitsToAmount(2010000n, 6)  // → '2.01'
formatBaseUnitsToAmount(100000000000000000000n, 18) // → '100'
```

### `AmountParseError`

Custom error class with a `code` property for programmatic handling:

| Error Code                      | Description                             |
| ------------------------------- | --------------------------------------- |
| `EMPTY_STRING`                  | Empty amount string                     |
| `INVALID_FORMAT`                | Not a valid number                      |
| `NEGATIVE_AMOUNT`               | Negative amounts not allowed            |
| `EXCESSIVE_PRECISION`           | More decimal places than token supports |
| `INVALID_DECIMALS`              | Decimals value out of range             |
| `SCIENTIFIC_NOTATION_PRECISION` | Scientific notation exceeds precision   |

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# LangChain Integration

Use WDK MCP tools in LangChain agents with zero-config server startup

You can use the WDK MCP Toolkit as a tool provider for [LangChain](https://www.langchain.com/) agents in both Python and TypeScript. LangChain's `MultiServerMCPClient` spawns the MCP server as a subprocess and converts WDK tools into LangChain-compatible tools, giving your agent access to wallet operations, pricing, swaps, bridges, lending, and more.

This integration uses the `serve` CLI command, which starts a fully configured MCP server on stdio with no server script required.

{% hint style="info" %}
This approach uses LangChain's MCP adapters to connect to the WDK MCP server. WDK does not ship a native LangChain integration, it leverages the standard MCP protocol that LangChain already supports.
{% endhint %}

{% hint style="info" %}
**Want more control?** The `serve` command is the fastest way to get running, but you can also [write your own MCP server](https://docs.wdk.tether.io/ai/get-started#manual-setup) with the programmatic API for full control over wallets, tools, and protocols. Then point LangChain's `MultiServerMCPClient` at it using `node your-server.js` instead of the `serve` command.
{% endhint %}

***

## The `serve` Command

The `serve` command provides zero-config MCP server startup so you don't need to write a server script:

{% code title="Terminal" %}

```bash
npx @tetherto/wdk-mcp-toolkit serve
```

{% endcode %}

Pass `WDK_SEED` to enable wallet operations, or omit it to run with pricing tools only:

{% code title="Terminal" %}

```bash
# With wallet operations
WDK_SEED="your twelve word seed phrase here" npx @tetherto/wdk-mcp-toolkit serve

# Pricing-only mode (no seed required)
npx @tetherto/wdk-mcp-toolkit serve
```

{% endcode %}

### Default Chains

By default, `serve` enables **three chains**: Ethereum, Arbitrum, and Bitcoin. For each enabled chain it dynamically imports the required wallet package and skips any that aren't installed. You can change the enabled set with the `WDK_CHAINS` environment variable.

### Built-in Registry

The command has built-in definitions for 13 chains and 4 protocol modules. When a chain is enabled and its package is installed, the wallet is registered automatically. Protocol modules are also auto-registered when their packages are installed and at least one of their target chains is enabled.

| Module                                                                                                       | Registers                                                                  | Default                       |
| ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ----------------------------- |
| [`@tetherto/wdk-wallet-evm`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm)                       | Ethereum, Arbitrum, Polygon, Optimism, Base, Avalanche, BNB, Plasma, Spark | Ethereum + Arbitrum enabled   |
| [`@tetherto/wdk-wallet-btc`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc)                       | Bitcoin                                                                    | Enabled                       |
| [`@tetherto/wdk-wallet-solana`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana)                 | Solana                                                                     | Not enabled by default        |
| [`@tetherto/wdk-wallet-ton`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton)                       | TON                                                                        | Not enabled by default        |
| [`@tetherto/wdk-wallet-tron`](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron)                     | Tron                                                                       | Not enabled by default        |
| [`@tetherto/wdk-protocol-swap-velora-evm`](https://docs.wdk.tether.io/sdk/swap-modules/swap-velora-evm)      | Swap tools (Ethereum, Arbitrum)                                            | --                            |
| [`@tetherto/wdk-protocol-bridge-usdt0-evm`](https://docs.wdk.tether.io/sdk/bridge-modules/bridge-usdt0-evm)  | Bridge tools (Ethereum, Arbitrum)                                          | --                            |
| [`@tetherto/wdk-protocol-lending-aave-evm`](https://docs.wdk.tether.io/sdk/lending-modules/lending-aave-evm) | Lending tools (Ethereum)                                                   | --                            |
| [`@tetherto/wdk-protocol-fiat-moonpay`](https://docs.wdk.tether.io/sdk/fiat-modules/fiat-moonpay)            | Fiat tools (Ethereum)                                                      | Requires `MOONPAY_*` env vars |

{% hint style="info" %}
Missing packages are silently skipped. Install only the modules you need and `serve` will pick them up. For chains or protocols **not** in the built-in registry, use a [custom config file](#custom-config-file).
{% endhint %}

***

## Quick Start

{% tabs %}
{% tab title="Python" %}
**Install dependencies**

{% code title="Terminal" %}

```bash
pip install langchain-mcp-adapters langgraph langchain-openai
```

{% endcode %}

**Create your agent**

{% code title="agent.py" lineNumbers="true" %}

```python
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

async def main():
    client = MultiServerMCPClient({
        "wdk": {
            "transport": "stdio",
            "command": "npx",
            "args": ["-y", "@tetherto/wdk-mcp-toolkit", "serve"],
            "env": {
                "WDK_SEED": "your twelve word seed phrase here",
                "WDK_MCP_ELICITATION": "false",
            },
        }
    })

    tools = await client.get_tools()
    agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools)

    result = await agent.ainvoke({
        "messages": [{"role": "user", "content": "What is my Ethereum address?"}]
    })
    print(result["messages"][-1].content)

    await client.close()

asyncio.run(main())
```

{% endcode %}

**Run it**

{% code title="Terminal" %}

```bash
export OPENAI_API_KEY="sk-..."
python agent.py
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
**Install dependencies**

{% code title="Terminal" %}

```bash
npm install @langchain/mcp-adapters @langchain/langgraph @langchain/core @langchain/openai
```

{% endcode %}

**Create your agent**

{% code title="agent.ts" lineNumbers="true" %}

```typescript
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";

const client = new MultiServerMCPClient({
  wdk: {
    transport: "stdio",
    command: "npx",
    args: ["-y", "@tetherto/wdk-mcp-toolkit", "serve"],
    env: {
      WDK_SEED: "your twelve word seed phrase here",
      WDK_MCP_ELICITATION: "false",
    },
  },
});

const tools = await client.getTools();
const agent = createReactAgent({
  llm: new ChatOpenAI({ model: "gpt-4o" }),
  tools,
});

const result = await agent.invoke({
  messages: [
    { role: "user", content: "What is the current price of Bitcoin?" },
  ],
});

console.log(result.messages[result.messages.length - 1].content);
await client.close();
```

{% endcode %}

**Run it**

{% code title="Terminal" %}

```bash
export OPENAI_API_KEY="sk-..."
npx tsx agent.ts
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Security** -- Always use a dedicated development wallet with limited funds. Set `WDK_MCP_ELICITATION` to `"false"` for programmatic agents since elicitation dialogs require a human in the loop.
{% endhint %}

***

## Configuration

### Environment Variables

Control `serve` behavior through environment variables:

| Variable              | Required | Default                     | Description                                                                        |
| --------------------- | -------- | --------------------------- | ---------------------------------------------------------------------------------- |
| `WDK_SEED`            | No       | --                          | BIP-39 seed phrase. If omitted, only pricing tools are available                   |
| `WDK_CHAINS`          | No       | `ethereum,arbitrum,bitcoin` | Comma-separated list of chains to enable                                           |
| `WDK_MCP_ELICITATION` | No       | `true`                      | Set to `"false"` for programmatic agents that cannot handle confirmation dialogs   |
| `WDK_RPC_<CHAIN>`     | No       | Built-in defaults           | Override the RPC endpoint for a chain (e.g. `WDK_RPC_ETHEREUM=https://my-rpc.com`) |
| `WDK_CONFIG`          | No       | --                          | Path to a `wdk.config.json` file for custom chains and protocols                   |
| `WDK_INDEXER_API_KEY` | No       | --                          | Enables indexer tools for balance and transfer history queries                     |
| `MOONPAY_API_KEY`     | No       | --                          | Enables fiat on/off-ramp tools                                                     |
| `MOONPAY_SECRET_KEY`  | No       | --                          | Required with `MOONPAY_API_KEY`                                                    |

### Custom Config File

For chains or protocols not in the built-in defaults, create a `wdk.config.json` and pass its path via `WDK_CONFIG`:

{% code title="Terminal" %}

```bash
WDK_CONFIG=./wdk.config.json WDK_SEED="..." npx @tetherto/wdk-mcp-toolkit serve
```

{% endcode %}

{% code title="wdk.config.json" %}

```json
{
  "chains": {
    "zksync": {
      "module": "@myorg/wdk-wallet-zksync",
      "config": { "provider": "https://mainnet.era.zksync.io" }
    },
    "ethereum": {
      "config": { "provider": "https://my-private-rpc.com" }
    }
  },
  "protocols": [
    {
      "module": "@myorg/wdk-protocol-swap-custom",
      "label": "custom-swap",
      "type": "swap",
      "chains": ["zksync"]
    }
  ],
  "enabledChains": ["ethereum", "zksync", "bitcoin"]
}
```

{% endcode %}

| Field           | Description                                                                                                                                                                   |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chains`        | Add new chains or override config for built-in ones. New chains require a `module` field; overrides for existing chains can omit it                                           |
| `protocols`     | Add custom protocols. Each entry requires `module`, `label`, and `chains`. The `type` field (`swap`, `bridge`, `lending`, `fiat`) maps to the corresponding built-in tool set |
| `enabledChains` | Overrides `WDK_CHAINS` env var. If omitted, `WDK_CHAINS` is used                                                                                                              |

***

## LLM Provider Support

Both the Python and TypeScript examples support OpenAI and Anthropic. Set the corresponding environment variable and install the matching package:

| Provider  | Environment Variable | Python Package        | TypeScript Package     |
| --------- | -------------------- | --------------------- | ---------------------- |
| OpenAI    | `OPENAI_API_KEY`     | `langchain-openai`    | `@langchain/openai`    |
| Anthropic | `ANTHROPIC_API_KEY`  | `langchain-anthropic` | `@langchain/anthropic` |

{% hint style="info" %}
The examples auto-detect which provider to use based on which API key is set. If both are set, OpenAI takes priority.
{% endhint %}

{% hint style="success" %}
**Full examples** -- See the complete interactive agent examples with conversation loops on GitHub: [`examples/langchain/python/`](https://github.com/tetherto/wdk-mcp-toolkit/tree/main/examples/langchain/python) and [`examples/langchain/typescript/`](https://github.com/tetherto/wdk-mcp-toolkit/tree/main/examples/langchain/typescript).
{% endhint %}

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Agent Skills

Give any AI agent self-custodial wallet capabilities with WDK agent skills

WDK provides agent skills: structured instruction sets that teach AI agents how to create wallets, send transactions, swap tokens, bridge assets, and interact with DeFi protocols across 20+ blockchains. All operations are self-custodial. Keys stay on your machine, with no third-party custody dependency.

{% hint style="info" %}
**Skill vs MCP Toolkit**: Use an **agent skill** when your agent platform works with file-based instructions (e.g., OpenClaw, Cursor). Use the [MCP Toolkit](https://docs.wdk.tether.io/ai/mcp-toolkit) when your agent supports the Model Context Protocol natively (e.g., Claude, Cursor). Use both for maximum coverage.
{% endhint %}

## What Are Agent Skills?

An agent skill is a structured set of instructions and reference documentation that teaches an AI agent to use a specific tool or SDK. Skills follow the [AgentSkills specification](https://agentskills.io/specification). Each skill is a `SKILL.md` file with frontmatter metadata and detailed instructions that any compatible agent can load and execute.

WDK publishes a skill that covers the full SDK surface: wallet modules, swap, bridge, lending, fiat on/off-ramps, and the indexer. When an agent loads the skill, it learns WDK's APIs so you don't need blockchain expertise to get started. You can view the full skill file on [GitHub](https://github.com/tetherto/wdk-docs/blob/main/skills/wdk/SKILL.md).

## Capabilities

Once an agent loads the WDK skill, it can:

| Category         | Operations                                                                                                         |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Wallets**      | Create and recover wallets across EVM chains, Bitcoin, Solana, Spark, TON, and Tron                                |
| **Transactions** | Send native tokens and token transfers (ERC-20, SPL, Jetton, TRC-20)                                               |
| **Swaps**        | DEX swaps via Velora (EVM) and StonFi (TON)                                                                        |
| **Bridges**      | Cross-chain bridges with USDT0 via LayerZero                                                                       |
| **Lending**      | Supply, borrow, repay, and withdraw via Aave V3                                                                    |
| **Fiat**         | Buy and sell crypto via MoonPay on/off-ramps                                                                       |
| **Gasless**      | Fee-free transfers on TON (via paymaster) and Tron (via gas-free service), and ERC-4337 account abstraction on EVM |

{% hint style="warning" %}
All write operations require explicit human confirmation. The skill instructs agents to estimate fees before sending and includes prompt injection protection guidance.
{% endhint %}

## How It Works

1. **Install the skill** by running `npx skills add tetherto/wdk-agent-skills` and selecting the agent you prefer
2. **Agent loads the skill** and reads `SKILL.md` along with per-module reference files to learn WDK's API surface
3. **Agent executes operations** when you ask it to create a wallet or send a transaction, generating the correct WDK code
4. **You confirm** before any write operation (transactions, swaps, bridges) goes through

The skill includes security guidance: pre-transaction validation checklists, prompt injection detection rules, and mandatory key cleanup patterns.

## Self-Custodial vs Hosted

WDK's agent skills use a self-custodial model where your agent controls its own keys locally. This differs from hosted solutions where a third party manages your keys.

| Feature          | WDK                                                            | Coinbase Agentic Wallet       | Privy Server Wallets          |
| ---------------- | -------------------------------------------------------------- | ----------------------------- | ----------------------------- |
| Custody model    | Self-custodial                                                 | Coinbase-hosted               | Privy-hosted (server)         |
| Multi-chain      | Yes (EVM, Bitcoin, Solana, TON, Tron, Spark + more)            | EVM + Solana                  | EVM + Solana + Bitcoin + more |
| Open source      | Yes (SDK + skills)                                             | CLI/skills open, infra closed | Skills open, API closed       |
| MCP support      | Yes ([MCP Toolkit](https://docs.wdk.tether.io/ai/mcp-toolkit)) | Via skills                    | Via skills                    |
| OpenClaw support | Yes (`npx skills add tetherto/wdk-agent-skills`)               | Yes (npx skills)              | Yes (ClawHub skill)           |
| x402 payments    | Via [community extensions](#community-projects)                | Yes (native)                  | No                            |
| Key management   | Local / self-managed                                           | Coinbase infrastructure       | Privy infrastructure          |

## Use With Agent Platforms

| Platform                     | How to Use                                                                                                                               |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **OpenClaw**                 | Run `npx skills add tetherto/wdk-agent-skills` and select your agent. See [OpenClaw Integration](https://docs.wdk.tether.io/ai/openclaw) |
| **Claude**                   | Upload `SKILL.md` as project knowledge, or paste into conversation                                                                       |
| **Cursor / Windsurf**        | Clone to `.cursor/skills/wdk` or `.windsurf/skills/wdk`                                                                                  |
| **Any MCP-compatible agent** | Use the [MCP Toolkit](https://docs.wdk.tether.io/ai/mcp-toolkit) for structured tool calling                                             |
| **Any other agent**          | Copy `SKILL.md` into system prompt or conversation context                                                                               |

## Community Projects

Projects built by the community using WDK's agentic capabilities:

| Project                                                                                           | Description                                                  |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| [wdk-wallet-evm-x402-facilitator](https://github.com/SemanticPay/wdk-wallet-evm-x402-facilitator) | Agent-to-agent payments using the x402 HTTP payment protocol |
| [x402-usdt0](https://github.com/baghdadgherras/x402-usdt0)                                        | Reference implementation of x402 on Plasma with USDT0        |
| [Novanet zkML Guardrails](https://github.com/hshadab/tether)                                      | Zero-knowledge ML safety checks for wallet operations        |

## Resources

* [WDK SKILL.md on GitHub](https://github.com/tetherto/wdk-docs/blob/main/skills/wdk/SKILL.md) - The full skill file agents consume
* [WDK Agent Skills](https://github.com/tetherto/wdk-agent-skills) - Install via `npx skills add tetherto/wdk-agent-skills`
* [AgentSkills Specification](https://agentskills.io/specification) - The skill format standard
* [WDK MCP Toolkit](https://github.com/tetherto/wdk-mcp-toolkit) - MCP server for structured tool calling
* [WDK Core](https://github.com/tetherto/wdk-core) - The core SDK

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# OpenClaw

Give your OpenClaw AI agent a self-custodial WDK wallet in minutes

{% hint style="warning" %}
The WDK skill for OpenClaw is a community skill, developed and maintained independently by a third-party contributor.

Tether and the WDK Team do not endorse or assume responsibility for its code, security, or maintenance. Use your own judgment and proceed at your own risk. Artificial intelligence has inherent risks and limitations. You assume full responsibility for any reliance and use of artificial intelligence and agree that any such reliance and use is entirely at your own risk.
{% endhint %}

[OpenClaw](https://openclaw.ai) is an open-source AI agent platform. With the WDK community skill, your OpenClaw agent can create wallets, send transactions, swap tokens, bridge assets, and interact with DeFi protocols. Everything stays self-custodial.

{% hint style="info" %}
The WDK community skill follows the [AgentSkills specification](https://agentskills.io/specification), so it works with any compatible agent platform. This page covers the OpenClaw-specific setup.
{% endhint %}

## Install the WDK Skill

```bash
npx skills add tetherto/wdk-agent-skills
```

The installer will prompt you to select which agent skill you want to install. Pick the one that fits your use case. Once installed, OpenClaw picks it up automatically on the next session.

{% hint style="info" %}
The skill will also be published on [ClawHub](https://clawhub.ai) shortly.
{% endhint %}

## Configuration

The WDK community skill does not require environment variables. Your agent will ask for a seed phrase in conversation when it needs to create or recover a wallet. The skill passes the seed phrase as a constructor parameter in code rather than reading it from configuration.

{% hint style="warning" %}
Your seed phrase controls real funds. Never share it, commit it to version control, or expose it in logs. The skill instructs agents to never log or expose seed phrases or private keys.
{% endhint %}

## Verify It Works

Start a new OpenClaw session and try a simple prompt:

```
Create a multi-chain wallet with Ethereum and Bitcoin support, then show me the addresses.
```

The agent should use the WDK community skill to create wallet accounts and return the generated addresses. All write operations (transactions, swaps, bridges) require your explicit confirmation before executing.

<figure><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-c0e9477d714e355479afea1900c8a6e92b04be86%2Fopenclaw-wallet-output.png?alt=media" alt="OpenClaw creating a multi-chain wallet using the WDK skill"><figcaption><p>Example output from the WDK skill creating a multi-chain wallet</p></figcaption></figure>

## What Your Agent Can Do

Once the skill is loaded, your agent can:

* **Create wallets** across 20+ blockchains (EVM, Bitcoin, Solana, TON, Tron, Spark)
* **Send transactions** and token transfers
* **Swap tokens** via DEX aggregators (Velora, StonFi)
* **Bridge assets** cross-chain with USDT0
* **Lend and borrow** through Aave V3
* **Buy and sell crypto** via MoonPay fiat on/off-ramps

For the full list of capabilities and how skills work, see [Agent Skills](https://docs.wdk.tether.io/ai/agent-skills).

## Security Risks and Safety Precautions

OpenClaw is powerful because it runs on your system and can take real actions like creating files, fetching data from the web, and executing transactions. That same power can become a security risk if you're not careful about how and where you run it.

This isn't a flaw in OpenClaw. It's what happens when you give any AI agent direct system access. Knowing these risks lets you use OpenClaw safely.

### Why running OpenClaw locally requires caution

When you run OpenClaw on your own computer or a virtual server, you're allowing a chat interface to trigger actions on that system. This is a concern if your bot:

* Has access to sensitive directories
* Runs with elevated privileges
* Is connected to a publicly accessible chat
* Receives poorly scoped instructions

It can unintentionally modify files, overwrite data, or expose information you didn't intend to share. The risk isn't that OpenClaw is malicious. The risk is that it will do exactly what it's told, even when the instruction is vague or unsafe.

### How to use OpenClaw safely

To reduce risk, here are some practical safety measures:

* Run OpenClaw as a non-privileged user
* Keep its working files in a dedicated directory
* Avoid connecting it to public or shared chats initially
* Be explicit when asking it to read or write files
* Test new capabilities on a disposable system or VM

Think of OpenClaw the same way you'd think about running scripts on your system: powerful and useful, but something you need to be careful with.

### Inherent Limitations of Artificial Intelligence

OpenClaw makes use of artificial intelligence and machine learning technologies. While the use of artificial intelligence and machine learning enables capabilities, it also involves inherent limitations and risks. These include:

1. The potential for inaccurate, incomplete, unexpected or misleading outputs or actions (including so-called hallucinations)
2. The risk that outputs or actions may contain biases
3. The possibility of errors related to document quality or text recognition of inputs
4. The possibility that the outputs may suggest specific immediate or near term actions that should not be relied upon
5. The risk that OpenClaw may take unexpected actions (including the sending of assets)

## Next Steps

* [Agent Skills](https://docs.wdk.tether.io/ai/agent-skills) - Full capabilities, how skills work, and a comparison with other agentic wallet solutions
* [MCP Toolkit](https://docs.wdk.tether.io/ai/mcp-toolkit) - Programmatic wallet access for MCP-compatible agents
* [OpenClaw Skills Documentation](https://docs.openclaw.ai/tools/skills) - How OpenClaw discovers and loads skills

***

## Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# x402

Accept and make instant USD₮ payments over HTTP using WDK self-custodial wallets

## What Is x402?

[x402](https://www.x402.org) is an open payment protocol, [originally developed by Coinbase](https://docs.x402.org/), that gives the long-reserved [HTTP 402 Payment Required](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/402) status code a concrete, blockchain-native meaning: if you want this resource, pay for it. No accounts, API keys, or checkout flows. Just plain HTTP.

This matters for AI agents because they need to pay for resources programmatically. x402 makes payment a first-class part of the web stack, so an agent can discover a price, sign a payment, and receive a resource in a single request-response cycle.

### The Three Roles

| Role                         | Description                                                                                                                                 |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **Client (Buyer)**           | The entity requesting a paid resource. Can be a human application, an AI agent, or any service with a wallet.                               |
| **Resource Server (Seller)** | The API or service providing the paid resource. Defines payment requirements and returns `402` for unpaid requests.                         |
| **Facilitator**              | An intermediary that verifies payment signatures and submits transactions on-chain. Never holds funds, only executes signed authorizations. |

### How the Protocol Works

{% stepper %}
{% step %}
**Client requests a resource**

A standard HTTP request. `GET`, `POST`, whatever your API expects.
{% endstep %}

{% step %}
**Server responds with 402 Payment Required**

The response body describes what to pay: amount, token, network, and recipient address.

```json
{
  "x402Version": 1,
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:9745",
    "maxAmountRequired": "1000000",
    "asset": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "resource": "https://api.example.com/data",
    "payTo": "0x1234...abcd"
  }]
}
```

{% endstep %}

{% step %}
**Client signs a payment**

The client constructs an [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009) `transferWithAuthorization` and signs it with their wallet. No tokens leave the wallet yet. It's a signed intent, not a transfer.
{% endstep %}

{% step %}
**Client retries with payment header**

The signed payload goes in the `X-PAYMENT` header on the same request.
{% endstep %}

{% step %}
**Facilitator verifies**

The server forwards the payload to the facilitator's `/verify` endpoint. The facilitator checks that the signature is valid, the amount is sufficient, and the payer has funds. No money moves yet.
{% endstep %}

{% step %}
**Server performs the work**

Inference, database query, generation, whatever the resource requires. This only happens after verification succeeds.
{% endstep %}

{% step %}
**Facilitator settles on-chain**

The server calls the facilitator's `/settle` endpoint. The facilitator submits the signed authorization on-chain, transferring tokens from buyer to seller.
{% endstep %}

{% step %}
**Server returns the resource**

`200 OK` with the result in the body and a settlement receipt in the `X-PAYMENT-RESPONSE` header.
{% endstep %}
{% endstepper %}

For the full protocol specification, see [x402.org](https://www.x402.org) and the [x402 GitHub repository](https://github.com/coinbase/x402).

## How to Use x402 With WDK

WDK wallets work as drop-in signers for x402. `WalletAccountEvm` satisfies the client x402 signer interface directly. Self-custodial x402 payments on any EVM chain.

This guide walks through three things:

1. **Client (Buyer)** - Pay for x402-protected resources using a WDK wallet
2. **Server with Hosted Facilitator** - Accept x402 payments by delegating verification and settlement to a third-party facilitator
3. **Server with Self-Hosted Facilitator** - Run verification and settlement in-process using a WDK wallet, with no external dependencies

{% hint style="warning" %}
The x402 integration described on this page uses community-developed modules and third-party facilitator services. Tether does not endorse, operate, or assume legal or financial responsibility for any third-party facilitator. You are solely responsible for using any service.

Artificial intelligence and blockchain transactions carry inherent risks and limitations.
{% endhint %}

### Recommended Chains

x402 with WDK works on any EVM chain where USD₮0 is deployed (see full list at [docs.usdt0.to](https://docs.usdt0.to/technical-documentation/deployments)). However, we recommend **Plasma** and **Stable** for x402 payments. Both chains are purpose-built for USD₮ transfers with near-instant finality and near-zero fees. Agents only need to hold USD₮.

| Chain      | CAIP-2        | RPC                      | USD₮0 Contract                               | Explorer                                                                                    |
| ---------- | ------------- | ------------------------ | -------------------------------------------- | ------------------------------------------------------------------------------------------- |
| **Plasma** | `eip155:9745` | `https://rpc.plasma.to`  | `0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb` | [plasmascan.to](https://plasmascan.to/address/0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb)   |
| **Stable** | `eip155:988`  | `https://rpc.stable.xyz` | `0x779Ded0c9e1022225f8E0630b35a9b54bE713736` | [stablescan.xyz](https://stablescan.xyz/address/0x779Ded0c9e1022225f8E0630b35a9b54bE713736) |

***

## Client: Paying for Resources

{% hint style="info" %}
See the full working client example at [`x402/client.js`](https://github.com/SemanticPay/x402-usdt0-demo/blob/main/x402/client.js).
{% endhint %}

```bash
npm install @tetherto/wdk-wallet-evm @x402/fetch @x402/evm
```

{% stepper %}
{% step %}
**Create a wallet**

```javascript
import WalletManagerEvm from "@tetherto/wdk-wallet-evm";

const account = await new WalletManagerEvm(process.env.SEED_PHRASE, {
  provider: "https://rpc.plasma.to", // or "https://rpc.stable.xyz"
}).getAccount();
```

{% endstep %}

{% step %}
**Register with x402**

`WalletAccountEvm` satisfies the `ClientEvmSigner` interface directly. No adapter needed.

```javascript
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";

const client = new x402Client();
registerExactEvmScheme(client, { signer: account });

const fetchWithPayment = wrapFetchWithPayment(fetch, client);
```

{% endstep %}

{% step %}
**Make a paid request**

`fetchWithPayment` intercepts any `402` response, signs an EIP-3009 authorization with your WDK wallet, and retries automatically.

```javascript
const response = await fetchWithPayment("https://api.example.com/weather", {
  method: "GET",
});

const data = await response.json();
console.log("Response:", data);
```

{% endstep %}
{% endstepper %}

{% hint style="warning" %}
Your seed phrase controls your funds. Never commit it to version control. Use environment variables or a secrets manager.
{% endhint %}

### Getting USD₮0 on Plasma or Stable

Before you can make x402 payments, your wallet needs USD₮0 on the target chain. If you hold USD₮ on Ethereum (or any supported EVM chain), bridge it using `@tetherto/wdk-protocol-bridge-usdt0-evm`.

{% hint style="info" %}
The bridge uses [LayerZero](https://layerzero.network) for secure cross-chain transfers. USD₮ on Ethereum is automatically converted to USD₮0 on the destination chain.
{% endhint %}

```bash
npm install @tetherto/wdk-wallet-evm @tetherto/wdk-protocol-bridge-usdt0-evm
```

#### Bridge USD₮ from Ethereum to Plasma / Stable

{% stepper %}
{% step %}
**Create wallet and bridge protocol**

```javascript
import WalletManagerEvm from "@tetherto/wdk-wallet-evm";
import Usdt0ProtocolEvm from "@tetherto/wdk-protocol-bridge-usdt0-evm";

const account = await new WalletManagerEvm(process.env.SEED_PHRASE, {
  provider: "https://eth.drpc.org",
}).getAccount();

const bridge = new Usdt0ProtocolEvm(account, {
  bridgeMaxFee: 100000000000000n, // Max 0.0001 ETH in bridge fees
});
```

{% endstep %}

{% step %}
**Get a quote (recommended)**

```javascript
const USDT_ETHEREUM = "0xdAC17F958D2ee523a2206206994597C13D831ec7";

const quote = await bridge.quoteBridge({
  targetChain: "plasma", // or "stable"
  recipient: await account.getAddress(),
  token: USDT_ETHEREUM,
  amount: 10000000n, // 10 USD₮ (6 decimals)
});

console.log("Total cost:", Number(quote.fee + quote.bridgeFee) / 1e18, "ETH");
```

{% endstep %}

{% step %}
**Execute the bridge**

```javascript
const result = await bridge.bridge({
  targetChain: "plasma", // or "stable"
  recipient: await account.getAddress(),
  token: USDT_ETHEREUM,
  amount: 10000000n,
});

console.log("Bridge tx:", result.hash);
```

USD₮0 arrives on the destination chain within a few minutes.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
You can bridge from any of 25+ supported EVM chains, not just Ethereum. Point your wallet at the source chain's RPC and use the [USD₮ token address](https://tether.to/es/supported-protocols/) on that chain. See the full [bridge module documentation](https://docs.wdk.tether.io/sdk/bridge-modules/bridge-usdt0-evm).
{% endhint %}

***

## Server: Accepting Payments (Hosted Facilitator)

Your server delegates verification and settlement to a hosted facilitator. You never interact with the chain directly.

{% hint style="info" %}
**About the Semantic facilitator:** [Semantic](https://docs.semanticpay.io) operates a public USD₮-enabled x402 facilitator at `https://x402.semanticpay.io`. This is a third-party service not operated, endorsed, or guaranteed by Tether.

The x402 protocol is an open standard. Anyone can build and host their own facilitator. For the API reference, see the [Semantic facilitator docs](https://docs.semanticpay.io/endpoints).

See the full working server example at [`x402/server.js`](https://github.com/SemanticPay/x402-usdt0-demo/blob/main/x402/server.js).
{% endhint %}

```bash
npm install @tetherto/wdk-wallet-evm @x402/express @x402/evm @x402/core express dotenv
```

{% stepper %}
{% step %}
**Derive your receiving address**

```javascript
import WalletManagerEvm from "@tetherto/wdk-wallet-evm";

const account = await new WalletManagerEvm(process.env.SEED_PHRASE, {
  provider: "https://rpc.plasma.to", // or "https://rpc.stable.xyz"
}).getAccount();

const sellerAddress = await account.getAddress();
```

{% endstep %}

{% step %}
**Create the facilitator client**

```javascript
import { HTTPFacilitatorClient } from "@x402/core/server";

const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.semanticpay.io/",
});
```

{% endstep %}

{% step %}
**Configure payment middleware**

```javascript
import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";

const PLASMA_NETWORK = "eip155:9745";   // or "eip155:988" for Stable
const USDT0_PLASMA = "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb";   // or "0x779Ded0c9e1022225f8E0630b35a9b54bE713736" on Stable

const app = express();

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            network: PLASMA_NETWORK,
            price: {
              amount: "1000", // $0.001 (6 decimals)
              asset: USDT0_PLASMA,
              extra: { name: "USDT0", version: "1", decimals: 6 },
            },
            payTo: sellerAddress,
          },
        ],
        description: "Weather data",
        mimeType: "application/json",
      },
    },
    new x402ResourceServer(facilitatorClient).register(
      PLASMA_NETWORK,
      new ExactEvmScheme(),
    ),
  ),
);
```

{% hint style="info" %}
The `extra` fields are passed to the buyer for EIP-712 signature construction. `name` and `version` must match what the on-chain USD₮0 contract expects.
{% endhint %}
{% endstep %}

{% step %}
**Add your routes**

```javascript
// Gated - requires payment
app.get("/weather", (req, res) => {
  res.json({ weather: "sunny", temperature: 70 });
});

// Not gated - no payment config
app.get("/health", (req, res) => {
  res.json({ status: "ok" });
});

app.listen(4021);
```

Routes not listed in the middleware config behave like normal Express routes.
{% endstep %}
{% endstepper %}

### Multi-Chain (Plasma + Stable)

To accept payments on both chains, add both networks to the `accepts` array and register both with the resource server. The buyer's client picks whichever network it has funds on.

```javascript
const NETWORKS = {
  plasma: { network: "eip155:9745", usdt0: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb" },
  stable: { network: "eip155:988",  usdt0: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736" },
};

const resourceServer = new x402ResourceServer(facilitatorClient)
  .register(NETWORKS.plasma.network, new ExactEvmScheme())
  .register(NETWORKS.stable.network, new ExactEvmScheme());

// In paymentMiddleware config:
// accepts: [
//   { scheme: "exact", network: NETWORKS.plasma.network, price: priceOnChain("plasma"), payTo },
//   { scheme: "exact", network: NETWORKS.stable.network, price: priceOnChain("stable"), payTo },
// ]
```

### Lifecycle Events

The Semantic facilitator supports an optional `X-Event-Callback` header. When provided, the facilitator POSTs real-time events to your callback URL during verification and settlement.

| Type               | When                              | Key Fields                          |
| ------------------ | --------------------------------- | ----------------------------------- |
| `verify_started`   | Facilitator begins verifying      | `details.network`, `details.checks` |
| `verify_completed` | Verification finished             | `details.isValid`                   |
| `verify_failed`    | Verification error                | `details.error`                     |
| `settle_started`   | Broadcasting on-chain transaction | `details.network`                   |
| `settle_completed` | Transaction confirmed             | `details.transactionHash`           |
| `settle_failed`    | Settlement error                  | `details.error`                     |

```javascript
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.semanticpay.io/",
  fetch: (url, init) =>
    fetch(url, {
      ...init,
      headers: { ...init?.headers, "X-Event-Callback": "http://localhost:4021/payment-events" },
    }),
});
```

{% hint style="info" %}
Events are fire-and-forget. If the callback URL is unreachable, events are silently dropped.
{% endhint %}

***

## Server: Self-Hosted Facilitator (In-Process)

Instead of relying on a hosted facilitator, you can run verification and settlement in-process using the `@semanticio/wdk-wallet-evm-x402-facilitator` community module. This wraps a WDK wallet as an x402 `FacilitatorEvmSigner`. Your server handles the entire payment lifecycle locally.

{% hint style="success" %}
Unlike the hosted Semantic facilitator (Plasma and Stable only), a self-hosted facilitator works with **any EVM chain where USD₮0 is deployed**. See the full deployment list at [docs.usdt0.to](https://docs.usdt0.to/technical-documentation/deployments).
{% endhint %}

{% hint style="warning" %}
`@semanticio/wdk-wallet-evm-x402-facilitator` is a community module developed and maintained by [Semantic Pay](https://www.semanticpay.io). Tether does not endorse, audit, or assume responsibility for this module. It is currently in beta. Test thoroughly before using in production.
{% endhint %}

{% hint style="info" %}
See the full working self-hosted server example at [`x402/server-inprocess.js`](https://github.com/SemanticPay/x402-usdt0-demo/blob/main/x402/server-inprocess.js).
{% endhint %}

```bash
npm install @semanticio/wdk-wallet-evm-x402-facilitator @tetherto/wdk-wallet-evm @x402/core @x402/evm @x402/express express dotenv
```

{% stepper %}
{% step %}
**Create the facilitator signer**

The facilitator wallet submits settlement transactions on-chain. It needs gas tokens on the target chain.

```javascript
import WalletManagerEvm from "@tetherto/wdk-wallet-evm";
import WalletAccountEvmX402Facilitator from "@semanticio/wdk-wallet-evm-x402-facilitator";

const walletAccount = await new WalletManagerEvm(process.env.FACILITATOR_MNEMONIC, {
  provider: process.env.RPC_URL, // Any EVM chain with USD₮0
}).getAccount();

const evmSigner = new WalletAccountEvmX402Facilitator(walletAccount);
```

{% hint style="info" %}
The facilitator wallet and the seller wallet can use different seed phrases. The facilitator pays gas; the seller receives USD₮. The facilitator wallet must have enough native token to pay gas.
{% endhint %}
{% endstep %}

{% step %}
**Initialize the facilitator**

```javascript
import { x402Facilitator } from "@x402/core/facilitator";
import { registerExactEvmScheme } from "@x402/evm/exact/facilitator";

const facilitator = new x402Facilitator()
  .onAfterVerify(async (ctx) => {
    console.log("[verify]", ctx.result?.isValid ? "valid" : "invalid");
  })
  .onAfterSettle(async (ctx) => {
    console.log("[settle] tx:", ctx.result?.transaction);
  });

registerExactEvmScheme(facilitator, {
  signer: evmSigner,
  networks: process.env.NETWORK_ID, // e.g. "eip155:9745"
});
```

Available hooks: `onBeforeVerify`, `onAfterVerify`, `onBeforeSettle`, `onAfterSettle`. All are `async` and receive a context object with the payment payload and result.
{% endstep %}

{% step %}
**Wire into Express**

Same `paymentMiddleware` pattern, but pass the in-process `facilitator` directly instead of an `HTTPFacilitatorClient`.

```javascript
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";

const NETWORK = process.env.NETWORK_ID || "eip155:9745";          // Stable: "eip155:988"
const USDT0 = process.env.USDT0_ADDRESS || "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"; // Stable: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736"

const resourceServer = new x402ResourceServer(facilitator).register(
  NETWORK,
  new ExactEvmScheme(),
);

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [{
          scheme: "exact",
          network: NETWORK,
          price: { amount: "1000", asset: USDT0, extra: { name: "USDT0", version: "1", decimals: 6 } },
          payTo: process.env.PAY_TO_ADDRESS,
        }],
        description: "Weather data",
        mimeType: "application/json",
      },
    },
    resourceServer,
  ),
);
```

{% endstep %}
{% endstepper %}

***

## Summary

| Role                     | Packages                                                                                                              | Notes                                                                   |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| **Buyer (Client)**       | `@tetherto/wdk-wallet-evm`, `@x402/fetch`, `@x402/evm`                                                                | `WalletAccountEvm` satisfies `ClientEvmSigner` directly.                |
| **Seller (Hosted)**      | `@tetherto/wdk-wallet-evm`, `@x402/express`, `@x402/evm`, `@x402/core`                                                | Delegates to a hosted facilitator. Semantic supports Plasma and Stable. |
| **Seller (Self-Hosted)** | `@tetherto/wdk-wallet-evm`, `@semanticio/wdk-wallet-evm-x402-facilitator`, `@x402/core`, `@x402/evm`, `@x402/express` | In-process facilitator. Any USD₮0 chain.                                |

***

## Resources

* [x402 Protocol Spec](https://www.x402.org) - The open standard specification
* [x402 GitHub](https://github.com/coinbase/x402) - Reference implementations and examples
* [Semantic Facilitator Docs](https://docs.semanticpay.io) - API reference for the hosted facilitator
* [Self-Hosted Facilitator Module](https://www.npmjs.com/package/@semanticio/wdk-wallet-evm-x402-facilitator) - Community in-process facilitator
* [x402-usdt0 Demo](https://github.com/SemanticPay/x402-usdt0-demo) - Full working buyer + seller demo
* [WDK EVM Wallet Module](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm) - WDK EVM wallet documentation
* [USD₮0 Deployments](https://docs.usdt0.to/technical-documentation/deployments) - Contract addresses on all chains
* [EIP-3009 Specification](https://eips.ethereum.org/EIPS/eip-3009) - The authorization standard enabling gasless USD₮ transfers


# Get Started

Learn about the SDK and modules architecture

The SDK is a comprehensive, modular plug-in framework designed to simplify multi-chain wallet development.

It is built on some core principles: **self-custodial and stateless** (private keys never leave your app and no data is stored by WDK), **unified interface** (consistent API across all blockchains), and **cross-platform compatibility** (works seamlessly from Node.js to React Native to embedded systems).

#### Capabilities

* **Multi-Chain Support**: Bitcoin, Ethereum, TON, TRON, Solana, Spark, and more
* **Account Abstraction**: Gasless transactions on supported chains
* **DeFi Integration**: Plug-in support for swaps, bridges, and lending protocols
* **Extensible Design**: Add custom modules for new blockchains or protocols

***

### Modular Architecture

WDK's architecture is built around the concept of composable modules. Each module is a specialized component that handles specific functionality, allowing you to build exactly what you need without unnecessary complexity.

Each module has a single responsibility. Wallet modules handle blockchain operations, protocol modules manage DeFi interactions, and the core module orchestrates everything.

New functionality is added through modules rather than modifying core code. Also, modules are configured through simple objects, making them easy to customize for different environments and use cases.

***

#### Module Types

WDK modules are organized into five main categories, each serving a specific purpose in the blockchain application stack:

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Core</strong></td><td>Main orchestrator and shared utilities</td><td><a href="core-module">core-module</a></td></tr><tr><td><strong>Wallet</strong></td><td>Blockchain-specific wallet operations</td><td><a href="wallet-modules">wallet-modules</a></td></tr><tr><td><strong>Swap</strong></td><td>Token swapping across DEXs</td><td><a href="swap-modules">swap-modules</a></td></tr><tr><td><strong>Bridge</strong></td><td>Cross-chain asset transfers</td><td><a href="bridge-modules">bridge-modules</a></td></tr><tr><td><strong>Lending</strong></td><td>DeFi lending and borrowing</td><td><a href="lending-modules">lending-modules</a></td></tr></tbody></table>

***

### How to use the SDK

The WDK SDK uses a registration-based system where modules are added to a central orchestrator. This creates a unified interface while maintaining module independence.

#### Registration Flow

**1. Core Module Initialization**

{% code title="Initialize WDK" lineNumbers="true" %}

```typescript
import WDK from '@tetherto/wdk'

// Generate 24-word seed phrase for higher security
const seedPhrase = WDK.getRandomSeedPhrase(24)

// Or use 12-word seed phrase (default)
// const seedPhrase = WDK.getRandomSeedPhrase()


const wdk = new WDK(seedPhrase)
```

{% endcode %}

**2. Wallet Module Registration**

{% code title="Register Wallets" lineNumbers="true" %}

```typescript
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'

const wdkWithWallets = wdk
  .registerWallet('ethereum', WalletManagerEvm, {
    provider: 'https://eth.drpc.org'
  })
  .registerWallet('bitcoin', WalletManagerBtc, {
    provider: 'https://blockstream.info/api'
  })
```

{% endcode %}

**3. Protocol Module Registration**

{% code title="Register Protocols" lineNumbers="true" %}

```typescript
import SwapveloraEvm from '@tetherto/wdk-protocol-swap-velora-evm'

const wdkWithProtocols = wdkWithWallets
  .registerProtocol('swap-velora-evm', SwapveloraEvm)
```

{% endcode %}

#### Unified Operations

Once registered, all modules work through the same interface:

{% code title="Unified Operations" lineNumbers="true" %}

```typescript
// Get accounts from different blockchains using the same method
const ethAccount = await wdkWithProtocols.getAccount('ethereum', 0)
const btcAccount = await wdkWithProtocols.getAccount('bitcoin', 0)

// Check balances using unified interface
const ethBalance = await ethAccount.getBalance()
const btcBalance = await btcAccount.getBalance()

// Send transactions with consistent API
const ethTx = await ethAccount.sendTransaction({
  to: '0x...',
  value: '1000000000000000000'
})

const btcTx = await btcAccount.sendTransaction({
  to: '1A1z...',
  value: 100000000
})

// Use DeFi protocols through the same interface
const swapResult = await wdkWithProtocols.executeProtocol('swap-velora-evm', {
  fromToken: 'ETH',
  toToken: 'USDT',
  amount: '1000000000000000000'
})
```

{% endcode %}

***

### Creating Custom Modules

{% hint style="success" %}
**Recommended**: Use the `create-wdk-module` CLI to scaffold a new module with all the boilerplate in place:

```bash
npx @tetherto/create-wdk-module@latest
```

See the [Create WDK Module](https://docs.wdk.tether.io/tools/create-wdk-module) page for the full guide, CLI options, and generated project structure.
{% endhint %}

WDK's modular architecture makes it straightforward to add support for new blockchains or protocols. Each module type has a specific interface that must be implemented.

#### Wallet Module Interface

{% code title="Custom Wallet Module Setup" lineNumbers="true" %}

```typescript
interface WalletModule {
  // Account management
  getAccount(index: number): Promise<Account>
  getAddress(index: number): Promise<string>
  getBalance(index: number): Promise<BigNumber>
  
  // Transaction operations
  sendTransaction(params: TransactionParams): Promise<TransactionResult>
  estimateTransaction(params: TransactionParams): Promise<TransactionQuote>
  
  // Key management
  signMessage(message: string, index: number): Promise<string>
  verifySignature(message: string, signature: string, address: string): Promise<boolean>
  
  // Blockchain-specific operations
  getTransactionHistory(index: number, limit?: number): Promise<Transaction[]>
  getTokenBalance(index: number, tokenAddress: string): Promise<BigNumber>
}
```

{% endcode %}

#### Protocol Module Interface

{% code title="Custom Protocol Module Setup" lineNumbers="true" %}

```typescript
interface ProtocolModule {
  // Protocol execution
  execute(params: ProtocolParams): Promise<ProtocolResult>
  estimate(params: ProtocolParams): Promise<ProtocolQuote>
  
  // Supported operations
  getSupportedTokens(): Promise<Token[]>
  getSupportedChains(): Promise<Chain[]>
  getOperationTypes(): Promise<OperationType[]>
  
  // Protocol-specific methods
  getLiquidityPools?(): Promise<Pool[]>
  getLendingRates?(): Promise<Rate[]>
  getBridgeRoutes?(): Promise<Route[]>
}
```

{% endcode %}

#### Module Implementation Example

{% code title="Custom Wallet Module Implementation" lineNumbers="true" %}

```typescript
class CustomWalletModule implements WalletModule {
  private provider: string
  private chainId: number
  
  constructor(config: { provider: string; chainId: number }) {
    this.provider = config.provider
    this.chainId = config.chainId
  }
  
  async getAccount(index: number): Promise<Account> {
    // Implement account derivation logic
    const privateKey = await this.derivePrivateKey(index)
    return new CustomAccount(privateKey, this.provider)
  }
  
  async getAddress(index: number): Promise<string> {
    const account = await this.getAccount(index)
    return account.getAddress()
  }
  
  async getBalance(index: number): Promise<BigNumber> {
    const address = await this.getAddress(index)
    // Implement balance fetching logic
    const balance = await this.fetchBalance(address)
    return new BigNumber(balance)
  }
  
  async sendTransaction(params: TransactionParams): Promise<TransactionResult> {
    // Implement transaction sending logic
    const account = await this.getAccount(params.accountIndex)
    const tx = await account.sendTransaction(params)
    return tx
  }
  
  // Additional methods...
}
```

{% endcode %}

#### Module Registration

{% code title="Custom Wallet Module Registration" lineNumbers="true" %}

```typescript
// Register your custom module
const wdkWithCustom = wdk.registerWallet('custom-chain', CustomWalletModule, {
  provider: 'https://custom-rpc-endpoint.com',
  chainId: 12345
})

// Use it like any other module
const customAccount = await wdkWithCustom.getAccount('custom-chain', 0)
const balance = await customAccount.getBalance()
```

{% endcode %}

{% hint style="info" %}
**Learn More**: For detailed information on creating custom modules, check out the [Create WDK Module](https://docs.wdk.tether.io/tools/create-wdk-module) tool and the [Community Modules](https://github.com/tetherto/wdk-docs/blob/main/community-modules/README.md) page.
{% endhint %}

***

### Quick Start Paths

Ready to start building? Choose your development environment:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../start-building/react-native-quickstart">react-native-quickstart</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# All Modules

Complete list of all available WDK modules including wallet, swap, bridge, lending, and fiat modules.

A comprehensive list of all available WDK modules. Each module is designed to be modular and can be used independently or combined with others.

## Core Module

The orchestrator that manages all WDK modules.

| Module                                                       | Description                              | Documentation                                      |
| ------------------------------------------------------------ | ---------------------------------------- | -------------------------------------------------- |
| [`@tetherto/wdk-core`](https://github.com/tetherto/wdk-core) | Central orchestrator for all WDK modules | [Docs](https://docs.wdk.tether.io/sdk/core-module) |

## Wallet Modules

Wallet modules provide blockchain-specific wallet functionality for managing addresses, balances, and transactions.

| Module                                                                                     | Blockchain | Description                                      | Documentation                                                             |
| ------------------------------------------------------------------------------------------ | ---------- | ------------------------------------------------ | ------------------------------------------------------------------------- |
| [`@tetherto/wdk-wallet-btc`](https://github.com/tetherto/wdk-wallet-btc)                   | Bitcoin    | Bitcoin SegWit wallet with BIP-39/BIP-44 support | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc)          |
| [`@tetherto/wdk-wallet-evm`](https://github.com/tetherto/wdk-wallet-evm)                   | EVM        | Ethereum and EVM-compatible chains wallet        | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm)          |
| [`@tetherto/wdk-wallet-evm-erc4337`](https://github.com/tetherto/wdk-wallet-evm-erc-4337)  | EVM        | ERC-4337 Account Abstraction for EVM chains      | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337) |
| [`@tetherto/wdk-wallet-ton`](https://github.com/tetherto/wdk-wallet-ton)                   | TON        | TON blockchain wallet                            | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton)          |
| [`@tetherto/wdk-wallet-ton-gasless`](https://github.com/tetherto/wdk-wallet-ton-gasless)   | TON        | Gasless transactions on TON                      | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless)  |
| [`@tetherto/wdk-wallet-tron`](https://github.com/tetherto/wdk-wallet-tron)                 | TRON       | TRON blockchain wallet                           | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron)         |
| [`@tetherto/wdk-wallet-tron-gasfree`](https://github.com/tetherto/wdk-wallet-tron-gasfree) | TRON       | Gas-free transactions on TRON                    | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron-gasfree) |
| [`@tetherto/wdk-wallet-solana`](https://github.com/tetherto/wdk-wallet-solana)             | Solana     | Solana blockchain wallet                         | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana)       |
| [`@tetherto/wdk-wallet-spark`](https://github.com/tetherto/wdk-wallet-spark)               | Spark      | Spark/Lightning Bitcoin L2 wallet                | [Docs](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark)        |

## Swap Modules

DEX swap functionality for token exchanges.

| Module                                                                                               | Blockchain | Description                       | Documentation                                                       |
| ---------------------------------------------------------------------------------------------------- | ---------- | --------------------------------- | ------------------------------------------------------------------- |
| [`@tetherto/wdk-protocol-swap-velora-evm`](https://github.com/tetherto/wdk-protocol-swap-velora-evm) | EVM        | DEX aggregator swap on EVM chains | [Docs](https://docs.wdk.tether.io/sdk/swap-modules/swap-velora-evm) |

## Bridge Modules

Cross-chain bridge functionality for token transfers between blockchains.

| Module                                                                                                 | Route               | Description                                                           | Documentation                                                          |
| ------------------------------------------------------------------------------------------------------ | ------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [`@tetherto/wdk-protocol-bridge-usdt0-evm`](https://github.com/tetherto/wdk-protocol-bridge-usdt0-evm) | EVM → EVM + Non-EVM | USD₮0 bridging from EVM source chains to EVM and non-EVM destinations | [Docs](https://docs.wdk.tether.io/sdk/bridge-modules/bridge-usdt0-evm) |

## Lending Modules

DeFi lending and borrowing functionality.

| Module                                                                                                 | Blockchain | Description                       | Documentation                                                           |
| ------------------------------------------------------------------------------------------------------ | ---------- | --------------------------------- | ----------------------------------------------------------------------- |
| [`@tetherto/wdk-protocol-lending-aave-evm`](https://github.com/tetherto/wdk-protocol-lending-aave-evm) | EVM        | Aave protocol integration for EVM | [Docs](https://docs.wdk.tether.io/sdk/lending-modules/lending-aave-evm) |

## Fiat Modules

On-ramp and off-ramp functionality for fiat currency integration.

| Module                                                                                         | Provider | Description                          | Documentation                                                    |
| ---------------------------------------------------------------------------------------------- | -------- | ------------------------------------ | ---------------------------------------------------------------- |
| [`@tetherto/wdk-protocol-fiat-moonpay`](https://github.com/tetherto/wdk-protocol-fiat-moonpay) | MoonPay  | MoonPay integration for fiat on-ramp | [Docs](https://docs.wdk.tether.io/sdk/fiat-modules/fiat-moonpay) |

## Community Modules

Modules built by the WDK community. See the [Community Modules](https://docs.wdk.tether.io/sdk/community-modules) page for more details.

| Module                                                                      | Blockchain    | Description                     | Documentation                                              |
| --------------------------------------------------------------------------- | ------------- | ------------------------------- | ---------------------------------------------------------- |
| [`@utexo/wdk-wallet-rgb`](https://github.com/UTEXO-Protocol/wdk-wallet-rgb) | Bitcoin (RGB) | RGB protocol wallet integration | [GitHub](https://github.com/UTEXO-Protocol/wdk-wallet-rgb) |


# Core Module

Overview of the @tetherto/wdk-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

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core Configuration</strong></td><td>Get started with WDK's configuration</td><td><a href="core-module/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core API</strong></td><td>Get started with WDK's API</td><td><a href="core-module/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core Usage</strong></td><td>Get started with WDK's usage</td><td><a href="core-module/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the WDK Core module.

The WDK Core module is the central orchestrator for your wallet interactions.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Getting Started</strong></td><td>Install and instantiate the WDK.</td><td><a href="usage/getting-started">getting-started</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Register Wallets</strong></td><td>Connect specific blockchains (Ethereum, TON, etc.).</td><td><a href="usage/wallet-registration">wallet-registration</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Retrieve accounts and check balances.</td><td><a href="usage/account-management">account-management</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send Transactions</strong></td><td>Transfer native tokens.</td><td><a href="usage/transactions">transactions</a></td></tr><tr><td><i class="fa-plug">:plug:</i></td><td><strong>Integrate Protocols</strong></td><td>Use Swap, Bridge, and Lending protocols.</td><td><a href="usage/protocol-integration">protocol-integration</a></td></tr><tr><td><i class="fa-layer-group">:layer-group:</i></td><td><strong>Configure Middleware</strong></td><td>Add logging and failover protection.</td><td><a href="usage/middleware">middleware</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Error Handling</strong></td><td>Best practices for security and stability.</td><td><a href="usage/error-handling">error-handling</a></td></tr></tbody></table>


# Getting Started

Install and instantiate the WDK Core module.

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:

{% code title="Import WDK Core" lineNumbers="true" %}

```typescript
import WDK from '@tetherto/wdk'
```

{% endcode %}

### 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.

{% code title="Create new WDK Instance" lineNumbers="true" %}

```typescript
// 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)
```

{% endcode %}

{% hint style="danger" %}
**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.
{% endhint %}

#### 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.

{% code title="Restore WDK Instance" lineNumbers="true" %}

```typescript
// 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)
```

{% endcode %}

## Next Steps

With your WDK instance ready, you can now [register wallet modules](https://docs.wdk.tether.io/sdk/core-module/usage/wallet-registration) to interact with specific blockchains like [Ethereum](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm), [TON](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton), or [Bitcoin](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc).


# Register Wallets

Learn how to register wallet modules for different blockchains.

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](https://docs.wdk.tether.io/sdk/api-reference#registerwalletblockchain-wallet-config)) 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](https://docs.wdk.tether.io/sdk/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:

{% code title="Import Modules" lineNumbers="true" %}

```typescript
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTron from '@tetherto/wdk-wallet-tron'
import WalletManagerBtc from '@tetherto/wdk-wallet-btc'
```

{% endcode %}

### Register the Wallets

Then, [instantiate WDK](https://docs.wdk.tether.io/sdk/core-module/getting-started#initialize-wdk) and chain the registration calls:

{% code title="Register Wallets" lineNumbers="true" %}

```typescript
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'
  })
```

{% endcode %}

{% hint style="info" %}
**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.
  {% endhint %}

{% hint style="info" %}
**TRON Networks:** Choose the correct provider for your environment.

* **Mainnet:** `https://api.trongrid.io`
* **Shasta (Testnet):** `https://api.shasta.trongrid.io`
  {% endhint %}

## Next Steps

Once your wallets are registered, you can [manage accounts and specific addresses](https://docs.wdk.tether.io/sdk/core-module/usage/account-management).


# Account Management

Learn how to work with accounts and addresses.

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.

{% code title="Get Account by Index" lineNumbers="true" %}

```typescript
// Get the first account (index 0) for Ethereum and TON
const ethAccount = await wdk.getAccount('ethereum', 0)
const tonAccount = await wdk.getAccount('ton', 0)
```

{% endcode %}

### By Derivation Path (Advanced)

If you need a specific hierarchy, you can request an account by its unique derivation path.

{% code title="Get Account by Path" lineNumbers="true" %}

```typescript
// Custom path for Ethereum
const customEthAccount = await wdk.getAccountByPath('ethereum', "0'/0/1")
```

{% endcode %}

{% hint style="info" %}
The WDK instance caches accounts. If you call `getAccount` twice using the same index, the function will return the same `Account` object instance.
{% endhint %}

{% hint style="warning" %}
**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.
  {% endhint %}

## View Addresses

Once you have an account object, you can retrieve its public blockchain address using the `getAddress` function.

{% code title="Get Addresses" lineNumbers="true" %}

```typescript
const ethAddress = await ethAccount.getAddress()
console.log('Ethereum address:', ethAddress)
```

{% endcode %}

## 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.

{% code title="Get Balance" lineNumbers="true" %}

```typescript
try {
  const balance = await ethAccount.getBalance()
  console.log('Balance:', balance)
} catch (error) {
  console.error('Failed to fetch balance:', error)
}
```

{% endcode %}

### 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.

{% code title="Check All Balances" lineNumbers="true" %}

```typescript
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`)
  }
}
```

{% endcode %}

## Next Steps

Now that you can access your accounts, learn how to [send transactions](https://docs.wdk.tether.io/sdk/core-module/usage/transactions).


# Send Transactions

Learn how to send native tokens on different blockchains.

You can send native tokens (like ETH, TON, or BTC) from any of your wallet accounts to another address.

{% hint style="info" %}
**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](https://docs.wdk.tether.io/resources-and-guides/concepts#testnet-funds--faucets) for a list of available faucets.
{% endhint %}

{% hint style="warning" %}
**BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers.
{% endhint %}

## 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

{% hint style="info" %}
On EVM chains, values are typically expressed in Wei (1 ETH = 10^18 Wei).
{% endhint %}

The following example will:

1. Retrieve the first Ethereum account (see [Manage Accounts](https://docs.wdk.tether.io/sdk/core-module/usage/account-management))
2. Send 0.001 ETH (1000000000000000 wei) to an account using `sendTransaction`.

{% code title="Send ETH" lineNumbers="true" %}

```typescript
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)
```

{% endcode %}

### TON Example

{% hint style="info" %}
On TON, values are expressed in Nanotons (1 TON = 10^9 Nanotons).
{% endhint %}

The following example will:

1. Retrieve the first TON account
2. Send 1 TON (1000000000 nton) to an account using `sendTransaction`.

{% code title="Send TON" lineNumbers="true" %}

```typescript
// 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)
```

{% endcode %}

## Handling Responses

The `sendTransaction` method returns a [transaction result object](https://docs.wdk.tether.io/sdk/core-module/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.

{% code title="Multi-Chain Payment" lineNumbers="true" %}

```typescript
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
  })
}
```

{% endcode %}

## Next Steps

For more complex interactions like swapping tokens or bridging assets, learn how to [integrate protocols](https://docs.wdk.tether.io/sdk/core-module/usage/protocol-integration).


# Protocol Integration

Learn how to use Swaps, Bridges, and Lending protocols.

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:

{% code title="Import Protocols" lineNumbers="true" %}

```typescript
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'
```

{% endcode %}

Then, register the protocols for the specific chains they support:

{% code title="Register Protocols" lineNumbers="true" %}

```typescript
// 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
  })
```

{% endcode %}

## 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.

{% code title="Swap Tokens" lineNumbers="true" %}

```typescript
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
})
```

{% endcode %}

### Bridging Assets

1. Use `getBridgeProtocol` to access cross-chain bridges.
2. Call `bridge` from the bridge protocol to send tokens from one protocol to another.

{% code title="Bridge Assets" lineNumbers="true" %}

```typescript
const ethAccount = await wdk.getAccount('ethereum', 0)
const usdt0 = ethAccount.getBridgeProtocol('usdt0')

const result = await usdt0.bridge({
  targetChain: 'ton',
  recipient: 'UQBla...', // TON address
  token: '0x...', // ERC20 Token Address
  amount: 1000000n
})
```

{% endcode %}

{% hint style="info" %}
**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.
{% endhint %}

## Next Steps

Learn how to [configure middleware](https://docs.wdk.tether.io/sdk/core-module/usage/middleware) to add logging or failover protection to your wallet interactions.


# Middleware

Learn how to intercept and enhance wallet operations with 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.

{% code title="Logging Middleware" lineNumbers="true" %}

```typescript
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
})
```

{% endcode %}

## 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.

{% code title="Failover Wrapper Usage" lineNumbers="true" %}

```typescript
import { createFallbackWallet } from '@tetherto/wdk-provider-failover'
import { WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'

const wallet = createFallbackWallet(
  WalletAccountReadOnlyEvm,
  ['0x...'], // constructor args
  {
    primary: { provider: 'https://eth.drpc.org' },
    fallbacks: [
      { provider: 'https://eth.llamarpc.com' },
      { provider: 'https://ethereum.publicnode.com' }
    ]
  }
)

// Use the wallet instance directly
const balance = await wallet.getBalance()
```

{% endcode %}

## Next Steps

Learn about [error handling and best practices](https://docs.wdk.tether.io/sdk/core-module/usage/error-handling) to ensure your application is robust and secure.


# Error Handling

Learn about common errors and 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.

{% code title="Check Registration Pattern" lineNumbers="true" %}

```typescript
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)
}
```

{% endcode %}

{% hint style="info" %}
Always use `try/catch` blocks when initializing sessions or accessing dynamic features.
{% endhint %}

## Memory Management

For security, you should clear sensitive data from memory when a session is complete. The WDK provides a `.dispose()` method for this purpose.

### Disposing the Instance

Calling `dispose()` clears the seed phrase and private keys derived in memory.

{% code title="Dispose WDK" lineNumbers="true" %}

```typescript
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.')
}
```

{% endcode %}

{% hint style="warning" %}
**After Disposal:** Once disposed, any attempt to use the `wdk` instance or its derived accounts will result in an error. You must instantiate a new instance to resume operations.
{% endhint %}

## 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).


# Configuration

Configuration options and settings for @tetherto/wdk

## WDK Manager Configuration

{% code title="Create WDK Instance" lineNumbers="true" %}

```javascript
import WDK from '@tetherto/wdk'

const wdk = new WDK(seedPhrase)
```

{% endcode %}

The WDK Manager itself only requires a seed phrase for initialization. Configuration is done through the registration of wallets and protocols.

## Wallet Registration Configuration

{% code title="Register WDK Wallet" lineNumbers="true" %}

```javascript
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'
  })
```

{% endcode %}

## Protocol Registration Configuration

{% code title="Register WDK Protocol" lineNumbers="true" %}

```javascript
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'

const wdk = new WDK(seedPhrase)
  .registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
    apiKey: 'YOUR_velora_API_KEY'
  })
```

{% endcode %}

## 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

{% code title="Ethereum WDK Wallet Configuration" lineNumbers="true" %}

```javascript
const ethereumWalletConfig = {
  provider: 'https://eth.drpc.org', // RPC endpoint
  // Additional EVM-specific configuration options
}

wdk.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
```

{% endcode %}

#### TON Wallet Configuration

{% code title="TON WDK Wallet Configuration" lineNumbers="true" %}

```javascript
const tonWalletConfig = {
  tonClient: {
    secretKey: 'YOUR_TON_API_KEY',
    url: 'https://toncenter.com/api/v2/jsonRPC'
  }
}

wdk.registerWallet('ton', WalletManagerTon, tonWalletConfig)
```

{% endcode %}

### Protocol Configuration

Protocols also require their own configuration objects when registered.

#### Swap Protocol Configuration

{% code title="Swap WDK Protocol Configuration" lineNumbers="true" %}

```javascript
const veloraProtocolConfig = {
  apiKey: 'YOUR_velora_API_KEY',
  baseUrl: 'https://apiv5.velora.io'
}

wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, veloraProtocolConfig)
```

{% endcode %}

### Middleware Configuration

Middleware functions can be registered to enhance account functionality.

{% code title="Middleware WDK Protocol Configuration" lineNumbers="true" %}

```javascript
// Simple logging middleware
wdk.registerMiddleware('ethereum', async (account) => {
  console.log('New account created:', await account.getAddress())
})
```

{% endcode %}

## Environment Variables

For production applications, consider using environment variables for sensitive configuration:

{% code title="WDK environment variables Configuration" lineNumbers="true" %}

```javascript
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
  })
```

{% endcode %}

## 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:

{% code title="Configuration errors" lineNumbers="true" %}

```javascript
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)
}
```

{% endcode %}

***

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core Usage</strong></td><td>Get started with WDK's usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core API</strong></td><td>Get started with WDK's API</td><td><a href="api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>Wallet Modules</strong></td><td>Explore blockchain-specific wallet modules</td><td><a href="../wallet-modules">wallet-modules</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>Bridge Modules</strong></td><td>Cross-chain USD₮0 bridges</td><td><a href="../bridge-modules">bridge-modules</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk

## Table of Contents

| Class                                                       | Description                                                                                                 | Methods                                          |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| [WDK](#wdk)                                                 | Main class for managing wallets across multiple blockchains. Orchestrates wallet managers and protocols.    | [Constructor](#constructor), [Methods](#methods) |
| [IWalletAccountWithProtocols](#iwalletaccountwithprotocols) | Extended wallet account interface that supports protocol registration and access. Extends `IWalletAccount`. | [Methods](#methods-1)                            |

## WDK

The main class for managing wallets across multiple blockchains. This class serves as an orchestrator that allows you to register different wallet managers and protocols, providing a unified interface for multi-chain operations.

### Constructor

{% code title="Constructor" lineNumbers="true" %}

```javascript
new WDK(seed)
```

{% endcode %}

**Parameters:**

* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes

**Example:**

{% code title="Initialize WDK" lineNumbers="true" %}

```javascript
import WDK from '@tetherto/wdk'

// With seed phrase
const wdk = new WDK('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about')

// With seed bytes
const seedBytes = new Uint8Array([...])
const wdk2 = new WDK(seedBytes)
```

{% endcode %}

### Methods

| Method                                                  | Description                                                   | Returns                                | Throws                   |
| ------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------- | ------------------------ |
| `registerWallet(blockchain, wallet, config)`            | Registers a new wallet manager for a blockchain               | `WDK`                                  | -                        |
| `registerProtocol(blockchain, label, protocol, config)` | Registers a protocol globally for a blockchain                | `WDK`                                  | -                        |
| `registerMiddleware(blockchain, middleware)`            | Registers middleware for account decoration                   | `WDK`                                  | -                        |
| `getAccount(blockchain, index?)`                        | Returns a wallet account for a blockchain and index           | `Promise<IWalletAccountWithProtocols>` | If wallet not registered |
| `getAccountByPath(blockchain, path)`                    | Returns a wallet account for a blockchain and derivation path | `Promise<IWalletAccountWithProtocols>` | If wallet not registered |
| `getFeeRates()`                                         | Returns current fee rates                                     | `Promise<FeeRates>`                    | -                        |
| `dispose()`                                             | Disposes all wallets and accounts, clearing sensitive data    | `void`                                 | -                        |

**`registerWallet(blockchain, wallet, config)`**

Registers a new wallet manager for a specific blockchain.

**Type Parameters:**

* `W`: `typeof WalletManager` - A class that extends the `@tetherto/wdk-wallet`'s `WalletManager` class

**Parameters:**

* `blockchain` (string): The name of the blockchain (e.g., "ethereum", "ton", "bitcoin")
* `wallet` (W): The wallet manager class
* `config` (ConstructorParameters\[1]): The configuration object for the wallet

**Returns:** `WDK` - The wdk manager instance (supports method chaining)

**Example:**

{% code title="Register Wallets" lineNumbers="true" %}

```javascript
import WDK from '@tetherto/wdk'
import WalletManagerEvm from '@tetherto/wdk-wallet-evm'
import WalletManagerTon from '@tetherto/wdk-wallet-ton'

const wdk = new WDK(seedPhrase)

// Register EVM wallet
wdk.registerWallet('ethereum', WalletManagerEvm, {
  provider: 'https://eth.drpc.org'
})

// Register TON wallet
wdk.registerWallet('ton', WalletManagerTon, {
  tonApiKey: 'YOUR_TON_API_KEY',
  tonApiEndpoint: 'https://tonapi.io'
})

// Method chaining
const wdk2 = new WDK(seedPhrase)
  .registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
  .registerWallet('ton', WalletManagerTon, tonWalletConfig)
```

{% endcode %}

**`registerProtocol(blockchain, label, protocol, config)`**

Registers a protocol globally for all accounts of a specific blockchain.

**Type Parameters:**

* `P`: `typeof SwapProtocol | typeof BridgeProtocol | typeof LendingProtocol` - A class that extends one of the `@tetherto/wdk-wallet/protocol`'s classes

**Parameters:**

* `blockchain` (string): The name of the blockchain
* `label` (string): Unique label for the protocol (must be unique per blockchain and protocol type)
* `protocol` (P): The protocol class
* `config` (ConstructorParameters

  \[1]): The protocol configuration

**Returns:** `WDK` - The wdk manager instance (supports method chaining)

**Example:**

{% code title="Register Protocols" lineNumbers="true" %}

```javascript
import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm'
import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm'

// Register swap protocol for Ethereum
wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, {
  apiKey: 'YOUR_velora_API_KEY'
})

// Register bridge protocol for Ethereum
wdk.registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm)

// Method chaining
const wdk2 = new WDK(seedPhrase)
  .registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
  .registerProtocol('ethereum', 'velora', veloraProtocolEvm, veloraProtocolConfig)
```

{% endcode %}

**`registerMiddleware(blockchain, middleware)`**

Registers middleware for account decoration and enhanced functionality.

**Parameters:**

* `blockchain` (string): The name of the blockchain
* `middleware` (`<A extends IWalletAccount>(account: A) => Promise<A | void>`): Middleware function called when deriving accounts

**Returns:** `WDK` - The wdk manager instance (supports method chaining)

**Example:**

{% code title="Register Middleware" lineNumbers="true" %}

```javascript
// Simple logging middleware
wdk.registerMiddleware('ethereum', async (account) => {
  console.log('New account:', await account.getAddress())
})

// Failover cascade middleware
import { getFailoverCascadeMiddleware } from '@tetherto/wdk-wrapper-failover-cascade'

wdk.registerMiddleware('ethereum', getFailoverCascadeMiddleware({
  fallbackOptions: {
    retries: 3,
    delay: 1000
  }
}))

// Method chaining
const wdk2 = new WDK(seedPhrase)
  .registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig)
  .registerMiddleware('ethereum', async (account) => {
    console.log('New account:', await account.getAddress())
  })
```

{% endcode %}

**`getAccount(blockchain, index?)`**

Returns a wallet account for a specific blockchain and index using BIP-44 derivation.

**Parameters:**

* `blockchain` (string): The name of the blockchain (e.g., "ethereum")
* `index` (number, optional): The index of the account to get (default: 0)

**Returns:** `Promise<IWalletAccountWithProtocols>` - The wallet account with protocol support

**Throws:** Error if no wallet has been registered for the given blockchain

**Example:**

{% code title="Get Account" lineNumbers="true" %}

```javascript
// Get first account (index 0)
const account = await wdk.getAccount('ethereum', 0)

// Get second account (index 1)
const account1 = await wdk.getAccount('ethereum', 1)

// Default index (0)
const defaultAccount = await wdk.getAccount('ethereum')

// This will throw an error if no wallet registered for 'tron'
try {
  const tronAccount = await wdk.getAccount('tron', 0)
} catch (error) {
  console.error('No wallet registered for tron blockchain')
}
```

{% endcode %}

**`getAccountByPath(blockchain, path)`**

Returns a wallet account for a specific blockchain and BIP-44 derivation path.

**Parameters:**

* `blockchain` (string): The name of the blockchain (e.g., "ethereum")
* `path` (string): The derivation path (e.g., "0'/0/0")

**Returns:** `Promise<IWalletAccountWithProtocols>` - The wallet account with protocol support

**Throws:** Error if no wallet has been registered for the given blockchain

**Example:**

{% code title="Get Account by Path" lineNumbers="true" %}

```javascript
// Full path: m/44'/60'/0'/0/1
const account = await wdk.getAccountByPath('ethereum', "0'/0/1")

// Different derivation path
const customAccount = await wdk.getAccountByPath('ton', "1'/2/3")
```

{% endcode %}

**`getFeeRates()`**

Returns current fee rates for all registered blockchains.

**Returns:** `Promise<FeeRates>` - The fee rates in base units

**Example:**

{% code title="Get Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wdk.getFeeRates()
console.log('Fee rates:', feeRates)
```

{% endcode %}

**`dispose()`**

Disposes all wallets and accounts, erasing any sensitive data from memory.

**Example:**

{% code title="Dispose WDK" lineNumbers="true" %}

```javascript
// Clean up all sensitive data
wdk.dispose()
```

{% endcode %}

### Static Methods

| Method                            | Description                                          | Returns   |
| --------------------------------- | ---------------------------------------------------- | --------- |
| `getRandomSeedPhrase(wordCount?)` | Returns a random BIP-39 seed phrase (12 or 24 words) | `string`  |
| `isValidSeedPhrase(seedPhrase)`   | Checks if a seed phrase is valid                     | `boolean` |

**`getRandomSeedPhrase(wordCount?)`**

Returns a random BIP-39 seed phrase. Supports both 12-word (128-bit entropy) and 24-word (256-bit entropy) seed phrases.

**Parameters:**

* `wordCount` (12 | 24, optional): The number of words in the seed phrase. Defaults to 12.

**Returns:** `string` - The seed phrase

**Example:**

{% code title="Generate Random Seed" lineNumbers="true" %}

```javascript
// Generate 12-word seed phrase (default)
const seedPhrase12 = WDK.getRandomSeedPhrase()
console.log('Generated 12-word seed:', seedPhrase12)
// Output: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"

// Generate 24-word seed phrase (higher security)
const seedPhrase24 = WDK.getRandomSeedPhrase(24)
console.log('Generated 24-word seed:', seedPhrase24)
// Output: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art"
```

{% endcode %}

**`isValidSeedPhrase(seedPhrase)`**

Checks if a seed phrase is valid according to BIP-39 standards.

**Parameters:**

* `seedPhrase` (string): The seed phrase to validate

**Returns:** `boolean` - True if the seed phrase is valid

**Example:**

{% code title="Validate Seed Phrase" lineNumbers="true" %}

```javascript
const isValid = WDK.isValidSeedPhrase('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about')
console.log('Seed phrase valid:', isValid) // true

const isInvalid = WDK.isValidSeedPhrase('invalid seed phrase')
console.log('Seed phrase valid:', isInvalid) // false
```

{% endcode %}

## 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:**

{% code title="Register Protocol for Account" lineNumbers="true" %}

```javascript
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)
```

{% endcode %}

**`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:**

{% code title="Get Swap Protocol" lineNumbers="true" %}

```javascript
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')
// }
```

{% endcode %}

**`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:**

{% code title="Get Bridge Protocol" lineNumbers="true" %}

```javascript
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
const bridgeResult = await usdt0.bridge({
  targetChain: 'arbitrum',
  recipient: '0x...',
  token: '0x...',
  amount: 1000000n
})
```

{% endcode %}

**`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:**

{% code title="Get Lending Protocol" lineNumbers="true" %}

```javascript
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
})
```

{% endcode %}

## Complete Example

{% code title="Complete WDK Flow" lineNumbers="true" %}

```javascript
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')
const bridgeResult = await usdt0.bridge(bridgeOptions)

// Clean up
wdk.dispose()
```

{% endcode %}

## Types

### FeeRates

{% code title="Type: FeeRates" lineNumbers="true" %}

```typescript
interface FeeRates {
  [blockchain: string]: {
    normal: number;
    fast: number;
  };
}
```

{% endcode %}

### Middleware Function

{% code title="Type: MiddlewareFunction" lineNumbers="true" %}

```typescript
type MiddlewareFunction = <A extends IWalletAccount>(
  account: A
) => Promise<A | void>;
```

{% endcode %}

### Protocol Types

{% code title="Types: Protocol Interfaces" lineNumbers="true" %}

```typescript
// Swap Protocol
interface ISwapProtocol {
  swap(options: SwapOptions): Promise<SwapResult>;
}

// Bridge Protocol  
interface IBridgeProtocol {
  bridge(options: BridgeOptions): Promise<BridgeResult>;
}

// Lending Protocol
interface ILendingProtocol {
  supply(options: LendingOptions): Promise<LendingResult>;
  withdraw(options: LendingOptions): Promise<LendingResult>;
  borrow(options: LendingOptions): Promise<LendingResult>;
  repay(options: LendingOptions): Promise<LendingResult>;
}
```

{% endcode %}

***

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core Configuration</strong></td><td>Get started with WDK's configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Core Usage</strong></td><td>Get started with WDK's Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>Wallet Modules</strong></td><td>Explore blockchain-specific wallet modules</td><td><a href="../wallet-modules">wallet-modules</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>Bridge Modules</strong></td><td>Cross-chain USD₮0 bridges</td><td><a href="../bridge-modules">bridge-modules</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# 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.

<table data-view="cards"><thead><tr><th></th><th>Type</th><th>Purpose</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-95701e517fe11c833033b58f3ea3006cc53b3920%2Fbitcoin-logo.png?alt=media" alt="Bitcoin Logo"></td><td><strong>Bitcoin</strong></td><td>Bitcoin Mainnet</td><td><a href="wallet-modules/wallet-btc">wallet-btc</a></td></tr><tr><td><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-0ecd41e7b9f079597cd8e408cf3a4ecb795029c0%2Fethereum-logo.png?alt=media" alt="Ethereum logo"></td><td><strong>EVM Chains</strong></td><td>Ethereum, Sepolia Testnet, L2s, etc.</td><td><a href="wallet-modules/wallet-evm">wallet-evm</a></td></tr><tr><td><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-3d42fb4ae7fed2d72f3562c5ea17a57dd55a9fba%2Ftron-logo.png?alt=media" alt="Tron Logo"></td><td><strong>TRON</strong></td><td>Tron Mainnet</td><td><a href="wallet-modules/wallet-tron">wallet-tron</a></td></tr><tr><td><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-90f9968cccff796368b266a6f497fdd7403091b3%2Fton-logo.png?alt=media" alt="Ton Logo"></td><td><strong>TON</strong></td><td>TON Mainnet</td><td><a href="wallet-modules/wallet-ton">wallet-ton</a></td></tr><tr><td><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-26aec35be0f047baaac46df6bd3206f4c12bf6d9%2Fsolana-logo.png?alt=media" alt="Solana Logo"></td><td><strong>Solana</strong></td><td>Solana Mainnet</td><td><a href="wallet-modules/wallet-solana">wallet-solana</a></td></tr><tr><td><picture><source srcset="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-bf38b0342abb2d0ac035ef38b9cbbc78a1bab312%2Fspark-logo-dark.png?alt=media" media="(prefers-color-scheme: dark)"><img src="https://1705527907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F35cNSL3foZ7T6bD7C8uL%2Fuploads%2Fgit-blob-00bd6dbf1e95be5e9e7a563749584be17c6062f3%2Fspark-logo-light.png?alt=media" alt="Spark Logo"></picture></td><td><strong>Spark</strong></td><td>Spark Mainnet</td><td><a href="wallet-modules/wallet-spark">wallet-spark</a></td></tr></tbody></table>

### 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](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm)    |
| [`@tetherto/wdk-wallet-ton`](https://github.com/tetherto/wdk-wallet-ton)       | TON        | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton)    |
| [`@tetherto/wdk-wallet-btc`](https://github.com/tetherto/wdk-wallet-btc)       | Bitcoin    | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc)    |
| [`@tetherto/wdk-wallet-spark`](https://github.com/tetherto/wdk-wallet-spark)   | Spark      | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark)  |
| [`@tetherto/wdk-wallet-tron`](https://github.com/tetherto/wdk-wallet-tron)     | TRON       | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron)   |
| [`@tetherto/wdk-wallet-solana`](https://github.com/tetherto/wdk-wallet-solana) | Solana     | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana) |
| `@tetherto/wdk-wallet-ark`                                                     | Ark        | In progress | -                                                                            |

### Account Abstraction Wallet Modules

Wallet implementations that support [Account Abstraction](https://docs.wdk.tether.io/resources-and-guides/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](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337) |
| [`@tetherto/wdk-wallet-ton-gasless`](https://github.com/tetherto/wdk-wallet-ton-gasless)   | TON        | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless)  |
| [`@tetherto/wdk-wallet-tron-gasfree`](https://github.com/tetherto/wdk-wallet-tron-gasfree) | TRON       | ✅ Ready     | [Documentation](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-tron-gasfree) |
| `@tetherto/wdk-wallet-solana-jupiterz`                                                     | Solana     | In progress | -                                                                                  |

### Community Wallet Modules

Wallet modules developed by the community. See the [Community Modules](https://docs.wdk.tether.io/sdk/community-modules) page for more details.

{% hint style="warning" %}
Community modules are developed and maintained independently. Use your own judgment and proceed at your own risk.
{% endhint %}

| 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 [Quick Start Guide](https://docs.wdk.tether.io/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](https://docs.wdk.tether.io/resources-and-guides/concepts#account-abstraction) and other important definitions
* Use one of our ready-to-use examples to be production ready


# wallet-btc

Overview of the @tetherto/wdk-wallet-btc module

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.

{% hint style="warning" %}
**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** (<= 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`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
{% endhint %}

## 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
* **Transaction Management**: Create, sign, and broadcast Bitcoin transactions (single recipient per transaction)
* **Fee Estimation**: Dynamic fee calculation via mempool.space API
* **Electrum Support**: Connect to Electrum servers for network interaction
* **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

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet Configuration</strong></td><td>Get started with WDK's Bitcoin Wallet configuration</td><td><a href="wallet-btc/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet API</strong></td><td>Get started with WDK's Bitcoin Wallet API</td><td><a href="wallet-btc/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet Usage</strong></td><td>Get started with WDK's Bitcoin Wallet usage</td><td><a href="wallet-btc/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-btc module.

The `@tetherto/wdk-wallet-btc` module provides wallet management for the Bitcoin blockchain.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Get Started</strong></td><td>Install the package and create your first wallet.</td><td><a href="usage/get-started">get-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Work with multiple accounts and custom derivation paths.</td><td><a href="usage/manage-accounts">manage-accounts</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query native BTC balances for owned and read-only accounts.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send BTC</strong></td><td>Send Bitcoin and estimate transaction fees.</td><td><a href="usage/send-transactions">send-transactions</a></td></tr><tr><td><i class="fa-history">:history:</i></td><td><strong>Transaction History</strong></td><td>Retrieve and filter transfer history.</td><td><a href="usage/get-transaction-history">get-transaction-history</a></td></tr><tr><td><i class="fa-key">:key:</i></td><td><strong>Sign and Verify Messages</strong></td><td>Sign messages and verify signatures.</td><td><a href="usage/sign-verify-messages">sign-verify-messages</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Handle Errors</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/handle-errors">handle-errors</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet Configuration</strong></td><td>Get started with WDK's Bitcoin Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet API</strong></td><td>Get started with WDK's Bitcoin Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Get Started

Install and create your first Bitcoin wallet.

This guide explains how to [install the package](#1-install-the-package), [create a wallet](#2-create-a-wallet), [get your first account](#3-get-your-first-account), and optionally [convert to read-only](#4-optional-convert-to-read-only).

## 1. Install the Package

### Prerequisites

* [**Node.js**](https://nodejs.org/): version 18 or higher.
* [**npm**](https://www.npmjs.com/): usually comes with Node.js.

{% code title="Install @tetherto/wdk-wallet-btc" lineNumbers="true" %}

```bash
npm install @tetherto/wdk-wallet-btc
```

{% endcode %}

## 2. Create a Wallet

You can create a new wallet instance using the [`WalletManagerBtc`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletmanagerbtc) constructor with a BIP-39 seed phrase and an Electrum client:

{% code title="Create Bitcoin Wallet" lineNumbers="true" %}

```javascript
import WalletManagerBtc, { ElectrumTcp } from '@tetherto/wdk-wallet-btc'

const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'

const client = new ElectrumTcp({
  host: 'electrum.blockstream.info',
  port: 50001
})

const wallet = new WalletManagerBtc(seedPhrase, {
  client,
  network: 'bitcoin'
})
```

{% endcode %}

{% hint style="danger" %}
**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.
{% endhint %}

{% hint style="warning" %}
**Electrum Server Performance:** Public servers like Blockstream's can be 10-300x slower than private servers. For production use, set up your own [Fulcrum](https://github.com/cculianu/Fulcrum) server. For development, consider `fulcrum.frznode.com` as a faster alternative.
{% endhint %}

## 3. Get Your First Account

You can retrieve an account at a given index using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index):

{% code title="Get Account" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Wallet address:', address)
```

{% endcode %}

{% hint style="info" %}
This implementation uses BIP-84 derivation paths and generates Native SegWit (bech32) addresses by default. Addresses start with `bc1` on mainnet. Set `bip: 44` in config for legacy (P2PKH) addresses.
{% endhint %}

## 4. (optional) Convert to Read-Only

You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount):

{% code title="Convert to Read-Only" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
```

{% endcode %}

## Next Steps

With your wallet ready, learn how to [manage multiple accounts](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/usage/manage-accounts).


# Manage Accounts

Work with multiple accounts and custom derivation paths.

This guide explains how to [retrieve accounts by index](#retrieve-accounts-by-index) and [use custom derivation paths](#retrieve-account-by-custom-derivation-path).

## Retrieve Accounts by Index

You can retrieve multiple accounts using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) with different index values:

{% code title="Retrieve Multiple Accounts" lineNumbers="true" %}

```javascript
const account0 = await wallet.getAccount(0)
const address0 = await account0.getAddress()
console.log('Account 0 address:', address0)

const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
```

{% endcode %}

You can iterate through multiple accounts using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) to inspect addresses and balances in bulk:

{% code title="Iterate Over Accounts" lineNumbers="true" %}

```javascript
for (let i = 0; i < 5; i++) {
  const account = await wallet.getAccount(i)
  const address = await account.getAddress()
  const balance = await account.getBalance()
  console.log(`Account ${i}: ${address} (${balance} satoshis)`)
}
```

{% endcode %}

## Retrieve Account by Custom Derivation Path

You can retrieve an account at a specific derivation path using [`wallet.getAccountByPath()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypath-path):

{% code title="Custom Derivation Path" lineNumbers="true" %}

```javascript
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)
```

{% endcode %}

{% hint style="info" %}
The default derivation scheme is BIP-84 (Native SegWit): `m/84'/0'/0'/0/{index}` on mainnet. Set `bip: 44` in the wallet configuration for legacy BIP-44 paths: `m/44'/0'/0'/0/{index}`.
{% endhint %}

## Next Steps

With accounts set up, learn how to [check balances](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/usage/check-balances).


# Check Balances

Query native BTC balances for owned and read-only accounts.

This guide explains how to check [native BTC balances](#native-btc-balance), [maximum spendable amounts](#maximum-spendable-amount), and [read-only account balances](#read-only-account-balances).

## Native BTC Balance

You can retrieve the confirmed balance in satoshis using [`account.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Get Native BTC Balance" lineNumbers="true" %}

```javascript
const balance = await account.getBalance()
console.log('Confirmed balance:', balance, 'satoshis')
```

{% endcode %}

{% hint style="info" %}
On Bitcoin, balances are expressed in satoshis (1 BTC = 100,000,000 satoshis). The [`getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance) method returns confirmed balance only.
{% endhint %}

## Maximum Spendable Amount

You can check the maximum amount available to send in a single transaction using [`account.getMaxSpendable()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getmaxspendable):

{% code title="Get Maximum Spendable" lineNumbers="true" %}

```javascript
const { amount, fee } = await account.getMaxSpendable()
console.log('Max spendable:', amount, 'satoshis')
console.log('Estimated fee:', fee, 'satoshis')
```

{% endcode %}

{% hint style="info" %}
The maximum spendable amount can differ from the total balance due to transaction fees, uneconomic UTXOs, the 200-input limit per transaction, and the dust threshold (294 satoshis for SegWit, 546 for legacy).
{% endhint %}

## Read-Only Account Balances

You can check balances for any Bitcoin address without a seed phrase using [`WalletAccountReadOnlyBtc`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlybtc):

{% code title="Create Read-Only Account" lineNumbers="true" %}

```javascript
import { WalletAccountReadOnlyBtc, ElectrumTcp } from '@tetherto/wdk-wallet-btc'

const client = new ElectrumTcp({
  host: 'electrum.blockstream.info',
  port: 50001
})

const readOnlyAccount = new WalletAccountReadOnlyBtc('bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', {
  client,
  network: 'bitcoin'
})
```

{% endcode %}

You can retrieve the balance from a read-only account using [`readOnlyAccount.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Read-Only Balance" lineNumbers="true" %}

```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Read-only account balance:', balance, 'satoshis')
```

{% endcode %}

{% hint style="info" %}
You can also create a read-only account from an existing owned account using [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount).
{% endhint %}

## Next Steps

With balance checks in place, learn how to [send BTC](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/usage/send-transactions).


# Send BTC

Send BTC and estimate transaction fees.

This guide explains how to [send BTC](#send-btc), [estimate fees before sending](#estimate-fees), [use a custom fee rate](#send-with-custom-fee-rate), and [target a specific confirmation time](#send-with-confirmation-target).

## Send BTC

You can send Bitcoin to a recipient using [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-options):

{% code title="Send BTC" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  value: 100000n // 0.001 BTC in satoshis
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'satoshis')
```

{% endcode %}

{% hint style="info" %}
Bitcoin transactions support a single recipient only. Amounts and fees are always in satoshis (1 BTC = 100,000,000 satoshis). The minimum amount must be above the dust limit (294 satoshis for SegWit, 546 for legacy).
{% endhint %}

## Estimate Fees

You can estimate the fee for a transaction without broadcasting it using [`account.quoteSendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotesendtransaction-options):

{% code title="Estimate Fee" lineNumbers="true" %}

```javascript
const quote = await account.quoteSendTransaction({
  to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  value: 100000n
})
console.log('Estimated fee:', quote.fee, 'satoshis')
```

{% endcode %}

## Send with Custom Fee Rate

You can override automatic fee estimation by providing a `feeRate` in sat/vB to [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-options):

{% code title="Custom Fee Rate" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  value: 100000n,
  feeRate: 10n // sat/vB
})
```

{% endcode %}

{% hint style="info" %}
When `feeRate` is provided, the `confirmationTarget` parameter is ignored.
{% endhint %}

## Send with Confirmation Target

You can target a specific number of blocks for confirmation using the `confirmationTarget` parameter in [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-options):

{% code title="Confirmation Target" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  value: 100000n,
  confirmationTarget: 6 // target 6 blocks (~1 hour)
})
```

{% endcode %}

## Next Steps

Learn how to [view transaction history](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/usage/get-transaction-history).


# Transaction History

Retrieve and filter Bitcoin transfer history.

This guide explains how to [retrieve all transfers](#retrieve-all-transfers), [filter by direction](#filter-by-direction), [paginate results](#paginate-results), and [check transaction receipts](#check-transaction-receipts).

## Retrieve All Transfers

You can retrieve the account's transfer history using [`account.getTransfers()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettransfers-options):

{% code title="Get All Transfers" lineNumbers="true" %}

```javascript
const transfers = await account.getTransfers()
console.log('Recent transfers:', transfers)
```

{% endcode %}

{% hint style="info" %}
The default limit is 10 transfers. Change outputs are automatically filtered out. Transfers are sorted by block height (newest first).
{% endhint %}

## Filter by Direction

You can filter transfers by direction using the `direction` option in [`account.getTransfers()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettransfers-options):

{% code title="Incoming Transfers" lineNumbers="true" %}

```javascript
const incoming = await account.getTransfers({ direction: 'incoming' })
console.log('Incoming transfers:', incoming)
```

{% endcode %}

You can retrieve outgoing transfers with a custom limit using [`account.getTransfers()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettransfers-options):

{% code title="Outgoing Transfers" lineNumbers="true" %}

```javascript
const outgoing = await account.getTransfers({
  direction: 'outgoing',
  limit: 5
})
console.log('Outgoing transfers:', outgoing)
```

{% endcode %}

## Paginate Results

You can paginate through transfer history using the `limit` and `skip` options in [`account.getTransfers()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettransfers-options):

{% code title="Paginate Transfers" lineNumbers="true" %}

```javascript
const page = await account.getTransfers({
  direction: 'all',
  limit: 20,
  skip: 10
})
console.log('Transfers 11-30:', page)
```

{% endcode %}

## Check Transaction Receipts

You can check whether a specific transaction has been confirmed using [`account.getTransactionReceipt()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettransactionreceipt-hash):

{% code title="Get Transaction Receipt" lineNumbers="true" %}

```javascript
const receipt = await account.getTransactionReceipt('abc123...')
if (receipt) {
  console.log('Transaction confirmed')
}
```

{% endcode %}

## Next Steps

Learn how to [sign and verify messages](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/usage/sign-verify-messages).


# Sign and Verify Messages

Sign messages and verify signatures with Bitcoin accounts.

This guide explains how to [sign messages](#sign-a-message) and [verify signatures](#verify-a-signature).

## Sign a Message

You can sign a message with the account's private key using [`account.sign()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sign-message):

{% code title="Sign Message" lineNumbers="true" %}

```javascript
const message = 'Hello, Bitcoin!'
const signature = await account.sign(message)
console.log('Signature:', signature)
```

{% endcode %}

{% hint style="info" %}
The signature is returned as a base64-encoded string.
{% endhint %}

## Verify a Signature

You can verify that a signature was produced by the corresponding private key using [`account.verify()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#verify-message-signature):

{% code title="Verify Signature" lineNumbers="true" %}

```javascript
const isValid = await account.verify(message, signature)
console.log('Signature valid:', isValid)
```

{% endcode %}

You can also verify signatures using a [read-only account](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlybtc). Use [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount) to create one from an owned account, then call [`readOnlyAccount.verify()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#verify-message-signature):

{% code title="Verify with Read-Only Account" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const isValid = await readOnlyAccount.verify('Hello, Bitcoin!', signature)
console.log('Verified with read-only account:', isValid)
```

{% endcode %}

## Next Steps

Learn how to [handle errors and manage resources](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-btc/usage/handle-errors).


# Handle Errors

Handle errors, manage fees, and dispose of sensitive data.

This guide explains how to [handle transaction errors](#transaction-errors), [handle connection errors](#connection-errors), and follow [best practices](#best-practices) for fee management and memory cleanup.

## Transaction Errors

Transactions sent via [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-options) can fail for several reasons. Wrap transaction calls in a `try/catch` block to handle specific error types:

{% code title="Handle Transaction Errors" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
    value: 100000n
  })
  console.log('Transaction hash:', result.hash)
} catch (error) {
  if (error.message.includes('Insufficient balance')) {
    console.error('Not enough funds in wallet')
  } else if (error.message.includes('dust limit')) {
    console.error('Amount is below the minimum dust limit')
  } else if (error.message.includes('Invalid address')) {
    console.error('Recipient address is invalid')
  } else {
    console.error('Transaction failed:', error.message)
  }
}
```

{% endcode %}

## Connection Errors

Network issues with the Electrum server can cause failures across all operations. Handle connection errors at a higher level:

{% code title="Handle Connection Errors" lineNumbers="true" %}

```javascript
try {
  const balance = await account.getBalance()
  console.log('Balance:', balance, 'satoshis')
} catch (error) {
  if (error.message.includes('ECONNREFUSED') || error.message.includes('timeout')) {
    console.error('Network error: check Electrum server connection')
  } else if (error.message.includes('Invalid seed')) {
    console.error('Invalid seed phrase provided')
  } else {
    console.error('Operation failed:', error.message)
  }
}
```

{% endcode %}

## Best Practices

### Fee Management

You can retrieve current network fee rates using [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates):

{% code title="Get Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'sat/vB')
console.log('Fast fee rate:', feeRates.fast, 'sat/vB')
```

{% endcode %}

{% hint style="info" %}
[`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates) fetches rates from the mempool.space API, while [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-options) estimates fees from the connected Electrum server. Use [`getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates) for display purposes.
{% endhint %}

### Dispose of Sensitive Data

For security, clear sensitive data from memory when a session is complete. Use [`account.dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose-1) and [`wallet.dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) to securely wipe private keys:

{% code title="Dispose Resources" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
    value: 100000n
  })
  console.log('Transaction hash:', result.hash)
} finally {
  account.dispose()
  wallet.dispose()
}
```

{% endcode %}

{% hint style="warning" %}
Always call [`dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) when finished with accounts. Private keys are securely wiped from memory using `sodium_memzero`. Electrum connections are automatically closed. Disposal is irreversible.
{% endhint %}


# Configuration

Configuration options and settings for @tetherto/wdk-wallet-btc

## Wallet Configuration

```javascript
import WalletManagerBtc, { ElectrumTcp } from '@tetherto/wdk-wallet-btc'

const client = new ElectrumTcp({
  host: 'electrum.blockstream.info',
  port: 50001
})

const wallet = new WalletManagerBtc(seedPhrase, {
  client,
  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 an Electrum client instance to use for blockchain data. When provided, the `host`, `port`, and `protocol` options are ignored.

**Type:** `IElectrumClient`

**Default:** None (falls back to host/port/protocol configuration)

**Example:**

```javascript
import { ElectrumTcp } from '@tetherto/wdk-wallet-btc'

const config = {
  client: new ElectrumTcp({ host: 'fulcrum.frznode.com', port: 50001 })
}
```

#### Built-in Transport Clients

The package provides four built-in transport clients:

```javascript
import { 
  ElectrumTcp,   // TCP transport (default, port 50001)
  ElectrumTls,   // TLS transport (port 50002)
  ElectrumSsl,   // SSL transport (port 50002)
  ElectrumWs     // WebSocket transport (port 50003)
} 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({ host: 'electrum.blockstream.info', port: 50003 })
```

#### Custom Electrum Client

You can implement your own client by extending `IElectrumClient`:

```javascript
import { IElectrumClient } from '@tetherto/wdk-wallet-btc'

class MyCustomElectrumClient implements IElectrumClient {
  // Implement the required interface methods
}

const wallet = new WalletManagerBtc(seedPhrase, {
  client: new MyCustomElectrumClient(params),
  network: 'bitcoin'
})
```

### Host

The `host` option specifies the Electrum server hostname to connect to for blockchain data. Ignored if `client` is provided.

**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 = {
  host: 'fulcrum.frznode.com' // Alternative public server
}
```

### Port

The `port` option specifies the Electrum server port to connect to. Ignored if `client` is provided.

**Type:** `number`

**Default:** `50001`

**Common Ports:**

* `50001` - TCP (default)
* `50002` - TLS/SSL
* `50003` - WebSocket

**Example:**

```javascript
const config = {
  port: 50001
}
```

### Protocol

The `protocol` option specifies the transport protocol to use. Ignored if `client` is provided.

**Type:** `string`

**Values:**

* `"tcp"` - TCP transport (default)
* `"tls"` - TLS transport
* `"ssl"` - SSL transport

**Default:** `"tcp"`

**Example:**

```javascript
const config = {
  host: 'electrum.blockstream.info',
  port: 50002,
  protocol: 'tls'
}
```

### Network

The `network` option specifies which Bitcoin network to use.

**Type:** `string`

**Values:**

* `"bitcoin"` - Bitcoin [mainnet](https://docs.wdk.tether.io/resources-and-guides/concepts#mainnet) (production)
* `"testnet"` - Bitcoin [testnet](https://docs.wdk.tether.io/resources-and-guides/concepts#testnet) (development)
* `"regtest"` - Bitcoin [regtest](https://docs.wdk.tether.io/resources-and-guides/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](https://docs.wdk.tether.io/resources-and-guides/concepts#bip-84-native-segwit) (P2WPKH / Native SegWit) - addresses start with `bc1` (mainnet) or `tb1` (testnet)
* `44` - [BIP-44](https://docs.wdk.tether.io/resources-and-guides/concepts#bip-44-legacy) (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).

{% hint style="warning" %}
**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** (<= 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`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
{% endhint %}

## 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

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK BTC Wallet Usage</strong></td><td>Get started with WDK's BTC Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK BTC Wallet API</strong></td><td>Get started with WDK's BTC Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk-wallet-btc

## 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 `IElectrumClient`.                                    | [Constructor](#constructor-3)                                                   |
| [ElectrumTls](#electrumtls)                           | TLS Electrum client. Implements `IElectrumClient`.                                             | [Constructor](#constructor-4)                                                   |
| [ElectrumSsl](#electrumssl)                           | SSL Electrum client. Implements `IElectrumClient`.                                             | [Constructor](#constructor-5)                                                   |
| [ElectrumWs](#electrumws)                             | WebSocket Electrum client for browser environments. Implements `IElectrumClient`.              | [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` (IElectrumClient, optional): Electrum client instance. If provided, host/port/protocol are ignored.
  * `host` (string, optional): Electrum server hostname (default: "electrum.blockstream.info"). Ignored if client is provided.
  * `port` (number, optional): Electrum server port (default: 50001). Ignored if client is provided.
  * `protocol` (string, optional): Transport protocol - "tcp", "tls", or "ssl" (default: "tcp"). Ignored if client is provided.
  * `network` (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")
  * `bip` (number, optional): BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)

### Methods

| Method                   | Description                                                                                               | Returns                                   |
| ------------------------ | --------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `getAccount(index)`      | Returns a wallet account at the specified index                                                           | `Promise<WalletAccountBtc>`               |
| `getAccountByPath(path)` | Returns a wallet account at the specified derivation path                                                 | `Promise<WalletAccountBtc>`               |
| `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<WalletAccountBtc>` - 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<WalletAccountBtc>` - 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` (IElectrumClient, optional): Electrum client instance. If provided, host/port/protocol are ignored.
  * `host` (string, optional): Electrum server hostname (default: "electrum.blockstream.info"). Ignored if client is provided.
  * `port` (number, optional): Electrum server port (default: 50001). Ignored if client is provided.
  * `protocol` (string, optional): Transport protocol - "tcp", "tls", or "ssl" (default: "tcp"). Ignored if client is provided.
  * `network` (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")
  * `bip` (number, optional): BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)

### Methods

| Method                          | Description                                                    | Returns                                  |
| ------------------------------- | -------------------------------------------------------------- | ---------------------------------------- |
| `getAddress()`                  | Returns the account's Bitcoin address                          | `Promise<string>`                        |
| `getBalance()`                  | Returns the confirmed account balance in satoshis              | `Promise<bigint>`                        |
| `sendTransaction(options)`      | Sends a Bitcoin transaction                                    | `Promise<{hash: string, fee: bigint}>`   |
| `quoteSendTransaction(options)` | Estimates the fee for a transaction                            | `Promise<{fee: bigint}>`                 |
| `getTransfers(options?)`        | Returns the account's transfer history                         | `Promise<BtcTransfer[]>`                 |
| `getTransactionReceipt(hash)`   | Returns a transaction's receipt                                | `Promise<BtcTransactionReceipt \| null>` |
| `getMaxSpendable()`             | Returns the maximum spendable amount                           | `Promise<BtcMaxSpendableResult>`         |
| `sign(message)`                 | Signs a message with the account's private key                 | `Promise<string>`                        |
| `verify(message, signature)`    | Verifies a message signature                                   | `Promise<boolean>`                       |
| `toReadOnlyAccount()`           | Creates a read-only version of this account                    | `Promise<WalletAccountReadOnlyBtc>`      |
| `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<string>` - 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 confirmed balance in satoshis.

**Returns:** `Promise<bigint>` - Balance in satoshis

**Example:**

```javascript
const balance = await account.getBalance()
console.log('Balance:', balance, 'satoshis')
```

**`sendTransaction(options)`**

Sends a Bitcoin transaction to a single recipient.

**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<{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')
```

**`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<BtcTransfer[]>` - 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<BtcTransactionReceipt | null>` - 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<BtcMaxSpendableResult>` - 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<string>` - 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<boolean>` - 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<WalletAccountReadOnlyBtc>` - 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   |

## 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` (IElectrumClient, optional): Electrum client instance. If provided, host/port/protocol are ignored.
  * `host` (string, optional): Electrum server hostname (default: "electrum.blockstream.info"). Ignored if client is provided.
  * `port` (number, optional): Electrum server port (default: 50001). Ignored if client is provided.
  * `protocol` (string, optional): Transport protocol - "tcp", "tls", or "ssl" (default: "tcp"). Ignored if client is provided.
  * `network` (string, optional): "bitcoin", "testnet", or "regtest" (default: "bitcoin")

### Methods

| Method                          | Description                                       | Returns                                  |
| ------------------------------- | ------------------------------------------------- | ---------------------------------------- |
| `getAddress()`                  | Returns the account's Bitcoin address             | `Promise<string>`                        |
| `getBalance()`                  | Returns the confirmed account balance in satoshis | `Promise<bigint>`                        |
| `quoteSendTransaction(options)` | Estimates the fee for a transaction               | `Promise<{fee: bigint}>`                 |
| `getTransactionReceipt(hash)`   | Returns a transaction's receipt                   | `Promise<BtcTransactionReceipt \| null>` |
| `getMaxSpendable()`             | Returns the maximum spendable amount              | `Promise<BtcMaxSpendableResult>`         |
| `verify(message, signature)`    | Verifies a message signature                      | `Promise<boolean>`                       |
| `dispose()`                     | Closes any internal Electrum connection           | `void`                                   |

**`getAddress()`**

Returns the account's Bitcoin address.

**Returns:** `Promise<string>` - 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<bigint>` - 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<BtcTransactionReceipt | null>` - 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<BtcMaxSpendableResult>` - 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<boolean>` - 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`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-btc/configuration/README.md#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 `IElectrumClient`.

#### Constructor

```javascript
new ElectrumTcp(config)
```

**Parameters:**

* `config` (Omit\<MempoolElectrumConfig, 'protocol'>): Configuration options
  * `host` (string): Electrum server hostname
  * `port` (number): Electrum server port

## ElectrumTls

Electrum client using TLS transport. Implements `IElectrumClient`.

#### Constructor

```javascript
new ElectrumTls(config)
```

**Parameters:**

* `config` (Omit\<MempoolElectrumConfig, 'protocol'>): Configuration options
  * `host` (string): Electrum server hostname
  * `port` (number): Electrum server port

## ElectrumSsl

Electrum client using SSL transport. Implements `IElectrumClient`.

#### Constructor

```javascript
new ElectrumSsl(config)
```

**Parameters:**

* `config` (Omit\<MempoolElectrumConfig, 'protocol'>): 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 `IElectrumClient`.

#### 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<void>`                  |
| `close()`                 | Closes the connection                                         | `Promise<void>`                  |
| `reconnect()`             | Recreates the underlying socket and reinitializes the session | `Promise<void>`                  |
| `getBalance(scripthash)`  | Returns balance for a script hash                             | `Promise<ElectrumBalance>`       |
| `listUnspent(scripthash)` | Returns UTXOs for a script hash                               | `Promise<ElectrumUtxo[]>`        |
| `getHistory(scripthash)`  | Returns transaction history                                   | `Promise<ElectrumHistoryItem[]>` |
| `getTransaction(txHash)`  | Returns raw transaction hex                                   | `Promise<string>`                |
| `broadcast(rawTx)`        | Broadcasts raw transaction                                    | `Promise<string>`                |
| `estimateFee(blocks)`     | Returns estimated fee rate                                    | `Promise<number>`                |

## 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
  privateKey: Uint8Array | null  // Private key bytes (null after dispose)
}
```

### BtcWalletConfig

```typescript
interface BtcWalletConfig {
  client?: IElectrumClient                    // Electrum client instance. If provided, host/port/protocol are ignored.
  host?: string                               // Electrum server hostname (default: "electrum.blockstream.info")
  port?: number                               // Electrum server port (default: 50001)
  protocol?: 'tcp' | 'tls' | 'ssl'            // Transport protocol (default: "tcp")
  network?: 'bitcoin' | 'testnet' | 'regtest' // Network to use (default: "bitcoin")
  bip?: 44 | 84                               // BIP address type - 44 (legacy) or 84 (native SegWit) (default: 84)
}
```

### IElectrumClient

Interface for implementing custom Electrum clients.

```typescript
interface IElectrumClient {
  connect(): Promise<void>
  close(): Promise<void>
  reconnect(): Promise<void>
  getBalance(scripthash: string): Promise<ElectrumBalance>
  listUnspent(scripthash: string): Promise<ElectrumUtxo[]>
  getHistory(scripthash: string): Promise<ElectrumHistoryItem[]>
  getTransaction(txHash: string): Promise<string>
  broadcast(rawTx: string): Promise<string>
  estimateFee(blocks: number): Promise<number>
}
```

### 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
}
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet Usage</strong></td><td>Get started with WDK's Bitcoin Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Bitcoin Wallet Configuration</strong></td><td>Get started with WDK's Bitcoin Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# wallet-evm

Overview of the @tetherto/wdk-wallet-evm module

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
* **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 both JSON-RPC URLs and EIP-1193 browser providers
* **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

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet Configuration</strong></td><td>Get started with WDK's EVM Wallet configuration</td><td><a href="wallet-evm/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet API</strong></td><td>Get started with WDK's EVM Wallet API</td><td><a href="wallet-evm/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet Usage</strong></td><td>Get started with WDK's EVM Wallet usage</td><td><a href="wallet-evm/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-evm module.

The `@tetherto/wdk-wallet-evm` module provides wallet management for Ethereum and EVM-compatible blockchains.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Getting Started</strong></td><td>Install the package and create your first wallet.</td><td><a href="usage/getting-started">getting-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Work with multiple accounts and custom derivation paths.</td><td><a href="https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/guides/account-management.md">https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/guides/account-management.md</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query native and ERC-20 token balances.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send Transactions</strong></td><td>Send native tokens with EIP-1559 or legacy gas settings.</td><td><a href="usage/send-transactions">send-transactions</a></td></tr><tr><td><i class="fa-coins">:coins:</i></td><td><strong>Transfer ERC-20 Tokens</strong></td><td>Transfer ERC-20 tokens and estimate fees.</td><td><a href="usage/transfer-tokens">transfer-tokens</a></td></tr><tr><td><i class="fa-key">:key:</i></td><td><strong>Sign and Verify Messages</strong></td><td>Sign messages and verify signatures.</td><td><a href="usage/sign-verify-messages">sign-verify-messages</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Error Handling</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/error-handling">error-handling</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet Configuration</strong></td><td>Get started with WDK's EVM Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet API</strong></td><td>Get started with WDK's EVM Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Getting Started

Install and create your first EVM wallet.

This guide explains how to install the [`@tetherto/wdk-wallet-evm`](https://www.npmjs.com/package/@tetherto/wdk-wallet-evm) package and create a new wallet instance.

## 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

{% code title="Install @tetherto/wdk-wallet-evm" lineNumbers="true" %}

```bash
npm install @tetherto/wdk-wallet-evm
```

{% endcode %}

## 2. Create a Wallet

Import the module and create a [`WalletManagerEvm`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#walletmanagerevm) instance with a BIP-39 seed phrase and an RPC provider.

{% code title="Create EVM Wallet" lineNumbers="true" %}

```javascript
import WalletManagerEvm, { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'

const seedPhrase = 'your twelve word seed phrase here'

const wallet = new WalletManagerEvm(seedPhrase, {
  provider: 'https://rpc.mevblocker.io/fast',
  transferMaxFee: 100000000000000 // Optional: maximum fee in wei
})
```

{% endcode %}

{% hint style="danger" %}
**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.
{% endhint %}

You can also pass an EIP-1193 provider (e.g., from a browser wallet) instead of an RPC URL:

{% code title="Use EIP-1193 Provider" lineNumbers="true" %}

```javascript
const wallet = new WalletManagerEvm(seedPhrase, {
  provider: window.ethereum,
  transferMaxFee: 100000000000000
})
```

{% endcode %}

## 3. Get Your First Account

Retrieve an account from the wallet and inspect its address.

{% code title="Get Account" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Wallet address:', address)

const readOnlyAccount = await account.toReadOnlyAccount()
```

{% endcode %}

{% hint style="info" %}
**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.
  {% endhint %}

{% hint style="info" %}
To use test/mock tokens instead of real funds, see the [configuration section](https://docs.wdk.tether.io/sdk/wallet-modules/configuration#network-support).
{% endhint %}

## Next Steps

With your wallet ready, learn how to [manage multiple accounts](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage/manage-accounts).


# Manage Accounts

Work with multiple EVM accounts and custom derivation paths.

This guide explains how to retrieve multiple accounts from your EVM wallet and use custom derivation paths.

## Retrieve Accounts by Index

Use `getAccount()` with a zero-based index to access accounts derived from the default BIP-44 path (`m/44'/60'/0'/0/{index}`).

{% code title="Get Accounts by Index" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Account 0 address:', address)

const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
```

{% endcode %}

## Retrieve Account by Custom Derivation Path

Use `getAccountByPath()` when you need a specific hierarchy beyond the default sequential index.

{% code title="Custom Derivation Path" lineNumbers="true" %}

```javascript
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)
```

{% endcode %}

## Iterate Over Multiple Accounts

You can loop through accounts to inspect addresses and balances in bulk.

{% code title="Multi-Account Iteration" lineNumbers="true" %}

```javascript
async function listAccounts(wallet) {
  const accounts = []

  for (let i = 0; i < 5; i++) {
    const account = await wallet.getAccount(i)
    const address = await account.getAddress()
    const balance = await account.getBalance()

    accounts.push({
      index: i,
      path: `m/44'/60'/0'/0/${i}`,
      address,
      balance
    })

    console.log(`Account ${i}:`, { address, balance: balance.toString() })
  }

  return accounts
}
```

{% endcode %}

## Next Steps

Now that you can access your accounts, learn how to [check balances](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage/check-balances).


# Check Balances

Query native and ERC-20 token balances on EVM chains.

This guide explains how to check native token and ERC-20 token balances for both owned and read-only accounts.

## Owned Account Balances

Use an account retrieved from [`WalletManagerEvm`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#walletmanagerevm) to query balances.

### Native Token Balance

You can retrieve the native token balance from an `Account` object using [`account.getBalance()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#getbalance):

{% code title="Get Native Balance" lineNumbers="true" %}

```javascript
const balance = await account.getBalance()
console.log('Native balance:', balance, 'wei')
```

{% endcode %}

### Single ERC-20 Token Balance

You can retrieve a single ERC-20 token balance from an `Account` object using [`account.getTokenBalance(tokenAddress)`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#gettokenbalance-tokenaddress):

{% code title="Get ERC-20 Balance" lineNumbers="true" %}

```javascript
const tokenAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT
const tokenBalance = await account.getTokenBalance(tokenAddress)
console.log('Token balance:', tokenBalance)
```

{% endcode %}

### Multiple ERC-20 Token Balances

You can retrieve multiple ERC-20 token balances from an `Account` object using [`account.getTokenBalances(tokenAddresses)`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#gettokenbalances-tokenaddresses), where `tokenAddresses` is an array of ERC-20 tokens:

{% code title="Get Multiple Token Balances" lineNumbers="true" %}

```javascript
const tokenBalances = await account.getTokenBalances([
  '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  '0x68749665FF8D2d112Fa859AA293F07A622782F38'  // XAUT
])
console.log('Multi-token balances:', tokenBalances)
```

{% endcode %}

## Read-Only Account Balances

Use [`WalletAccountReadOnlyEvm`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#walletaccountreadonlyevm) to check balances for any public address without a seed phrase.

### Native Balance

{% code title="Read-Only Native Balance" lineNumbers="true" %}

```javascript
import { WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm'

const readOnlyAccount = new WalletAccountReadOnlyEvm('0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', {
   provider: 'https://rpc.mevblocker.io/fast',
})

const balance = await readOnlyAccount.getBalance()
console.log('Native balance:', balance, 'wei')
```

{% endcode %}

### Single Token Balance

{% code title="Read-Only Token Balance" lineNumbers="true" %}

```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7')
console.log('Token balance:', tokenBalance)
```

{% endcode %}

### Multiple Token Balances

{% code title="Read-Only Multiple Token Balances" lineNumbers="true" %}

```javascript
const tokenBalances = await readOnlyAccount.getTokenBalances([
  '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  '0x68749665FF8D2d112Fa859AA293F07A622782F38'  // XAUT
])
console.log('Multi-token balances:', tokenBalances)
```

{% endcode %}

{% hint style="info" %}
You can also create a read-only account from an existing owned account using [`await account.toReadOnlyAccount()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#toreadonlyaccount).
{% endhint %}

## Next Steps

With balance checks in place, learn how to [send transactions](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage/send-transactions).


# Send Transactions

Send native tokens on EVM chains with EIP-1559 or legacy gas settings.

This guide explains how to send native tokens (ETH, MATIC, BNB, etc.) on EVM chains, estimate fees, and configure gas parameters.

{% hint style="warning" %}
**BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers.
{% endhint %}

## Send with EIP-1559 Gas Parameters

You can use [`account.sendTransaction()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#sendtransaction-tx) to send an EIP-1559 transaction. EIP-1559 transactions provide more predictable gas fees and faster inclusion times.

{% code title="EIP-1559 Transaction" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000000n, // 1 ETH in wei
  maxFeePerGas: 30000000000,
  maxPriorityFeePerGas: 2000000000
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'wei')
```

{% endcode %}

## Send with Legacy Gas Parameters

You can also use [`account.sendTransaction()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#sendtransaction-tx) with legacy gas settings for chains that do not support EIP-1559.

{% code title="Legacy Transaction" lineNumbers="true" %}

```javascript
const legacyResult = await account.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000000n,
  gasPrice: 20000000000n,
  gasLimit: 21000
})
console.log('Transaction hash:', legacyResult.hash)
```

{% endcode %}

## Estimate Transaction Fees

Use [`account.quoteSendTransaction()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#quotesendtransaction-tx) to get a fee estimate before sending.

{% code title="Quote Transaction Fee" lineNumbers="true" %}

```javascript
const quote = await account.quoteSendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000000n
})
console.log('Estimated fee:', quote.fee, 'wei')
```

{% endcode %}

## Use Dynamic Fee Rates

Retrieve current fee rates using [`wallet.getFeeRates()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#getfeerates) and apply them to your transaction.

{% code title="Dynamic Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei')
console.log('Fast fee rate:', feeRates.fast, 'wei')

const result = await account.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000000n,
  data: '0x',
  gasLimit: 21000,
  maxFeePerGas: feeRates.fast,
  maxPriorityFeePerGas: 2000000000n
})
console.log('Transaction sent:', result.hash)
console.log('Fee paid:', result.fee, 'wei')
```

{% endcode %}

{% hint style="info" %}
**Gas Estimation:** The `maxFeePerGas` and `maxPriorityFeePerGas` fields enable EIP-1559 transactions, ensuring more predictable gas fees and faster inclusion times.
{% endhint %}

## Next Steps

To transfer ERC-20 tokens instead of native tokens, see [Transfer ERC-20 Tokens](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage/transfer-tokens).


# Transfer ERC-20 Tokens

Transfer ERC-20 tokens and estimate transfer fees on EVM chains.

This guide explains how to transfer ERC-20 tokens (such as USD₮ or XAU₮), estimate fees, and validate inputs before executing.

## Transfer Tokens

Use [`account.transfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#transfer-options) to send ERC-20 tokens to a recipient address.

{% code title="Transfer ERC-20 Tokens" lineNumbers="true" %}

```javascript
const transferResult = await account.transfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000000000000000n // 1 token in base units
})
console.log('Transfer hash:', transferResult.hash)
console.log('Transfer fee:', transferResult.fee, 'wei')
```

{% endcode %}

## Estimate Transfer Fees

Use [`account.quoteTransfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#quotetransfer-options) to get a fee estimate before executing the transfer.

{% code title="Quote Token Transfer" lineNumbers="true" %}

```javascript
const transferQuote = await account.quoteTransfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000000000000000n
})
console.log('Transfer fee estimate:', transferQuote.fee, 'wei')
```

{% endcode %}

## Transfer with Validation

You can use `transferTokenWithValidation()` to validate addresses and check balances before transferring to catch errors early.

### 1. Validate Addresses

{% code title="Address Validation" lineNumbers="true" %}

```javascript
if (!tokenAddress.startsWith('0x') || tokenAddress.length !== 42) {
  throw new Error('Invalid token address')
}

if (!recipient.startsWith('0x') || recipient.length !== 42) {
  throw new Error('Invalid recipient address')
}
```

{% endcode %}

### 2. Check Balances

Use [`account.getTokenBalance()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#gettokenbalance-tokenaddress) and [`account.getBalance()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#getbalance) to verify sufficient funds:

{% code title="Balance Check" lineNumbers="true" %}

```javascript
const balance = await account.getTokenBalance(tokenAddress)
if (balance < amount) {
  throw new Error('Insufficient token balance')
}

const nativeBalance = await account.getBalance()
if (nativeBalance === 0n) {
  throw new Error('Need ETH for gas fees')
}
```

{% endcode %}

### 3. Quote and Execute Transfer

Use [`account.quoteTransfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#quotetransfer-options) to estimate fees, then [`account.transfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#transfer-options) to execute:

{% code title="Quote and Execute" lineNumbers="true" %}

```javascript
const quote = await account.quoteTransfer({
  token: tokenAddress,
  recipient,
  amount
})
console.log('Transfer fee estimate:', quote.fee, 'wei')

const result = await account.transfer({
  token: tokenAddress,
  recipient,
  amount
})
console.log('Transfer completed:', result.hash)
console.log('Fee paid:', result.fee, 'wei')
```

{% endcode %}

## Next Steps

Learn how to [sign and verify messages](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage/sign-verify-messages) with your EVM account.


# Sign and Verify Messages

Sign messages and verify signatures with EVM accounts.

This guide explains how to sign arbitrary messages with an owned account and verify signatures using a read-only account.

## Sign a Message

Use [`account.sign()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#sign-message) to produce a cryptographic signature for any string message.

{% code title="Sign a Message" lineNumbers="true" %}

```javascript
const message = 'Hello, Ethereum!'
const signature = await account.sign(message)
console.log('Signature:', signature)
```

{% endcode %}

## Verify a Signature

You can get a [read-only account](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#walletaccountreadonlyevm) from any `Account` object by calling [`account.toReadOnlyAccount()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#toreadonlyaccount). Use a read-only account to [`verify()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#verify-message-signature-1) that a signature was produced by the corresponding private key.

{% code title="Verify a Signature" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const isValid = await readOnlyAccount.verify(message, signature)
console.log('Signature valid:', isValid)
```

{% endcode %}

{% hint style="info" %}
You can also create a [`WalletAccountReadOnlyEvm`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#walletaccountreadonlyevm) from any public address to verify signatures without access to the private key.
{% endhint %}

## Next Steps

For best practices on handling errors, managing fees, and cleaning up memory, see [Error Handling](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm/usage/error-handling).


# Error Handling

Handle errors, manage fees, and dispose of sensitive data in EVM wallets.

This guide covers best practices for handling transaction errors, managing fee limits, and cleaning up sensitive data from memory.

## Handle Transaction Errors

Wrap transactions in `try/catch` blocks to handle common failure scenarios such as insufficient funds or exceeded fee limits.

{% code title="Transaction Error Handling" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
    value: 1000000000000000000n
  })
  console.log('Transaction successful:', result.hash)
} catch (error) {
  console.error('Transaction failed:', error.message)
  if (error.message.includes('insufficient funds')) {
    console.log('Please add more funds to your wallet')
  }
  if (error.message.includes('Exceeded maximum fee')) {
    console.log('Transfer fee too high')
  }
}
```

{% endcode %}

## Handle Token Transfer Errors

Token transfers can fail for additional reasons such as invalid addresses or insufficient token balances.

{% code title="Token Transfer Error Handling" lineNumbers="true" %}

```javascript
try {
  const result = await account.transfer({
    token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
    recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
    amount: 1000000000000000000n
  })
  console.log('Transfer completed:', result.hash)
} catch (error) {
  console.error('Transfer failed:', error.message)
  if (error.message.includes('Exceeded maximum fee')) {
    console.log('Transfer fee too high')
  }
}
```

{% endcode %}

## Manage Fee Limits

Set `transferMaxFee` when creating the wallet to prevent transactions from exceeding a maximum gas cost. Retrieve current network rates with [`getFeeRates()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#getfeerates) to make informed decisions.

{% code title="Fee Management" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei')
console.log('Fast fee rate:', feeRates.fast, 'wei')
```

{% endcode %}

## Dispose of Sensitive Data

Call [`dispose()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#dispose-1) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed.

{% code title="Memory Cleanup" lineNumbers="true" %}

```javascript
account.dispose()

wallet.dispose()
```

{% endcode %}

{% hint style="warning" %}
Always call [`dispose()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-evm/api-reference/README.md#dispose-1) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs.
{% endhint %}


# Configuration

Configuration options and settings for @tetherto/wdk-wallet-evm

## 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 or EIP-1193 provider (required for blockchain operations)
  provider: 'https://eth.drpc.org',
  
  // 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 either a URL string or an EIP-1193 compatible provider instance.

**Type:** `string | Eip1193Provider`

**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')
}
```

### 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

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet Usage</strong></td><td>Get started with WDK's EVM Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet API</strong></td><td>Get started with WDK's EVM Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk-wallet-evm

## 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, optional): RPC endpoint URL or EIP-1193 provider instance
  * `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<WalletAccountEvm>`               | -                     |
| `getAccountByPath(path)`          | Returns a wallet account at the specified BIP-44 derivation path | `Promise<WalletAccountEvm>`               | -                     |
| `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<WalletAccountEvm>` - 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<WalletAccountEvm>` - 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, optional): RPC endpoint URL or EIP-1193 provider instance
  * `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<string>`                        | -                                 |
| `sign(message)`                         | Signs a message using the account's private key                | `Promise<string>`                        | -                                 |
| `signTypedData(typedData)`              | Signs typed data according to EIP-712                          | `Promise<string>`                        | -                                 |
| `verify(message, signature)`            | Verifies a message signature                                   | `Promise<boolean>`                       | -                                 |
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712)                      | `Promise<boolean>`                       | -                                 |
| `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<bigint>`                        | If no provider                    |
| `getTokenBalance(tokenAddress)`         | Returns the balance of a specific ERC20 token                  | `Promise<bigint>`                        | If no provider                    |
| `getTokenBalances(tokenAddresses)`      | Returns balances for multiple ERC20 tokens                     | `Promise<Record<string, bigint>>`        | 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<bigint>`                        | If no provider                    |
| `getTransactionReceipt(hash)`           | Returns a transaction's receipt                                | `Promise<EvmTransactionReceipt \| null>` | If no provider                    |
| `toReadOnlyAccount()`                   | Returns a read-only copy of the account                        | `Promise<WalletAccountReadOnlyEvm>`      | -                                 |
| `dispose()`                             | Disposes the wallet account, clearing private keys from memory | `void`                                   | -                                 |

#### `getAddress()`

Returns the account's Ethereum address.

**Returns:** `Promise<string>` - 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<string>` - 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\<string, TypedDataField\[]>): The type definitions
  * `message` (Record\<string, unknown>): The message data

**Returns:** `Promise<string>` - 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)
```

#### `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<boolean>` - 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<boolean>` - 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

**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<bigint>` - 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<bigint>` - 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<Record<string, bigint>>` - 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<bigint>` - 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<EvmTransactionReceipt | null>` - 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<WalletAccountReadOnlyEvm>` - 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\<EvmWalletConfig, 'transferMaxFee'>, optional): Configuration object (same as `EvmWalletConfig` but without `transferMaxFee`, since read-only accounts cannot send transactions)
  * `provider` (string | Eip1193Provider, optional): RPC endpoint URL or EIP-1193 provider instance

**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<string>`                        | -              |
| `getBalance()`                          | Returns the native token balance (in wei)     | `Promise<bigint>`                        | If no provider |
| `getTokenBalance(tokenAddress)`         | Returns the balance of a specific ERC20 token | `Promise<bigint>`                        | If no provider |
| `getTokenBalances(tokenAddresses)`      | Returns balances for multiple ERC20 tokens    | `Promise<Record<string, bigint>>`        | 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<boolean>`                       | -              |
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712)     | `Promise<boolean>`                       | -              |
| `getTransactionReceipt(hash)`           | Returns a transaction's receipt               | `Promise<EvmTransactionReceipt \| null>` | If no provider |
| `getAllowance(token, spender)`          | Returns current allowance for a spender       | `Promise<bigint>`                        | If no provider |

#### `getAddress()`

Returns the account's Ethereum address.

**Returns:** `Promise<string>` - 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<bigint>` - 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<bigint>` - 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<Record<string, bigint>>` - 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<boolean>` - 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<boolean>` - 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<EvmTransactionReceipt | null>` - 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<bigint>` - 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)
}
```

### 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<string, TypedDataField[]>;           // The type definitions
  message: Record<string, unknown>;                  // 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;  // RPC URL or EIP-1193 provider instance
  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<Log>;                  // 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)
}
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet Usage</strong></td><td>Get started with WDK's EVM Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM Wallet Configuration</strong></td><td>Get started with WDK's EVM Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# wallet-evm-erc-4337

Overview of the @tetherto/wdk-wallet-evm-erc-4337 module

A simple and secure package to manage ERC-4337 compliant wallets for EVM-compatible blockchains. This package provides a clean API for creating, managing, and interacting with account abstraction wallets using BIP-39 seed phrases and EVM-specific 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 account abstraction wallets from a single seed phrase
* **ERC-4337 Support**: Full implementation of ERC-4337 account abstraction standard
* **UserOperation Management**: Create and send UserOperations through bundlers
* **Message Signing**: Sign and verify messages using EVM cryptography
* **EIP-712 Typed Data Support**: Sign and verify typed data payloads
* **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
* **Bundler Integration**: Support for ERC-4337 bundler services
* **Gas Optimization**: Paymaster support and gas estimation for UserOperations
* **Fee Estimation**: Dynamic fee calculation with bundler-aware estimation

## Supported Networks

ERC-4337 support depends on the Safe4337Module contract being deployed on the target chain, along with a compatible bundler and paymaster service. The following networks are verified:

* **Ethereum Mainnet** (Chain ID: 1)
* **Polygon** (Chain ID: 137)
* **Arbitrum One** (Chain ID: 42161)
* **Plasma** (Chain ID: 9745)
* **Ethereum Sepolia Testnet** (Chain ID: 11155111)

See [Configuration](https://docs.wdk.tether.io/sdk/wallet-modules/configuration#verified-supported-networks) for the full compatibility matrix and ready-to-use config examples.

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet Configuration</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet configuration</td><td><a href="wallet-evm-erc-4337/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet API</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet API</td><td><a href="wallet-evm-erc-4337/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet Usage</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet usage</td><td><a href="wallet-evm-erc-4337/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-evm-erc-4337 module.

The `@tetherto/wdk-wallet-evm-erc-4337` module provides account abstraction wallet management for EVM-compatible blockchains using the ERC-4337 standard.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Get Started</strong></td><td>Install the package and create your first smart account.</td><td><a href="usage/get-started">get-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Work with multiple smart accounts and custom derivation paths.</td><td><a href="usage/manage-accounts">manage-accounts</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query native, ERC-20, and paymaster token balances.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send Transactions</strong></td><td>Send gasless transactions and estimate fees.</td><td><a href="usage/send-transactions">send-transactions</a></td></tr><tr><td><i class="fa-coins">:coins:</i></td><td><strong>Transfer Tokens</strong></td><td>Transfer ERC-20 tokens with gasless transactions.</td><td><a href="usage/transfer-tokens">transfer-tokens</a></td></tr><tr><td><i class="fa-key">:key:</i></td><td><strong>Sign and Verify Messages</strong></td><td>Sign messages and EIP-712 typed data.</td><td><a href="usage/sign-verify-messages">sign-verify-messages</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Handle Errors</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/handle-errors">handle-errors</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM ERC-4337 Wallet Configuration</strong></td><td>Get started with WDK's EVM ERC-4337 Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM ERC-4337 Wallet API</strong></td><td>Get started with WDK's EVM ERC-4337 Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Get Started

Install and create your first ERC-4337 smart account wallet.

This guide explains how to [install the package](#1-install-the-package), [create a wallet](#2-create-a-wallet), [get your first account](#3-get-your-first-account), and optionally [convert to read-only](#4-optional-convert-to-read-only).

## 1. Install the Package

### Prerequisites

* [**Node.js**](https://nodejs.org/): version 18 or higher.
* [**npm**](https://www.npmjs.com/): usually comes with Node.js.

{% code title="Install @tetherto/wdk-wallet-evm-erc-4337" lineNumbers="true" %}

```bash
npm install @tetherto/wdk-wallet-evm-erc-4337
```

{% endcode %}

## 2. Create a Wallet

You can create a new wallet instance using the [`WalletManagerEvmErc4337`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletmanagerevmerc4337) constructor with a BIP-39 seed phrase and ERC-4337 configuration:

{% code title="Create ERC-4337 Wallet" lineNumbers="true" %}

```javascript
import WalletManagerEvmErc4337 from '@tetherto/wdk-wallet-evm-erc-4337'

const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'

const wallet = new WalletManagerEvmErc4337(seedPhrase, {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT
  }
})
```

{% endcode %}

{% hint style="danger" %}
**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.
{% endhint %}

{% hint style="info" %}
To use test/mock tokens instead of real funds, see the [testnet configuration section](https://docs.wdk.tether.io/sdk/wallet-modules/configuration#network-specific-configurations).
{% endhint %}

## 3. Get Your First Account

You can retrieve a smart account at a given index using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index):

{% code title="Get Account" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Smart account address:', address)
```

{% endcode %}

## 4. (optional) Convert to Read-Only

You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount):

{% code title="Convert to Read-Only" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
```

{% endcode %}

## Next Steps

With your wallet ready, learn how to [manage multiple accounts](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/usage/manage-accounts).


# Manage Accounts

Work with multiple smart accounts and custom derivation paths.

This guide explains how to [retrieve accounts by index](#retrieve-accounts-by-index) and [use custom derivation paths](#retrieve-account-by-custom-derivation-path).

## Retrieve Accounts by Index

You can retrieve multiple smart accounts using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) with different index values:

{% code title="Retrieve Multiple Accounts" lineNumbers="true" %}

```javascript
const account0 = await wallet.getAccount(0)
const address0 = await account0.getAddress()
console.log('Account 0 address:', address0)

const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
```

{% endcode %}

## Retrieve Account by Custom Derivation Path

You can retrieve an account at a specific derivation path using [`wallet.getAccountByPath()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypath-path):

{% code title="Custom Derivation Path" lineNumbers="true" %}

```javascript
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)
```

{% endcode %}

## Next Steps

With accounts set up, learn how to [check balances](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/usage/check-balances).


# Check Balances

Query native, ERC-20, and paymaster token balances.

This guide explains how to check [native token balances](#native-token-balance), [ERC-20 token balances](#erc-20-token-balance), [multiple token balances](#multiple-token-balances), [paymaster token balances](#paymaster-token-balance), and [read-only account balances](#read-only-account-balances).

## Native Token Balance

You can retrieve the native token balance (e.g., ETH) using [`account.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Get Native Balance" lineNumbers="true" %}

```javascript
const balance = await account.getBalance()
console.log('Native balance:', balance, 'wei')
```

{% endcode %}

## ERC-20 Token Balance

You can check the balance of a specific ERC-20 token using [`account.getTokenBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettokenbalance-tokenaddress):

{% code title="Get ERC-20 Balance" lineNumbers="true" %}

```javascript
const tokenBalance = await account.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7') // USDT
console.log('USDT balance:', tokenBalance)
```

{% endcode %}

## Multiple Token Balances

You can check balances for multiple ERC-20 tokens in a single call using [`account.getTokenBalances()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettokenbalances-tokenaddresses):

{% code title="Get Multiple Token Balances" lineNumbers="true" %}

```javascript
const tokenBalances = await account.getTokenBalances([
  '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  '0x68749665FF8D2d112Fa859AA293F07A622782F38'  // XAUT
])
console.log('Multi-token balances:', tokenBalances)
```

{% endcode %}

## Paymaster Token Balance

You can check the paymaster token balance used for paying gas fees using [`account.getPaymasterTokenBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getpaymastertokenbalance):

{% code title="Get Paymaster Token Balance" lineNumbers="true" %}

```javascript
const paymasterBalance = await account.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)
```

{% endcode %}

{% hint style="info" %}
The paymaster token balance determines how many gasless transactions you can execute. Ensure the paymaster has sufficient token balance before initiating gasless operations.
{% endhint %}

## Read-Only Account Balances

You can check balances for any smart account address without a seed phrase using [`WalletAccountReadOnlyEvmErc4337`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlyevmerc4337):

{% code title="Read-Only Balance" lineNumbers="true" %}

```javascript
import { WalletAccountReadOnlyEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337'

const readOnlyAccount = new WalletAccountReadOnlyEvmErc4337('0x...', {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
  }
})

const balance = await readOnlyAccount.getBalance()
console.log('Read-only account balance:', balance, 'wei')
```

{% endcode %}

## Next Steps

With balance checks in place, learn how to [send gasless transactions](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/usage/send-transactions).


# Send Transactions

Send gasless transactions and estimate fees.

This guide explains how to [send a gasless transaction](#send-a-gasless-transaction), [estimate fees](#estimate-fees), and [use a custom paymaster token](#send-with-custom-paymaster-token).

## Send a Gasless Transaction

You can send a transaction with gas fees paid in the paymaster token using [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-tx-config):

{% code title="Send Gasless Transaction" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000n // 0.001 ETH in wei
})
console.log('Transaction hash:', result.hash)
console.log('Fee paid in paymaster token:', result.fee)
```

{% endcode %}

{% hint style="info" %}
ERC-4337 transactions are gasless for the end user. Gas fees are paid through the configured paymaster using the specified paymaster token (e.g., USD₮).
{% endhint %}

## Estimate Fees

You can estimate the fee for a transaction without broadcasting it using [`account.quoteSendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotesendtransaction-tx-config):

{% code title="Estimate Fee" lineNumbers="true" %}

```javascript
const quote = await account.quoteSendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000n
})
console.log('Estimated fee:', quote.fee)
```

{% endcode %}

## Send with Custom Paymaster Token

You can override the default paymaster token for a specific transaction by passing a config object to [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-tx-config):

{% code title="Custom Paymaster Token" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000n
}, {
  paymasterToken: {
    address: '0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT
  }
})
```

{% endcode %}

## Next Steps

Learn how to [transfer ERC-20 tokens](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/usage/transfer-tokens).


# Transfer Tokens

Transfer ERC-20 tokens with gasless transactions.

This guide explains how to [transfer ERC-20 tokens](#transfer-erc-20-tokens), [estimate transfer fees](#estimate-transfer-fees), and [set a maximum fee limit](#transfer-with-maximum-fee-limit).

## Transfer ERC-20 Tokens

You can transfer ERC-20 tokens using gasless transactions with [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options-config):

{% code title="Transfer ERC-20 Tokens" lineNumbers="true" %}

```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)
```

{% endcode %}

## Estimate Transfer Fees

You can estimate the fee for a token transfer without executing it using [`account.quoteTransfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotetransfer-options-config):

{% code title="Estimate Transfer Fee" lineNumbers="true" %}

```javascript
const quote = await account.quoteTransfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000
})
console.log('Estimated transfer fee:', quote.fee)
```

{% endcode %}

## Transfer with Maximum Fee Limit

You can set a maximum fee for a specific transfer by passing a `transferMaxFee` in the config object to [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options-config):

{% code title="Transfer with Fee Limit" lineNumbers="true" %}

```javascript
const result = await account.transfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000
}, {
  transferMaxFee: 100000
})
```

{% endcode %}

{% hint style="warning" %}
If the estimated fee exceeds `transferMaxFee`, the transfer is cancelled with an "Exceeded maximum fee" error.
{% endhint %}

## Next Steps

Learn how to [sign and verify messages](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/usage/sign-verify-messages).


# Sign and Verify Messages

Sign messages and EIP-712 typed data with smart accounts.

This guide explains how to [sign messages](#sign-a-message), [verify signatures](#verify-a-signature), and [sign EIP-712 typed data](#sign-typed-data-eip-712).

## Sign a Message

You can sign a message with the account's private key using [`account.sign()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sign-message):

{% code title="Sign Message" lineNumbers="true" %}

```javascript
const signature = await account.sign('Hello, ERC-4337!')
console.log('Signature:', signature)
```

{% endcode %}

## Verify a Signature

You can verify a signature using a read-only account. Use [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount) to create one, then call [`readOnlyAccount.verify()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#verify-message-signature):

{% code title="Verify Signature" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const isValid = await readOnlyAccount.verify('Hello, ERC-4337!', signature)
console.log('Signature valid:', isValid)
```

{% endcode %}

## Sign Typed Data (EIP-712)

You can sign EIP-712 structured data using [`account.signTypedData()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#signtypeddata-typeddata):

{% code title="Sign Typed Data" lineNumbers="true" %}

```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: '0x1234567890abcdef1234567890abcdef12345678',
    to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
    contents: 'Hello!'
  }
}

const typedDataSignature = await account.signTypedData(typedData)
console.log('Typed data signature:', typedDataSignature)
```

{% endcode %}

You can verify typed data signatures using [`readOnlyAccount.verifyTypedData()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#verifytypeddata-typeddata-signature):

{% code title="Verify Typed Data" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const isValid = await readOnlyAccount.verifyTypedData(typedData, typedDataSignature)
console.log('Typed data signature valid:', isValid)
```

{% endcode %}

## Next Steps

Learn how to [handle errors and manage resources](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-evm-erc-4337/usage/handle-errors).


# Handle Errors

Handle errors, manage fees, and dispose of sensitive data.

This guide explains how to [handle transaction errors](#transaction-errors), [handle transfer errors](#transfer-errors), and follow [best practices](#best-practices) for fee management and memory cleanup.

## Transaction Errors

Transactions sent via [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-tx-config) can fail when the paymaster token balance is insufficient. Wrap calls in a `try/catch` block:

{% code title="Handle Transaction Errors" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
    value: 1000000000000000n
  })
  console.log('Transaction hash:', result.hash)
} catch (error) {
  if (error.message.includes('not enough funds')) {
    console.error('Insufficient paymaster token balance')
  } else {
    console.error('Transaction failed:', error.message)
  }
}
```

{% endcode %}

## Transfer Errors

Token transfers via [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options-config) can fail due to insufficient balance or exceeding the maximum fee limit:

{% code title="Handle Transfer Errors" lineNumbers="true" %}

```javascript
try {
  const result = await account.transfer({
    token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
    recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
    amount: 1000000
  })
  console.log('Transfer hash:', result.hash)
} catch (error) {
  if (error.message.includes('Exceeded maximum fee')) {
    console.error('Transfer cancelled: fee exceeds the configured limit')
  } else if (error.message.includes('not enough funds')) {
    console.error('Insufficient paymaster token balance')
  } else {
    console.error('Transfer failed:', error.message)
  }
}
```

{% endcode %}

## Best Practices

### Fee Management

You can retrieve current network fee rates using [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates):

{% code title="Get Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal)
console.log('Fast fee rate:', feeRates.fast)
```

{% endcode %}

### Dispose of Sensitive Data

For security, clear sensitive data from memory when a session is complete. Use [`account.dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose-1) and [`wallet.dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) to securely wipe private keys:

{% code title="Dispose Resources" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
    value: 1000000000000000n
  })
  console.log('Transaction hash:', result.hash)
} finally {
  account.dispose()
  wallet.dispose()
}
```

{% endcode %}

{% hint style="warning" %}
Always call [`dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) when finished with accounts. Private keys are securely wiped from memory. Disposal is irreversible.
{% endhint %}


# Configuration

Configuration options and settings for @tetherto/wdk-wallet-evm-erc-4337

## Wallet Configuration

The `WalletManagerEvmErc4337` requires a complete ERC-4337 configuration object with all required parameters:

```javascript
import WalletManagerEvmErc4337 from '@tetherto/wdk-wallet-evm-erc-4337'

const config = {
  // Required parameters
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  safeModulesVersion: '0.3.0', // '0.2.0' and '0.3.0' are valid
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  bundlerUrl: `https://api.pimlico.io/v1/ethereum/rpc?apikey=${PIMLICO_API_KEY}`,
  paymasterUrl: `https://api.pimlico.io/v2/ethereum/rpc?apikey=${PIMLICO_API_KEY}`,
  paymasterAddress: '0x777777777777AeC03fd955926DbF81597e66834C',
  transferMaxFee: 100000000000000,
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
  }
}

const wallet = new WalletManagerEvmErc4337(seedPhrase, config)
```

## Account Configuration

Both `WalletAccountEvmErc4337` and `WalletAccountReadOnlyEvmErc4337` use the same configuration structure:

```javascript
import { WalletAccountEvmErc4337, WalletAccountReadOnlyEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337'

// Full access account
const account = new WalletAccountEvmErc4337(
  seedPhrase,
  "0'/0/0", // BIP-44 derivation path
  config    // Same config as wallet manager
)

// Read-only account (transferMaxFee not needed)
const readOnlyAccount = new WalletAccountReadOnlyEvmErc4337(
  '0x...', // Smart contract wallet address
  {
    chainId: 1,
    provider: 'https://rpc.mevblocker.io/fast',
    bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
    paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
    entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
    safeModulesVersion: '0.3.0',
    paymasterToken: {
      address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
    }
    // Note: transferMaxFee omitted for read-only accounts
  }
)
```

## Configuration Options

### Chain ID

The `chainId` option specifies the blockchain network ID. **Required** for fee estimation and Safe4337Pack initialization.

**Type:** `number`\
**Required:** Yes

**Examples:**

```javascript
// Ethereum Mainnet
const config = { chainId: 1 }

// Polygon Mainnet  
const config = { chainId: 137 }

// Arbitrum One
const config = { chainId: 42161 }

// Plasma
const config = { chainId: 9745 }
```

### Provider

The `provider` option specifies the RPC endpoint or EIP-1193 provider instance for blockchain interactions. **Required** for all operations.

**Type:** `string | Eip1193Provider`\
**Required:** Yes

**Examples:**

```javascript
// Using RPC URL
const config = {
  provider: 'https://rpc.mevblocker.io/fast'
}

// Using browser provider (MetaMask)
const config = {
  provider: window.ethereum
}

// Using custom ethers provider
import { JsonRpcProvider } from 'ethers'
const config = {
  provider: new JsonRpcProvider('https://rpc.mevblocker.io/fast')
}
```

### Bundler URL

The `bundlerUrl` option specifies the URL of the ERC-4337 bundler service that handles UserOperation bundling and submission to the mempool. **Required** for transaction processing.

**Type:** `string`\
**Required:** Yes

**Example:**

```javascript
const config = {
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum'
}
```

### Paymaster URL

The `paymasterUrl` option specifies the URL of the paymaster service that sponsors transaction fees using ERC-20 tokens or sponsorship policies.

**Type:** `string`\
**Required:** Yes, for Paymaster Token mode and Sponsorship Policy mode. Not used in Native Coins mode.

**Example:**

```javascript
const config = {
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum'
}
```

### Paymaster Address

The `paymasterAddress` option specifies the address of the paymaster smart contract.

**Type:** `string`\
**Required:** Yes, for Paymaster Token mode only. Not used in Sponsorship Policy or Native Coins modes.

**Example:**

```javascript
const config = {
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba'
}
```

### Entry Point Address

The `entryPointAddress` option specifies the address of the ERC-4337 EntryPoint smart contract. **Required** for UserOperation processing.

**Type:** `string`\
**Required:** Yes

**Standard EntryPoint v0.7:**

```javascript
const config = {
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032'
}
```

### Safe Modules Version

The `safeModulesVersion` option specifies the Safe modules version for smart contract wallet implementation. **Required** for Safe4337Pack initialization.

**Type:** `string`\
**Required:** Yes

**Example:**

```javascript
const config = {
  safeModulesVersion: '0.3.0'
}
```

### Paymaster Token

The `paymasterToken` option specifies the ERC-20 token used for paying transaction fees through the paymaster.

**Type:** `object`\
**Required:** Yes, for Paymaster Token mode only. Not used in Sponsorship Policy or Native Coins modes.

**Properties:**

* `address` (string): The ERC-20 token contract address

**Example:**

```javascript
const config = {
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USD₮
  }
}
```

### Sponsorship Policy ID

The `sponsorshipPolicyId` option specifies the sponsorship policy identifier for sponsored transactions.

**Type:** `string`\
**Required:** No (optional), only used in Sponsorship Policy mode.

**Example:**

```javascript
const config = {
  isSponsored: true,
  sponsorshipPolicyId: 'sp_my_policy_id'
}
```

### Gas Payment Mode Flags

These boolean flags control which gas payment mode is used. Only one mode should be active at a time.

#### `isSponsored`

Enables Sponsorship Policy mode, where a sponsor covers transaction fees.

**Type:** `boolean`\
**Default:** `false`

```javascript
const config = {
  isSponsored: true,
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum'
}
```

#### `useNativeCoins`

Enables Native Coins mode, where the user pays fees in the chain's native currency (ETH, MATIC, etc.).

**Type:** `boolean`\
**Default:** `false`

```javascript
const config = {
  useNativeCoins: true,
  transferMaxFee: 100000000000000n // Optional: max fee in wei
}
```

### Transfer Max Fee

The `transferMaxFee` option sets the maximum fee amount **in paymaster token units** for transfer operations. This prevents transactions with unexpectedly high fees. **Optional** parameter.

**Type:** `number | bigint`\
**Required:** No (optional)\
**Unit:** Paymaster token base units

**Example:**

```javascript
const config = {
  transferMaxFee: 100000 // 100,000 paymaster token units (e.g., 0.1 USD₮ if 6 decimals)
}

// Usage with error handling
try {
  const result = await account.transfer({
    token: '0x...',
    recipient: '0x...',
    amount: 1000000
  })
} catch (error) {
  if (error.message.includes('Exceeded maximum fee')) {
    console.error('Transfer cancelled: Fee too high')
  }
}
```

## Network-Specific Configurations

ERC-4337 account abstraction requires three independent layers on any given chain:

1. **Safe4337Module contract** deployed and registered in `@safe-global/safe-modules-deployments`
2. **Bundler service** (Pimlico or Candide) that supports the chain
3. **Paymaster service** (Pimlico or Candide) that supports the chain

If any layer is missing for a chain, the SDK will fail. The following networks have been verified to support all three layers.

### Verified Supported Networks

| Network           | Chain ID | Bundler           | Paymaster         | Status    |
| ----------------- | -------- | ----------------- | ----------------- | --------- |
| Ethereum          | 1        | Candide           | Candide           | Supported |
| Polygon           | 137      | Candide           | Candide           | Supported |
| Arbitrum One      | 42161    | Pimlico (public)  | Pimlico (public)  | Supported |
| Plasma            | 9745     | Candide           | Candide           | Supported |
| Sepolia (testnet) | 11155111 | Pimlico / Candide | Pimlico / Candide | Supported |

{% hint style="danger" %}
**Avalanche C-Chain (43114) is not supported.** The Safe4337Module v0.3.0 contract is not deployed on Avalanche. Attempting to use ERC-4337 on Avalanche will fail with `Safe4337Module not available for chain 43114`.
{% endhint %}

### Ethereum Mainnet

{% hint style="info" %}
**Supported Paymaster Tokens**

The following tokens are supported for gas payments on Ethereum Mainnet:

* **USD₮**: `0xdAC17F958D2ee523a2206206994597C13D831ec7`
* **USA₮**: `0x07041776f5007aca2a54844f50503a18a72a8b68`
* **XAU₮**: `0x68749665ff8d2d112fa859aa293f07a622782f38`
  {% endhint %}

```javascript
const ethereumConfig = {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT
  },
  transferMaxFee: 100000 // 100,000 paymaster token units (e.g., 0.1 USDT if 6 decimals)
}
```

### Polygon Mainnet

```javascript
const polygonConfig = {
  chainId: 137,
  provider: 'https://polygon-bor-rpc.publicnode.com',
  bundlerUrl: 'https://api.candide.dev/public/v3/polygon',
  paymasterUrl: 'https://api.candide.dev/public/v3/polygon',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F' // USDT on Polygon
  },
  transferMaxFee: 100000
}
```

### Arbitrum One

```javascript
const arbitrumConfig = {
  chainId: 42161,
  provider: 'https://arb1.arbitrum.io/rpc',
  bundlerUrl: 'https://public.pimlico.io/v2/42161/rpc',
  paymasterUrl: 'https://public.pimlico.io/v2/42161/rpc',
  paymasterAddress: '0x777777777777AeC03fd955926DbF81597e66834C',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' // USDT on Arbitrum
  },
  transferMaxFee: 100000
}
```

### Plasma

```javascript
const plasmaConfig = {
  chainId: 9745,
  provider: 'https://plasma.drpc.org',
  bundlerUrl: 'https://api.candide.dev/public/v3/9745',
  paymasterUrl: 'https://api.candide.dev/public/v3/9745',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb' // USDT
  },
  transferMaxFee: 100000 // 100,000 paymaster token units (e.g., 0.1 USDT if 6 decimals)
}
```

### Sepolia Testnet (USD₮ ERC-20 mock/testnet only)

```javascript

// Pimlico
const sepoliaConfigPimlico = {
  chainId: 11155111,
  provider: 'https://sepolia.drpc.org',
  bundlerUrl: 'https://public.pimlico.io/v2/11155111/rpc',
  paymasterUrl: 'https://public.pimlico.io/v2/11155111/rpc',
  paymasterAddress: '0x777777777777AeC03fd955926DbF81597e66834C',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xd077a400968890eacc75cdc901f0356c943e4fdb' // USDT Sepolia
  }, 
  transferMaxFee: 100000 // 0.1 USDT (6 decimals)
}

// Candide
const sepoliaConfigCandide = {
  chainId: 11155111,
  provider: 'https://sepolia.drpc.org',
  bundlerUrl: 'https://api.candide.dev/public/v3/11155111',
  paymasterUrl: 'https://api.candide.dev/public/v3/11155111',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterToken: {
    address: '0xd077a400968890eacc75cdc901f0356c943e4fdb' // USDT Sepolia
  },   
  transferMaxFee: 100000
}
```

**Important** Ethereum Sepolia is a testnet. The USD₮ tokens available at the links below are not real and do not entitle the holder to anything. In particular, they cannot be redeemed with Tether International, S.A. de C.V. ("Tether International") and are not Tether Tokens as described in [Tether International's Terms of Service](https://tether.to/en/legal). The USD₮ tokens available at the links below on this testnet are intended for testing WDK on Ethereum Sepolia. The links below are links to third-party websites and are Third-Party Information as described in Tether Operations, S.A. de [C.V.'s Website Terms](https://tether.io/terms/)

**USD₮ on Sepolia contract:** [0xd077a400968890eacc75cdc901f0356c943e4fdb](https://sepolia.etherscan.io/address/0xd077a400968890eacc75cdc901f0356c943e4fdb)

**Get test USD₮:**

* [Pimlico faucet](https://dashboard.pimlico.io/test-erc20-faucet)
* [Candide faucet](https://dashboard.candide.dev/faucet)

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet Usage</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet API</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk-wallet-evm-erc-4337

## Table of Contents

| Class                                                               | Description                                                                                                                   | Methods                                                                         |
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [WalletManagerEvmErc4337](#walletmanagerevmerc4337)                 | Main class for managing ERC-4337 EVM wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`.                            | [Constructor](#constructor), [Methods](#methods)                                |
| [WalletAccountEvmErc4337](#walletaccountevmerc4337)                 | Individual ERC-4337 wallet account implementation. Extends `WalletAccountReadOnlyEvmErc4337` and implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) |
| [WalletAccountReadOnlyEvmErc4337](#walletaccountreadonlyevmerc4337) | Read-only ERC-4337 wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`.                               | [Constructor](#constructor-2), [Methods](#methods-2)                            |
| [ConfigurationError](#configurationerror)                           | Error thrown when the wallet configuration is invalid or has missing required fields.                                         | -                                                                               |

## WalletManagerEvmErc4337

The main class for managing ERC-4337 EVM wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`.

### Constructor

```javascript
new WalletManagerEvmErc4337(seed, config)
```

**Parameters:**

* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `config` (EvmErc4337WalletConfig): Configuration object with common fields and a gas payment mode

**Common config fields (required for all modes):**

* `chainId` (number): The blockchain's ID (e.g., 1 for Ethereum mainnet)
* `provider` (string | Eip1193Provider): RPC endpoint URL or EIP-1193 provider instance
* `bundlerUrl` (string): The URL of the bundler service
* `entryPointAddress` (string): The address of the entry point smart contract
* `safeModulesVersion` (string): The Safe modules version (e.g., `'0.3.0'`)

**Gas payment mode** (one of the following):

{% tabs %}
{% tab title="Paymaster Token" %}
Fees are paid using an ERC-20 token through a paymaster service.

* `paymasterUrl` (string): The URL of the paymaster service
* `paymasterAddress` (string): The address of the paymaster smart contract
* `paymasterToken` (object): The paymaster token configuration
  * `address` (string): The address of the ERC-20 token used for fees
* `transferMaxFee` (number | bigint, optional): Maximum fee limit in paymaster token units

```javascript
const wallet = new WalletManagerEvmErc4337(seedPhrase, {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  // Paymaster token mode
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT
  },
  transferMaxFee: 100000 // Optional: max fee in token units
})
```

{% endtab %}

{% tab title="Sponsorship" %}
Fees are sponsored by a third party via a sponsorship policy.

* `isSponsored` (true): Enables sponsorship mode
* `paymasterUrl` (string): The URL of the paymaster service
* `sponsorshipPolicyId` (string, optional): The sponsorship policy ID

```javascript
const wallet = new WalletManagerEvmErc4337(seedPhrase, {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  // Sponsorship mode
  isSponsored: true,
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  sponsorshipPolicyId: 'your-policy-id' // Optional
})
```

{% endtab %}

{% tab title="Native Coins" %}
Fees are paid using the chain's native token (e.g., ETH).

* `useNativeCoins` (true): Enables native coin fee payment
* `transferMaxFee` (number | bigint, optional): Maximum fee limit in native token units

```javascript
const wallet = new WalletManagerEvmErc4337(seedPhrase, {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  // Native coins mode
  useNativeCoins: true,
  transferMaxFee: 100000000000000n // Optional: max fee in wei
})
```

{% endtab %}
{% endtabs %}

### 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<WalletAccountEvmErc4337>`        | -              |
| `getAccountByPath(path)`          | Returns a wallet account at the specified BIP-44 derivation path | `Promise<WalletAccountEvmErc4337>`        | -              |
| `getFeeRates()`                   | Returns current fee rates for transactions                       | `Promise<{normal: bigint, fast: bigint}>` | If no provider |
| `dispose()`                       | Disposes all wallet accounts, clearing private keys from memory  | `void`                                    | -              |

### Properties

| Property | Type         | Description                       |
| -------- | ------------ | --------------------------------- |
| `seed`   | `Uint8Array` | The wallet's seed phrase as 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 = WalletManagerEvmErc4337.getRandomSeedPhrase()
console.log('Seed phrase:', seedPhrase) // 12 words

const longSeedPhrase = WalletManagerEvmErc4337.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 = WalletManagerEvmErc4337.isValidSeedPhrase('abandon abandon abandon ...')
console.log('Valid:', isValid)
```

#### `getAccount(index)`

Returns a wallet account at the specified index using BIP-44 derivation.

**Parameters:**

* `index` (number, optional): The index of the account to get (default: 0)

**Returns:** `Promise<WalletAccountEvmErc4337>` - The wallet account

**Example:**

```javascript
// Get first account (index 0)
const account = await wallet.getAccount(0)

// Get default account
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<WalletAccountEvmErc4337>` - The wallet account

**Example:**

```javascript
// Full derivation path: m/44'/60'/0'/0/1
const account = await wallet.getAccountByPath("0'/0/1")
```

#### `getFeeRates()`

Returns current fee rates with ERC-4337 specific multipliers.

**Returns:** `Promise<{normal: bigint, fast: bigint}>` - Fee rates in wei

**Throws:** Error if no provider is configured

**Example:**

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'wei') // base fee × 1.1
console.log('Fast fee rate:', feeRates.fast, 'wei')     // base fee × 2.0
```

#### `dispose()`

Disposes all wallet accounts, clearing private keys from memory.

**Example:**

```javascript
// Clean up when done
wallet.dispose()
```

## WalletAccountEvmErc4337

Represents an individual ERC-4337 wallet account. Extends `WalletAccountReadOnlyEvmErc4337` and implements `IWalletAccount`.

### Constructor

```javascript
new WalletAccountEvmErc4337(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` (EvmErc4337WalletConfig): Configuration object (same as [WalletManagerEvmErc4337](#constructor))

**Example:**

```javascript
const account = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
  }
})
```

### Methods

| Method                                  | Description                                                    | Returns                                    | Throws             |
| --------------------------------------- | -------------------------------------------------------------- | ------------------------------------------ | ------------------ |
| `predictSafeAddress(owner, config)`     | (static) Predicts the Safe address for a given owner           | `string`                                   | -                  |
| `getAddress()`                          | Returns the Safe account's address                             | `Promise<string>`                          | -                  |
| `sign(message)`                         | Signs a message using the account's private key                | `Promise<string>`                          | -                  |
| `signTypedData(typedData)`              | Signs typed data according to EIP-712                          | `Promise<string>`                          | -                  |
| `verify(message, signature)`            | Verifies a message signature                                   | `Promise<boolean>`                         | -                  |
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712)                      | `Promise<boolean>`                         | -                  |
| `sendTransaction(tx, config?)`          | Sends a transaction via UserOperation                          | `Promise<{hash: string, fee: bigint}>`     | If fee exceeds max |
| `quoteSendTransaction(tx, config?)`     | Estimates the fee for a UserOperation                          | `Promise<{fee: bigint}>`                   | -                  |
| `transfer(options, config?)`            | Transfers ERC20 tokens via UserOperation                       | `Promise<{hash: string, fee: bigint}>`     | If fee exceeds max |
| `quoteTransfer(options, config?)`       | Estimates the fee for an ERC20 transfer                        | `Promise<{fee: bigint}>`                   | -                  |
| `approve(options)`                      | Approves a spender to spend ERC20 tokens                       | `Promise<{hash: string, fee: bigint}>`     | -                  |
| `getBalance()`                          | Returns the native token balance (in wei)                      | `Promise<bigint>`                          | -                  |
| `getTokenBalance(tokenAddress)`         | Returns the balance of a specific ERC20 token                  | `Promise<bigint>`                          | -                  |
| `getTokenBalances(tokenAddresses)`      | Returns balances for multiple ERC20 tokens                     | `Promise<Record<string, bigint>>`          | -                  |
| `getPaymasterTokenBalance()`            | Returns the paymaster token balance                            | `Promise<bigint>`                          | -                  |
| `getAllowance(token, spender)`          | Returns current token allowance for a spender                  | `Promise<bigint>`                          | -                  |
| `getTransactionReceipt(hash)`           | Returns a transaction receipt                                  | `Promise<EvmTransactionReceipt \| null>`   | -                  |
| `getUserOperationReceipt(hash)`         | Returns a UserOperation receipt                                | `Promise<UserOperationReceipt \| null>`    | -                  |
| `toReadOnlyAccount()`                   | Returns a read-only copy of the account                        | `Promise<WalletAccountReadOnlyEvmErc4337>` | -                  |
| `dispose()`                             | Disposes the wallet account, clearing private keys from memory | `void`                                     | -                  |

**`getAddress()`**

Returns the Safe smart contract wallet address (not the underlying EOA address).

**Returns:** `Promise<string>` - The Safe account's address

**Example:**

```javascript
const address = await account.getAddress()
console.log('Safe account address:', address) // 0x... (Smart contract address)
```

**`sign(message)`**

Signs a message using the underlying EOA private key.

**Parameters:**

* `message` (string): The message to sign

**Returns:** `Promise<string>` - The message signature

**Example:**

```javascript
const message = 'Hello, ERC-4337!'
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

**Returns:** `Promise<string>` - 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('Typed data signature:', signature)
```

**`verify(message, signature)`**

Verifies a message signature against the underlying EOA address.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify

**Returns:** `Promise<boolean>` - True if signature is valid

**Example:**

```javascript
const isValid = await account.verify(message, signature)
console.log('Signature valid:', isValid)
```

**`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<boolean>` - True if signature is valid

**Example:**

```javascript
const isValid = await account.verifyTypedData(typedData, signature)
console.log('Typed data signature valid:', isValid)
```

**`sendTransaction(tx, config?)`**

Sends a transaction via UserOperation through the bundler.

**Parameters:**

* `tx` (EvmTransaction | EvmTransaction\[]): Transaction object or array for batch transactions
  * `to` (string): Recipient address
  * `value` (number | bigint): Amount in wei
  * `data` (string, optional): Transaction data in hex format
* `config` (optional): Per-call configuration override. Accepts a partial version of the gas payment mode fields (see [Config Override](#config-override)).

**Returns:** `Promise<{hash: string, fee: bigint}>` - UserOperation hash and fee

**Throws:** Error if fee exceeds `transferMaxFee`

**Example:**

```javascript
// Single transaction
const result = await account.sendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000000n, // 1 ETH
  data: '0x'
})
console.log('UserOperation hash:', result.hash)
console.log('Fee paid:', result.fee)

// Batch transactions
const batchResult = await account.sendTransaction([
  { to: '0x...', value: 100000000000000000n },
  { to: '0x...', value: 200000000000000000n }
])

// With per-call config override
const customResult = await account.sendTransaction({
  to: '0x...',
  value: 1000000000000000000n
}, {
  paymasterToken: { address: '0xNewToken...' }
})
```

**`quoteSendTransaction(tx, config?)`**

Estimates the fee for a UserOperation without sending it.

**Parameters:**

* `tx` (EvmTransaction | EvmTransaction\[]): Transaction object or array (same as sendTransaction)
* `config` (optional): Per-call configuration override (see [Config Override](#config-override))

**Returns:** `Promise<{fee: bigint}>` - Fee estimate

**Example:**

```javascript
const quote = await account.quoteSendTransaction({
  to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  value: 1000000000000000000n
})
console.log('Estimated fee:', quote.fee)
```

**`transfer(options, config?)`**

Transfers ERC20 tokens via UserOperation.

**Parameters:**

* `options` (TransferOptions): Transfer options
  * `token` (string): ERC20 token contract address
  * `recipient` (string): Recipient address
  * `amount` (number | bigint): Amount in token base units
* `config` (optional): Per-call configuration override (see [Config Override](#config-override))

**Returns:** `Promise<{hash: string, fee: bigint}>` - UserOperation hash and fee

**Throws:**

* Error if fee exceeds `transferMaxFee`
* Error if insufficient token balance

**Example:**

```javascript
const result = await account.transfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000 // 1 USDT (6 decimals)
}, {
  transferMaxFee: 50000 // Override max fee for this call
})
console.log('Transfer hash:', result.hash)
console.log('Transfer fee:', result.fee)
```

**`quoteTransfer(options, config?)`**

Estimates the fee for an ERC20 token transfer.

**Parameters:**

* `options` (TransferOptions): Transfer options (same as transfer)
* `config` (optional): Per-call configuration override (see [Config Override](#config-override))

**Returns:** `Promise<{fee: bigint}>` - Fee estimate

**Example:**

```javascript
const quote = await account.quoteTransfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee)
```

**`getBalance()`**

Returns the Safe account's native token balance.

**Returns:** `Promise<bigint>` - Balance in wei

**Example:**

```javascript
const balance = await account.getBalance()
console.log('Native balance:', balance, 'wei')
```

**`getTokenBalance(tokenAddress)`**

Returns the balance of a specific ERC20 token in the Safe account.

**Parameters:**

* `tokenAddress` (string): The ERC20 token contract address

**Returns:** `Promise<bigint>` - Token balance in base units

**Example:**

```javascript
const tokenBalance = await account.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7')
console.log('USDT balance:', tokenBalance) // In 6 decimal units
```

**`getTokenBalances(tokenAddresses)`**

Returns balances for multiple ERC20 tokens in one call.

**Parameters:**

* `tokenAddresses` (string\[]): List of ERC20 token contract addresses

**Returns:** `Promise<Record<string, bigint>>` - Object mapping each token address to its balance in base units

**Example:**

```javascript
const tokenBalances = await account.getTokenBalances([
  '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  '0x68749665FF8D2d112Fa859AA293F07A622782F38'  // XAUT
])
console.log('Token balances:', tokenBalances)
```

**`getPaymasterTokenBalance()`**

Returns the balance of the configured paymaster token used for paying fees.

**Returns:** `Promise<bigint>` - Paymaster token balance in base units

**Example:**

```javascript
const paymasterBalance = await account.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)

// Check if sufficient for transaction
if (paymasterBalance < 10000n) {
  console.warn('Low paymaster token balance - may not cover fees')
}
```

**`approve(options)`**

Approves a spender to spend ERC20 tokens on behalf of the Safe account.

**Parameters:**

* `options` (ApproveOptions): Approve options
  * `token` (string): ERC20 token contract address
  * `spender` (string): The address allowed to spend the tokens
  * `amount` (number | bigint): Amount to approve in token base units

**Returns:** `Promise<{hash: string, fee: bigint}>` - Transaction result

**Example:**

```javascript
const result = await account.approve({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  spender: '0xSpenderContract...',
  amount: 1000000n // 1 USDT
})
console.log('Approval 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<bigint>` - The current allowance

**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<EvmTransactionReceipt | null>` - Transaction receipt or null if not mined

**Example:**

```javascript
const receipt = await account.getTransactionReceipt('0x...')
if (receipt) {
  console.log('Confirmed in block:', receipt.blockNumber)
}
```

**`getUserOperationReceipt(hash)`**

Returns a UserOperation receipt by hash.

**Parameters:**

* `hash` (string): The UserOperation hash

**Returns:** `Promise<UserOperationReceipt | null>` - UserOperation receipt or null if not processed

**Example:**

```javascript
const receipt = await account.getUserOperationReceipt('0x...')
if (receipt) {
  console.log('UserOp receipt:', receipt)
}
```

**`toReadOnlyAccount()`**

Creates a read-only copy of the account with the same Safe address and configuration.

**Returns:** `Promise<WalletAccountReadOnlyEvmErc4337>` - 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 not be available
```

**`dispose()`**

Disposes the wallet account, clearing private keys from memory.

**Example:**

```javascript
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) |

**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 (null after dispose)
```

⚠️ **Security Note**: The `keyPair` property contains sensitive cryptographic material. Never log, display, or expose the private key.

## WalletAccountReadOnlyEvmErc4337

Represents a read-only ERC-4337 wallet account that can query balances and estimate fees but cannot send transactions.

### Constructor

```javascript
new WalletAccountReadOnlyEvmErc4337(address, config)
```

**Parameters:**

* `address` (string): The EOA address (owner address)
* `config` (Omit\<EvmErc4337WalletConfig, 'transferMaxFee'>): Configuration object without `transferMaxFee`

**Example:**

```javascript
const readOnlyAccount = new WalletAccountReadOnlyEvmErc4337('0x...', {
  chainId: 1,
  provider: 'https://rpc.mevblocker.io/fast',
  bundlerUrl: 'https://api.candide.dev/public/v3/ethereum',
  entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
  safeModulesVersion: '0.3.0',
  paymasterUrl: 'https://api.candide.dev/public/v3/ethereum',
  paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba',
  paymasterToken: {
    address: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
  }
})
```

### Static Methods

| Method                              | Description                                                                  | Returns  |
| ----------------------------------- | ---------------------------------------------------------------------------- | -------- |
| `predictSafeAddress(owner, config)` | Predicts the Safe address for a given owner without instantiating an account | `string` |

#### `predictSafeAddress(owner, config)` (static)

Predicts the address of a Safe account.

**Parameters:**

* `owner` (string): The Safe owner's EOA address
* `config` (object): Configuration with:
  * `chainId` (number): The blockchain ID
  * `safeModulesVersion` (string): The Safe modules version

**Returns:** `string` - The predicted Safe address

**Example:**

```javascript
const safeAddress = WalletAccountReadOnlyEvmErc4337.predictSafeAddress(
  '0xOwnerEOA...',
  { chainId: 1, safeModulesVersion: '0.3.0' }
)
console.log('Predicted Safe address:', safeAddress)

// Also available on WalletAccountEvmErc4337 (inherited)
const sameAddress = WalletAccountEvmErc4337.predictSafeAddress(
  '0xOwnerEOA...',
  { chainId: 1, safeModulesVersion: '0.3.0' }
)
```

### Methods

| Method                                  | Description                                   | Returns                                  | Throws              |
| --------------------------------------- | --------------------------------------------- | ---------------------------------------- | ------------------- |
| `getAddress()`                          | Returns the Safe account's address            | `Promise<string>`                        | -                   |
| `verify(message, signature)`            | Verifies a message signature                  | `Promise<boolean>`                       | -                   |
| `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712)     | `Promise<boolean>`                       | -                   |
| `getBalance()`                          | Returns the native token balance (in wei)     | `Promise<bigint>`                        | -                   |
| `getTokenBalance(tokenAddress)`         | Returns the balance of a specific ERC20 token | `Promise<bigint>`                        | -                   |
| `getTokenBalances(tokenAddresses)`      | Returns balances for multiple ERC20 tokens    | `Promise<Record<string, bigint>>`        | -                   |
| `getPaymasterTokenBalance()`            | Returns the paymaster token balance           | `Promise<bigint>`                        | -                   |
| `getAllowance(token, spender)`          | Returns current token allowance for a spender | `Promise<bigint>`                        | -                   |
| `quoteSendTransaction(tx, config?)`     | Estimates the fee for a UserOperation         | `Promise<{fee: bigint}>`                 | If simulation fails |
| `quoteTransfer(options, config?)`       | Estimates the fee for an ERC20 transfer       | `Promise<{fee: bigint}>`                 | If simulation fails |
| `getTransactionReceipt(hash)`           | Returns a transaction receipt                 | `Promise<EvmTransactionReceipt \| null>` | -                   |
| `getUserOperationReceipt(hash)`         | Returns a UserOperation receipt               | `Promise<UserOperationReceipt \| null>`  | -                   |

**`getAddress()`**

Returns the Safe smart contract wallet address.

**Returns:** `Promise<string>` - The Safe account's address

**Example:**

```javascript
const address = await readOnlyAccount.getAddress()
console.log('Safe address:', address)
```

**`verify(message, signature)`**

Verifies a message signature against the underlying EOA address.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify

**Returns:** `Promise<boolean>` - True if signature is valid

**Example:**

```javascript
const isValid = await readOnlyAccount.verify(message, signature)
console.log('Signature valid:', isValid)
```

**`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<boolean>` - True if signature is valid

**Example:**

```javascript
const isValid = await readOnlyAccount.verifyTypedData(typedData, signature)
console.log('Typed data signature valid:', isValid)
```

**`getBalance()`**

Returns the Safe account's native token balance.

**Returns:** `Promise<bigint>` - Balance in wei

**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<bigint>` - Token balance in base units

**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<Record<string, bigint>>` - Object mapping each token address to its balance in base units

**Example:**

```javascript
const tokenBalances = await readOnlyAccount.getTokenBalances([
  '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  '0x68749665FF8D2d112Fa859AA293F07A622782F38'  // XAUT
])
console.log('Token balances:', tokenBalances)
```

**`getPaymasterTokenBalance()`**

Returns the balance of the configured paymaster token.

**Returns:** `Promise<bigint>` - Paymaster token balance in base units

**Example:**

```javascript
const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance()
console.log('Paymaster token balance:', paymasterBalance)
```

**`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<bigint>` - The current allowance

**Example:**

```javascript
const allowance = await readOnlyAccount.getAllowance(
  '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  '0xSpenderContract...'
)
console.log('Allowance:', allowance)
```

**`quoteSendTransaction(tx, config?)`**

Estimates the fee for a UserOperation.

**Parameters:**

* `tx` (EvmTransaction | EvmTransaction\[]): Transaction object or array
* `config` (optional): Per-call configuration override (see [Config Override](#config-override))

**Returns:** `Promise<{fee: bigint}>` - Fee estimate

**Throws:** Error if simulation fails

**Example:**

```javascript
try {
  const quote = await readOnlyAccount.quoteSendTransaction({
    to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
    value: 1000000000000000000n
  })
  console.log('Estimated fee:', quote.fee)
} catch (error) {
  if (error.message.includes('not enough funds')) {
    console.error('Insufficient paymaster token balance')
  }
}
```

**`quoteTransfer(options, config?)`**

Estimates the fee for an ERC20 token transfer.

**Parameters:**

* `options` (TransferOptions): Transfer options
* `config` (optional): Per-call configuration override (see [Config Override](#config-override))

**Returns:** `Promise<{fee: bigint}>` - Fee estimate

**Example:**

```javascript
const quote = await readOnlyAccount.quoteTransfer({
  token: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
  recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6',
  amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee)
```

**`getTransactionReceipt(hash)`**

Returns a transaction receipt by hash.

**Parameters:**

* `hash` (string): The transaction hash

**Returns:** `Promise<EvmTransactionReceipt | null>` - Transaction receipt or null if not mined

**Example:**

```javascript
const receipt = await readOnlyAccount.getTransactionReceipt('0x...')
if (receipt) {
  console.log('Transaction confirmed in block:', receipt.blockNumber)
  console.log('Status:', receipt.status) // 1 = success, 0 = failed
} else {
  console.log('Transaction not yet mined')
}
```

**`getUserOperationReceipt(hash)`**

Returns a UserOperation receipt by hash.

**Parameters:**

* `hash` (string): The UserOperation hash

**Returns:** `Promise<UserOperationReceipt | null>` - UserOperation receipt or null if not processed

**Example:**

```javascript
const receipt = await readOnlyAccount.getUserOperationReceipt('0x...')
if (receipt) {
  console.log('UserOp receipt:', receipt)
}
```

## Types

The following types are exported from `@tetherto/wdk-wallet-evm-erc-4337` and can be imported directly.

**Exported configuration subtypes:**

* `EvmErc4337WalletCommonConfig`
* `EvmErc4337WalletPaymasterTokenConfig`
* `EvmErc4337WalletSponsorshipPolicyConfig`
* `EvmErc4337WalletNativeCoinsConfig`

### TypedData

```typescript
interface TypedData {
  domain: TypedDataDomain;                           // The domain separator
  types: Record<string, TypedDataField[]>;           // The type definitions
  message: Record<string, unknown>;                  // 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')
}
```

### EvmErc4337WalletConfig

The configuration is a union type combining common fields with one of three gas payment modes:

```typescript
// Common fields (required for all modes)
interface EvmErc4337WalletCommonConfig {
  chainId: number;                          // Blockchain ID
  provider: string | Eip1193Provider;       // RPC provider
  bundlerUrl: string;                       // Bundler service URL
  entryPointAddress: string;                // EntryPoint contract address
  safeModulesVersion: string;               // Safe modules version (e.g., '0.3.0')
}

// Mode 1: Paymaster Token
interface EvmErc4337WalletPaymasterTokenConfig {
  isSponsored?: false;
  useNativeCoins?: false;
  paymasterUrl: string;                     // Paymaster service URL
  paymasterAddress: string;                 // Paymaster contract address
  paymasterToken: { address: string };      // ERC-20 token for fees
  transferMaxFee?: number | bigint;         // Maximum fee limit
}

// Mode 2: Sponsorship Policy
interface EvmErc4337WalletSponsorshipPolicyConfig {
  isSponsored: true;
  useNativeCoins?: false;
  paymasterUrl: string;                     // Paymaster service URL
  sponsorshipPolicyId?: string;             // Sponsorship policy ID
}

// Mode 3: Native Coins
interface EvmErc4337WalletNativeCoinsConfig {
  isSponsored?: false;
  useNativeCoins: true;
  transferMaxFee?: number | bigint;         // Maximum fee limit
}

// Full config type
type EvmErc4337WalletConfig = EvmErc4337WalletCommonConfig &
  (EvmErc4337WalletPaymasterTokenConfig |
   EvmErc4337WalletSponsorshipPolicyConfig |
   EvmErc4337WalletNativeCoinsConfig);
```

### Config Override

The `config` parameter on `sendTransaction`, `quoteSendTransaction`, `transfer`, and `quoteTransfer` allows per-call overrides of gas payment settings:

```typescript
type ConfigOverride = Partial<
  EvmErc4337WalletPaymasterTokenConfig |
  EvmErc4337WalletSponsorshipPolicyConfig |
  EvmErc4337WalletNativeCoinsConfig
>;
```

**Available override fields:**

* `isSponsored` (boolean): Switch to sponsorship mode
* `useNativeCoins` (boolean): Switch to native coin mode
* `paymasterUrl` (string): Override paymaster URL
* `paymasterAddress` (string): Override paymaster contract
* `paymasterToken` ({address: string}): Override paymaster token
* `sponsorshipPolicyId` (string): Set sponsorship policy
* `transferMaxFee` (number | bigint): Override maximum fee

### EvmTransaction

```typescript
interface EvmTransaction {
  to: string;                               // Recipient address
  value: number | bigint;                   // Amount in wei
  data?: string;                            // Transaction data (optional)
  gasLimit?: number | bigint;               // Gas limit (optional)
  gasPrice?: number | bigint;               // Legacy gas price (optional)
  maxFeePerGas?: number | bigint;           // EIP-1559 max fee (optional)
  maxPriorityFeePerGas?: number | bigint;   // EIP-1559 priority fee (optional)
}
```

### TransferOptions

```typescript
interface TransferOptions {
  token: string;                            // ERC20 token contract address
  recipient: string;                        // Recipient address
  amount: number | bigint;                  // Amount in token base units
}
```

### 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
}
```

### TransactionResult

```typescript
interface TransactionResult {
  hash: string;                             // UserOperation hash
  fee: bigint;                              // Fee paid
}
```

### TransferResult

```typescript
interface TransferResult {
  hash: string;                             // UserOperation hash
  fee: bigint;                              // Fee paid
}
```

### UserOperationReceipt

```typescript
interface UserOperationReceipt {
  userOpHash: string;                       // UserOperation hash
  sender: string;                           // Sender address
  nonce: bigint;                            // Nonce
  actualGasUsed: bigint;                    // Gas used
  actualGasCost: bigint;                    // Gas cost
  success: boolean;                         // Whether the operation succeeded
  receipt: EvmTransactionReceipt;           // The underlying transaction receipt
}
```

### ConfigurationError

```typescript
class ConfigurationError extends Error {
  // Thrown when the wallet configuration is invalid
  // e.g., missing required fields for the selected gas payment mode
}
```

### FeeRates

```typescript
interface FeeRates {
  normal: bigint;                             // Fee rate for normal priority
  fast: bigint;                               // Fee rate for fast priority
}
```

### KeyPair

```typescript
interface KeyPair {
  publicKey: Uint8Array;                      // The public key
  privateKey: Uint8Array | null;              // The private key (null after dispose)
}
```

### Internal Constants

The following constants are used internally by the SDK and are **not importable** from the package entry point.

```typescript
// Used by predictSafeAddress() for deterministic address generation
// Not re-exported from '@tetherto/wdk-wallet-evm-erc-4337'
const SALT_NONCE: string = '0x69b348339eea4ed93f9d11931c3b894c8f9d8c7663a053024b11cb7eb4e5a1f6';

// Fee rate multipliers (protected static on WalletManagerEvm)
// Applied internally by getFeeRates()
const _FEE_RATE_NORMAL_MULTIPLIER: bigint;  // ~110%
const _FEE_RATE_FAST_MULTIPLIER: bigint;    // ~200%
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet Usage</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK EVM with ERC-4337 Wallet Configuration</strong></td><td>Get started with WDK's EVM with ERC-4337 Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# wallet-solana

Overview of the @tetherto/wdk-wallet-solana module

A simple and secure package to manage BIP-44 wallets for the Solana blockchain. This package provides a clean API for creating, managing, and interacting with Solana wallets using BIP-39 seed phrases and Solana-specific derivation paths.

{% hint style="warning" %}
**Default Derivation Path Change in v1.0.0-beta.4+**

The default derivation path was updated in v1.0.0-beta.4 to match ecosystem conventions:

* **Before** (<= v1.0.0-beta.3): `m/44'/501'/0'/0/{index}`
* **After** (v1.0.0-beta.4+): `m/44'/501'/{index}'/0'`

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`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
{% endhint %}

## Features

* **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases
* **Solana Derivation Paths**: Support for BIP-44 standard derivation paths for Solana (m/44'/501')
* **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
* **Solana Address Support**: Generate and manage Solana public keys and addresses
* **Message Signing**: Sign and verify messages using Ed25519 cryptography
* **Transaction Management**: Send transactions and get fee estimates
* **SPL Token Support**: Query native SOL and SPL token balances
* **TypeScript Support**: Full TypeScript definitions included
* **Memory Safety**: Secure private key management with memory-safe implementation
* **Provider Flexibility**: Support for custom Solana RPC endpoints
* **Fee Estimation**: Dynamic fee calculation with recent blockhash
* **Program Interaction**: Support for interacting with Solana programs

## Supported Networks

This package works with the Solana blockchain, including:

* **Solana Mainnet**
* **Solana Devnet**
* **Solana Testnet**
* **Localnet**

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet Configuration</strong></td><td>Get started with WDK's Solana Wallet configuration</td><td><a href="wallet-solana/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet API</strong></td><td>Get started with WDK's Solana Wallet API</td><td><a href="wallet-solana/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet Usage</strong></td><td>Get started with WDK's with Solana Wallet usage</td><td><a href="wallet-solana/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-solana module.

The `@tetherto/wdk-wallet-solana` module provides wallet management for the Solana blockchain.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Getting Started</strong></td><td>Install the package and create your first wallet.</td><td><a href="usage/getting-started">getting-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Work with multiple accounts and custom derivation paths.</td><td><a href="usage/account-management">account-management</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query SOL and SPL token balances.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send SOL</strong></td><td>Send native SOL and estimate transaction fees.</td><td><a href="usage/send-transactions">send-transactions</a></td></tr><tr><td><i class="fa-coins">:coins:</i></td><td><strong>Transfer SPL Tokens</strong></td><td>Transfer SPL tokens and estimate fees.</td><td><a href="usage/transfer-tokens">transfer-tokens</a></td></tr><tr><td><i class="fa-key">:key:</i></td><td><strong>Sign and Verify Messages</strong></td><td>Sign messages and verify Ed25519 signatures.</td><td><a href="usage/sign-verify-messages">sign-verify-messages</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Error Handling</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/error-handling">error-handling</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet Configuration</strong></td><td>Get started with WDK's Solana Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet API</strong></td><td>Get started with WDK's Solana Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Getting Started

Install and create your first Solana wallet.

This guide explains how to install the [`@tetherto/wdk-wallet-solana`](https://www.npmjs.com/package/@tetherto/wdk-wallet-solana) package and create a new wallet instance.

## 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

{% code title="Install @tetherto/wdk-wallet-solana" lineNumbers="true" %}

```bash
npm install @tetherto/wdk-wallet-solana
```

{% endcode %}

## 2. Create a Wallet

Import the module and create a [`WalletManagerSolana`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#walletmanagersolana) instance with a BIP-39 seed phrase and a Solana RPC endpoint.

{% code title="Create Solana Wallet" lineNumbers="true" %}

```javascript
import WalletManagerSolana, {
  WalletAccountSolana,
  WalletAccountReadOnlySolana
} from '@tetherto/wdk-wallet-solana'

const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'

const wallet = new WalletManagerSolana(seedPhrase, {
  rpcUrl: 'https://api.mainnet-beta.solana.com',
  commitment: 'confirmed' // Optional: commitment level
})
```

{% endcode %}

{% hint style="danger" %}
**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.
{% endhint %}

## 3. Get Your First Account

Retrieve an account from the wallet and inspect its address.

{% code title="Get Account" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Wallet address:', address)

const readOnlyAccount = await account.toReadOnlyAccount()
```

{% endcode %}

{% hint style="info" %}
All Solana addresses are base58-encoded public keys. Accounts inherit the provider configuration from the wallet manager.
{% endhint %}

## Next Steps

With your wallet ready, learn how to [manage multiple accounts](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/usage/account-management).


# Manage Accounts

Work with multiple Solana accounts and custom derivation paths.

This guide explains how to retrieve multiple accounts from your Solana wallet and use custom derivation paths.

## Retrieve Accounts by Index

Use [`getAccount()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#getaccount-index) with a zero-based index to access accounts derived from the default derivation path.

{% code title="Get Accounts by Index" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Account 0 address:', address)

const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
```

{% endcode %}

## Retrieve Account by Custom Derivation Path

Use [`getAccountByPath()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#getaccountbypath-path) when you need a specific hierarchy beyond the default sequential index.

{% code title="Custom Derivation Path" lineNumbers="true" %}

```javascript
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)
```

{% endcode %}

{% hint style="info" %}
All addresses are base58-encoded Solana public keys. All accounts inherit the provider configuration from the wallet manager.
{% endhint %}

## Iterate Over Multiple Accounts

You can loop through accounts to inspect addresses and balances in bulk.

{% code title="Multi-Account Iteration" lineNumbers="true" %}

```javascript
async function listAccounts(wallet) {
  const accounts = []

  for (let i = 0; i < 5; i++) {
    const account = await wallet.getAccount(i)
    const address = await account.getAddress()
    const balance = await account.getBalance()

    accounts.push({ index: i, address, balance })
  }

  return accounts
}
```

{% endcode %}

## Next Steps

Now that you can access your accounts, learn how to [check balances](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/usage/check-balances).


# Check Balances

Query SOL and SPL token balances on Solana.

This guide explains how to check native SOL and SPL token balances for both owned and read-only accounts.

## Owned Account Balances

Use an account retrieved from [`WalletManagerSolana`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#walletmanagersolana) to query balances.

### Native SOL Balance

You can retrieve the native SOL balance from an `Account` object using [`account.getBalance()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#getbalance):

{% code title="Get SOL Balance" lineNumbers="true" %}

```javascript
const balance = await account.getBalance()
console.log('Native SOL balance:', balance, 'lamports')
```

{% endcode %}

### SPL Token Balance

You can retrieve an SPL token balance from an `Account` object using [`account.getTokenBalance(tokenMint)`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#gettokenbalance-tokenmint):

{% code title="Get SPL Token Balance" lineNumbers="true" %}

```javascript
const splTokenAddress = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB' // USDT mint address
const splTokenBalance = await account.getTokenBalance(splTokenAddress)
console.log('SPL token balance:', splTokenBalance)
```

{% endcode %}

{% hint style="info" %}
Token balances are returned in the token's smallest units. Adjust for the token's decimals when displaying (e.g., USD₮ has 6 decimals).
{% endhint %}

## Read-Only Account Balances

Use [`WalletAccountReadOnlySolana`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#walletaccountreadonlysolana) to check balances for any public key without a seed phrase.

### Native Balance

{% code title="Read-Only SOL Balance" lineNumbers="true" %}

```javascript
import { WalletAccountReadOnlySolana } from '@tetherto/wdk-wallet-solana'

const readOnlyAccount = new WalletAccountReadOnlySolana('publicKey', {
  rpcUrl: 'https://api.mainnet-beta.solana.com',
  commitment: 'confirmed'
})

const balance = await readOnlyAccount.getBalance()
console.log('Native balance:', balance, 'lamports')
```

{% endcode %}

### Token Balance

{% code title="Read-Only Token Balance" lineNumbers="true" %}

```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB')
console.log('Token balance:', tokenBalance)
```

{% endcode %}

{% hint style="info" %}
You can also create a read-only account from an existing owned account using [`await account.toReadOnlyAccount()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#toreadonlyaccount).
{% endhint %}

## Next Steps

With balance checks in place, learn how to [send SOL](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/usage/send-transactions).


# Send SOL

Send native SOL and estimate transaction fees on Solana.

This guide explains how to send native SOL, estimate transaction fees, and use dynamic fee rates.

{% hint style="warning" %}
**BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers.
{% endhint %}

{% hint style="info" %}
On Solana, values are expressed in lamports (1 SOL = 10^9 lamports). Fees are calculated based on the recent blockhash and instruction count.
{% endhint %}

## Send Native SOL

Use [`account.sendTransaction()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#sendtransaction-tx) to transfer SOL to a recipient address.

{% code title="Send SOL" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  recipient: 'publicKey', // Recipient's base58-encoded public key
  value: 1000000000n, // 1 SOL in lamports
  commitment: 'confirmed' // Optional: commitment level
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'lamports')
```

{% endcode %}

## Estimate Transaction Fees

Use [`account.quoteSendTransaction()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#quotesendtransaction-tx) to get a fee estimate before sending.

{% code title="Quote Transaction Fee" lineNumbers="true" %}

```javascript
const quote = await account.quoteSendTransaction({
  recipient: 'publicKey',
  value: 1000000000n
})
console.log('Estimated fee:', quote.fee, 'lamports')
```

{% endcode %}

## Use Dynamic Fee Rates

Retrieve current fee rates using [`wallet.getFeeRates()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#getfeerates). Rates are calculated based on the recent blockhash and compute unit prices.

{% code title="Dynamic Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'lamports')
console.log('Fast fee rate:', feeRates.fast, 'lamports')
```

{% endcode %}

## Complete Example

{% code title="Full SOL Transfer Flow" lineNumbers="true" %}

```javascript
async function sendSOLTransfer(account, wallet) {
  const solBalance = await account.getBalance()
  const transferAmount = 1000000000n // 1 SOL

  if (solBalance < transferAmount) {
    throw new Error('Insufficient SOL balance')
  }

  const quote = await account.quoteSendTransaction({
    recipient: '11111111111111111111111111111112',
    value: transferAmount
  })
  console.log('Estimated fee:', quote.fee, 'lamports')

  const result = await account.sendTransaction({
    recipient: '11111111111111111111111111111112',
    value: transferAmount
  })

  console.log('Transaction hash:', result.hash)
  console.log('Fee paid:', result.fee, 'lamports')

  return result
}
```

{% endcode %}

## Next Steps

To transfer SPL tokens instead of native SOL, see [Transfer SPL Tokens](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/usage/transfer-tokens).


# Transfer SPL Tokens

Transfer SPL tokens and estimate transfer fees on Solana.

This guide explains how to transfer SPL tokens (such as USD₮), estimate fees, and validate inputs before executing.

## Transfer Tokens

Use [`account.transfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#transfer-options) to send SPL tokens to a recipient address. If the recipient does not have a token account, one is created automatically.

{% code title="Transfer SPL Tokens" lineNumbers="true" %}

```javascript
const transferResult = await account.transfer({
  token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', // USDT mint address
  recipient: 'publicKey', // Recipient's base58-encoded public key
  amount: 1000000n // Amount in token's base units (6 decimals for USDT)
}, {
  commitment: 'confirmed' // Optional: commitment level
})
console.log('Transfer hash:', transferResult.hash)
console.log('Transfer fee:', transferResult.fee, 'lamports')
```

{% endcode %}

## Estimate Transfer Fees

Use [`account.quoteTransfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#quotetransfer-options) to get a fee estimate before executing the transfer.

{% code title="Quote Token Transfer" lineNumbers="true" %}

```javascript
const transferQuote = await account.quoteTransfer({
  token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
  recipient: 'publicKey',
  amount: 1000000n
})
console.log('Transfer fee estimate:', transferQuote.fee, 'lamports')
```

{% endcode %}

## Transfer with Validation

You can validate addresses and check balances before transferring to catch errors early.

### 1. Validate Addresses

{% code title="Address Validation" lineNumbers="true" %}

```javascript
if (typeof splTokenMint !== 'string' || splTokenMint.length < 32) {
  throw new Error('Invalid SPL token mint address')
}

if (typeof recipient !== 'string' || recipient.length < 32) {
  throw new Error('Invalid recipient address')
}
```

{% endcode %}

### 2. Check Balance

Use [`account.getTokenBalance()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#gettokenbalance-tokenmint) to verify sufficient funds:

{% code title="Balance Check" lineNumbers="true" %}

```javascript
const balance = await account.getTokenBalance(splTokenMint)
if (balance < amount) {
  throw new Error('Insufficient SPL token balance')
}
```

{% endcode %}

### 3. Quote and Execute Transfer

Use [`account.quoteTransfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#quotetransfer-options) to estimate fees, then [`account.transfer()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#transfer-options) to execute:

{% code title="Quote and Execute" lineNumbers="true" %}

```javascript
const quote = await account.quoteTransfer({
  token: splTokenMint,
  recipient,
  amount
})
console.log('Transfer fee estimate:', quote.fee, 'lamports')

const result = await account.transfer({
  token: splTokenMint,
  recipient,
  amount
})
console.log('Transfer hash:', result.hash)
console.log('Actual fee:', result.fee, 'lamports')
```

{% endcode %}

## Next Steps

Learn how to [sign and verify messages](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/usage/sign-verify-messages) with your Solana account.


# Sign and Verify Messages

Sign messages and verify signatures with Solana accounts using Ed25519.

This guide explains how to sign arbitrary messages with an owned account and verify signatures using a read-only account. Solana uses Ed25519 cryptography for signing.

## Sign a Message

Use [`account.sign()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#sign-message) to produce an Ed25519 signature for any string message.

{% code title="Sign a Message" lineNumbers="true" %}

```javascript
const message = 'Hello, Solana!'
const signature = await account.sign(message)
console.log('Signature:', signature)
```

{% endcode %}

## Verify a Signature

You can get a [read-only account](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#walletaccountreadonlysolana) from any `Account` object by calling [`account.toReadOnlyAccount()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#toreadonlyaccount). Use a read-only account to [`verify()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#verify-message-signature) that a signature was produced by the corresponding private key.

{% code title="Verify a Signature" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const isValid = await readOnlyAccount.verify(message, signature)
console.log('Signature valid:', isValid)
```

{% endcode %}

{% hint style="info" %}
You can also create a [`WalletAccountReadOnlySolana`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#walletaccountreadonlysolana) from any public key to verify signatures without access to the private key.
{% endhint %}

## Next Steps

For best practices on handling errors, managing fees, and cleaning up memory, see [Error Handling](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-solana/usage/error-handling).


# Error Handling

Handle errors, manage fees, and dispose of sensitive data in Solana wallets.

This guide covers best practices for handling transaction errors, managing fee limits, and cleaning up sensitive data from memory.

## Handle Transaction Errors

Wrap transactions in `try/catch` blocks to handle common failure scenarios such as insufficient balance, invalid addresses, or exceeded fee limits.

{% code title="Transaction Error Handling" lineNumbers="true" %}

```javascript
try {
  const result = await account.transfer({
    token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', // USDT mint address
    recipient: '11111111111111111111111111111112',
    amount: 1000000n
  })
  console.log('Transfer submitted:', result.hash)
} catch (error) {
  console.error('Transfer failed:', error.message)
  if (error.message.toLowerCase().includes('insufficient')) {
    console.log('Please add more tokens to your wallet')
  } else if (error.message.toLowerCase().includes('fee')) {
    console.log('The transfer fee exceeds your configured maximum')
  }
}
```

{% endcode %}

## Handle SOL Transfer Errors

Native SOL transfers can fail for reasons including insufficient balance or invalid recipient addresses.

{% code title="SOL Transfer Error Handling" lineNumbers="true" %}

```javascript
async function safeTransfer(account, wallet) {
  try {
    const solBalance = await account.getBalance()
    const transferAmount = 1000000000n // 1 SOL

    if (solBalance < transferAmount) {
      throw new Error('Insufficient SOL balance')
    }

    const quote = await account.quoteSendTransaction({
      recipient: '11111111111111111111111111111112',
      value: transferAmount
    })
    console.log('Estimated fee:', quote.fee, 'lamports')

    const result = await account.sendTransaction({
      recipient: '11111111111111111111111111111112',
      value: transferAmount
    })
    console.log('Transaction successful:', result.hash)

    return result
  } catch (error) {
    if (error.message.includes('Insufficient SOL')) {
      console.error('Please add more SOL to your wallet')
    } else if (error.message.includes('invalid address')) {
      console.error('The recipient address is invalid')
    } else if (error.message.includes('max fee')) {
      console.error('The transfer fee exceeds your configured maximum')
    } else {
      console.error('Transaction failed:', error.message)
    }
    throw error
  } finally {
    account.dispose()
    wallet.dispose()
  }
}
```

{% endcode %}

## Manage Fee Limits

Set `transferMaxFee` when creating the wallet to prevent transactions from exceeding a maximum cost. Retrieve current network rates with [`getFeeRates()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#getfeerates) to make informed decisions.

{% code title="Fee Management" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'lamports')
console.log('Fast fee rate:', feeRates.fast, 'lamports')
```

{% endcode %}

## Dispose of Sensitive Data

Call [`dispose()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#dispose) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed.

{% code title="Memory Cleanup" lineNumbers="true" %}

```javascript
account.dispose()

wallet.dispose()
```

{% endcode %}

{% hint style="warning" %}
Always call [`dispose()`](https://github.com/tetherto/wdk-docs/blob/main/sdk/wallet-modules/wallet-solana/api-reference/README.md#dispose) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs.
{% endhint %}


# Configuration

Configuration options and settings for @tetherto/wdk-wallet-solana

## Wallet Configuration

The `WalletManagerSolana` accepts an optional configuration object that defines how the wallet interacts with the Solana blockchain:

```javascript
import WalletManagerSolana from '@tetherto/wdk-wallet-solana'

const config = {
  rpcUrl: 'https://api.mainnet-beta.solana.com', // Solana RPC endpoint
  transferMaxFee: 10000000 // Optional: Maximum fee in lamports
}

const wallet = new WalletManagerSolana(seedPhrase, config)
```

## Account Configuration

Accounts are obtained through the `WalletManagerSolana` instance using `getAccount()` or `getAccountByPath()`:

```javascript
import WalletManagerSolana from '@tetherto/wdk-wallet-solana'

const accountConfig = {
  rpcUrl: 'https://api.mainnet-beta.solana.com',
  transferMaxFee: 10000000 // Optional: Maximum fee in lamports
}

const wallet = new WalletManagerSolana(seedPhrase, accountConfig)

// Get account by index
const account = await wallet.getAccount(0)

// Or get account by custom derivation path
const customAccount = await wallet.getAccountByPath("0'/0/5")
```

## Configuration Options

### rpcUrl

The `rpcUrl` option specifies the Solana RPC endpoint for blockchain interactions.

**Type:** `string` (optional)

**Default:** If not provided, wallet functionality that requires RPC will throw an error

**Examples:**

```javascript
// Mainnet
const config = {
  rpcUrl: 'https://api.mainnet-beta.solana.com'
}

// Devnet
const config = {
  rpcUrl: 'https://api.devnet.solana.com'
}

// Custom RPC
const config = {
  rpcUrl: 'https://your-custom-rpc-endpoint.com'
}
```

### transferMaxFee

The `transferMaxFee` option sets the maximum allowed fee (in lamports) for transfer operations. This helps prevent unexpectedly high transaction fees.

**Type:** `number` (optional)

**Unit:** Lamports (1 SOL = 1,000,000,000 lamports)

**Example:**

```javascript
const config = {
  transferMaxFee: 10000000 // 0.01 SOL in lamports
}
```

## Complete Configuration Example

```javascript
import WalletManagerSolana from '@tetherto/wdk-wallet-solana'

const config = {
  // Required for most operations
  rpcUrl: 'https://api.mainnet-beta.solana.com',
  
  // Optional: Fee protection
  transferMaxFee: 10000000 // 0.01 SOL maximum fee
}

const wallet = new WalletManagerSolana(seedPhrase, config)
```

## Network Endpoints

### Mainnet

* RPC: `https://api.mainnet-beta.solana.com`
* WebSocket: `wss://api.mainnet-beta.solana.com/`

### Devnet

* RPC: `https://api.devnet.solana.com`
* WebSocket: `wss://api.devnet.solana.com/`

### Testnet

* RPC: `https://api.testnet.solana.com`
* WebSocket: `wss://api.testnet.solana.com/`

## Derivation Paths

Solana wallets use BIP-44 standard derivation paths. The default derivation path follows ecosystem conventions:

* Default path: `m/44'/501'/{index}'/0'` (where `{index}` is the account index)

{% hint style="warning" %}
**Default Derivation Path Change in v1.0.0-beta.4+**

The default derivation path was updated in v1.0.0-beta.4 to match ecosystem conventions:

* **Before** (<= v1.0.0-beta.3): `m/44'/501'/0'/0/{index}`
* **After** (v1.0.0-beta.4+): `m/44'/501'/{index}'/0'`

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`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
{% endhint %}

## Security Considerations

* Always use HTTPS URLs for RPC endpoints
* Set appropriate `transferMaxFee` limits for your use case
* Consider using environment variables for configuration in production
* Use trusted RPC providers or run your own Solana validator for production applications

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet Usage</strong></td><td>Get started with WDK's Solana Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet API</strong></td><td>Get started with WDK's Solana Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk-wallet-solana

### Table of Contents

| Class                                                       | Description                                                                                                             | Methods                                                                         |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [WalletManagerSolana](#walletmanagersolana)                 | Main class for managing Solana wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`.                            | [Constructor](#constructor), [Methods](#methods)                                |
| [WalletAccountSolana](#walletaccountsolana)                 | Individual Solana wallet account implementation. Extends `WalletAccountReadOnlySolana` and implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) |
| [WalletAccountReadOnlySolana](#walletaccountreadonlysolana) | Read-only Solana wallet account.                                                                                        | [Constructor](#constructor-2), [Methods](#methods-2)                            |

### WalletManagerSolana

The main class for managing Solana wallets.\
Extends `WalletManager` from `@tetherto/wdk-wallet`.

#### Constructor

```javascript
new WalletManagerSolana(seed, config)
```

**Parameters:**

* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `config` (object): Configuration object
  * `rpcUrl` (string | Connection): RPC endpoint URL or Solana Connection instance
  * `commitment` (string, optional): Commitment level ('processed', 'confirmed', or 'finalized')
  * `transferMaxFee` (number, optional): Maximum fee amount for transfer operations (in lamports)

**Example:**

```javascript
const wallet = new WalletManagerSolana(seedPhrase, {
  rpcUrl: 'https://api.mainnet-beta.solana.com',
  commitment: 'confirmed',
  transferMaxFee: 5000 // Maximum fee in lamports
})
```

#### Methods

| Method                   | Description                                                      | Returns                                   |
| ------------------------ | ---------------------------------------------------------------- | ----------------------------------------- |
| `getAccount(index)`      | Returns a wallet account at the specified index                  | `Promise<WalletAccountSolana>`            |
| `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise<WalletAccountSolana>`            |
| `getFeeRates()`          | Returns current fee rates for transactions                       | `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.

**Parameters:**

* `index` (number, optional): The index of the account to get (default: 0)

**Returns:** `Promise<WalletAccountSolana>` - The wallet account

**Example:**

```javascript
const account = await wallet.getAccount(0)
```

**`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<WalletAccountSolana>` - The wallet account

**Example:**

```javascript
const account = await wallet.getAccountByPath("0'/0/1")
```

**`getFeeRates()`**

Returns current fee rates for transactions based on recent prioritization fees.

**Returns:** `Promise<{normal: bigint, fast: bigint}>` - Object containing fee rates in lamports

**Throws:** Error if wallet is not connected to a provider

**Example:**

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'lamports')
console.log('Fast fee rate:', feeRates.fast, 'lamports')
```

**`dispose()`**

Disposes all wallet accounts, clearing private keys from memory.

**Example:**

```javascript
wallet.dispose()
```

### WalletAccountSolana

Represents an individual Solana wallet account. Extends `WalletAccountReadOnlySolana` and implements `IWalletAccount`.

#### Constructor

```javascript
new WalletAccountSolana(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` (SolanaWalletConfig, optional): Configuration object

#### Methods

| Method                        | Description                                                    | Returns                                     |
| ----------------------------- | -------------------------------------------------------------- | ------------------------------------------- |
| `getAddress()`                | Returns the account's Solana address                           | `Promise<string>`                           |
| `sign(message)`               | Signs a message using the account's private key                | `Promise<string>`                           |
| `verify(message, signature)`  | Verifies a message signature                                   | `Promise<boolean>`                          |
| `sendTransaction(tx)`         | Sends a Solana transaction                                     | `Promise<{hash: string, fee: bigint}>`      |
| `quoteSendTransaction(tx)`    | Estimates the fee for a transaction                            | `Promise<{fee: bigint}>`                    |
| `transfer(options)`           | Transfers SPL tokens to another address                        | `Promise<{hash: string, fee: bigint}>`      |
| `quoteTransfer(options)`      | Estimates the fee for an SPL token transfer                    | `Promise<{fee: bigint}>`                    |
| `getBalance()`                | Returns the native SOL balance (in lamports)                   | `Promise<bigint>`                           |
| `getTokenBalance(tokenMint)`  | Returns the balance of a specific SPL token                    | `Promise<bigint>`                           |
| `getTransactionReceipt(hash)` | Gets the transaction receipt for a given transaction hash      | `Promise<SolanaTransactionReceipt \| null>` |
| `toReadOnlyAccount()`         | Returns a read-only copy of the account                        | `Promise<WalletAccountReadOnlySolana>`      |
| `dispose()`                   | Disposes the wallet account, clearing private keys from memory | `void`                                      |

**`getAddress()`**

Returns the account's Solana address.

**Returns:** `Promise<string>` - The account's base58-encoded Solana address

**Example:**

```javascript
const address = await account.getAddress()
console.log('Account address:', address)
```

**`sign(message)`**

Signs a message using the account's private key.

**Parameters:**

* `message` (string): The message to sign

**Returns:** `Promise<string>` - The message signature (hex-encoded)

**Example:**

```javascript
const signature = await account.sign('Hello, Solana!')
console.log('Signature:', signature)
```

**`verify(message, signature)`**

Verifies a message signature against the account's address.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify (hex-encoded)

**Returns:** `Promise<boolean>` - True if the signature is valid

**Example:**

```javascript
const isValid = await account.verify('Hello, Solana!', signature)
console.log('Signature valid:', isValid)
```

**`sendTransaction(tx)`**

Sends a Solana transaction.

**Parameters:**

* `tx` (SolanaTransaction): The transaction object
  * `to` (string): Recipient's Solana address (base58-encoded)
  * `value` (number): Amount in lamports

**Returns:** `Promise<{hash: string, fee: bigint}>` - Object containing transaction hash and fee (in lamports)

**Throws:** Error if wallet is not connected to a provider

**Example:**

```javascript
const result = await account.sendTransaction({
  to: '11111111111111111111111111111112',
  value: 1000000000 // 1 SOL in lamports
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'lamports')
```

**`quoteSendTransaction(tx)`**

Estimates the fee for a Solana transaction.

**Parameters:**

* `tx` (SolanaTransaction): The transaction object (same as sendTransaction)

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in lamports)

**Example:**

```javascript
const quote = await account.quoteSendTransaction({
  to: '11111111111111111111111111111112',
  value: 1000000000
})
console.log('Estimated fee:', quote.fee, 'lamports')
```

**`transfer(options)`**

Transfers SPL tokens to another address.

**Parameters:**

* `options` (TransferOptions): Transfer options
  * `token` (string): Token mint address (base58-encoded)
  * `recipient` (string): Recipient's Solana address (base58-encoded)
  * `amount` (number): Amount in token's base units

**Returns:** `Promise<{hash: string, fee: bigint}>` - Object containing transaction hash and fee (in lamports)

**Throws:** Error if wallet is not connected to a provider or if fee exceeds maximum

**Example:**

```javascript
const result = await account.transfer({
  token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', // USDT mint
  recipient: '11111111111111111111111111111112',
  amount: 1000000 // 1 USDT (6 decimals)
})
console.log('Transfer hash:', result.hash)
console.log('Transfer fee:', result.fee, 'lamports')
```

**`quoteTransfer(options)`**

Estimates the fee for an SPL token transfer.

**Parameters:**

* `options` (TransferOptions): Transfer options (same as transfer)

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in lamports)

**Example:**

```javascript
const quote = await account.quoteTransfer({
  token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
  recipient: '11111111111111111111111111111112',
  amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee, 'lamports')
```

**`getBalance()`**

Returns the native SOL balance (in lamports).

**Returns:** `Promise<bigint>` - Balance in lamports

**Example:**

```javascript
const balance = await account.getBalance()
console.log('SOL balance:', balance, 'lamports')
```

**`getTokenBalance(tokenMint)`**

Returns the balance of a specific SPL token.

**Parameters:**

* `tokenMint` (string): Token mint address (base58-encoded)

**Returns:** `Promise<bigint>` - Token balance in base units

**Example:**

```javascript
const tokenBalance = await account.getTokenBalance('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB')
console.log('USDT balance:', tokenBalance)
```

**`getTransactionReceipt(hash)`**

Gets the transaction receipt for a given transaction hash.

**Parameters:**

* `hash` (string): Transaction hash

**Returns:** `Promise<SolanaTransactionReceipt | null>` - Transaction receipt details, or null if not found

**Example:**

```javascript
const receipt = await account.getTransactionReceipt('5....')
console.log('Transaction receipt:', receipt)
```

**`toReadOnlyAccount()`**

Returns a read-only copy of the account.

**Returns:** `Promise<WalletAccountReadOnlySolana>` - The read-only account

**Example:**

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
```

**`dispose()`**

Disposes the wallet account, clearing private keys from memory.

**Example:**

```javascript
account.dispose()
```

#### Properties

| Property  | Type                                      | Description                                 |
| --------- | ----------------------------------------- | ------------------------------------------- |
| `index`   | `number`                                  | The derivation path's index of this account |
| `path`    | `string`                                  | The full derivation path of this account    |
| `keyPair` | `{publicKey: Buffer, privateKey: Buffer}` | The account's Ed25519 key pair              |

⚠️ **Security Note**: The `keyPair` property contains sensitive cryptographic material. Never log, display, or expose the private key.

### WalletAccountReadOnlySolana

Represents a read-only Solana wallet account.

#### Constructor

```javascript
new WalletAccountReadOnlySolana(publicKey, config)
```

**Parameters:**

* `publicKey` (string): The account's public key (base58-encoded)
* `config` (SolanaWalletConfig, optional): Configuration object

#### Methods

| Method                       | Description                                  | Returns                  |
| ---------------------------- | -------------------------------------------- | ------------------------ |
| `getAddress()`               | Returns the account's Solana address         | `Promise<string>`        |
| `getBalance()`               | Returns the native SOL balance (in lamports) | `Promise<bigint>`        |
| `getTokenBalance(tokenMint)` | Returns the balance of a specific SPL token  | `Promise<bigint>`        |
| `verify(message, signature)` | Verifies a message signature                 | `Promise<boolean>`       |
| `quoteSendTransaction(tx)`   | Estimates the fee for a transaction          | `Promise<{fee: bigint}>` |
| `quoteTransfer(options)`     | Estimates the fee for an SPL token transfer  | `Promise<{fee: bigint}>` |

**`getAddress()`**

Returns the account's Solana address.

**Returns:** `Promise<string>` - The account's base58-encoded Solana address

**Example:**

```javascript
const address = await readOnlyAccount.getAddress()
console.log('Account address:', address)
```

**`getBalance()`**

Returns the native SOL balance (in lamports).

**Returns:** `Promise<bigint>` - Balance in lamports

**Example:**

```javascript
const balance = await readOnlyAccount.getBalance()
console.log('SOL balance:', balance, 'lamports')
```

**`getTokenBalance(tokenMint)`**

Returns the balance of a specific SPL token.

**Parameters:**

* `tokenMint` (string): Token mint address (base58-encoded)

**Returns:** `Promise<bigint>` - Token balance in base units

**Example:**

```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB')
console.log('USDT balance:', tokenBalance)
```

**`verify(message, signature)`**

Verifies a message signature.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify (hex-encoded)

**Returns:** `Promise<boolean>` - True if the signature is valid

**Example:**

```javascript
const isValid = await readOnlyAccount.verify('Hello, Solana!', signature)
console.log('Signature valid:', isValid)
```

**`quoteSendTransaction(tx)`**

Estimates the fee for a transaction.

**Parameters:**

* `tx` (SolanaTransaction): The transaction object
  * `to` (string): Recipient's Solana address (base58-encoded)
  * `value` (number): Amount in lamports

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in lamports)

**Example:**

```javascript
const quote = await readOnlyAccount.quoteSendTransaction({
  to: '11111111111111111111111111111112',
  value: 1000000000
})
console.log('Estimated fee:', quote.fee, 'lamports')
```

**`quoteTransfer(options)`**

Estimates the fee for an SPL token transfer.

**Parameters:**

* `options` (TransferOptions): Transfer options
  * `token` (string): Token mint address (base58-encoded)
  * `recipient` (string): Recipient's Solana address (base58-encoded)
  * `amount` (number): Amount in token's base units

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in lamports)

**Example:**

```javascript
const quote = await readOnlyAccount.quoteTransfer({
  token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
  recipient: '11111111111111111111111111111112',
  amount: 1000000
})
console.log('Transfer fee estimate:', quote.fee, 'lamports')
```

## Types

### TransferOptions

```typescript
interface TransferOptions {
  token: string;
  recipient: string;
  amount: number;
}
```

### KeyPair

```typescript
interface KeyPair {
  publicKey: Uint8Array
  privateKey: Uint8Array
}
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet Usage</strong></td><td>Get started with WDK's Solana Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Solana Wallet Configuration</strong></td><td>Get started with WDK's Solana Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# wallet-spark

Overview of the @tetherto/wdk-wallet-spark module

A simple and secure package to manage BIP-32 wallets for the Spark blockchain. This package provides a clean API for creating, managing, and interacting with Spark wallets using [BIP-39 seed phrases](https://github.com/tetherto/wdk-docs/blob/main/sdk/resources/concepts.md#bip-39-mnemonic-seed-phrases), [BIP-44 derivation paths](https://github.com/tetherto/wdk-docs/blob/main/sdk/resources/concepts.md#bip-44-multi-account-hierarchy), and the Spark SDK for Bitcoin [layer 2](https://github.com/tetherto/wdk-docs/blob/main/sdk/resources/concepts.md#layer-2-solutions) functionality including [Lightning Network](https://github.com/tetherto/wdk-docs/blob/main/sdk/resources/concepts.md#lightning-network) integration.

## Features

* **Spark Blockchain Support**: Full integration with the Spark Bitcoin [layer 2](https://docs.wdk.tether.io/resources-and-guides/concepts#layer-2-solutions) network
* **Lightning Network Integration**: Create and pay [Lightning Network](https://docs.wdk.tether.io/resources-and-guides/concepts#lightning-network) invoices directly
* **Spark Invoices**: Create and pay Spark invoices for receiving sats and tokens directly on the Spark network
* **Token Transfers**: Transfer tokens to other Spark addresses
* **Bitcoin Layer 1 Bridge**: Deposit and withdraw Bitcoin between layer 1 and Spark
* **Static Deposit Addresses**: Reusable deposit addresses for Bitcoin layer 1 deposits
* **Deposit Refunds**: Refund static deposits back to Bitcoin addresses
* **Withdrawal Fee Quotes**: Get fee quotes before withdrawing funds
* [**BIP-44 Derivation Paths**](https://docs.wdk.tether.io/resources-and-guides/concepts#bip-44-multi-account-hierarchy): Support for standard BIP-44 derivation paths with Spark-specific coin type (998)
* [**BIP-39 Seed Phrase Support**](https://docs.wdk.tether.io/resources-and-guides/concepts#bip-39-mnemonic-seed-phrases): Generate and validate BIP-39 mnemonic seed phrases
* **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
* **Single-Use Deposit Addresses**: Generate unique deposit addresses for Bitcoin layer 1 deposits
* **Fee-Free Transactions**: Spark transactions are fee-free on the layer 2 network
* **Transaction History**: Complete transaction history with incoming/outgoing transfers
* **Message Signing**: Sign and verify messages using Spark identity keys
* **Memory Safety**: Secure private key management with automatic memory cleanup
* **TypeScript Support**: Full TypeScript definitions included
* **Network Support**: Support for Spark [mainnet](https://docs.wdk.tether.io/resources-and-guides/concepts#mainnet) and [regtest](https://docs.wdk.tether.io/resources-and-guides/concepts#regtest) networks

## Supported Networks

This package supports the following Spark networks:

* **Spark Mainnet**: Production Spark network
* **Spark Signet**: Spark testing network
* **Spark Regtest**: Local Spark network for testing

{% hint style="info" %}
**Regtest Faucet**

You can obtain test funds for your Regtest environment from the [Lightspark Regtest Faucet](https://app.lightspark.com/regtest-faucet).
{% endhint %}

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet Configuration</strong></td><td>Get started with WDK's Spark Wallet configuration</td><td><a href="wallet-spark/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet API</strong></td><td>Get started with WDK's Spark Wallet API</td><td><a href="wallet-spark/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet Usage</strong></td><td>Get started with WDK's with Spark Wallet usage</td><td><a href="wallet-spark/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-spark module.

The `@tetherto/wdk-wallet-spark` module provides wallet management for the Spark network.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Get Started</strong></td><td>Install the package and create your first Spark wallet.</td><td><a href="usage/get-started">get-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Retrieve accounts by index and iterate over them.</td><td><a href="usage/manage-accounts">manage-accounts</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query native Spark balances and read-only accounts.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send and Transfer</strong></td><td>Send native Spark, transfer tokens, and estimate fees.</td><td><a href="usage/send-and-transfer">send-and-transfer</a></td></tr><tr><td><i class="fa-bolt">:bolt:</i></td><td><strong>Lightning Payments</strong></td><td>Create and pay Lightning invoices and inspect payment status.</td><td><a href="usage/lightning-payments">lightning-payments</a></td></tr><tr><td><i class="fa-link">:link:</i></td><td><strong>Deposits and Withdrawals</strong></td><td>Fund from Bitcoin layer 1 and withdraw on-chain.</td><td><a href="usage/deposits-and-withdrawals">deposits-and-withdrawals</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Handle Errors</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/handle-errors">handle-errors</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet Configuration</strong></td><td>Get started with WDK's Spark Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet API</strong></td><td>Get started with WDK's Spark Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Get Started

Install the Spark wallet package and create your first account.

This guide explains how to [install the package](#1-install-the-package), [create a wallet](#2-create-a-wallet), [get your first account](#3-get-your-first-account), and optionally [convert the account to read-only](#4-optional-convert-to-read-only).

## 1. Install the Package

### Prerequisites

* [**Node.js**](https://nodejs.org/): version 18 or higher.
* [**npm**](https://www.npmjs.com/): usually comes with Node.js.

Install [@tetherto/wdk-wallet-spark](https://www.npmjs.com/package/@tetherto/wdk-wallet-spark):

{% code title="Install @tetherto/wdk-wallet-spark" lineNumbers="true" %}

```bash
npm install @tetherto/wdk-wallet-spark
```

{% endcode %}

{% hint style="info" %}
The WDK Spark wallet module uses ES Modules (`import` / `export`). Set `"type": "module"` in `package.json`, or run in an environment that supports ESM.
{% endhint %}

## 2. Create a Wallet

You can create a wallet manager using the [`WalletManagerSpark`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletmanagerspark) constructor with a BIP-39 seed phrase:

{% code title="Create Spark Wallet" lineNumbers="true" %}

```javascript
import WalletManagerSpark from '@tetherto/wdk-wallet-spark'

const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'

const wallet = new WalletManagerSpark(seedPhrase)

const walletRegtest = new WalletManagerSpark(seedPhrase, {
  network: 'REGTEST'
})
```

{% endcode %}

{% hint style="danger" %}
**Secure the seed phrase:** Store this seed phrase securely. If it is lost, the user will permanently lose access to their funds.
{% endhint %}

{% hint style="info" %}
For development on **REGTEST**, you can request test funds from the [Lightspark Regtest Faucet](https://app.lightspark.com/regtest-faucet).
{% endhint %}

{% hint style="info" %}
The Spark wallet uses `@buildonspark/spark-sdk`. Network options are `MAINNET`, `SIGNET`, or `REGTEST`. There is no custom RPC provider option.
{% endhint %}

## 3. Get Your First Account

1. Call [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) with index `0`.
2. Call [`account.getAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaddress) to read the Spark address.

You can retrieve the first account using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index):

{% code title="Get First Account" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Account address:', address)
```

{% endcode %}

## 4. (optional) Convert to Read-Only

You can create a read-only view of the account using [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount):

{% code title="Convert to Read-Only" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
```

{% endcode %}

## Next Steps

With your wallet ready, learn how to [manage multiple accounts](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/manage-accounts).


# Manage Accounts

Retrieve Spark accounts by index and iterate over them.

This guide explains how to [retrieve accounts by index](#retrieve-accounts-by-index), [retrieve accounts by derivation path](#retrieve-accounts-by-derivation-path), and [iterate over accounts](#iterate-over-accounts).

## Retrieve Accounts by Index

1. Call [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) with the account index.
2. Call [`account.getAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaddress) for each account.

You can retrieve multiple accounts using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) with different index values:

{% code title="Retrieve Accounts by Index" lineNumbers="true" %}

```javascript
const account0 = await wallet.getAccount(0)
const address0 = await account0.getAddress()
console.log('Account 0 address:', address0)

const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
```

{% endcode %}

{% hint style="info" %}
Accounts use BIP-44 paths `m/44'/998'/{networkNumber}'/0/{index}` where `998` is Spark’s coin type and `networkNumber` is `0` for MAINNET, `2` for SIGNET, or `3` for REGTEST.
{% endhint %}

## Retrieve Accounts by Derivation Path

You can retrieve an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypath-path):

{% code title="Retrieve Account by Path" lineNumbers="true" %}

```javascript
const account = await wallet.getAccountByPath("0'/0/0")
const address = await account.getAddress()
console.log('Account address:', address)
```

{% endcode %}

{% hint style="info" %}
The path segment is appended to the base path `m/44'/998'/`. For example, `"0'/0/0"` resolves to `m/44'/998'/0'/0/0` on MAINNET. See [`getAccountByPath()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypath-path) in the API reference.
{% endhint %}

## Iterate Over Accounts

You can walk a range of indices using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) inside a loop:

{% code title="Iterate Over Accounts" lineNumbers="true" %}

```javascript
for (let i = 0; i < 5; i++) {
  const account = await wallet.getAccount(i)
  const address = await account.getAddress()
  const balance = await account.getBalance()
  console.log(`Account ${i}: ${address} (${balance} satoshis)`)
}
```

{% endcode %}

## Next Steps

With accounts set up, learn how to [check balances](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/check-balances).


# Check Balances

Query native Spark balances and read-only account balances.

This guide explains how to read a [native Spark balance](#native-spark-balance), query a [token balance](#token-balance), and check [read-only account balances](#read-only-account-balances).

## Native Spark Balance

You can read the account balance in satoshis using [`account.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Native Spark Balance" lineNumbers="true" %}

```javascript
const balance = await account.getBalance()
console.log('Balance:', balance, 'satoshis')
console.log('Balance in BTC:', Number(balance) / 100000000)
```

{% endcode %}

{% hint style="info" %}
Balances are in satoshis (1 BTC = 100,000,000 satoshis).
{% endhint %}

## Token Balance

You can read a specific token balance using [`account.getTokenBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettokenbalance-tokenaddress):

{% code title="Token Balance" lineNumbers="true" %}

```javascript
const tokenBalance = await account.getTokenBalance('token_address...')
console.log('Token balance:', tokenBalance)
```

{% endcode %}

## Read-Only Account Balances

1. Construct a [`WalletAccountReadOnlySpark`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlyspark) instance with the Spark address and optional config.
2. Call [`readOnlyAccount.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance).

You can create a read-only account from a Spark address using the [`WalletAccountReadOnlySpark`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlyspark) constructor:

{% code title="Read-Only Account" lineNumbers="true" %}

```javascript
import { WalletAccountReadOnlySpark } from '@tetherto/wdk-wallet-spark'

const readOnlyAccount = new WalletAccountReadOnlySpark('spark1...', {
  network: 'MAINNET'
})
```

{% endcode %}

You can read the native balance from that account using [`readOnlyAccount.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Read-Only Native Balance" lineNumbers="true" %}

```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Read-only balance:', balance, 'satoshis')
```

{% endcode %}

You can read a token balance on a read-only account using [`readOnlyAccount.getTokenBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettokenbalance-tokenaddress):

{% code title="Read-Only Token Balance" lineNumbers="true" %}

```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('token_address...')
console.log('Read-only token balance:', tokenBalance)
```

{% endcode %}

{% hint style="info" %}
You can also obtain a read-only handle from an owned account with [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount).
{% endhint %}

## Next Steps

With balances verified, learn how to [send Spark and transfer tokens](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/send-and-transfer).


# Send and Transfer

Send native Spark, transfer tokens, and estimate fees.

This guide explains how to [send native Spark](#send-spark), [transfer tokens](#transfer-tokens), and [estimate fees](#estimate-fees).

## Send Spark

1. Build the recipient Spark address and amount in satoshis.
2. Call [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-to-value).

You can send native Spark (satoshis) using [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-to-value):

{% code title="Send Native Spark" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: 'spark1...',
  value: 1000000
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee)
```

{% endcode %}

{% hint style="info" %}
On-chain Spark transfers report `fee` as `0`. Memos are not supported on [`sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-to-value). Use valid Spark network addresses.
{% endhint %}

## Transfer Tokens

You can move tokens to another Spark address using [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options):

{% code title="Transfer Tokens" lineNumbers="true" %}

```javascript
const transferResult = await account.transfer({
  token: 'btkn1...',
  amount: BigInt(1000000),
  recipient: 'spark1...'
})
console.log('Transfer hash:', transferResult.hash)
console.log('Transfer fee:', Number(transferResult.fee))
```

{% endcode %}

{% hint style="info" %}
Token identifiers use Bech32m (for example `btkn1...`). Amounts use the token’s base units.
{% endhint %}

## Estimate Fees

### Spark native and token transfer quotes

You can preview the fee for a native send using [`account.quoteSendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotesendtransaction-to-value):

{% code title="Quote Native Send" lineNumbers="true" %}

```javascript
const quote = await account.quoteSendTransaction({
  to: 'spark1...',
  value: 1000000
})
console.log('Estimated fee:', quote.fee)
```

{% endcode %}

You can preview the fee for a token transfer using [`account.quoteTransfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotetransfer-options):

{% code title="Quote Token Transfer" lineNumbers="true" %}

```javascript
const transferQuote = await account.quoteTransfer({
  token: 'btkn1...',
  amount: BigInt(1000000),
  recipient: 'spark1...'
})
console.log('Estimated transfer fee:', Number(transferQuote.fee))
```

{% endcode %}

### Wallet-level fee rates

You can read wallet-level fee rate placeholders using [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates):

{% code title="Wallet Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal:', feeRates.normal)
console.log('Fast:', feeRates.fast)
```

{% endcode %}

{% hint style="info" %}
Spark network fees for native sends and token transfers are zero; [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates) returns `{ normal: 0n, fast: 0n }`. Lightning flows can still incur fees; see [Lightning payments](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/lightning-payments).
{% endhint %}

## Next Steps

Learn how to [create and pay Lightning invoices](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/lightning-payments).


# Lightning Payments

Create Lightning invoices, pay invoices, and inspect payment status.

This guide explains how to [create a Lightning invoice](#create-a-lightning-invoice), [pay a Lightning invoice](#pay-a-lightning-invoice), [estimate Lightning fees](#estimate-lightning-fees), and [fetch a Lightning send request](#fetch-a-lightning-send-request).

## Create a Lightning Invoice

1. Choose an amount in satoshis and an optional memo.
2. Call [`account.createLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#createlightninginvoice-options).

You can create a BOLT11 invoice using [`account.createLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#createlightninginvoice-options):

{% code title="Create Lightning Invoice" lineNumbers="true" %}

```javascript
const invoice = await account.createLightningInvoice({
  amountSats: 50000,
  memo: 'Payment for services'
})
console.log('Lightning invoice:', invoice.invoice)
```

{% endcode %}

## Pay a Lightning Invoice

1. Obtain a BOLT11 `encodedInvoice` string.
2. Set `maxFeeSats` to cap routing fees.
3. Call [`account.payLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#paylightninginvoice-options).

You can pay an invoice using [`account.payLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#paylightninginvoice-options):

{% code title="Pay Lightning Invoice" lineNumbers="true" %}

```javascript
const payment = await account.payLightningInvoice({
  encodedInvoice: 'lnbc500u1p...',
  maxFeeSats: 1000
})
console.log('Payment result:', payment)
```

{% endcode %}

## Estimate Lightning Fees

You can estimate the routing fee before paying using [`account.quotePayLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotepaylightninginvoice-options):

{% code title="Quote Lightning Payment Fee" lineNumbers="true" %}

```javascript
const feeEstimate = await account.quotePayLightningInvoice({
  encodedInvoice: 'lnbc500u1p...'
})
console.log('Fee estimate:', Number(feeEstimate), 'satoshis')
```

{% endcode %}

{% hint style="info" %}
Older references to `getLightningSendFeeEstimate()` map to [`quotePayLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotepaylightninginvoice-options).
{% endhint %}

## Fetch a Lightning Send Request

You can load a prior send request by id using [`account.getLightningSendRequest()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getlightningsendrequest-requestid):

{% code title="Get Lightning Send Request" lineNumbers="true" %}

```javascript
const sendRequest = await account.getLightningSendRequest(payment.id)
if (sendRequest) {
  console.log('Payment status:', sendRequest.status)
}
```

{% endcode %}

{% hint style="info" %}
Use the `id` from the object returned by [`payLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#paylightninginvoice-options).
{% endhint %}

## Next Steps

Learn how to [handle Bitcoin layer 1 deposits and withdrawals](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/deposits-and-withdrawals).


# Deposits and Withdrawals

Fund Spark from Bitcoin layer 1 and withdraw back on-chain.

This guide explains how to [get a single-use deposit address](#get-a-single-use-deposit-address), [claim deposits](#claim-deposits), [query static deposit addresses](#query-static-deposit-addresses), [query UTXOs for a deposit address](#query-utxos-for-a-deposit-address), and [withdraw to Bitcoin layer 1](#withdraw-to-bitcoin-layer-1).

## Get a Single-Use Deposit Address

1. Call [`account.getSingleUseDepositAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getsingleusedepositaddress).
2. Send Bitcoin to the returned on-chain address and wait for confirmation.

You can generate a one-time Bitcoin deposit address using [`account.getSingleUseDepositAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getsingleusedepositaddress):

{% code title="Single-Use Deposit Address" lineNumbers="true" %}

```javascript
const depositAddress = await account.getSingleUseDepositAddress()
console.log('Send Bitcoin to:', depositAddress)
```

{% endcode %}

## Claim Deposits

1. Identify the Bitcoin transaction id that funded the deposit.
2. Call [`account.claimDeposit()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#claimdeposit-txid) with that id.

You can credit the wallet after the deposit confirms using [`account.claimDeposit()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#claimdeposit-txid):

{% code title="Claim Single-Use Deposit" lineNumbers="true" %}

```javascript
const txId = 'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16'
const walletLeaves = await account.claimDeposit(txId)
console.log('Deposit claimed:', walletLeaves)
```

{% endcode %}

### 1. (optional) Use a static deposit address

You can reuse one on-chain deposit address using [`account.getStaticDepositAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getstaticdepositaddress), then credit the wallet with [`account.claimStaticDeposit()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#claimstaticdeposit-txid) after the Bitcoin transaction confirms:

{% code title="Static Deposit Flow" lineNumbers="true" %}

```javascript
const staticAddress = await account.getStaticDepositAddress()
console.log('Static deposit address:', staticAddress)

const staticLeaves = await account.claimStaticDeposit(
  'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16'
)
console.log('Static deposit claimed:', staticLeaves)
```

{% endcode %}

{% hint style="info" %}
You can list unused single-use addresses with [`account.getUnusedDepositAddresses()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getunuseddepositaddresses-options). The method returns a paginated result with `depositAddresses` and `offset` fields.
{% endhint %}

## Query Static Deposit Addresses

You can list all existing static deposit addresses using [`account.getStaticDepositAddresses()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getstaticdepositaddresses):

{% code title="Query Static Deposit Addresses" lineNumbers="true" %}

```javascript
const addresses = await account.getStaticDepositAddresses()
console.log('Static deposit addresses:', addresses)
```

{% endcode %}

## Query UTXOs for a Deposit Address

You can check confirmed UTXOs for a specific deposit address using [`account.getUtxosForDepositAddress()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getutxosfordepositaddress-options):

{% code title="Query UTXOs" lineNumbers="true" %}

```javascript
const result = await account.getUtxosForDepositAddress({
  depositAddress: 'bc1q...'
})
console.log('Confirmed UTXOs:', result.utxos)
console.log('Offset:', result.offset)
```

{% endcode %}

## Withdraw to Bitcoin Layer 1

1. Choose a Bitcoin `onchainAddress` and `amountSats`.
2. Request a cooperative exit quote with [`account.quoteWithdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotewithdraw-options).
3. Call [`account.withdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#withdraw-options) with the destination and amount.

You can request a withdrawal fee quote using [`account.quoteWithdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotewithdraw-options):

{% code title="Quote Withdrawal" lineNumbers="true" %}

```javascript
const feeQuote = await account.quoteWithdraw({
  withdrawalAddress: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  amountSats: 100000
})
console.log('Withdrawal fee quote:', feeQuote)
```

{% endcode %}

You can initiate the withdrawal using [`account.withdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#withdraw-options):

{% code title="Withdraw to On-Chain Bitcoin" lineNumbers="true" %}

```javascript
const withdrawal = await account.withdraw({
  onchainAddress: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  amountSats: 100000
})
console.log('Withdrawal request:', withdrawal)
```

{% endcode %}

{% hint style="info" %}
[`withdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#withdraw-options) accepts `onchainAddress` and `amountSats`. Run [`quoteWithdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotewithdraw-options) first to understand the cooperative exit costs before initiating the withdrawal.
{% endhint %}

## Next Steps

Learn how to [handle errors and follow operational best practices](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage/handle-errors).


# Handle Errors

Handle Spark transaction and connection failures, plus fees and disposal.

This guide explains how to [handle transaction errors](#transaction-errors), [handle connection errors](#connection-errors), and apply [best practices](#best-practices) for fees and secure cleanup.

## Transaction Errors

Operations such as [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-to-value), [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options), [`account.payLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#paylightninginvoice-options), and [`account.withdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#withdraw-options) can throw. Wrap each call in `try/catch` and branch on `message` or error type when your runtime allows it:

{% code title="Handle Transaction Errors" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: 'spark1...',
    value: 1000000
  })
  console.log('Transaction hash:', result.hash)
} catch (error) {
  console.error('Send failed:', error.message)
}
```

{% endcode %}

You can isolate Lightning failures by wrapping [`account.payLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#paylightninginvoice-options):

{% code title="Handle Lightning Errors" lineNumbers="true" %}

```javascript
try {
  const payment = await account.payLightningInvoice({
    encodedInvoice: 'lnbc500u1p...',
    maxFeeSats: 1000
  })
  console.log('Payment id:', payment.id)
} catch (error) {
  console.error('Lightning payment failed:', error.message)
}
```

{% endcode %}

## Connection Errors

Spark relies on network access through the Spark SDK. Failures may surface as timeouts, refused connections, or generic SDK errors. Handle them around any async wallet call:

{% code title="Handle Connection Errors" lineNumbers="true" %}

```javascript
try {
  const balance = await account.getBalance()
  console.log('Balance:', balance, 'satoshis')
} catch (error) {
  if (error.message.includes('timeout') || error.message.includes('ECONNREFUSED')) {
    console.error('Network error: check connectivity and Spark service status')
  } else {
    console.error('Operation failed:', error.message)
  }
}
```

{% endcode %}

## Best Practices

### Fee management

Native Spark sends and token transfers report zero fees, but withdrawals and Lightning payments can charge fees. Use [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates) for wallet-level rate placeholders and [`account.quotePayLightningInvoice()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotepaylightninginvoice-options) for Lightning sends:

{% code title="Inspect Spark Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal)
console.log('Fast fee rate:', feeRates.fast)
```

{% endcode %}

{% code title="Quote Lightning Fee Before Paying" lineNumbers="true" %}

```javascript
const lightningFee = await account.quotePayLightningInvoice({
  encodedInvoice: 'lnbc500u1p...'
})
console.log('Estimated Lightning fee:', Number(lightningFee), 'satoshis')
```

{% endcode %}

{% hint style="info" %}
[`quoteWithdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotewithdraw-options) should run before [`withdraw()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#withdraw-options) so you understand cooperative exit costs.
{% endhint %}

### Dispose of sensitive data

Clear keys from memory when a session ends. Call [`account.dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose-1) for each account and [`wallet.dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) on the manager:

{% code title="Dispose Wallet Resources" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: 'spark1...',
    value: 1000000
  })
  console.log('Transaction hash:', result.hash)
} finally {
  account.dispose()
  wallet.dispose()
}
```

{% endcode %}

{% hint style="warning" %}
After [`dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose-1), the account cannot sign new operations. Call disposal when the wallet UI or job is finished.
{% endhint %}

## Next Steps

Return to the [Spark wallet usage overview](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/usage) or open the [API Reference](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-spark/api-reference) for full method signatures.


# Configuration

Configuration options and settings for @tetherto/wdk-wallet-spark

## Wallet Configuration

```javascript
const config = {
  network: 'MAINNET' // 'MAINNET', 'SIGNET', or 'REGTEST'
}

const wallet = new WalletManagerSpark(seedPhrase, config)
```

## Account Creation

```javascript
// WalletAccountSpark is created by the WalletManagerSpark
// It does not take configuration parameters directly
const account = await wallet.getAccount(0) // Get account at index 0
```

## Configuration Options

### Network

The `network` option specifies which Spark network to use.

**Type:** `string`

**Values:**

* `"MAINNET"` - Spark mainnet (production)
* `"SIGNET"` - Spark signet (testing)
* `"REGTEST"` - Spark regtest (local development) - [Get test funds](https://app.lightspark.com/regtest-faucet)

**Default:** `"MAINNET"`

**Example:**

```javascript
const config = {
  network: 'REGTEST' // Use REGTEST for development
}
```

## Network Configuration

The wallet can be configured for different Spark networks:

```javascript
// Mainnet configuration
const mainnetConfig = {
  network: 'MAINNET'
}



// Regtest configuration
const regtestConfig = {
  network: 'REGTEST'
}
```

## BIP-44 Derivation Path

Spark uses the [BIP-44](https://docs.wdk.tether.io/resources-and-guides/concepts#bip-44-multi-account-hierarchy) coin type 998, resulting in derivation paths like:

* `m/44'/998'/0'/0/0` for MAINNET account index 0
* `m/44'/998'/0'/0/1` for MAINNET account index 1
* `m/44'/998'/2'/0/0` for SIGNET account index 0
* `m/44'/998'/3'/0/0` for REGTEST account index 0

The path follows the pattern `m/44'/998'/{networkNumber}'/0/{index}` where:

* `998` is the coin type for Spark
* `networkNumber` is 0 for MAINNET, 2 for SIGNET, or 3 for REGTEST
* `index` is the account index

This ensures compatibility with standard [BIP-44](https://docs.wdk.tether.io/resources-and-guides/concepts#bip-44-multi-account-hierarchy) wallets while using Spark's unique coin type identifier.

## Complete Configuration Example

```javascript
import WalletManagerSpark from '@tetherto/wdk-wallet-spark'

// Create wallet manager with configuration
const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
const wallet = new WalletManagerSpark(seedPhrase, {
  network: 'MAINNET'
})

// Get accounts (no additional configuration needed)
const account0 = await wallet.getAccount(0)
const account1 = await wallet.getAccount(1)

// Clean up when done
wallet.dispose()
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet Usage</strong></td><td>Get started with WDK's Spark Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet API</strong></td><td>Get started with WDK's Spark Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk-wallet-spark

### 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-2), [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')

### Methods

| Method                   | Description                                                        | Returns                                   |
| ------------------------ | ------------------------------------------------------------------ | ----------------------------------------- |
| `getAccount(index)`      | Returns a wallet account at the specified index                    | `Promise<WalletAccountSpark>`             |
| `getAccountByPath(path)` | Returns a wallet account at a specific BIP-44 derivation path      | `Promise<WalletAccountSpark>`             |
| `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<WalletAccountSpark>` - 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<WalletAccountSpark>` - The wallet account

**Example:**

```javascript
const account = await wallet.getAccountByPath("0'/0/0")
const address = await account.getAddress()
console.log('Account address:', address)
```

**Important Notes:**

* All Spark transactions have zero fees
* Network configuration is limited to predefined values

## WalletAccountSpark

Represents an individual Spark wallet account. Implements `IWalletAccount` from `@tetherto/wdk-wallet`.

**Note**: WalletAccountSpark instances are created internally by `WalletManagerSpark.getAccount()` and are not intended to be constructed directly.

### Methods

| Method                                  | Description                                        | Returns                                                                    |
| --------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------- |
| `getAddress()`                          | Returns the account's Spark address                | `Promise<SparkAddressFormat>`                                              |
| `sign(message)`                         | Signs a message using the account's identity key   | `Promise<string>`                                                          |
| `getIdentityKey()`                      | Returns the account's identity public key          | `Promise<string>`                                                          |
| `verify(message, signature)`            | Verifies a message signature                       | `Promise<boolean>`                                                         |
| `sendTransaction(tx)`                   | Sends a Spark transaction                          | `Promise<{hash: string, fee: bigint}>`                                     |
| `quoteSendTransaction(tx)`              | Estimates transaction fee (always 0)               | `Promise<{fee: bigint}>`                                                   |
| `transfer(options)`                     | Transfers tokens to another address                | `Promise<{hash: string, fee: bigint}>`                                     |
| `quoteTransfer(options)`                | Quotes the costs of a transfer operation           | `Promise<{fee: bigint}>`                                                   |
| `getBalance()`                          | Returns the native token balance in satoshis       | `Promise<bigint>`                                                          |
| `getTokenBalance(tokenAddress)`         | Returns the balance for a specific token           | `Promise<bigint>`                                                          |
| `getTransactionReceipt(hash)`           | Returns a Spark transfer by its ID                 | `Promise<SparkTransfer \| null>`                                           |
| `getTransfers(options?)`                | Returns the account's transfer history             | `Promise<SparkTransfer[]>`                                                 |
| `getSingleUseDepositAddress()`          | Generates a single-use Bitcoin deposit address     | `Promise<string>`                                                          |
| `getUnusedDepositAddresses(options?)`   | Returns unused single-use deposit addresses        | `Promise<{depositAddresses: DepositAddressQueryResult[], offset: number}>` |
| `getStaticDepositAddress()`             | Gets or creates a reusable static deposit address  | `Promise<string>`                                                          |
| `getStaticDepositAddresses()`           | Returns all existing static deposit addresses      | `Promise<DepositAddressQueryResult[]>`                                     |
| `getUtxosForDepositAddress(options)`    | Returns confirmed UTXOs for a deposit address      | `Promise<{utxos: {txid: string, vout: number}[], offset: number}>`         |
| `claimDeposit(txId)`                    | Claims a Bitcoin deposit to the wallet             | `Promise<WalletLeaf[] \| undefined>`                                       |
| `claimStaticDeposit(txId)`              | Claims a static Bitcoin deposit to the wallet      | `Promise<WalletLeaf[] \| undefined>`                                       |
| `refundStaticDeposit(options)`          | Refunds a static deposit back to a Bitcoin address | `Promise<string>`                                                          |
| `quoteWithdraw(options)`                | Gets a fee quote for withdrawing funds             | `Promise<CoopExitFeeQuote>`                                                |
| `withdraw(options)`                     | Withdraws funds to a Bitcoin address               | `Promise<CoopExitRequest \| null \| undefined>`                            |
| `createLightningInvoice(options)`       | Creates a Lightning invoice                        | `Promise<LightningReceiveRequest>`                                         |
| `getLightningReceiveRequest(invoiceId)` | Gets Lightning receive request by id               | `Promise<LightningReceiveRequest \| null>`                                 |
| `getLightningSendRequest(requestId)`    | Gets Lightning send request by id                  | `Promise<LightningSendRequest \| null>`                                    |
| `payLightningInvoice(options)`          | Pays a Lightning invoice                           | `Promise<LightningSendRequest>`                                            |
| `quotePayLightningInvoice(options)`     | Gets fee estimate for Lightning payments           | `Promise<bigint>`                                                          |
| `createSparkSatsInvoice(options)`       | Creates a Spark invoice for receiving sats         | `Promise<SparkAddressFormat>`                                              |
| `createSparkTokensInvoice(options)`     | Creates a Spark invoice for receiving tokens       | `Promise<SparkAddressFormat>`                                              |
| `paySparkInvoice(invoices)`             | Pays one or more Spark invoices                    | `Promise<FulfillSparkInvoiceResponse>`                                     |
| `getSparkInvoices(params)`              | Queries the status of Spark invoices               | `Promise<{invoiceStatuses: InvoiceResponse[], offset: number}>`            |
| `toReadOnlyAccount()`                   | Creates a read-only version of this account        | `Promise<WalletAccountReadOnlySpark>`                                      |
| `cleanupConnections()`                  | Cleans up network connections and resources        | `Promise<void>`                                                            |
| `dispose()`                             | Disposes the wallet account, clearing private keys | `void`                                                                     |

**`getAddress()`**

Returns the account's Spark network address.

**Returns:** `Promise<SparkAddressFormat>` - The Spark address

**Example:**

```javascript
const address = await account.getAddress()
console.log('Spark address:', address)
```

**`sign(message)`**

Signs a message using the account's identity key.

**Parameters:**

* `message` (string): The message to sign

**Returns:** `Promise<string>` - The message signature

**Example:**

```javascript
const signature = await account.sign('Hello, Spark!')
console.log('Signature:', signature)
```

**`getIdentityKey()`**

Returns the account's identity public key (hex-encoded).

**Returns:** `Promise<string>` - The identity public key

**Example:**

```javascript
const identityKey = await account.getIdentityKey()
console.log('Identity key:', identityKey) // 02eda8...
```

**`sendTransaction({to, value})`**

Sends a Spark transaction.

**Parameters:**

* `to` (string): Recipient's Spark address
* `value` (number): Amount in satoshis

**Returns:** `Promise<{hash: string, fee: bigint}>` (fee is always 0)

**Example:**

```javascript
const result = await account.sendTransaction({
  to: 'spark1...',
  value: 1000000
})
console.log('Transaction hash:', result.hash)
console.log('Fee:', Number(result.fee)) // Always 0
```

**`quoteSendTransaction({to, value})`**

Estimates the fee for a Spark transaction (always returns 0).

**Parameters:**

* `to` (string): Recipient's Spark address
* `value` (number): Amount in satoshis

**Returns:** `Promise<{fee: bigint}>` - Fee estimate (always 0)

**Example:**

```javascript
const quote = await account.quoteSendTransaction({
  to: 'spark1...',
  value: 1000000
})
console.log('Estimated fee:', Number(quote.fee)) // Always 0
```

**`transfer(options)`**

Transfers tokens to another address.

**Parameters:**

* `options` (object): Transfer options
  * `token` (string): Token identifier (Bech32m token identifier, e.g., `btkn1...`)
  * `amount` (bigint): Amount of tokens to transfer
  * `recipient` (string): Recipient Spark address

**Returns:** `Promise<{hash: string, fee: bigint}>` - Transfer result

**Example:**

```javascript
const result = await account.transfer({
  token: 'btkn1...',
  amount: BigInt(1000000),
  recipient: 'spark1...'
})
console.log('Transfer hash:', result.hash)
```

**`quoteTransfer(options)`**

Quotes the costs of a transfer operation.

**Parameters:**

* `options` (object): Transfer options (same as `transfer`)

**Returns:** `Promise<{fee: bigint}>` - Transfer fee quote

**Example:**

```javascript
const quote = await account.quoteTransfer({
  token: 'btkn1...',
  amount: BigInt(1000000),
  recipient: 'spark1...'
})
console.log('Transfer fee:', Number(quote.fee))
```

**`getBalance()`**

Returns the account's native token balance in satoshis.

**Returns:** `Promise<bigint>` - Balance in satoshis

**Example:**

```javascript
const balance = await account.getBalance()
console.log('Balance:', balance, 'satoshis')
console.log('Balance in BTC:', Number(balance) / 1e8)
```

**`getTokenBalance(tokenAddress)`**

Returns the balance for a specific token.

**Parameters:**

* `tokenAddress` (string): Token contract address

**Returns:** `Promise<bigint>` - Token balance in base unit

**Example:**

```javascript
const tokenBalance = await account.getTokenBalance('token_address...')
console.log('Token balance:', tokenBalance)
```

**`getTransactionReceipt(hash)`**

Returns a Spark transfer by its ID. Only returns Spark transfers, not on-chain Bitcoin transactions.

**Parameters:**

* `hash` (string): The Spark transfer ID

**Returns:** `Promise<SparkTransfer | null>` - The Spark transfer, or null if not found

**Example:**

```javascript
const transfer = await account.getTransactionReceipt('transfer_id...')
console.log('Transfer details:', transfer)
```

**`getTransfers(options?)`**

Returns the Spark transfer history of the account. Only returns Spark transfers, not on-chain Bitcoin transactions.

**Parameters:**

* `options` (GetTransfersOptions, optional): Filter options
  * `direction` (string): 'all', 'incoming', or 'outgoing' (default: 'all')
  * `limit` (number): Maximum transfers to return (default: 10)
  * `skip` (number): Number of transfers to skip (default: 0)

**Returns:** `Promise<SparkTransfer[]>` - Array of Spark transfers

**Example:**

```javascript
const transfers = await account.getTransfers({
  direction: 'incoming',
  limit: 5
})
console.log('Recent incoming transfers:', transfers)
```

**`getSingleUseDepositAddress()`**

Generates a single-use Bitcoin deposit address for funding the Spark wallet.

**Returns:** `Promise<string>` - Bitcoin deposit address

**Example:**

```javascript
const depositAddress = await account.getSingleUseDepositAddress()
console.log('Send Bitcoin to:', depositAddress)
```

**`getUnusedDepositAddresses(options?)`**

Returns unused single-use deposit addresses for the account.

**Parameters:**

* `options` (Omit\<QueryDepositAddressesParams, 'sparkAddress'>, optional): Query options

**Returns:** `Promise<{depositAddresses: DepositAddressQueryResult[], offset: number}>` - The unused deposit addresses with pagination offset

**Example:**

```javascript
const result = await account.getUnusedDepositAddresses()
console.log('Unused addresses:', result.depositAddresses)
console.log('Offset:', result.offset)
```

**`getStaticDepositAddress()`**

Returns a static deposit address for Bitcoin deposits from layer 1, generating one if it does not already exist. This address can be reused.

**Returns:** `Promise<string>` - The static deposit address

**Example:**

```javascript
const depositAddress = await account.getStaticDepositAddress()
console.log('Static deposit address:', depositAddress)
```

**`getStaticDepositAddresses()`**

Returns all existing static deposit addresses for the account.

**Returns:** `Promise<DepositAddressQueryResult[]>` - The static deposit addresses

**Example:**

```javascript
const addresses = await account.getStaticDepositAddresses()
console.log('Static deposit addresses:', addresses)
```

**`getUtxosForDepositAddress(options)`**

Returns confirmed UTXOs for a specific deposit address.

**Parameters:**

* `options` (GetUtxosParams): Query options

**Returns:** `Promise<{utxos: {txid: string, vout: number}[], offset: number}>` - The confirmed UTXOs with pagination offset

**Example:**

```javascript
const result = await account.getUtxosForDepositAddress({
  depositAddress: 'bc1q...'
})
console.log('UTXOs:', result.utxos)
```

**`claimDeposit(txId)`**

Claims a Bitcoin deposit to add funds to the Spark wallet.

**Parameters:**

* `txId` (string): Bitcoin transaction ID of the deposit

**Returns:** `Promise<WalletLeaf[] | undefined>` - Wallet leaves created from the deposit

**Example:**

```javascript
const leaves = await account.claimDeposit('bitcoin_tx_id...')
console.log('Claimed deposit:', leaves)
```

**`claimStaticDeposit(txId)`**

Claims a static Bitcoin deposit to add funds to the Spark wallet.

**Parameters:**

* `txId` (string): Bitcoin transaction ID of the deposit

**Returns:** `Promise<WalletLeaf[] | undefined>` - Wallet leaves created from the deposit

**Example:**

```javascript
const leaves = await account.claimStaticDeposit('bitcoin_tx_id...')
console.log('Claimed static deposit:', leaves)
```

**`refundStaticDeposit(options)`**

Refunds a deposit made to a static deposit address back to a specified Bitcoin address. The minimum fee is 300 satoshis.

**Parameters:**

* `options` (object): Refund options
  * `depositTransactionId` (string): The transaction ID of the original deposit
  * `outputIndex` (number): The output index of the deposit
  * `destinationAddress` (string): The Bitcoin address to send the refund to
  * `satsPerVbyteFee` (number): The fee rate in sats per vbyte for the refund transaction

**Returns:** `Promise<string>` - The refund transaction as a hex string that needs to be broadcast

**Example:**

```javascript
const refundTx = await account.refundStaticDeposit({
  depositTransactionId: 'txid...',
  outputIndex: 0,
  destinationAddress: 'bc1q...',
  satsPerVbyteFee: 10
})
console.log('Refund transaction (hex):', refundTx)
// Note: This transaction needs to be broadcast to the Bitcoin network
```

**`quoteWithdraw(options)`**

Gets a fee quote for withdrawing funds from Spark cooperatively to an on-chain Bitcoin address.

**Parameters:**

* `options` (object): Withdrawal quote options
  * `withdrawalAddress` (string): The Bitcoin address where the funds should be sent
  * `amountSats` (number): The amount in satoshis to withdraw

**Returns:** `Promise<CoopExitFeeQuote>` - The withdrawal fee quote

**Example:**

```javascript
const feeQuote = await account.quoteWithdraw({
  withdrawalAddress: 'bc1q...',
  amountSats: 1000000
})
console.log('Withdrawal fee quote:', feeQuote)
```

**`withdraw(options)`**

Initiates a withdrawal to move funds from the Spark network to an on-chain Bitcoin address.

**Parameters:**

* `options` (WithdrawOptions): Withdrawal options object (`Omit<WithdrawParams, 'feeQuote'>`)
  * `onchainAddress` (string): Bitcoin address to withdraw to
  * `amountSats` (number): Amount in satoshis to withdraw

**Returns:** `Promise<CoopExitRequest | null | undefined>` - The withdrawal request details, or null/undefined if the request cannot be completed

**Example:**

```javascript
const withdrawal = await account.withdraw({
  onchainAddress: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
  amountSats: 100000
})
console.log('Withdrawal request:', withdrawal)
```

**`createLightningInvoice(options)`**

Creates a Lightning invoice for receiving payments.

**Parameters:**

* `options` (CreateLightningInvoiceParams): Invoice options object
  * `amountSats` (number, optional): Amount in satoshis
  * `memo` (string, optional): Invoice description
  * Additional options from `CreateLightningInvoiceParams` may be supported

**Returns:** `Promise<LightningReceiveRequest>` - Lightning invoice details

**Example:**

```javascript
const invoice = await account.createLightningInvoice({
  amountSats: 100000,
  memo: 'Payment for services'
})
console.log('Invoice:', invoice.invoice)
```

**`getLightningReceiveRequest(invoiceId)`**

Gets details of a previously created Lightning receive request.

**Parameters:**

* `invoiceId` (string): Invoice ID

**Returns:** `Promise<LightningReceiveRequest | null>` - Invoice details, or null if not found

**Example:**

```javascript
const request = await account.getLightningReceiveRequest(invoiceId)
if (request) {
  console.log('Invoice status:', request.status)
}
```

**`getLightningSendRequest(requestId)`**

Gets a Lightning send request by id.

**Parameters:**

* `requestId` (string): The id of the Lightning send request

**Returns:** `Promise<LightningSendRequest | null>` - The Lightning send request

**Example:**

```javascript
const request = await account.getLightningSendRequest(requestId)
if (request) {
  console.log('Lightning send request:', request)
}
```

**`payLightningInvoice(options)`**

Pays a Lightning invoice.

**Parameters:**

* `options` (PayLightningInvoiceParams): Payment options object
  * `encodedInvoice` (string): BOLT11 Lightning invoice
  * `maxFeeSats` (number, optional): Maximum fee willing to pay in satoshis
  * Additional options from `PayLightningInvoiceParams` may be supported

**Returns:** `Promise<LightningSendRequest>` - Payment details

**Example:**

```javascript
const payment = await account.payLightningInvoice({
  encodedInvoice: 'lnbc...',
  maxFeeSats: 1000
})
console.log('Payment result:', payment)
```

**`quotePayLightningInvoice(options)`**

Estimates the fee for paying a Lightning invoice.

**Parameters:**

* `options` (LightningSendFeeEstimateInput): Fee estimation options
  * `encodedInvoice` (string): BOLT11 Lightning invoice
  * Additional options may be supported

**Returns:** `Promise<bigint>` - Estimated fee in satoshis

**Example:**

```javascript
const feeEstimate = await account.quotePayLightningInvoice({
  encodedInvoice: 'lnbc...'
})
console.log('Estimated Lightning fee:', Number(feeEstimate), 'satoshis')
```

**`verify(message, signature)`**

Verifies a message signature against the account's identity key.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify

**Returns:** `Promise<boolean>` - True if the signature is valid

**Example:**

```javascript
const isValid = await account.verify('Hello, Spark!', signature)
console.log('Signature valid:', isValid)
```

**`createSparkSatsInvoice(options)`**

Creates a Spark invoice for receiving a sats payment.

**Parameters:**

* `options` (object): Invoice options
  * `amount` (number, optional): The amount of sats to receive (optional for open invoices)
  * `memo` (string, optional): Optional memo/description for the payment
  * `senderSparkAddress` (SparkAddressFormat, optional): Optional Spark address of the expected sender
  * `expiryTime` (Date, optional): Optional expiry time for the invoice

**Returns:** `Promise<SparkAddressFormat>` - A Spark invoice that can be paid by another Spark wallet

**Example:**

```javascript
const invoice = await account.createSparkSatsInvoice({
  amount: 100000,
  memo: 'Payment for services'
})
console.log('Spark invoice:', invoice)
```

**`createSparkTokensInvoice(options)`**

Creates a Spark invoice for receiving a token payment.

**Parameters:**

* `options` (object): Invoice options
  * `tokenIdentifier` (string, optional): The Bech32m token identifier (e.g., `btkn1...`)
  * `amount` (bigint, optional): The amount of tokens to receive
  * `memo` (string, optional): Optional memo/description for the payment
  * `senderSparkAddress` (SparkAddressFormat, optional): Optional Spark address of the expected sender
  * `expiryTime` (Date, optional): Optional expiry time for the invoice

**Returns:** `Promise<SparkAddressFormat>` - A Spark invoice that can be paid by another Spark wallet

**Example:**

```javascript
const invoice = await account.createSparkTokensInvoice({
  tokenIdentifier: 'btkn1...',
  amount: BigInt(1000),
  memo: 'Token payment'
})
console.log('Spark token invoice:', invoice)
```

**`paySparkInvoice(invoices)`**

Fulfills one or more Spark invoices by paying them.

**Parameters:**

* `invoices` (SparkInvoice\[]): Array of invoices to fulfill
  * Each invoice has:
    * `invoice` (SparkAddressFormat): The Spark invoice to pay
    * `amount` (bigint, optional): Amount to pay (required for invoices without encoded amount)

**Returns:** `Promise<FulfillSparkInvoiceResponse>` - Response containing transaction results and errors

**Example:**

```javascript
const result = await account.paySparkInvoice([
  {
    invoice: 'spark1...',
    amount: BigInt(100000)
  }
])
console.log('Payment result:', result)
```

**`getSparkInvoices(params)`**

Queries the status of Spark invoices.

**Parameters:**

* `params` (QuerySparkInvoicesParams): The query parameters

**Returns:** `Promise<{invoiceStatuses: InvoiceResponse[], offset: number}>` - The invoice statuses with pagination offset

**Example:**

```javascript
const result = await account.getSparkInvoices({
  sparkAddress: await account.getAddress()
})
console.log('Invoice statuses:', result.invoiceStatuses)
```

**`toReadOnlyAccount()`**

Creates a read-only version of this account that can query data but not sign transactions.

**Returns:** `Promise<WalletAccountReadOnlySpark>` - Read-only account instance

**Example:**

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const balance = await readOnlyAccount.getBalance()
```

**`cleanupConnections()`**

Cleans up network connections and resources.

**Returns:** `Promise<void>`

**Example:**

```javascript
await account.cleanupConnections()
```

**`dispose()`**

Disposes the wallet account, securely erasing private keys from memory.

**Returns:** `void`

**Example:**

```javascript
account.dispose()
// Private keys are now cleared from memory
```

#### Properties

| Property  | Type      | Description                               |
| --------- | --------- | ----------------------------------------- |
| `index`   | `number`  | The derivation path index of this account |
| `path`    | `string`  | The full BIP-44 derivation path           |
| `keyPair` | `KeyPair` | The account's public and private key pair |

## WalletAccountReadOnlySpark

Represents a read-only wallet account. Implements `WalletAccountReadOnly` from `@tetherto/wdk-wallet`.

### Constructor

```javascript
new WalletAccountReadOnlySpark(address, config)
```

**Parameters:**

* `address` (string): The account's Spark address
* `config` (SparkWalletConfig, optional): Configuration object

### Methods

| Method                                | Description                                   | Returns                                                                    |
| ------------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------- |
| `getAddress()`                        | Returns the account's Spark address           | `Promise<SparkAddressFormat>`                                              |
| `getIdentityKey()`                    | Returns the account's identity public key     | `Promise<string>`                                                          |
| `getBalance()`                        | Returns the native token balance in satoshis  | `Promise<bigint>`                                                          |
| `getTokenBalance(tokenAddress)`       | Returns the balance for a specific token      | `Promise<bigint>`                                                          |
| `getTransactionReceipt(hash)`         | Returns a Spark transfer by its ID            | `Promise<SparkTransfer \| null>`                                           |
| `getTransfers(options?)`              | Returns the account's Spark transfer history  | `Promise<SparkTransfer[]>`                                                 |
| `getUnusedDepositAddresses(options?)` | Returns unused single-use deposit addresses   | `Promise<{depositAddresses: DepositAddressQueryResult[], offset: number}>` |
| `getStaticDepositAddresses()`         | Returns all existing static deposit addresses | `Promise<DepositAddressQueryResult[]>`                                     |
| `getUtxosForDepositAddress(options)`  | Returns confirmed UTXOs for a deposit address | `Promise<{utxos: {txid: string, vout: number}[], offset: number}>`         |
| `getSparkInvoices(params)`            | Queries the status of Spark invoices          | `Promise<{invoiceStatuses: InvoiceResponse[], offset: number}>`            |
| `quoteSendTransaction(tx)`            | Estimates transaction fee (always 0)          | `Promise<{fee: bigint}>`                                                   |
| `quoteTransfer(options)`              | Quotes the costs of a transfer operation      | `Promise<{fee: bigint}>`                                                   |

**`getAddress()`**

Returns the account's Spark network address.

**Returns:** `Promise<SparkAddressFormat>` - The Spark address

**Example:**

```javascript
const address = await readOnlyAccount.getAddress()
console.log('Spark address:', address)
```

**`getIdentityKey()`**

Returns the account's identity public key (hex-encoded).

**Returns:** `Promise<string>` - The identity public key

**Example:**

```javascript
const identityKey = await readOnlyAccount.getIdentityKey()
console.log('Identity key:', identityKey) // 02eda8...
```

**`getBalance()`**

Returns the account's native token balance in satoshis.

**Returns:** `Promise<bigint>` - Balance in satoshis

**Example:**

```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Balance:', balance, 'satoshis')
```

**`getTokenBalance(tokenAddress)`**

Returns the balance for a specific token.

**Parameters:**

* `tokenAddress` (string): Token contract address

**Returns:** `Promise<bigint>` - Token balance in base unit

**Example:**

```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('token_address...')
console.log('Token balance:', tokenBalance)
```

**`getTransactionReceipt(hash)`**

Returns a Spark transfer by its ID. Only returns Spark transfers, not on-chain Bitcoin transactions.

**Parameters:**

* `hash` (string): The Spark transfer ID

**Returns:** `Promise<SparkTransfer | null>` - The Spark transfer, or null if not found

**Example:**

```javascript
const transfer = await readOnlyAccount.getTransactionReceipt('transfer_id...')
console.log('Transfer details:', transfer)
```

**`getTransfers(options?)`**

Returns the Spark transfer history of the account. Only returns Spark transfers, not on-chain Bitcoin transactions.

**Parameters:**

* `options` (GetTransfersOptions, optional): Filter options
  * `direction` (string): 'all', 'incoming', or 'outgoing' (default: 'all')
  * `limit` (number): Maximum transfers to return (default: 10)
  * `skip` (number): Number of transfers to skip (default: 0)

**Returns:** `Promise<SparkTransfer[]>` - Array of Spark transfers

**Example:**

```javascript
const transfers = await readOnlyAccount.getTransfers({
  direction: 'incoming',
  limit: 5
})
console.log('Recent incoming transfers:', transfers)
```

**`getUnusedDepositAddresses(options?)`**

Returns unused single-use deposit addresses for the account.

**Parameters:**

* `options` (Omit\<QueryDepositAddressesParams, 'sparkAddress'>, optional): Query options

**Returns:** `Promise<{depositAddresses: DepositAddressQueryResult[], offset: number}>` - The unused deposit addresses with pagination offset

**Example:**

```javascript
const result = await readOnlyAccount.getUnusedDepositAddresses()
console.log('Unused addresses:', result.depositAddresses)
```

**`getStaticDepositAddresses()`**

Returns all existing static deposit addresses for the account.

**Returns:** `Promise<DepositAddressQueryResult[]>` - The static deposit addresses

**Example:**

```javascript
const addresses = await readOnlyAccount.getStaticDepositAddresses()
console.log('Static deposit addresses:', addresses)
```

**`getUtxosForDepositAddress(options)`**

Returns confirmed UTXOs for a specific deposit address.

**Parameters:**

* `options` (GetUtxosParams): Query options

**Returns:** `Promise<{utxos: {txid: string, vout: number}[], offset: number}>` - The confirmed UTXOs with pagination offset

**Example:**

```javascript
const result = await readOnlyAccount.getUtxosForDepositAddress({
  depositAddress: 'bc1q...'
})
console.log('UTXOs:', result.utxos)
```

**`getSparkInvoices(params)`**

Queries the status of Spark invoices.

**Parameters:**

* `params` (QuerySparkInvoicesParams): The query parameters

**Returns:** `Promise<{invoiceStatuses: InvoiceResponse[], offset: number}>` - The invoice statuses with pagination offset

**Example:**

```javascript
const result = await readOnlyAccount.getSparkInvoices({
  sparkAddress: await readOnlyAccount.getAddress()
})
console.log('Invoice statuses:', result.invoiceStatuses)
```

**`quoteSendTransaction({to, value})`**

Estimates the fee for a Spark transaction (always returns 0).

**Parameters:**

* `to` (string): Recipient's Spark address
* `value` (number): Amount in satoshis

**Returns:** `Promise<{fee: bigint}>` - Fee estimate (always 0)

**Example:**

```javascript
const quote = await readOnlyAccount.quoteSendTransaction({
  to: 'spark1...',
  value: 1000000
})
console.log('Estimated fee:', Number(quote.fee))
```

**`quoteTransfer(options)`**

Quotes the costs of a transfer operation.

**Parameters:**

* `options` (object): Transfer options
  * `token` (string): Token identifier
  * `amount` (bigint): Amount of tokens
  * `recipient` (string): Recipient Spark address

**Returns:** `Promise<{fee: bigint}>` - Transfer fee quote

**Example:**

```javascript
const quote = await readOnlyAccount.quoteTransfer({
  token: 'btkn1...',
  amount: BigInt(1000000),
  recipient: 'spark1...'
})
console.log('Transfer fee:', Number(quote.fee))
```

## Types

### SparkWalletConfig

```typescript
interface SparkWalletConfig {
  network?: 'MAINNET' | 'SIGNET' | 'REGTEST'  // The network (default: "MAINNET")
}
```

### SparkTransaction

```typescript
interface SparkTransaction {
  to: string              // The transaction's recipient (Spark address)
  value: number | bigint  // The amount of bitcoins to send to the recipient (in satoshis)
}
```

### TransactionResult

```typescript
interface TransactionResult {
  hash: string  // Transaction hash/ID
  fee: bigint   // Transaction fee in satoshis (always 0n for Spark)
}
```

### KeyPair

```typescript
interface KeyPair {
  publicKey: Uint8Array   // Public key bytes
  privateKey: Uint8Array  // Private key bytes
}
```

### LightningReceiveRequest

```typescript
interface LightningReceiveRequest {
  invoice: string    // BOLT11 encoded Lightning invoice
  id: string        // Invoice ID for tracking
  amountSats: number // Amount in satoshis
  memo?: string     // Optional description
}
```

### LightningSendRequest

```typescript
interface LightningSendRequest {
  id: string           // Payment request ID
  invoice: string      // BOLT11 encoded invoice that was paid
  maxFeeSats: number   // Maximum fee that was allowed
  status: string       // Payment status
}
```

### WalletLeaf

```typescript
interface WalletLeaf {
  // Spark SDK internal structure for wallet state
  // Exact properties depend on Spark SDK implementation
}
```

### CoopExitRequest

```typescript
interface CoopExitRequest {
  id: string              // Withdrawal request ID
  onchainAddress: string  // Bitcoin address for withdrawal
  amountSats: number      // Amount in satoshis
  exitSpeed: string       // Withdrawal speed ('FAST', 'MEDIUM', 'SLOW') - default: 'MEDIUM'
  status: string          // Withdrawal status
}
```

### TransferOptions

```typescript
interface TransferOptions {
  token: string      // Token identifier (Bech32m, e.g. btkn1...)
  amount: bigint     // Amount of tokens to transfer
  recipient: string  // Recipient Spark address
}
```

### GetTransfersOptions

```typescript
interface GetTransfersOptions {
  direction?: 'incoming' | 'outgoing' | 'all'  // Filter by direction (default: 'all')
  limit?: number                               // Number of transfers to return (default: 10)
  skip?: number                                // Number of transfers to skip (default: 0)
}
```

### SparkTransfer

Type alias for `Transfer` from `@buildonspark/spark-sdk/proto/spark`. Key properties include:

```typescript
interface SparkTransfer {
  id: string                    // Transfer ID
  status: string                // Transfer status
  totalValue: number            // Total value in satoshis
  transferDirection: string     // 'INCOMING' or 'OUTGOING'
  type: string                  // Transfer type
  createdTime?: Date            // When the transfer was created
  updatedTime?: Date            // Last update timestamp
}
```

### DepositAddressQueryResult

From `@buildonspark/spark-sdk/proto/spark`:

```typescript
interface DepositAddressQueryResult {
  address: string       // The deposit address
  confirmationStatus: string  // Confirmation status
}
```

### InvoiceResponse

From `@buildonspark/spark-sdk/proto/spark`:

```typescript
interface InvoiceResponse {
  invoiceId: string     // The invoice identifier
  status: string        // The invoice status
}
```

### QueryDepositAddressesParams

```typescript
interface QueryDepositAddressesParams {
  sparkAddress: string  // The Spark address to query deposit addresses for
  offset?: number       // Pagination offset
  limit?: number        // Maximum results to return
}
```

### GetUtxosParams

```typescript
interface GetUtxosParams {
  depositAddress: string  // The deposit address to query UTXOs for
  offset?: number         // Pagination offset
  limit?: number          // Maximum results to return
}
```

### QuerySparkInvoicesParams

```typescript
interface QuerySparkInvoicesParams {
  sparkAddress: string  // The Spark address to query invoices for
  offset?: number       // Pagination offset
  limit?: number        // Maximum results to return
}
```

### Lightning Invoice Options

```typescript
// Use CreateLightningInvoiceParams from @buildonspark/spark-sdk
// Basic options include:
interface CreateLightningInvoiceParams {
  amountSats?: number  // Amount in satoshis
  memo?: string         // Optional description for the invoice
  // Additional options may be available
}
```

### Lightning Payment Options

```typescript
// Use PayLightningInvoiceParams from @buildonspark/spark-sdk
// Basic options include:
interface PayLightningInvoiceParams {
  encodedInvoice: string  // BOLT11-encoded Lightning invoice to pay
  maxFeeSats?: number     // Maximum fee in satoshis to pay
  // Additional options may be available
}
```

### Lightning Fee Estimate Options

```typescript
// Use LightningSendFeeEstimateInput from @buildonspark/spark-sdk/types
// Basic options include:
interface LightningSendFeeEstimateInput {
  encodedInvoice: string  // BOLT11-encoded Lightning invoice to estimate fees for
  // Additional options may be available
}
```

### Withdrawal Options

```typescript
// WithdrawOptions = Omit<WithdrawParams, 'feeQuote'>
interface WithdrawOptions {
  onchainAddress: string  // Bitcoin address where the funds should be sent
  amountSats: number      // Amount in satoshis to withdraw
}

interface QuoteWithdrawOptions {
  withdrawalAddress: string  // Bitcoin address where the funds should be sent
  amountSats: number        // Amount in satoshis to withdraw
}
```

### Spark Invoice Options

```typescript
interface CreateSatsInvoiceOptions {
  amount?: number              // Amount of sats to receive (optional for open invoices)
  memo?: string                // Optional memo/description
  senderSparkAddress?: string  // Optional Spark address of expected sender
  expiryTime?: Date           // Optional expiry time
}

interface CreateTokensInvoiceOptions {
  tokenIdentifier?: string     // Bech32m token identifier (e.g., btkn1...)
  amount?: bigint             // Amount of tokens to receive
  memo?: string                // Optional memo/description
  senderSparkAddress?: string  // Optional Spark address of expected sender
  expiryTime?: Date           // Optional expiry time
}

interface SparkInvoice {
  invoice: string   // The Spark invoice to pay
  amount?: bigint   // Amount to pay (required for invoices without encoded amount)
}
```

### Refund Options

```typescript
interface RefundStaticDepositOptions {
  depositTransactionId: string  // Transaction ID of the original deposit
  outputIndex: number            // Output index of the deposit
  destinationAddress: string     // Bitcoin address to send refund to
  satsPerVbyteFee: number        // Fee rate in sats per vbyte
}
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet Usage</strong></td><td>Get started with WDK's Spark Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK Spark Wallet Configuration</strong></td><td>Get started with WDK's Spark Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# wallet-ton

Overview of the @tetherto/wdk-wallet-ton module

A simple and secure package to manage BIP-44 wallets for the TON blockchain. This package provides a clean API for creating, managing, and interacting with TON wallets using BIP-39 seed phrases and TON-specific derivation paths.

{% hint style="warning" %}
**Default Derivation Path Change in v1.0.0-beta.6+**

The default derivation path was updated in v1.0.0-beta.6 to match ecosystem conventions:

* **Previous path** (<= v1.0.0-beta.5): `m/44'/607'/0'/0/{index}`
* **Current path** (v1.0.0-beta.6+): `m/44'/607'/{index}'`

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`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
{% endhint %}

## Features

* **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases
* **TON Derivation Paths**: Support for BIP-44 standard derivation paths for TON (m/44'/607')
* **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
* **TON Address Support**: Generate and manage TON addresses using V5R1 wallet contracts
* **Message Signing**: Sign and verify messages using TON cryptography
* **Transaction Management**: Send transactions and get fee estimates
* **Jetton Support**: Query native TON and Jetton token balances
* **TypeScript Support**: Full TypeScript definitions included
* **Memory Safety**: Secure private key management with automatic memory cleanup using sodium-universal
* **Provider Flexibility**: Support for custom TON RPC endpoints and TON Center API

## Supported Networks

This package works with the TON blockchain (The Open Network), including:

* **TON Mainnet**
* **TON Testnet**

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet Configuration</strong></td><td>Get started with WDK's TON Wallet configuration</td><td><a href="wallet-ton/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet API</strong></td><td>Get started with WDK's TON Wallet API</td><td><a href="wallet-ton/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet Usage</strong></td><td>Get started with WDK's TON Wallet usage</td><td><a href="wallet-ton/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-ton module.

The `@tetherto/wdk-wallet-ton` module provides wallet management for the TON blockchain.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Get Started</strong></td><td>Install the package and create your first wallet.</td><td><a href="usage/get-started">get-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Work with multiple accounts and custom derivation paths.</td><td><a href="usage/manage-accounts">manage-accounts</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query native TON and Jetton token balances.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send TON</strong></td><td>Send native TON and estimate transaction fees.</td><td><a href="usage/send-transactions">send-transactions</a></td></tr><tr><td><i class="fa-coins">:coins:</i></td><td><strong>Transfer Jetton Tokens</strong></td><td>Transfer Jetton tokens and estimate fees.</td><td><a href="usage/transfer-tokens">transfer-tokens</a></td></tr><tr><td><i class="fa-key">:key:</i></td><td><strong>Sign and Verify Messages</strong></td><td>Sign messages and verify signatures.</td><td><a href="usage/sign-verify-messages">sign-verify-messages</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Handle Errors</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/handle-errors">handle-errors</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet Configuration</strong></td><td>Get started with WDK's TON Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet API</strong></td><td>Get started with WDK's TON Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Get Started

Install and create your first TON wallet.

This guide explains how to [install the package](#1-install-the-package), [create a wallet](#2-create-a-wallet), and [get your first account](#3-get-your-first-account).

## 1. Install the Package

### Prerequisites

* [**Node.js**](https://nodejs.org/): version 18 or higher.
* [**npm**](https://www.npmjs.com/): usually comes with Node.js.

{% code title="Install @tetherto/wdk-wallet-ton" lineNumbers="true" %}

```bash
npm install @tetherto/wdk-wallet-ton
```

{% endcode %}

## 2. Create a Wallet

You can create a new wallet instance using the [`WalletManagerTon`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletmanagerton) constructor with a BIP-39 seed phrase and a TON Center client configuration:

{% code title="Create TON Wallet" lineNumbers="true" %}

```javascript
import WalletManagerTon, { WalletAccountTon, WalletAccountReadOnlyTon } from '@tetherto/wdk-wallet-ton'

const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'

const wallet = new WalletManagerTon(seedPhrase, {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key' // Optional
  }
})
```

{% endcode %}

{% hint style="danger" %}
**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.
{% endhint %}

## 3. Get Your First Account

You can retrieve an account at a given index using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index):

{% code title="Get Account" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Wallet address:', address)
```

{% endcode %}

## 4. (optional) Convert to Read-Only

You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount):

{% code title="Convert to Read-Only" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
```

{% endcode %}

## Next Steps

With your wallet ready, learn how to [manage multiple accounts](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage/manage-accounts).


# Manage Accounts

Work with multiple TON accounts and custom derivation paths.

This guide explains how to [retrieve accounts by index](#retrieve-accounts-by-index), [use custom derivation paths](#retrieve-account-by-custom-derivation-path), and [iterate over multiple accounts](#iterate-over-multiple-accounts).

## Retrieve Accounts by Index

You can access accounts derived from the default BIP-44 path using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index):

{% code title="Get Accounts by Index" lineNumbers="true" %}

```javascript
const account = await wallet.getAccount(0)
const address = await account.getAddress()
console.log('Account 0 address:', address)

const account1 = await wallet.getAccount(1)
const address1 = await account1.getAddress()
console.log('Account 1 address:', address1)
```

{% endcode %}

## Retrieve Account by Custom Derivation Path

You can request an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypath-path):

{% code title="Custom Derivation Path" lineNumbers="true" %}

```javascript
const customAccount = await wallet.getAccountByPath("0'/0/5")
const customAddress = await customAccount.getAddress()
console.log('Custom account address:', customAddress)
```

{% endcode %}

## Iterate Over Multiple Accounts

You can loop through multiple accounts using [`wallet.getAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccount-index) to inspect addresses and balances in bulk:

{% code title="Multi-Account Iteration" lineNumbers="true" %}

```javascript
async function listAccounts(wallet) {
  const accounts = []

  for (let i = 0; i < 5; i++) {
    const account = await wallet.getAccount(i)
    const address = await account.getAddress()
    const balance = await account.getBalance()

    accounts.push({ index: i, address, balance })
  }

  return accounts
}
```

{% endcode %}

## Next Steps

Now that you can access your accounts, learn how to [check balances](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage/check-balances).


# Check Balances

Query native TON and Jetton token balances.

This guide explains how to check [native TON balances](#native-ton-balance), [Jetton token balances](#jetton-token-balance), and [read-only account balances](#read-only-account-balances).

## Native TON Balance

You can retrieve the native TON balance using [`account.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Get Native TON Balance" lineNumbers="true" %}

```javascript
const balance = await account.getBalance()
console.log('Native TON balance:', balance, 'nanotons')
```

{% endcode %}

{% hint style="info" %}
On TON, values are expressed in nanotons (1 TON = 10^9 nanotons).
{% endhint %}

## Jetton Token Balance

You can check the balance of a specific Jetton token using [`account.getTokenBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettokenbalance-tokenaddress):

{% code title="Get Jetton Token Balance" lineNumbers="true" %}

```javascript
const jettonAddress = 'EQ...' // Jetton contract address
const jettonBalance = await account.getTokenBalance(jettonAddress)
console.log('Jetton token balance:', jettonBalance)
```

{% endcode %}

## Read-Only Account Balances

You can check balances for any public key without a seed phrase using [`WalletAccountReadOnlyTon`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlyton):

{% code title="Create Read-Only Account" lineNumbers="true" %}

```javascript
import { WalletAccountReadOnlyTon } from '@tetherto/wdk-wallet-ton'

const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key' // Optional
  }
})
```

{% endcode %}

You can retrieve the native balance from a read-only account using [`readOnlyAccount.getBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getbalance):

{% code title="Read-Only Native Balance" lineNumbers="true" %}

```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Read-only account balance:', balance)
```

{% endcode %}

{% hint style="info" %}
You can also create a read-only account from an existing owned account using [`account.toReadOnlyAccount()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#toreadonlyaccount).
{% endhint %}

## Next Steps

With balance checks in place, learn how to [send TON](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage/send-transactions).


# Send TON

Send native TON and estimate transaction fees.

This guide explains how to [send native TON](#send-native-ton), [estimate transaction fees](#estimate-transaction-fees), and [use dynamic fee rates](#use-dynamic-fee-rates).

{% hint style="info" %}
On TON, values are expressed in nanotons (1 TON = 10^9 nanotons). Transactions support an optional `bounceable` parameter specific to the TON network.
{% endhint %}

## Send Native TON

You can transfer TON to a recipient address using [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-tx):

{% code title="Send TON" lineNumbers="true" %}

```javascript
const result = await account.sendTransaction({
  to: 'EQ...', // TON address
  value: 1000000000, // 1 TON in nanotons
  bounceable: true // Optional: specify if the address is bounceable
})
console.log('Transaction hash:', result.hash)
console.log('Transaction fee:', result.fee, 'nanotons')
```

{% endcode %}

## Estimate Transaction Fees

You can get a fee estimate before sending using [`account.quoteSendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotesendtransaction-tx):

{% code title="Quote Transaction Fee" lineNumbers="true" %}

```javascript
const quote = await account.quoteSendTransaction({
  to: 'EQ...',
  value: 1000000000,
  bounceable: true
})
console.log('Estimated fee:', quote.fee, 'nanotons')
```

{% endcode %}

## Use Dynamic Fee Rates

You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates):

{% code title="Get Fee Rates" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'nanotons')
console.log('Fast fee rate:', feeRates.fast, 'nanotons')
```

{% endcode %}

## Next Steps

To transfer Jetton tokens instead of native TON, see [Transfer Jetton Tokens](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage/transfer-tokens).


# Transfer Jetton Tokens

Transfer Jetton tokens and estimate transfer fees on TON.

This guide explains how to [transfer Jetton tokens](#transfer-tokens), [estimate transfer fees](#estimate-transfer-fees), and [validate inputs before executing](#transfer-with-validation).

## Transfer Tokens

You can send Jetton tokens to a recipient address using [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options):

{% code title="Transfer Jetton Tokens" lineNumbers="true" %}

```javascript
const transferResult = await account.transfer({
  token: 'EQ...',      // Jetton contract address
  recipient: 'EQ...',  // Recipient's TON address
  amount: 1000000      // Amount in Jetton's base units
})
console.log('Transfer hash:', transferResult.hash)
console.log('Transfer fee:', transferResult.fee, 'nanotons')
```

{% endcode %}

## Estimate Transfer Fees

You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotetransfer-options):

{% code title="Quote Token Transfer" lineNumbers="true" %}

```javascript
const transferQuote = await account.quoteTransfer({
  token: 'EQ...',      // Jetton contract address
  recipient: 'EQ...',  // Recipient's TON address
  amount: 1000000      // Amount in Jetton's base units
})
console.log('Transfer fee estimate:', transferQuote.fee, 'nanotons')
```

{% endcode %}

## Transfer with Validation

Validate addresses and check balances before transferring to catch errors early:

1. Use [`account.getTokenBalance()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#gettokenbalance-tokenaddress) to verify sufficient funds.
2. Use [`account.quoteTransfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#quotetransfer-options) to confirm fees.
3. Execute the transfer with [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options):

{% code title="Validated Jetton Transfer" lineNumbers="true" %}

```javascript
async function transferJettonWithValidation(account, jettonAddress, recipient, amount) {
  if (typeof jettonAddress !== 'string' || jettonAddress.length === 0) {
    throw new Error('Invalid Jetton address format')
  }

  if (typeof recipient !== 'string' || recipient.length === 0) {
    throw new Error('Invalid recipient address format')
  }

  const balance = await account.getTokenBalance(jettonAddress)
  if (balance < amount) {
    throw new Error('Insufficient Jetton balance')
  }

  const quote = await account.quoteTransfer({
    token: jettonAddress,
    recipient,
    amount
  })
  console.log('Estimated fee:', quote.fee, 'nanotons')

  const result = await account.transfer({
    token: jettonAddress,
    recipient,
    amount
  })
  console.log('Transfer hash:', result.hash)
  console.log('Actual fee:', result.fee, 'nanotons')

  return result
}
```

{% endcode %}

## Next Steps

Learn how to [sign and verify messages](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage/sign-verify-messages) with your TON account.


# Sign and Verify Messages

Sign messages and verify signatures with TON accounts.

This guide explains how to [sign messages](#sign-a-message) with an owned account and [verify signatures](#verify-a-signature) using a read-only account.

## Sign a Message

You can produce a cryptographic signature for any string message using [`account.sign()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sign-message):

{% code title="Sign a Message" lineNumbers="true" %}

```javascript
const message = 'Hello, TON!'
const signature = await account.sign(message)
console.log('Signature:', signature)
```

{% endcode %}

## Verify a Signature

You can verify that a signature was produced by the corresponding private key using [`readOnlyAccount.verify()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#verify-message-signature):

{% code title="Verify a Signature" lineNumbers="true" %}

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const isValid = await readOnlyAccount.verify(message, signature)
console.log('Signature valid:', isValid)
```

{% endcode %}

{% hint style="info" %}
You can also create a [`WalletAccountReadOnlyTon`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#walletaccountreadonlyton) from any public key to verify signatures without access to the private key.
{% endhint %}

## Next Steps

For best practices on handling errors, managing fees, and cleaning up memory, see [Handle Errors](https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage/handle-errors).


# Handle Errors

Handle errors, manage fees, and dispose of sensitive data in TON wallets.

This guide covers how to [handle transaction errors](#handle-transaction-errors) and [handle token transfer errors](#handle-token-transfer-errors), plus [best practices](#best-practices) for fee management and memory cleanup.

## Handle Transaction Errors

Wrap transactions in `try/catch` blocks to handle common failure scenarios. Use [`account.sendTransaction()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#sendtransaction-tx) with proper error handling:

{% code title="Transaction Error Handling" lineNumbers="true" %}

```javascript
try {
  const result = await account.sendTransaction({
    to: 'EQ...',
    value: 1000000000,
    bounceable: true
  })
  console.log('Transaction hash:', result.hash)
  console.log('Fee paid:', result.fee, 'nanotons')
} catch (error) {
  if (error.message.includes('insufficient balance')) {
    console.error('Not enough TON to complete transaction')
  } else if (error.message.includes('invalid address')) {
    console.error('Invalid recipient address')
  } else if (error.message.includes('timeout')) {
    console.error('Network timeout, please try again')
  } else {
    console.error('Transaction failed:', error.message)
  }
}
```

{% endcode %}

## Handle Token Transfer Errors

Jetton transfers can fail for multiple reasons, such as insufficient token balances. Use [`account.transfer()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#transfer-options) with error handling:

{% code title="Token Transfer Error Handling" lineNumbers="true" %}

```javascript
try {
  const result = await account.transfer({
    token: 'EQ...',
    recipient: 'EQ...',
    amount: 1000000
  })
  console.log('Transfer submitted:', result.hash)
} catch (error) {
  console.error('Transfer failed:', error.message)
  if (error.message.toLowerCase().includes('insufficient')) {
    console.log('Please add more tokens to your wallet')
  } else if (error.message.toLowerCase().includes('fee')) {
    console.log('The transfer fee exceeds your configured maximum')
  }
}
```

{% endcode %}

## Best Practices

### Manage Fee Limits

Set `transferMaxFee` when creating the wallet to prevent transactions from exceeding a maximum cost. You can retrieve current network rates using [`wallet.getFeeRates()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getfeerates):

{% code title="Fee Management" lineNumbers="true" %}

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'nanotons')
console.log('Fast fee rate:', feeRates.fast, 'nanotons')
```

{% endcode %}

### Dispose of Sensitive Data

Call [`dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed:

{% code title="Memory Cleanup" lineNumbers="true" %}

```javascript
account.dispose()

wallet.dispose()
```

{% endcode %}

{% hint style="warning" %}
Always call [`dispose()`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#dispose) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs.
{% endhint %}


# Configuration

Configuration options and settings for @tetherto/wdk-wallet-ton

## Wallet Configuration

The `WalletManagerTon` accepts a configuration object that defines how the wallet interacts with the TON blockchain:

```javascript
import WalletManagerTon from '@tetherto/wdk-wallet-ton'

const config = {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key' // Optional
  },
  transferMaxFee: 10000000 // Optional: maximum fee in nanotons for transfer operations
}

const wallet = new WalletManagerTon(seedPhrase, config) // config is optional
```

## Account Configuration

```javascript
import { WalletAccountTon } from '@tetherto/wdk-wallet-ton'

const accountConfig = {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key' // Optional
  },
  transferMaxFee: 10000000 // Optional: maximum fee in nanotons for transfer operations
}

const account = new WalletAccountTon(seedPhrase, "0'/0/0", accountConfig) // config is optional
```

## Configuration Options

### tonClient

The `tonClient` option configures the TON Center API client for blockchain interactions. You can pass either a configuration object or an existing `TonClient` instance.

**Type:**

```typescript
type TonClientOption = TonClientConfig | TonClient;

interface TonClientConfig {
  /**
   * TON Center API endpoint URL
   * @example 'https://toncenter.com/api/v3'
   */
  url: string;

  /**
   * Optional API key for TON Center
   * Required for higher rate limits
   */
  secretKey?: string;
}
```

**Required:** No (optional)

**Examples:**

```javascript
// Basic configuration
const config = {
  tonClient: { 
    url: 'https://toncenter.com/api/v3'
  }
}

// With API key for higher rate limits
const config = {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key'
  }
}
```

### transferMaxFee

The `transferMaxFee` option sets the maximum allowed fee (in nanotons) for transfer operations. This helps prevent unexpectedly high transaction fees.

**Type:** `number | bigint`

**Required:** No **Default:** No maximum (undefined)

**Examples:**

```javascript
const config = {
  transferMaxFee: 1000000000 // 1 TON in nanotons
}

// Example with both options
const config = {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key'
  },
  transferMaxFee: 1000000000
}
```

## Read-Only Account Configuration

For read-only accounts, you only need the TON client configuration:

```javascript
import { WalletAccountReadOnlyTon } from '@tetherto/wdk-wallet-ton'

const readOnlyConfig = {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key' // Optional
  }
}

const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, readOnlyConfig)
```

## Network Selection

The TON network (mainnet or testnet) is determined by the TON Center API endpoint URL:

* Mainnet: `https://toncenter.com/api/v3`
* Testnet: `https://testnet.toncenter.com/api/v3`

## Derivation Paths

TON wallets use BIP-44 standard derivation paths. The default derivation path follows ecosystem conventions:

* Default path: `m/44'/607'/{index}'` (where `{index}` is the account index)

{% hint style="warning" %}
**Default Derivation Path Change in v1.0.0-beta.6+**

The default derivation path was updated in v1.0.0-beta.6 to match ecosystem conventions:

* **Previous path** (<= v1.0.0-beta.5): `m/44'/607'/0'/0/{index}`
* **Current path** (v1.0.0-beta.6+): `m/44'/607'/{index}'`

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`](https://docs.wdk.tether.io/sdk/wallet-modules/api-reference#getaccountbypathpath) to supply an explicit derivation path when importing or recreating legacy wallets.
{% endhint %}

## Security Considerations

* Always use HTTPS URLs for TON Center API endpoints
* Keep API keys secure and never expose them in client-side code
* Consider using environment variables for API keys
* Set appropriate `transferMaxFee` limits for your use case

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet Usage</strong></td><td>Get started with WDK's TON Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet API</strong></td><td>Get started with WDK's TON Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# API Reference

Complete API documentation for @tetherto/wdk-wallet-ton

### API Reference

#### Table of Contents

| Class                                                 | Description                                  | Methods                                              |
| ----------------------------------------------------- | -------------------------------------------- | ---------------------------------------------------- |
| [WalletManagerTon](#walletmanagerton)                 | Main class for managing TON wallets          | [Constructor](#constructor), [Methods](#methods)     |
| [WalletAccountTon](#walletaccountton)                 | Individual TON wallet account implementation | [Constructor](#constructor-1), [Methods](#methods-1) |
| [WalletAccountReadOnlyTon](#walletaccountreadonlyton) | Read-only TON wallet account                 | [Constructor](#constructor-2), [Methods](#methods-2) |

#### WalletManagerTon

The main class for managing TON wallets.\
Extends `WalletManager` from `@tetherto/wdk-wallet`.

**Constructor**

```javascript
new WalletManagerTon(seed, config)
```

**Parameters:**

* `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes
* `config` (object, optional): Configuration object
  * `tonClient` (object | TonClient, optional): TON client configuration or instance
    * `url` (string): TON Center API URL (e.g., '<https://toncenter.com/api/v3>')
    * `secretKey` (string, optional): API key for TON Center
  * `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations (in nanotons)

**Example:**

```javascript
const wallet = new WalletManagerTon(seedPhrase, {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key'
  },
  transferMaxFee: 1000000000 // Maximum fee in nanotons (1 TON)
})
```

**Methods**

| Method                   | Description                                                      | Returns                                   |
| ------------------------ | ---------------------------------------------------------------- | ----------------------------------------- |
| `getAccount(index)`      | Returns a wallet account at the specified index                  | `Promise<WalletAccountTon>`               |
| `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise<WalletAccountTon>`               |
| `getFeeRates()`          | Returns current fee rates for transactions                       | `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.

**Parameters:**

* `index` (number, optional): The index of the account to get (default: 0)

**Returns:** `Promise<WalletAccountTon>` - The wallet account

**Example:**

```javascript
const account = await wallet.getAccount(0)
```

**`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<WalletAccountTon>` - The wallet account

**Example:**

```javascript
const account = await wallet.getAccountByPath("0'/0/1")
```

**`getFeeRates()`**

Returns current fee rates for normal and fast transactions.

**Returns:** `Promise<FeeRates>` - Object containing normal and fast fee rates (as `bigint` values)

**Example:**

```javascript
const feeRates = await wallet.getFeeRates()
console.log('Normal fee rate:', feeRates.normal, 'nanotons')
console.log('Fast fee rate:', feeRates.fast, 'nanotons')
```

**`dispose()`**

Disposes all wallet accounts, clearing private keys from memory.

**Example:**

```javascript
wallet.dispose()
```

**Properties**

**`seed`**

The wallet's seed bytes.

**Type:** `Uint8Array`

**Example:**

```javascript
console.log('Seed:', wallet.seed)
```

#### WalletAccountTon

Individual TON wallet account implementation. Extends `WalletAccountReadOnlyTon` and implements `IWalletAccount`.

**Constructor**

```javascript
new WalletAccountTon(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
  * `tonClient` (object | TonClient, optional): TON client configuration or instance
    * `url` (string): TON Center API URL
    * `secretKey` (string, optional): API key for TON Center
  * `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations

**Example:**

```javascript
const account = new WalletAccountTon(seedPhrase, "0'/0/0", {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key'
  },
  transferMaxFee: 10000000 // Maximum fee in nanotons (e.g., 0.01 TON)
})
```

**Methods**

| Method                          | Description                                                    | Returns                                |
| ------------------------------- | -------------------------------------------------------------- | -------------------------------------- |
| `getAddress()`                  | Returns the account's TON address                              | `Promise<string>`                      |
| `sign(message)`                 | Signs a message using the account's private key                | `Promise<string>`                      |
| `verify(message, signature)`    | Verifies a message signature                                   | `Promise<boolean>`                     |
| `sendTransaction(tx)`           | Sends a TON transaction                                        | `Promise<{hash: string, fee: bigint}>` |
| `quoteSendTransaction(tx)`      | Estimates the fee for a TON transaction                        | `Promise<{fee: bigint}>`               |
| `transfer(options)`             | Transfers Jetton tokens to another address                     | `Promise<{hash: string, fee: bigint}>` |
| `quoteTransfer(options)`        | Estimates the fee for a Jetton transfer                        | `Promise<{fee: bigint}>`               |
| `getBalance()`                  | Returns the native TON balance (in nanotons)                   | `Promise<bigint>`                      |
| `getTokenBalance(tokenAddress)` | Returns the balance of a specific Jetton token                 | `Promise<bigint>`                      |
| `getTransactionReceipt(hash)`   | Returns a transaction's receipt                                | \`Promise\<TonTransactionReceipt       |
| `toReadOnlyAccount()`           | Returns a read-only copy of the account                        | `Promise<WalletAccountReadOnlyTon>`    |
| `dispose()`                     | Disposes the wallet account, clearing private keys from memory | `void`                                 |

**`getAddress()`**

Returns the account's address.

**Returns:** `Promise<string>` - The account's TON address

**Example:**

```javascript
const address = await account.getAddress()
console.log('Account address:', address)
```

**`sign(message)`**

Signs a message using the account's private key.

**Parameters:**

* `message` (string): The message to sign

**Returns:** `Promise<string>` - The message signature

**Example:**

```javascript
const signature = await account.sign('Hello, World!')
console.log('Signature:', signature)
```

**`verify(message, signature)`**

Verifies a message signature.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify

**Returns:** `Promise<boolean>` - True if the signature is valid

**Example:**

```javascript
const isValid = await account.verify('Hello, World!', signature)
console.log('Signature valid:', isValid)
```

**`sendTransaction(tx)`**

Sends a TON transaction and returns the result with hash and fee.

**Parameters:**

* `tx` (object): The transaction object
  * `to` (string): Recipient TON address (e.g., 'EQ...')
  * `value` (number | bigint): Amount in nanotons (1 TON = 1,000,000,000 nanotons)
  * `bounceable` (boolean, optional): Whether the address is bounceable (TON-specific, optional)
  * `body` (string | Cell, optional): Optional message body

**Returns:** `Promise<{hash: string, fee: bigint}>` - Object containing hash and fee (in nanotons)

**Example:**

```javascript
const result = await account.sendTransaction({
  to: 'EQ...', // TON address
  value: 1000000000 // 1 TON in nanotons
});
console.log('Transaction hash:', result.hash);
console.log('Transaction fee:', result.fee, 'nanotons');
```

**`quoteSendTransaction(tx)`**

Estimates the fee for a transaction.

**Parameters:**

* `tx` (object): The transaction object (same as sendTransaction)
  * `to` (string): Recipient TON address (e.g., 'EQ...')
  * `value` (number | bigint): Amount in nanotons (1 TON = 1,000,000,000 nanotons)
  * `bounceable` (boolean, optional): Whether the address is bounceable (TON-specific, optional)
  * `body` (string | Cell, optional): Optional message body

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in nanotons)

**Example:**

```javascript
const quote = await account.quoteSendTransaction({
  to: 'EQ...', // TON address
  value: 1000000000 // 1 TON in nanotons
});
console.log('Estimated fee:', quote.fee, 'nanotons');
```

**`transfer(options)`**

Transfers Jettons (TON tokens) to another address.

**Parameters:**

* `options` (object): Transfer options
  * `token` (string): Jetton master contract address (TON format, e.g., 'EQ...')
  * `recipient` (string): Recipient TON address (e.g., 'EQ...')
  * `amount` (number | bigint): Amount in Jetton's base units

**Returns:** `Promise<{hash: string, fee: bigint}>` - Object containing hash and fee (in nanotons)

**Example:**

```javascript
const result = await account.transfer({
  token: 'EQ...',      // Jetton master contract address
  recipient: 'EQ...',  // Recipient's TON address
  amount: 1000000000    // Amount in Jetton's base units
});
console.log('Transfer hash:', result.hash);
console.log('Transfer fee:', result.fee, 'nanotons');
```

**`quoteTransfer(options)`**

Estimates the fee for a Jetton (TON token) transfer.

**Parameters:**

* `options` (object): Transfer options (same as transfer)
  * `token` (string): Jetton master contract address (TON format, e.g., 'EQ...')
  * `recipient` (string): Recipient TON address (e.g., 'EQ...')
  * `amount` (number | bigint): Amount in Jetton's base units

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in nanotons)

**Example:**

```javascript
const quote = await account.quoteTransfer({
  token: 'EQ...',      // Jetton master contract address
  recipient: 'EQ...',  // Recipient's TON address
  amount: 1000000000    // Amount in Jetton's base units
});
console.log('Transfer fee estimate:', quote.fee, 'nanotons');
```

**`getBalance()`**

Returns the native TON balance (in nanotons).

**Returns:** `Promise<bigint>` - Balance in nanotons

**Example:**

```javascript
const balance = await account.getBalance();
console.log('Balance:', balance, 'nanotons');
```

**`getTokenBalance(tokenAddress)`**

Returns the balance of a specific Jetton (TON token).

**Parameters:**

* `tokenAddress` (string): The Jetton master contract address (TON format, e.g., 'EQ...')

**Returns:** `Promise<bigint>` - Token balance in base units

**Example:**

```javascript
const tokenBalance = await account.getTokenBalance('EQ...');
console.log('Token balance:', tokenBalance, 'nanotons');
```

**`getTransactionReceipt(hash)`**

Returns a transaction's receipt if it has been mined.

**Parameters:**

* `hash` (string): The transaction hash

**Returns:** `Promise<TonTransactionReceipt | null>` - Transaction receipt or null if not yet mined

**Example:**

```javascript
const receipt = await account.getTransactionReceipt('EQ...')
console.log('Transaction confirmed:', receipt.success)
```

**`toReadOnlyAccount()`**

Returns a read-only copy of the account.

**Returns:** `Promise<WalletAccountReadOnlyTon>` - The read-only account

**Example:**

```javascript
const readOnlyAccount = await account.toReadOnlyAccount()
const address = await readOnlyAccount.getAddress()
console.log('Read-only account address:', address)
```

**`dispose()`**

Disposes the wallet account, clearing private keys from memory.

**Example:**

```javascript
account.dispose()
```

**Properties**

| Property  | Type                                                      | Description                                 |
| --------- | --------------------------------------------------------- | ------------------------------------------- |
| `index`   | `number`                                                  | The derivation path's index of this account |
| `path`    | `string`                                                  | The full derivation path of this account    |
| `keyPair` | `{publicKey: Uint8Array, privateKey: Uint8Array \| null}` | The account's public and private key pair   |

**Example:**

```javascript
const { publicKey, privateKey } = account.keyPair
console.log('Public key length:', publicKey.length)
console.log('Private key length:', privateKey.length)
```

#### WalletAccountReadOnlyTon

Read-only TON wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`.

**Constructor**

```javascript
new WalletAccountReadOnlyTon(publicKey, config)
```

**Parameters:**

* `publicKey` (string | Uint8Array): The account's public key
* `config` (object, optional): Configuration object (`Omit<TonWalletConfig, 'transferMaxFee'>`)
  * `tonClient` (object | TonClient, optional): TON client configuration or instance
    * `url` (string): TON Center API URL
    * `secretKey` (string, optional): API key for TON Center

**Example:**

```javascript
const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, {
  tonClient: {
    url: 'https://toncenter.com/api/v3',
    secretKey: 'your-api-key'
  }
})
```

**Methods**

| Method                          | Description                                    | Returns                                  |
| ------------------------------- | ---------------------------------------------- | ---------------------------------------- |
| `getAddress()`                  | Returns the account's TON address              | `Promise<string>`                        |
| `verify(message, signature)`    | Verifies a message signature                   | `Promise<boolean>`                       |
| `getBalance()`                  | Returns the native TON balance (in nanotons)   | `Promise<bigint>`                        |
| `getTokenBalance(tokenAddress)` | Returns the balance of a specific Jetton token | `Promise<bigint>`                        |
| `quoteSendTransaction(tx)`      | Estimates the fee for a TON transaction        | `Promise<{fee: bigint}>`                 |
| `quoteTransfer(options)`        | Estimates the fee for a Jetton transfer        | `Promise<{fee: bigint}>`                 |
| `getTransactionReceipt(hash)`   | Returns a transaction's receipt                | `Promise<TonTransactionReceipt \| null>` |

**`getAddress()`**

Returns the account's address.

**Returns:** `Promise<string>` - The account's TON address

**Example:**

```javascript
const address = await readOnlyAccount.getAddress()
console.log('Account address:', address)
```

**`verify(message, signature)`**

Verifies a message signature.

**Parameters:**

* `message` (string): The original message
* `signature` (string): The signature to verify

**Returns:** `Promise<boolean>` - True if the signature is valid

**Example:**

```javascript
const isValid = await readOnlyAccount.verify('Hello, World!', signature)
console.log('Signature valid:', isValid)
```

**`getBalance()`**

Returns the native TON balance (in nanotons).

**Returns:** `Promise<bigint>` - Balance in nanotons

**Example:**

```javascript
const balance = await readOnlyAccount.getBalance()
console.log('Balance:', balance, 'nanotons')
```

**`getTokenBalance(tokenAddress)`**

Returns the balance of a specific Jetton (TON token).

**Parameters:**

* `tokenAddress` (string): The Jetton master contract address (TON format, e.g., 'EQ...')

**Returns:** `Promise<bigint>` - Token balance in base units

**Example:**

```javascript
const tokenBalance = await readOnlyAccount.getTokenBalance('EQ...')
console.log('Token balance:', tokenBalance)
```

**`quoteSendTransaction(tx)`**

Estimates the fee for a transaction.

**Parameters:**

* `tx` (object): The transaction object
  * `to` (string): Recipient TON address
  * `value` (number | bigint): Amount in nanotons
  * `bounceable` (boolean, optional): Whether the address is bounceable
  * `body` (string | Cell, optional): Optional message body

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in nanotons)

**Example:**

```javascript
const quote = await readOnlyAccount.quoteSendTransaction({
  to: 'EQ...',
  value: 1000000000
})
console.log('Estimated fee:', quote.fee, 'nanotons')
```

**`quoteTransfer(options)`**

Estimates the fee for a Jetton (TON token) transfer.

**Parameters:**

* `options` (object): Transfer options
  * `token` (string): Jetton master contract address
  * `recipient` (string): Recipient TON address
  * `amount` (number | bigint): Amount in Jetton's base units

**Returns:** `Promise<{fee: bigint}>` - Object containing fee estimate (in nanotons)

**Example:**

```javascript
const quote = await readOnlyAccount.quoteTransfer({
  token: 'EQ...',
  recipient: 'EQ...',
  amount: 1000000000
})
console.log('Transfer fee estimate:', quote.fee, 'nanotons')
```

**`getTransactionReceipt(hash)`**

Returns a transaction's receipt if it has been mined.

**Parameters:**

* `hash` (string): The transaction hash

**Returns:** `Promise<TonTransactionReceipt | null>` - Transaction receipt or null if not yet mined

**Example:**

```javascript
const receipt = await readOnlyAccount.getTransactionReceipt('EQ...')
console.log('Transaction confirmed:', receipt !== null)
```

### Types

#### TonTransaction

```typescript
interface TonTransaction {
  /**
   * Recipient's TON address in base64 format
   * @example 'EQD4FPq...'
   */
  to: string;

  /**
   * Amount to send in nanotons (1 TON = 1,000,000,000 nanotons)
   * @example 1000000000 // 1 TON
   */
  value: number | bigint;

  /**
   * Whether the destination address is bounceable
   */
  bounceable?: boolean;

  /**
   * Optional message body
   */
  body?: string | Cell;
}
```

#### TransferOptions

```typescript
interface TransferOptions {
  /**
   * Jetton master contract address
   * @example 'EQD4FPq...'
   */
  token: string;

  /**
   * Recipient's TON address
   * @example 'EQD4FPq...'
   */
  recipient: string;

  /**
   * Amount in Jetton's base units
   * @example 1000000000 // Amount depends on token decimals
   */
  amount: number | bigint;
}
```

#### TransactionResult

```typescript
interface TransactionResult {
  /**
   * Transaction hash in base64 format
   * @example 'EQD4FPq...'
   */
  hash: string;

  /**
   * Transaction fee in nanotons
   * @example 100000n // 0.0001 TON
   */
  fee: bigint;
}
```

#### TransferResult

```typescript
interface TransferResult {
  /**
   * Transfer operation hash
   */
  hash: string;

  /**
   * Transfer fee in nanotons
   */
  fee: bigint;
}
```

#### FeeRates

```typescript
interface FeeRates {
  /**
   * Fee rate for normal priority transactions (in nanotons)
   * @example 100000000n // 0.1 TON
   */
  normal: bigint;

  /**
   * Fee rate for high priority transactions (in nanotons)
   * @example 200000000n // 0.2 TON
   */
  fast: bigint;
}
```

#### KeyPair

```typescript
interface KeyPair {
  /**
   * Ed25519 public key
   */
  publicKey: Uint8Array;

  /**
   * Ed25519 private key (null if the account has been disposed)
   * @security Never expose or log this value
   */
  privateKey: Uint8Array | null;
}
```

#### TonWalletConfig

```typescript
interface TonWalletConfig {
  /**
   * TON Center client configuration or an instance of TonClient
   */
  tonClient?: TonClientConfig | TonClient;

  /**
   * Maximum allowed fee for transfers (in nanotons)
   * @example 1000000000n // 1 TON
   */
  transferMaxFee?: number | bigint;
}
```

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet Usage</strong></td><td>Get started with WDK's TON Wallet Usage</td><td><a href="usage">usage</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Wallet Configuration</strong></td><td>Get started with WDK's TON Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr></tbody></table>

***

#### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# wallet-ton-gasless

Overview of the @tetherto/wdk-wallet-ton-gasless module

A simple and secure package to manage gasless transactions on the TON blockchain. This package provides a clean API for creating, managing, and interacting with TON wallets using BIP-39 seed phrases and TON-specific derivation paths, with support for gasless transactions through a paymaster system.

## Features

* **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases
* **TON Derivation Paths**: Support for BIP-44 standard derivation paths for TON (m/44'/607')
* **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase
* **TON Address Support**: Generate and manage TON addresses using V5R1 wallet contracts
* **Message Signing**: Sign and verify messages using TON cryptography
* **Gasless Transactions**: Execute transactions without requiring TON for gas fees
* **Paymaster Integration**: Built-in support for paymaster-based fee delegation
* **Jetton Support**: Query native TON and Jetton token balances
* **TypeScript Support**: Full TypeScript definitions included
* **Memory Safety**: Secure private key management with automatic memory cleanup using sodium-universal
* **Provider Flexibility**: Support for both TON Center and TON API endpoints

## Supported Networks

This package works with the TON blockchain (The Open Network), including:

* **TON Mainnet**
* **TON Testnet**

## Next Steps

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Gasless Wallet Configuration</strong></td><td>Get started with WDK's TON Gasless Wallet configuration</td><td><a href="wallet-ton-gasless/configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Gasless Wallet API</strong></td><td>Get started with WDK's TON Gasless Wallet API</td><td><a href="wallet-ton-gasless/api-reference">api-reference</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Gasless Wallet Usage</strong></td><td>Get started with WDK's with TON Gasless Wallet usage</td><td><a href="wallet-ton-gasless/usage">usage</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>


# Usage

Guide to using the @tetherto/wdk-wallet-ton-gasless module.

The `@tetherto/wdk-wallet-ton-gasless` module provides wallet management for the TON blockchain with gasless transaction support, where transfer fees are paid using a configured paymaster token instead of native TON.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-rocket">:rocket:</i></td><td><strong>Get Started</strong></td><td>Install the package and create your first gasless wallet.</td><td><a href="usage/get-started">get-started</a></td></tr><tr><td><i class="fa-user">:user:</i></td><td><strong>Manage Accounts</strong></td><td>Work with multiple accounts and custom derivation paths.</td><td><a href="usage/manage-accounts">manage-accounts</a></td></tr><tr><td><i class="fa-wallet">:wallet:</i></td><td><strong>Check Balances</strong></td><td>Query native TON, Jetton, and paymaster token balances.</td><td><a href="usage/check-balances">check-balances</a></td></tr><tr><td><i class="fa-exchange-alt">:exchange-alt:</i></td><td><strong>Send TON</strong></td><td>Send native TON transactions.</td><td><a href="usage/send-transactions">send-transactions</a></td></tr><tr><td><i class="fa-coins">:coins:</i></td><td><strong>Transfer Jetton Tokens</strong></td><td>Transfer Jetton tokens gaslessly with paymaster fees.</td><td><a href="usage/transfer-tokens">transfer-tokens</a></td></tr><tr><td><i class="fa-key">:key:</i></td><td><strong>Sign and Verify Messages</strong></td><td>Sign messages and verify signatures.</td><td><a href="usage/sign-verify-messages">sign-verify-messages</a></td></tr><tr><td><i class="fa-exclamation-triangle">:exclamation-triangle:</i></td><td><strong>Handle Errors</strong></td><td>Handle errors, manage fees, and dispose of sensitive data.</td><td><a href="usage/handle-errors">handle-errors</a></td></tr></tbody></table>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-code">:code:</i></td><td><strong>Node.js Quickstart</strong></td><td>Get started with WDK in a Node.js environment</td><td><a href="../../../start-building/nodejs-bare-quickstart">nodejs-bare-quickstart</a></td></tr><tr><td><i class="fa-mobile-alt">:mobile-alt:</i></td><td><strong>React Native Quickstart</strong></td><td>Build mobile wallets with React Native Expo</td><td><a href="../../../start-building/react-native-quickstart">react-native-quickstart</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Gasless Wallet Configuration</strong></td><td>Get started with WDK's TON Gasless Wallet Configuration</td><td><a href="configuration">configuration</a></td></tr><tr><td><i class="fa-code">:code:</i></td><td><strong>WDK TON Gasless Wallet API</strong></td><td>Get started with WDK's TON Gasless Wallet API</td><td><a href="api-reference">api-reference</a></td></tr></tbody></table>

***

### Need Help?

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><i class="fa-discord">:discord:</i></td><td><strong>Discord Community</strong></td><td>Connect with developers, ask questions, share your projects</td><td><a href="https://discord.gg/arYXDhHB2w" class="button primary">Join Community</a></td><td><a href="https://discord.gg/arYXDhHB2w">https://discord.gg/arYXDhHB2w</a></td></tr><tr><td><i class="fa-github">:github:</i></td><td><strong>GitHub Issues</strong></td><td>Report bugs, request features, and get technical help</td><td><a href="https://github.com/tetherto/wdk-core" class="button secondary">Open an Issue</a></td><td><a href="https://github.com/tetherto/wdk-core">https://github.com/tetherto/wdk-core</a></td></tr><tr><td><i class="fa-envelope">:envelope:</i></td><td><strong>Email Contact</strong></td><td>For sensitive or private matters, contact our team directly</td><td><a href="mailto:wallet-info.tether.io" class="button secondary">Send an email</a></td><td><a href="mailto:wallet-info.tether.io">mailto:wallet-info.tether.io</a></td></tr></tbody></table>




---

[Next Page](/llms-full.txt/1)

