# Welcome to WDK (/) The **Wallet Development Kit *by Tether* (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. *** ### Discover WDK Understand WDK core features and design principles Discover our philosophy and idea for the future wallets Learn foundational concepts and terminology *** ### Start Building Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Deploy WDK in lightweight environments Explore our React Native UI Kit with pre-built components *** ### Get Involved # Agent Skills (/ai/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. **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](mcp-toolkit/) when your agent supports the Model Context Protocol natively (e.g., Claude, Cursor). Use both for maximum coverage. ## 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 | All write operations require explicit human confirmation. The skill instructs agents to estimate fees before sending and includes prompt injection protection guidance. ## How It Works 1. **Install the skill** by cloning the skill repository or installing from a skill registry like [ClawHub](https://clawhub.ai/HumanRupert/tether-wallet-development-kit) 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](mcp-toolkit/)) | Via skills | Via skills | | OpenClaw support | Yes ([ClawHub skill](https://clawhub.ai/HumanRupert/tether-wallet-development-kit)) | 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** | Install from [ClawHub](openclaw) or clone to workspace. See [OpenClaw Integration](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](mcp-toolkit/) for structured tool calling | | **Any other agent** | Copy `SKILL.md` into system prompt or conversation context | ## Community Projects Community-built projects 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 Skill on ClawHub](https://clawhub.ai/HumanRupert/tether-wallet-development-kit) - Install the skill * [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? # OpenClaw (Community Skill) (/ai/openclaw) 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. [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. 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. ## Install the WDK Community Skill Install from [ClawHub](https://clawhub.ai/HumanRupert/tether-wallet-development-kit): ```bash npx clawhub install tether-wallet-development-kit ``` This installs the skill into your workspace's `skills/` directory. OpenClaw picks it up automatically on the next session. You might see a VirusTotal warning during installation. It flags the skill as suspicious because it handles crypto keys and calls external APIs. This is normal for any wallet SDK skill, nevertheless review the skill's source code on [ClawHub](https://clawhub.ai/HumanRupert/tether-wallet-development-kit) before proceeding. We plan to publish the official WDK skill to its own GitHub repository. Once that's live, you'll also be able to install via `git clone`. ## 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. 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. ## 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. OpenClaw creating a multi-chain wallet using the WDK skill *Example output from the WDK skill creating a multi-chain wallet* ## 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](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](agent-skills) - Full capabilities, how skills work, and a comparison with other agentic wallet solutions * [MCP Toolkit](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? # x402 (/ai/x402) ## 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 #### Client requests a resource A standard HTTP request. `GET`, `POST`, whatever your API expects. #### 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" }] } ``` #### 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. #### Client retries with payment header The signed payload goes in the `X-PAYMENT` header on the same request. #### 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. #### Server performs the work Inference, database query, generation, whatever the resource requires. This only happens after verification succeeds. #### 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. #### Server returns the resource `200 OK` with the result in the body and a settlement receipt in the `X-PAYMENT-RESPONSE` header. 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 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. ### 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 See the full working client example at [`x402/client.js`](https://github.com/SemanticPay/x402-usdt0-demo/blob/main/x402/client.js). ```bash npm install @tetherto/wdk-wallet-evm @x402/fetch @x402/evm ``` #### 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(); ``` #### 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); ``` #### 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); ``` Your seed phrase controls your funds. Never commit it to version control. Use environment variables or a secrets manager. ### 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`. 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. ```bash npm install @tetherto/wdk-wallet-evm @tetherto/wdk-protocol-bridge-usdt0-evm ``` #### Bridge USD₮ from Ethereum to Plasma / Stable #### 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 }); ``` #### 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"); ``` #### 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. 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](../sdk/bridge-modules/bridge-usdt0-evm/). *** ## Server: Accepting Payments (Hosted Facilitator) Your server delegates verification and settlement to a hosted facilitator. You never interact with the chain directly. **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 a facilitator or use one of their choice. See the full working server example at [`x402/server.js`](https://github.com/SemanticPay/x402-usdt0-demo/blob/main/x402/server.js). ```bash npm install @tetherto/wdk-wallet-evm @x402/express @x402/evm @x402/core express dotenv ``` #### Create the seller wallet ```javascript import WalletManagerEvm from "@tetherto/wdk-wallet-evm"; const sellerAccount = await new WalletManagerEvm(process.env.SEED_PHRASE, { provider: "https://rpc.plasma.to", }).getAccount(); const sellerAddress = await sellerAccount.getAddress(); ``` #### Create the facilitator client ```javascript import { HTTPFacilitatorClient } from "@x402/core"; const facilitatorClient = new HTTPFacilitatorClient({ url: "https://x402.semanticpay.io/", }); ``` #### 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"; const USDT0_PLASMA = "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"; 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(), ), ), ); ``` 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. #### 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. ### 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()); ``` ### 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" }, }), }); ``` Events are fire-and-forget. If the callback URL is unreachable, events are silently dropped. *** ## 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. 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). `@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. 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). ```bash npm install @semanticio/wdk-wallet-evm-x402-facilitator @tetherto/wdk-wallet-evm @x402/core @x402/evm @x402/express express dotenv ``` #### 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); ``` 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. #### 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. #### 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"; const USDT0 = process.env.USDT0_ADDRESS || "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"; 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, ), ); ``` *** ## 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](../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 # React Native Starter (Alpha) (/examples-and-starters/react-native-starter) The React Native Starter Alpha is an Expo + React Native app showing how to build a multi-chain wallet using WDK via BareKit worklets and secure secret management. This starter includes wallet creation/import flows, balances, transactions, and a modular service layer. *** **Prerequisites:** Node.js 22+, and either Xcode (iOS) or Android SDK API 29+ (Android). See the [React Native Quickstart](../start-building/react-native-quickstart#prerequisites) for details. ### Quickstart Get your React Native wallet running in minutes with these simple steps: #### Clone and Install ```bash git clone https://github.com/tetherto/wdk-starter-react-native.git && cd wdk-starter-react-native && npm install ``` #### Configure Environment ```bash cp .env.example .env ``` Get your free WDK Indexer API key [here](../tools/indexer-api/get-started) and add it to your `.env` file: ```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 ``` #### Run Your App For first-time setup, generate native project files: ```bash npx expo prebuild ``` Then run the app: ```bash npm run ios # iOS Simulator npm run android # Android Emulator ``` *** **Need detailed instructions?** Check out the complete [React Native Quickstart](../start-building/react-native-quickstart) guide for step-by-step setup, configuration, and troubleshooting. ### Features **Multi-Token & Chain Support** * **BTC**: Native SegWit transfers on Bitcoin network * **USD₮**: Gasless transactions on EVM (Ethereum, Polygon, Arbitrum), native transfers on TON and Tron * **XAU₮**: Gasless transactions on Ethereum network **Wallet Management** * **Secure Seed Generation**: Cryptographically secure entropy generation * **Seed Import**: Import existing 12-word mnemonic phrases * **Encrypted Storage**: Secure key storage via [`@tetherto/wdk-secret-manager`](https://github.com/tetherto/wdk-secret-manager) * **Multi-Account Support**: Derive multiple accounts from single seed **Asset Management** * **Real-Time Balances**: Live balance updates via [WDK Indexer](../tools/indexer-api/) * **Transaction History**: Complete transaction tracking and history via [WDK Indexer](../tools/indexer-api/) * **Price Conversion**: Real-time fiat pricing via [Pricing Provider](../tools/price-rates/) **User Experience** * **QR Code Scanner**: Scan addresses and payment requests via camera * **Send/Receive Flows**: Intuitive transfer interfaces * **Network Selection**: Choose optimal network for each transaction * **Token Selection**: Multi-token transfer support * **Activity Feed**: Real-time transaction monitoring *** ### Project Structure The starter includes a modular architecture designed for scalability and maintainability: ```text title="Project Structure" src/ ├── app/ # Expo Router screens (file-based routing) │ ├── onboarding/ # First-time user flows │ ├── wallet-setup/ # Create/import wallet screens │ ├── send/ & receive/ # Transaction flows │ ├── settings.tsx # Configuration & preferences │ └── token-details.tsx # Individual asset views ├── components/ # Reusable UI components ├── config/ # Network, asset, and chain settings ├── services/ # Business logic (pricing integration) ├── hooks/ # Custom React hooks └── utils/ # Formatting & helper functions ``` Detailed project structure can be found in the [Github Repository](https://github.com/tetherto/wdk-starter-react-native/tree/main?tab=readme-ov-file#-project-structure). *** ### Available Scripts | Script | Description | | ------------------------ | --------------------------------------------- | | `npm start` | Start Expo development server with dev client | | `npm run android` | Run on Android emulator/device | | `npm run ios` | Run on iOS simulator | | `npm run web` | Start web development server | | `npm run prebuild` | Generate native project files | | `npm run prebuild:clean` | Clean and regenerate native project files | | `npm run lint` | Run ESLint | | `npm run lint:fix` | Fix ESLint errors | | `npm run format` | Format code with Prettier | | `npm run format:check` | Check code formatting | | `npm run typecheck` | Run TypeScript type checking | *** ### Technology Stack #### Core Technologies * **Expo**: \~54.0.8 with development client * **React Native**: 0.81.4 * **React**: 19.1.0 * **TypeScript**: \~5.9.2 * **Reanimated**: \~4.1.0 * **New Architecture**: Enabled #### Build Configuration * **Android**: minSdkVersion 29 * **iOS**: Latest Xcode toolchain * **Build Properties**: Configured via `expo-build-properties` *** ### Next Steps **Customizing the UI** This starter uses components from the [WDK React Native UI Kit](../ui-kits/react-native-ui-kit/). To customize the look and feel: * [**Theming Guide**](../ui-kits/react-native-ui-kit/theming) - Deep dive into theming capabilities * [**Component Reference**](../ui-kits/react-native-ui-kit/api-reference) - Complete component documentation **Add new functionality** This starter provides a solid foundation that you can extend with additional functionality: * **Add support for other tokens** using wallet modules in the [WDK SDK](../sdk/get-started) * **Add DeFi protocols** like swaps, bridges, and lending using [protocol modules](../sdk/get-started) **Or explore documentation** * [**WDK SDK Documentation**](../sdk/get-started) - Learn about the underlying SDK * [**UI Kit Documentation**](../ui-kits/react-native-ui-kit/get-started) - Customize the interface * [**WDK Indexer**](../tools/indexer-api/) - Understand data fetching * [**Secret Manager**](../tools/secret-manager/) - Learn about secure key management *** ## Need Help? # About WDK (/overview/about) The **Wallet Development Kit *by Tether* (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 Works with Node.js, Bare runtime, mobile (React Native), and future embedded environments Pick only the modules you need; extend functionality with custom modules Clear SDK design, strong TypeScript typing, extensive docs, and ready-to-use starters Stateless and self-custodial architecture ensures keys never leave user control Transparent, community-driven, and free to adopt with no vendor lock-in Maintained and supported by Tether with strong community involvement *** ## What WDK Provides WDK combines four core components to deliver a complete wallet development solution: Unified APIs for wallet and protocol operations across multiple blockchains Reliable blockchain data access for balances, transactions, and historical data Reusable React Native components for building wallet interfaces Production-ready wallet templates and reference implementations *** ## Supported Blockchains & Protocols WDK natively supports a broad set of blockchains and standards out of the box: | Blockchain/Module | Support | | --------------------------------------------------------------- | ------- | | [Bitcoin](../sdk/wallet-modules/wallet-btc/) | ✅ | | [Ethereum & EVM](../sdk/wallet-modules/wallet-evm/) | ✅ | | [Ethereum ERC-4337](../sdk/wallet-modules/wallet-evm-erc-4337/) | ✅ | | [TON](../sdk/wallet-modules/wallet-ton/) | ✅ | | [TON Gasless](../sdk/wallet-modules/wallet-ton-gasless/) | ✅ | | [TRON](../sdk/wallet-modules/wallet-tron/) | ✅ | | [TRON Gasfree](../sdk/wallet-modules/wallet-tron-gasfree/) | ✅ | | [Solana](../sdk/wallet-modules/wallet-solana/) | ✅ | | [Spark/Lightning](../sdk/wallet-modules/wallet-spark/) | ✅ | | Protocol/Module | Support | | -------------------------------------------------------------- | ----------- | | [velora (EVM)](../sdk/swap-modules/swap-velora-evm/) | ✅ | | StonFi (TON) | In progress | | [USD₮0 Bridge (EVM)](../sdk/bridge-modules/bridge-usdt0-evm/) | ✅ | | [Aave Lending (EVM)](../sdk/lending-modules/lending-aave-evm/) | ✅ | 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](../start-building/nodejs-bare-quickstart) or dive into our [SDK documentation](../sdk/get-started). # Changelog (/overview/changelog) Stay up to date with the latest improvements, new features, and bug fixes across all WDK modules. *** ### April 22, 2026 **Fixes** * **wdk-core** ([v1.0.0-beta.8](https://github.com/tetherto/wdk/releases/tag/v1.0.0-beta.8)): Fix `WDK.getRandomSeedPhrase(wordCount?)` so client code can generate 24-word BIP-39 seed phrases instead of always receiving the default 12-word mnemonic. *** ### April 19, 2026 **Changes** * **lending-aave-evm** ([v1.0.0-beta.4](https://www.npmjs.com/package/@tetherto/wdk-protocol-lending-aave-evm/v/1.0.0-beta.4)): Expand per-operation ERC‑4337 config overrides from `paymasterToken`-only to the wallet module's paymaster-token, sponsorship-policy, and native-coin gas modes. **Fixes** * **failover-provider** ([v1.0.0-beta.2](https://www.npmjs.com/package/@tetherto/wdk-failover-provider/v/1.0.0-beta.2)): Remove unnecessary published type definitions without changing the runtime failover behavior. * **wallet-solana** ([v1.0.0-beta.7](https://www.npmjs.com/package/@tetherto/wdk-wallet-solana/v/1.0.0-beta.7)): Fix `SolanaWalletConfig.rpcUrl` typings to accept ordered `string[]` failover endpoints and align the published TypeScript definitions with the beta.6 runtime behavior. *** ### April 15, 2026 **Changes** * **wallet-solana** ([v1.0.0-beta.6](https://www.npmjs.com/package/@tetherto/wdk-wallet-solana/v/1.0.0-beta.6)): Add runtime RPC failover support for ordered `rpcUrl` lists plus `retries`, and tighten custom `TransactionMessage` and derivation-path validation for durable nonce lifetimes, fee payer matching, and hardened SLIP-0010 child paths. *** ### April 14, 2026 **What's New** * **failover-provider** ([v1.0.0-beta.1](https://github.com/tetherto/wdk-failover-provider/releases/tag/v1.0.0-beta.1)): Initial release of a generic `FailoverProvider\` that chains provider candidates and retries sync or async failures with configurable `retries` and `shouldRetryOn(error)` logic. **Changes** * **fiat-moonpay** ([v1.0.0-beta.2](https://github.com/tetherto/wdk-protocol-fiat-moonpay/releases/tag/v1.0.0-beta.2)): \[Breaking] Replace `secretKey` signing with optional backend `signUrl`, add `environment` selection for production or sandbox widget URLs, and return unsigned widget URLs when no signer is configured. *** ### April 13, 2026 **What's New** * **wdk-utils** ([v1.0.0-beta.2](https://github.com/tetherto/wdk-utils/releases/tag/v1.0.0-beta.2)): Add EIP-681 request parsing utilities for transfer deeplinks, including request detection and structured parse results. * **wdk-core** ([v1.0.0-beta.7](https://github.com/tetherto/wdk/releases/tag/v1.0.0-beta.7)): Added `dispose(blockchains?)`, so you can dispose one or more registered wallets without tearing down every wallet in the WDK instance. * **pear-wrk-wdk** ([v1.0.0-beta.8](../tools/pear-wrk-wdk)): Adds `resetWdkWallets({ config })` so custom Bare hosts can selectively dispose and re-register wallet modules from a new `networks` config. **Changes** * **wallet-spark** ([v1.0.0-beta.13](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.13)): Refresh `@buildonspark/bare` and `@buildonspark/spark-sdk` dependencies. * **wallet-spark** ([v1.0.0-beta.14](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.14)): Add SparkScan-backed balance polling for `getBalance()`. * **wallet-spark** ([v1.0.0-beta.15](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.15)): Refresh `@buildonspark/bare`, `@buildonspark/spark-sdk`, and `bare-node-runtime` dependencies. * **wallet-spark** ([v1.0.0-beta.16](https://github.com/tetherto/wdk-wallet-spark/releases/tag/v1.0.0-beta.16)): Add `syncAndRetry` and `syncWalletBalance()` for retrying failed `sendTransaction()` and `payLightningInvoice()` calls once after syncing wallet state. **Fixes** * **worklet-bundler** ([v1.0.0-beta.3](https://github.com/tetherto/wdk-worklet-bundler/releases/tag/v1.0.0-beta.3)): Generated worklet entrypoints now suspend and resume both HTTP and HTTPS global agents with Bare thread lifecycle events. * **wallet-btc** ([v1.0.0-beta.8](https://github.com/tetherto/wdk-wallet-btc/releases/tag/v1.0.0-beta.8)): `getBalance()` now includes unconfirmed funds when present, and `sendTransaction()` accepts an optional `timeoutMs` to keep polling after broadcast until spent inputs disappear from unspent outputs. * **wallet-evm** ([v1.0.0-beta.11](https://github.com/tetherto/wdk-wallet-evm/releases/tag/v1.0.0-beta.11)): Pin string-backed RPC providers to a static network during EVM account setup. * **wallet-evm-erc-4337** ([v1.0.0-beta.6](https://github.com/tetherto/wdk-wallet-evm-erc-4337/releases/tag/v1.0.0-beta.6)): Reuse the internal EVM read-only helper during ERC-4337 method calls instead of recreating it on each call. *** ### 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`](../sdk/wallet-modules/wallet-spark/api-reference) gained [`getTransfers()`](../sdk/wallet-modules/wallet-spark/api-reference), [`getUnusedDepositAddresses()`](../sdk/wallet-modules/wallet-spark/api-reference) (paginated return type), [`getStaticDepositAddresses()`](../sdk/wallet-modules/wallet-spark/api-reference), [`getUtxosForDepositAddress()`](../sdk/wallet-modules/wallet-spark/api-reference), and [`getSparkInvoices()`](../sdk/wallet-modules/wallet-spark/api-reference) (new parameter type). Removed `sparkScanApiKey` config option and `SparkTransactionReceipt` type after dropping the `@sparkscan/api-node-sdk-client` dependency. [`getTransactionReceipt()`](../sdk/wallet-modules/wallet-spark/api-reference) now returns `SparkTransfer` instead. Added [`getAccountByPath()`](../sdk/wallet-modules/wallet-spark/api-reference) to [`WalletManagerSpark`](../sdk/wallet-modules/wallet-spark/api-reference). 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](../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](../tools/react-native-core/api-reference) covering `WdkAppProvider`, `useWdkApp`, `useWalletManager`, `useAccount`, `useBalance`, and more. Updated [React Native Quickstart](../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`](../sdk/wallet-modules/wallet-btc/api-reference) 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`) * **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`](../tools/create-wdk-module) CLI scaffolding tool. Updated [Community Modules](../sdk/community-modules/) and [SDK Get Started](../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)`](../sdk/wallet-modules/wallet-evm/api-reference) to [`WalletAccountReadOnlyEvm`](../sdk/wallet-modules/wallet-evm/api-reference), also available on [`WalletAccountEvm`](../sdk/wallet-modules/wallet-evm/api-reference) 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)`](../sdk/wallet-modules/wallet-evm-erc-4337/api-reference) and [`verifyTypedData(typedData, signature)`](../sdk/wallet-modules/wallet-evm-erc-4337/api-reference), plus multicall token balance method [`getTokenBalances(tokenAddresses)`](../sdk/wallet-modules/wallet-evm-erc-4337/api-reference). *** ### 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](../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](../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](../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()`](../sdk/wallet-modules/wallet-spark/api-reference) method to [`WalletAccountReadOnlySpark`](../sdk/wallet-modules/wallet-spark/api-reference) 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](../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](../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)`](../sdk/wallet-modules/wallet-evm/api-reference) method to [`WalletAccountEvm`](../sdk/wallet-modules/wallet-evm/api-reference) for signing structured data * Added [`verifyTypedData(typedData, signature)`](../sdk/wallet-modules/wallet-evm/api-reference) method to [`WalletAccountEvm`](../sdk/wallet-modules/wallet-evm/api-reference) and [`WalletAccountReadOnlyEvm`](../sdk/wallet-modules/wallet-evm/api-reference) 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](../sdk/wallet-modules/wallet-evm-erc-4337/configuration#gas-payment-mode-flags) and [Native Coins](../sdk/wallet-modules/wallet-evm-erc-4337/configuration#gas-payment-mode-flags), alongside the existing Paymaster Token mode * Added per-call [config override](../sdk/wallet-modules/wallet-evm-erc-4337/api-reference) parameter to `sendTransaction`, `transfer`, `quoteSendTransaction`, and `quoteTransfer` * Added [`getUserOperationReceipt(hash)`](../sdk/wallet-modules/wallet-evm-erc-4337/api-reference) method for retrieving ERC-4337 UserOperation receipts * Added [`ConfigurationError`](../sdk/wallet-modules/wallet-evm-erc-4337/api-reference) error type for invalid configuration validation *** ### February 10, 2026 **What's New** * **[Build with AI](../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](../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`](../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`](../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`](../sdk/wallet-modules/wallet-btc/api-reference) * Added Pluggable Transport classes: [`ElectrumTcp`](../sdk/wallet-modules/wallet-btc/api-reference), [`ElectrumTls`](../sdk/wallet-modules/wallet-btc/api-reference), [`ElectrumSsl`](../sdk/wallet-modules/wallet-btc/api-reference), [`ElectrumWs`](../sdk/wallet-modules/wallet-btc/api-reference) * **wallet-evm**: Added `verify` method to [`WalletAccountReadOnlyEvm`](../sdk/wallet-modules/wallet-evm/api-reference) ([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`](../sdk/wallet-modules/wallet-solana/api-reference) ([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`](../sdk/wallet-modules/wallet-ton/api-reference) ([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`](../sdk/wallet-modules/wallet-tron/api-reference) ([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`](../sdk/wallet-modules/wallet-spark/api-reference) ([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](../sdk/core-module/guides/getting-started) covering: * [Getting Started](../sdk/core-module/guides/getting-started) - Installation and instantiation * [Wallet Registration](../sdk/core-module/guides/wallet-registration) - Registering wallet modules for different blockchains * [Account Management](../sdk/core-module/guides/account-management) - Working with accounts and addresses * [Transactions](../sdk/core-module/guides/transactions) - Sending native tokens * [Protocol Integration](../sdk/core-module/guides/protocol-integration) - Using swaps, bridges, and lending protocols * [Middleware](../sdk/core-module/guides/middleware) - Configuring logging and failover protection * [Error Handling](../sdk/core-module/guides/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](../sdk/fiat-modules/fiat-moonpay/) for on-ramp and off-ramp functionality * Added [Community Modules](../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](../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](../tools/pear-wrk-wdk)) **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 # Partner with WDK (/overview/partner-program) 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--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. [Become a Project Partner](https://forms.monday.com/forms/6d484c4b34949e3a238988c47bf0a1b6?r=euc1) *** ## 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. [Become a Technology Partner](https://tether.to/en/partner-with-us/) *** ## 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. **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. [Become a Consulting & Implementation Partner](https://tether.to/en/partner-with-us/) # Showcase (/overview/showcase) 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. Looking for community-built WDK modules you can install and use in your project? Check out the [Community Modules](../sdk/community-modules/) page instead. ## 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. wdk-starter-browser-extension demo *** ### 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/rezerov)) **Repository:** [github.com/rezerov/wdk-mcp](https://github.com/rezerov/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. Share it with us through the community form or the showcase channel below. # Get Support (/overview/support) We're here to help you succeed with WDK. Don't hesitate to reach out. # Our Vision (/overview/vision) 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 WDK enables a future with millions of wallets built on top of it, each tailored to specific needs and use cases WDK enables trillions of AI agents to have their own wallet, managing resources autonomously in the digital economy Any developer, company, organization, or country can build their own white-label wallet and manage their assets independently From IoT devices to autonomous vehicles, every connected device can have its own wallet and financial identity *** ## 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](../start-building/nodejs-bare-quickstart) or dive into our [SDK documentation](../sdk/get-started). # Build with AI (/start-building/build-with-ai) 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)** - Native support for the `.su` docs environment is still rolling out. 2. **[Connect via Markdown](#connect-wdk-docs-via-markdown)** - Works with any AI tool. Feed documentation directly into the context window. **Want to give AI agents wallet access?** The [MCP Toolkit](../ai/mcp-toolkit/) creates an MCP server that exposes WDK wallets as tools - letting AI agents check balances, send transactions, swap tokens, and more. *** ## Connect WDK Docs via MCP Server The dedicated MCP endpoint for `docs.wdk.tether.su` is still being finalized. If you need environment-matched context on this preview site today, use the Markdown endpoints below instead. The `.su` docs environment does not publish its own MCP server yet. Use `/llms.txt`, `/llms-full.txt`, or the raw `.md` page URLs from this environment until the endpoint is available. **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. ### 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-\` - 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-\-\-\` - 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: [docs.wdk.tether.su](/) - 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.wdk.tether.su/llms.txt](/llms.txt) | Index of all page URLs and titles | | Full docs | [docs.wdk.tether.su/llms-full.txt](/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 multi-chain 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 multi-chain 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](nodejs-bare-quickstart) or [React Native Quickstart](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. # Node.js & Bare Runtime Quickstart (/start-building/nodejs-bare-quickstart) ## 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 **Want to build faster?** Connect your AI coding assistant to WDK docs for context-aware help. [Learn how →](build-with-ai) *** ## Prerequisites Before we start, make sure you have: | Tool | Version | Why You Need It | | --------------- | ------- | ---------------------- | | **Node.js** | 20+ | To run JavaScript code | | **npm** | Latest | To install packages | | **Code Editor** | Any | To write code | | 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` You can try all features without real funds required. You can use the Pimlico or Candide faucets to get some Sepolia USD₮. [Get mock/test USD₮ on Pimlico](https://dashboard.pimlico.io/test-erc20-faucet) [Get mock/test USD₮ on Candide](https://dashboard.candide.dev/faucet) See the [configuration](../sdk/wallet-modules/wallet-evm-erc-4337/configuration) for quick setup and Sepolia testnet configuration. *** ## 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 ``` Learn more about WDK modules: * [**@tetherto/wdk**](../sdk/core-module/) - The main SDK module * [**@tetherto/wdk-wallet-evm**](../sdk/wallet-modules/wallet-evm/) - Ethereum and EVM-compatible chains support * [**@tetherto/wdk-wallet-tron**](../sdk/wallet-modules/wallet-tron/) - TRON blockchain support * [**@tetherto/wdk-wallet-btc**](../sdk/wallet-modules/wallet-btc/) - Bitcoin blockchain support *** ## Step 2: Create Your First Wallet Create a file called `app.js`: ```javascript title="app.js" 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) } ``` Now, add the following code to generate a seed phrase: ```typescript title="app.js" try { const seedPhrase = WDK.getRandomSeedPhrase() console.log('Generated seed phrase:', seedPhrase) } catch (error) { console.error('Application error:', error.message) process.exit(1) } ``` Now, let's register wallets for different blockchains: ```typescript title="app.js" // 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') ``` To learn more about configuring the wallet modules: * [Configuring @tetherto/wdk-wallet-evm](../sdk/wallet-modules/wallet-evm/configuration) * [Configuring @tetherto/wdk-wallet-tron](../sdk/wallet-modules/wallet-tron/configuration) * [Configuring @tetherto/wdk-wallet-btc](../sdk/wallet-modules/wallet-btc/configuration) *** ## Step 3: Check Balances To check balances, we first need to get accounts and addresses. Let's get accounts and addresses for all blockchains: ```typescript title="app.js" // 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}`) } ``` 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: ```javascript title="app.js" 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) } ``` *** ## Step 4: Run Your App Execute your app: ```bash node app.js ``` ```bash bare app.js ``` 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 ``` ```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' }) ``` ### Estimate Transaction Costs ```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`) } } ``` ### **Send Transactions** ```typescript const result = await ethAccount.sendTransaction({ to: '0x742d35Cc6634C05...a3b8D9C5c8b7b6e5f6e5', value: 1000000000000000000n // 1 ETH }) console.log('Transaction hash:', result.hash) ``` ### **Use DeFi Protocols** ```bash npm install @tetherto/wdk-protocol-swap-velora-evm ``` ```typescript import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' wdk.registerProtocol('ethereum', 'swap-velora-evm', VeloraProtocolEvm, { provider: 'https://eth.drpc.org' }) ``` *** ## 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 Help? # React Native Quickstart (/start-building/react-native-quickstart) ## 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 You can try all features without real funds required. You can use the Pimlico or Candide faucets to get some Sepolia USD₮. * [Get mock/test USD₮ on Pimlico](https://dashboard.pimlico.io/test-erc20-faucet) * [Get mock/test USD₮ on Candide](https://dashboard.candide.dev/faucet) See the [ERC-4337 configuration](../sdk/wallet-modules/wallet-evm-erc-4337/configuration) for quick setup and Sepolia testnet configuration. **Want to build faster?** Connect your AI coding assistant to WDK docs for context-aware help. [Learn how →](build-with-ai) ## 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 | *** ## Quickstart Paths You have 2 options for using WDK in a React Native. Choose your preferred starting point: Get up and running in 3 minutes with our pre-configured starter template. [**→ Jump to Starter Template Setup**](#option-1-starter-template) Integrate WDK into your existing React Native or Expo app. [**→ Jump to Library Integration**](#option-2-add-to-existing-app) *** ## 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 ``` **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](../tools/indexer-api/get-started). ### Step 4: Run Your App ```bash npm run ios ``` ```bash npm run android ``` **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`. 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 ``` Update `android/build.gradle`: ```groovy buildscript { ext { minSdkVersion = 29 // ... other config } } ``` ### Step 3: Configure the Bundle The WDK engine runs inside a Bare worklet. You need to provide a bundle - choose one of two approaches: 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' ``` **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). 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' ``` 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. ### 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 }, } ``` 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](../sdk/core-module/configuration). ### Step 5: Add WdkAppProvider Wrap your app with `WdkAppProvider` to enable wallet functionality throughout your app. 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 ( ) } ``` 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 ( ) } ``` ### 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 Loading... case 'NO_WALLET': return ) } ``` *** ## Custom Themes ### Brand Themes Apply your brand colors and fonts using `createThemeFromBrand`: ```tsx title="Brand Theme Creation" import { ThemeProvider, createThemeFromBrand } from '@tetherto/wdk-uikit-react-native' const brandTheme = createThemeFromBrand({ primaryColor: '#007AFF', secondaryColor: '#FF3B30', fontFamily: { regular: 'Inter-Regular', bold: 'Inter-Bold', }, }, 'light') {/* Your branded app */} ``` **BrandConfig Interface** ```typescript title="BrandConfig Type" type BrandConfig = { primaryColor: string secondaryColor?: string fontFamily?: { regular?: string medium?: string semiBold?: string bold?: string } } ``` ### Custom Theme Create a completely custom theme with full control over all design tokens: ```tsx title="Custom Theme" import { ThemeProvider } from '@tetherto/wdk-uikit-react-native' const myLightTheme = { mode: 'light' as const, colors: { primary: '#007AFF', primaryLight: '#4DA6FF', primaryDark: '#0056CC', onPrimary: '#FFFFFF', secondary: '#FF3B30', secondaryLight: '#FF6B60', secondaryDark: '#CC2F26', background: '#FFFFFF', surface: '#F9FAFB', surfaceVariant: '#F3F4F6', surfaceElevated: '#E5E7EB', text: '#111827', textSecondary: '#6B7280', textDisabled: '#9CA3AF', border: '#E5E7EB', borderLight: '#F3F4F6', error: '#EF4444', warning: '#F59E0B', success: '#10B981', info: '#3B82F6', }, typography: { fontFamily: { regular: 'System', medium: 'System', semiBold: 'System', bold: 'System' }, fontSize: { xs: 10, sm: 12, base: 14, md: 16, lg: 18, xl: 20, xxl: 24, xxxl: 30 }, fontWeight: { regular: '400', medium: '500', semiBold: '600', bold: '700' }, }, spacing: { xs: 4, sm: 8, base: 12, md: 16, lg: 24, xl: 32, xxl: 48, xxxl: 64 }, borderRadius: { none: 0, sm: 4, md: 8, lg: 16, xl: 24, xxl: 32, full: 9999 }, } {/* Your app */} ``` **Theme Interface** ```typescript title="Theme Type" type Theme = { mode: 'light' | 'dark' | 'auto' colors: ColorPalette typography: Typography spacing: Spacing borderRadius: BorderRadius componentVariants?: ComponentVariant componentOverrides?: ComponentOverrides } ``` *** ## Component Customization You can customize the components with fine-grained control. Fine-grained style overrides for specific component parts: ```tsx title="Component Overrides" {/* Your app */} ``` Set default visual variants per component: ```tsx title="Component Variants" const customTheme = { ...lightTheme, componentVariants: { 'AmountInput.default': { /* variant styles */ }, 'TransactionItem.compact': { /* variant styles */ } } } ``` *** ## Using Theme Anywhere Access theme values anywhere in your components: **useTheme Hook** ```tsx title="useTheme Hook" import { useTheme } from '@tetherto/wdk-uikit-react-native' function MyComponent() { const { theme } = useTheme() return ( Hello World ) } ``` *** ## Theme Structure ### Color Palette The theming system uses semantic naming for colors: | Token | Purpose | | ------------------------ | -------------------------------- | | `colors.primary` | Primary brand color | | `colors.primaryLight` | Light variant of primary | | `colors.primaryDark` | Dark variant of primary | | `colors.onPrimary` | Text color on primary background | | `colors.secondary` | Secondary brand color | | `colors.secondaryLight` | Light variant of secondary | | `colors.secondaryDark` | Dark variant of secondary | | `colors.background` | Main background color | | `colors.surface` | Card/container background | | `colors.surfaceVariant` | Alternative surface color | | `colors.surfaceElevated` | Elevated surface color | | `colors.text` | Primary text color | | `colors.textSecondary` | Secondary text color | | `colors.textDisabled` | Disabled text color | | `colors.border` | Border color | | `colors.borderLight` | Light border color | | `colors.error` | Error state color | | `colors.warning` | Warning state color | | `colors.success` | Success state color | | `colors.info` | Info state color | ### Typography | Token | Purpose | | -------------------------------- | ----------------------------- | | `typography.fontFamily.regular` | Regular font family | | `typography.fontFamily.medium` | Medium font family | | `typography.fontFamily.semiBold` | Semi-bold font family | | `typography.fontFamily.bold` | Bold font family | | `typography.fontSize.xs` | Extra small font size (10px) | | `typography.fontSize.sm` | Small font size (12px) | | `typography.fontSize.base` | Base font size (14px) | | `typography.fontSize.md` | Medium font size (16px) | | `typography.fontSize.lg` | Large font size (18px) | | `typography.fontSize.xl` | Extra large font size (20px) | | `typography.fontSize.xxl` | 2X large font size (24px) | | `typography.fontSize.xxxl` | 3X large font size (30px) | | `typography.fontWeight.regular` | Regular font weight ('400') | | `typography.fontWeight.medium` | Medium font weight ('500') | | `typography.fontWeight.semiBold` | Semi-bold font weight ('600') | | `typography.fontWeight.bold` | Bold font weight ('700') | ### Spacing | Token | Purpose | | -------------- | -------------------------- | | `spacing.xs` | Extra small spacing (4px) | | `spacing.sm` | Small spacing (8px) | | `spacing.base` | Base spacing (12px) | | `spacing.md` | Medium spacing (16px) | | `spacing.lg` | Large spacing (24px) | | `spacing.xl` | Extra large spacing (32px) | | `spacing.xxl` | 2X large spacing (48px) | | `spacing.xxxl` | 3X large spacing (64px) | ### Border Radius | Token | Purpose | | ------------------- | -------------------------------- | | `borderRadius.none` | No border radius (0px) | | `borderRadius.sm` | Small border radius (4px) | | `borderRadius.md` | Medium border radius (8px) | | `borderRadius.lg` | Large border radius (16px) | | `borderRadius.xl` | Extra large border radius (24px) | | `borderRadius.xxl` | 2X large border radius (32px) | | `borderRadius.full` | Full border radius (9999px) | *** ## Advanced Usage **Dynamic Theme Updates** Update themes dynamically at runtime: ```tsx title="Dynamic Theme Updates" function Settings() { const { setBrandConfig, setComponentOverrides } = useTheme() const updateBrand = () => { setBrandConfig({ primaryColor: '#FF6501', }) } const customizeTransactions = () => { setComponentOverrides({ TransactionItem: { container: { backgroundColor: 'rgba(255, 101, 1, 0.1)', }, }, }) } return ( <> ) } ``` ## Next Steps * [Get Started](get-started) - Quick start guide for the UI Kit * [Components List](api-reference) - Complete API Reference for all components * [React Native Quickstart](../../start-building/react-native-quickstart) - See theming in action *** ## Need Help? # Bridge Modules Overview (/sdk/bridge-modules) The Wallet Development Kit (WDK) provides a set of modules that support bridging between different blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations. ## Bridge Protocol Modules Cross-chain bridge functionality for token transfers between blockchains: | Module | Route | Status | Documentation | | ------------------------------------------------------------------------------------------------------ | ------------------- | ------- | ------------------------------------ | | [`@tetherto/wdk-protocol-bridge-usdt0-evm`](https://github.com/tetherto/wdk-protocol-bridge-usdt0-evm) | EVM → EVM + Non-EVM | ✅ Ready | [Documentation](./bridge-usdt0-evm/) | {/* | [`@tetherto/wdk-protocol-bridge-usdt0-ton`](https://github.com/tetherto/wdk-protocol-bridge-usdt0-ton) | TON ↔ EVM | In progress | [Documentation](./bridge-usdt0-ton/) | */} ## Next steps To get started with WDK modules, follow these steps: 1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart) 2. Choose the modules that best fit your needs from the tables above 3. Check specific documentation for modules you wish to use You can also: * Learn about key concepts like [Account Abstraction](../../resources/concepts#account-abstraction) and other important definitions * Use one of our ready-to-use examples to be production ready # Community Modules (/sdk/community-modules) The WDK ecosystem is enriched by modules developed by our community. These modules extend WDK's capabilities to support additional blockchains, protocols, and use cases. Community modules are developed and maintained independently by third-party contributors. Tether and the WDK Team do not endorse or assume responsibility for their code, security, or maintenance. Use your own judgment and proceed at your own risk. ## Available Community Modules | Module | Type | Description | Author | | ------------------------------------------------------------------------------ | ------------- | ---------------------------------------------------- | ------------------------------------------ | | [@utexo/wdk-wallet-rgb](https://github.com/UTEXO-Protocol/wdk-wallet-rgb) | Wallet Module | Wallet module for RGB, Bitcoin-based smart contracts | [UTEXO](https://github.com/UTEXO-Protocol) | | [@base58-io/wdk-wallet-cosmos](https://github.com/base58-io/wdk-wallet-cosmos) | Wallet Module | Wallet module for Cosmos-compatible blockchains | [Base58](https://base58.io/) | *** ## Create Your Own Module Want to extend WDK with your own custom module? Use the `create-wdk-module` CLI to scaffold a fully configured project in seconds: ```bash title="Scaffold a new module" npx @tetherto/create-wdk-module@latest ``` The CLI generates source files, tests, TypeScript type definitions, and CI workflows for all five module types (wallet, swap, bridge, lending, fiat). See the [Create WDK Module documentation](../../tools/create-wdk-module) for the full guide, CLI options, and generated project structure. You can also: 1. **Study existing modules** - Review the source code of official WDK modules on [GitHub](https://github.com/orgs/tetherto/repositories?q=wdk) to understand the patterns and interfaces 2. **Join the community** - Connect with other developers on our [Discord](https://discord.gg/arYXDhHB2w) to discuss your ideas 3. **Open an issue** - Have questions? Open an issue on the relevant repository *** ## Submit Your Module If you've built a WDK module, we'd love to feature it here! **To submit your module:** 1. Ensure your module follows WDK interface conventions 2. Include comprehensive documentation and a clear README 3. Make the repository publicly accessible 4. Submit through our [Community Form](https://forms.gle/wmNwc5epxaa85u8a9) or share on our **#wdk-showcase** Discord channel Your module may be featured in our documentation and community showcases. *** ## Guidelines for Community Modules Community modules should: * Implement the standard WDK module interface * Include TypeScript type definitions * Provide clear installation and usage instructions * Be open source or publicly accessible * Include appropriate tests and examples # WDK Core API Reference (/sdk/core-module/api-reference) # API Reference ## 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 ```javascript title="Constructor" new WDK(seed) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes **Example:** ```javascript title="Initialize WDK" 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) ``` ### 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\` | If wallet not registered | | `getAccountByPath(blockchain, path)` | Returns a wallet account for a blockchain and derivation path | `Promise\` | If wallet not registered | | `getFeeRates()` | Returns current fee rates | `Promise\` | - | | `dispose(blockchains?)` | Disposes all registered wallets, or only the named blockchains, and clears their 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:** ```javascript title="Register Wallets" import WDK from '@tetherto/wdk' import WalletManagerEvm from '@tetherto/wdk-wallet-evm' import WalletManagerTon from '@tetherto/wdk-wallet-ton' const wdk = new WDK(seedPhrase) // Register EVM wallet wdk.registerWallet('ethereum', WalletManagerEvm, { provider: 'https://eth.drpc.org' }) // Register TON wallet wdk.registerWallet('ton', WalletManagerTon, { tonApiKey: 'YOUR_TON_API_KEY', tonApiEndpoint: 'https://tonapi.io' }) // Method chaining const wdk2 = new WDK(seedPhrase) .registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig) .registerWallet('ton', WalletManagerTon, tonWalletConfig) ``` ##### `registerProtocol(blockchain, label, protocol, config)` Registers a protocol globally for all accounts of a specific blockchain. **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:** ```javascript title="Register Protocols" 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) ``` ##### `registerMiddleware(blockchain, middleware)` Registers middleware for account decoration and enhanced functionality. **Parameters:** * `blockchain` (string): The name of the blockchain * `middleware` (`\(account: A) =\> Promise\`): Middleware function called when deriving accounts **Returns:** `WDK` - The wdk manager instance (supports method chaining) **Example:** ```javascript title="Register Middleware" // 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()) }) ``` ##### `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\` - The wallet account with protocol support **Throws:** Error if no wallet has been registered for the given blockchain **Example:** ```javascript title="Get Account" // Get first account (index 0) const account = await wdk.getAccount('ethereum', 0) // Get second account (index 1) const account1 = await wdk.getAccount('ethereum', 1) // Default index (0) const defaultAccount = await wdk.getAccount('ethereum') // This will throw an error if no wallet registered for 'tron' try { const tronAccount = await wdk.getAccount('tron', 0) } catch (error) { console.error('No wallet registered for tron blockchain') } ``` ##### `getAccountByPath(blockchain, path)` Returns a wallet account for a specific blockchain and BIP-44 derivation path. **Parameters:** * `blockchain` (string): The name of the blockchain (e.g., "ethereum") * `path` (string): The derivation path (e.g., "0'/0/0") **Returns:** `Promise\` - The wallet account with protocol support **Throws:** Error if no wallet has been registered for the given blockchain **Example:** ```javascript title="Get Account by Path" // Full path: m/44'/60'/0'/0/1 const account = await wdk.getAccountByPath('ethereum', "0'/0/1") // Different derivation path const customAccount = await wdk.getAccountByPath('ton', "1'/2/3") ``` ##### `getFeeRates()` Returns current fee rates for all registered blockchains. **Returns:** `Promise\` - The fee rates in base units **Example:** ```javascript title="Get Fee Rates" const feeRates = await wdk.getFeeRates() console.log('Fee rates:', feeRates) ``` ##### `dispose(blockchains?)` Disposes all registered wallets when called without arguments, or only the wallets for the named blockchains when you pass a string array. **Parameters:** * `blockchains` (string\[], optional): The blockchain identifiers to dispose. Omit this parameter to dispose every registered wallet. **Example:** ```javascript title="Dispose WDK" // Clean up all sensitive data wdk.dispose() // Dispose only one registered wallet wdk.dispose(['ethereum']) ``` ### Static Methods | Method | Description | Returns | | --------------------------------- | ---------------------------------------------------- | --------- | | `getRandomSeedPhrase(wordCount?)` | Returns a random BIP-39 seed phrase (12 or 24 words) | `string` | | `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:** ```javascript title="Generate Random Seed" // 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" ``` ##### `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:** ```javascript title="Validate Seed Phrase" 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 ``` ## IWalletAccountWithProtocols Extended wallet account interface that supports protocol registration and access. Extends `IWalletAccount` from `@tetherto/wdk-wallet`. ### Methods | Method | Description | Returns | Throws | | ------------------------------------------- | ------------------------------------------------- | ----------------------------- | --------------------- | | `registerProtocol(label, protocol, config)` | Registers a protocol for this specific account | `IWalletAccountWithProtocols` | - | | `getSwapProtocol(label)` | Returns the swap protocol with the given label | `ISwapProtocol` | If protocol not found | | `getBridgeProtocol(label)` | Returns the bridge protocol with the given label | `IBridgeProtocol` | If protocol not found | | `getLendingProtocol(label)` | Returns the lending protocol with the given label | `ILendingProtocol` | If protocol not found | ##### `registerProtocol(label, protocol, config)` Registers a new protocol for this specific account. **Type Parameters:** * `P`: `typeof SwapProtocol | typeof BridgeProtocol | typeof LendingProtocol` - A class that extends one of the `@tetherto/wdk-wallet/protocol`'s classes **Parameters:** * `label` (string): Unique label for the protocol (must be unique per account and protocol type) * `protocol` (P): The protocol class * `config` (`ConstructorParameters

[1]`): The protocol configuration **Returns:** `IWalletAccountWithProtocols` - The account instance (supports method chaining) **Example:** ```javascript title="Register Protocol for Account" import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' const account = await wdk.getAccount('ethereum', 0) // Register protocol for this specific account account.registerProtocol('usdt0', Usdt0ProtocolEvm, { apiKey: 'YOUR_API_KEY' }) // Method chaining const account2 = await wdk.getAccount('ethereum', 1) .registerProtocol('usdt0', Usdt0ProtocolEvm, usdt0ProtocolConfig) ``` ##### `getSwapProtocol(label)` Returns the swap protocol with the given label. **Parameters:** * `label` (string): The protocol label **Returns:** `ISwapProtocol` - The swap protocol instance **Throws:** Error if no swap protocol with the given label has been registered **Example:** ```javascript title="Get Swap Protocol" import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' // Register swap protocol account.registerProtocol('velora', veloraProtocolEvm, veloraProtocolConfig) // Get swap protocol const velora = account.getSwapProtocol('velora') // Use the protocol const swapResult = await velora.swap({ tokenIn: '0x...', tokenOut: '0x...', tokenInAmount: 1000000n }) // This will throw an error // try { // const uniswap = account.getSwapProtocol('uniswap') // } catch (error) { // console.error('No swap protocol with label "uniswap" found') // } ``` ##### `getBridgeProtocol(label)` Returns the bridge protocol with the given label. **Parameters:** * `label` (string): The protocol label **Returns:** `IBridgeProtocol` - The bridge protocol instance **Throws:** Error if no bridge protocol with the given label has been registered **Example:** ```javascript title="Get Bridge Protocol" import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' // Register bridge protocol account.registerProtocol('usdt0', Usdt0ProtocolEvm) // Get bridge protocol const usdt0 = account.getBridgeProtocol('usdt0') // Use the protocol const bridgeResult = await usdt0.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000n }) ``` ##### `getLendingProtocol(label)` Returns the lending protocol with the given label. **Parameters:** * `label` (string): The protocol label **Returns:** `ILendingProtocol` - The lending protocol instance **Throws:** Error if no lending protocol with the given label has been registered **Example:** ```javascript title="Get Lending Protocol" import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm' // Register lending protocol account.registerProtocol('aave', AaveProtocolEvm, aaveProtocolConfig) // Get lending protocol const aave = account.getLendingProtocol('aave') // Use the protocol const supplyResult = await aave.supply({ token: '0x...', amount: 1000000n }) ``` ## Complete Example ```javascript title="Complete WDK Flow" import WDK from '@tetherto/wdk' import WalletManagerEvm from '@tetherto/wdk-wallet-evm' import WalletManagerTon from '@tetherto/wdk-wallet-ton' import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' // Initialize WDK Manager const wdk = new WDK(seedPhrase) .registerWallet('ethereum', WalletManagerEvm, { provider: 'https://eth.drpc.org' }) .registerWallet('ton', WalletManagerTon, { tonApiKey: 'YOUR_TON_API_KEY', tonApiEndpoint: 'https://tonapi.io' }) .registerProtocol('ethereum', 'velora', veloraProtocolEvm, { apiKey: 'YOUR_velora_API_KEY' }) .registerProtocol('ethereum', 'usdt0', Usdt0ProtocolEvm) // Get accounts const accountEth = await wdk.getAccount('ethereum', 3) const accountTon = await wdk.getAccountByPath('ton', "1'/2/3") // Use wallet account methods const { hash, fee } = await accountEth.sendTransaction({ to: '0x...', value: 1000000000000000000n // 1 ETH }) // Use protocols const velora = accountEth.getSwapProtocol('velora') const swapResult = await velora.swap(swapOptions) const usdt0 = accountEth.getBridgeProtocol('usdt0') const bridgeResult = await usdt0.bridge(bridgeOptions) // Clean up wdk.dispose() ``` ## Types ### FeeRates ```typescript title="Type: FeeRates" interface FeeRates { [blockchain: string]: { normal: number; fast: number; }; } ``` ### Middleware Function ```typescript title="Type: MiddlewareFunction" type MiddlewareFunction = ( account: A ) => Promise; ``` ### Protocol Types ```typescript title="Types: Protocol Interfaces" // Swap Protocol interface ISwapProtocol { swap(options: SwapOptions): Promise; } // Bridge Protocol interface IBridgeProtocol { bridge(options: BridgeOptions): Promise; } // Lending Protocol interface ILendingProtocol { supply(options: LendingOptions): Promise; withdraw(options: LendingOptions): Promise; borrow(options: LendingOptions): Promise; repay(options: LendingOptions): Promise; } ``` *** ## Next Steps Get started with WDK's configuration Get started with WDK's Usage Explore blockchain-specific wallet modules Cross-chain USD₮0 bridges *** ### Need Help? # WDK Core Configuration (/sdk/core-module/configuration) # Configuration ## WDK Manager Configuration ```javascript title="Create WDK Instance" import WDK from '@tetherto/wdk' const wdk = new WDK(seedPhrase) ``` The WDK Manager itself only requires a seed phrase for initialization. Configuration is done through the registration of wallets and protocols. ## Wallet Registration Configuration ```javascript title="Register WDK Wallet" import WDK from '@tetherto/wdk' import WalletManagerEvm from '@tetherto/wdk-wallet-evm' import WalletManagerTon from '@tetherto/wdk-wallet-ton' const wdk = new WDK(seedPhrase) .registerWallet('ethereum', WalletManagerEvm, { provider: 'https://eth.drpc.org' }) .registerWallet('ton', WalletManagerTon, { tonApiKey: 'YOUR_TON_API_KEY', tonApiEndpoint: 'https://tonapi.io' }) ``` ## Protocol Registration Configuration ```javascript title="Register WDK Protocol" import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' const wdk = new WDK(seedPhrase) .registerProtocol('ethereum', 'velora', veloraProtocolEvm, { apiKey: 'YOUR_velora_API_KEY' }) ``` ## Configuration Options ### Wallet Configuration Each wallet manager requires its own configuration object when registered. The configuration depends on the specific wallet module being used. #### EVM Wallet Configuration ```javascript title="Ethereum WDK Wallet Configuration" const ethereumWalletConfig = { provider: 'https://eth.drpc.org', // RPC endpoint // Additional EVM-specific configuration options } wdk.registerWallet('ethereum', WalletManagerEvm, ethereumWalletConfig) ``` #### TON Wallet Configuration ```javascript title="TON WDK Wallet Configuration" const tonWalletConfig = { tonClient: { secretKey: 'YOUR_TON_API_KEY', url: 'https://toncenter.com/api/v2/jsonRPC' } } wdk.registerWallet('ton', WalletManagerTon, tonWalletConfig) ``` ### Protocol Configuration Protocols also require their own configuration objects when registered. #### Swap Protocol Configuration ```javascript title="Swap WDK Protocol Configuration" const veloraProtocolConfig = { apiKey: 'YOUR_velora_API_KEY', baseUrl: 'https://apiv5.velora.io' } wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, veloraProtocolConfig) ``` ### Middleware Configuration Middleware functions can be registered to enhance account functionality. ```javascript title="Middleware WDK Protocol Configuration" // Simple logging middleware wdk.registerMiddleware('ethereum', async (account) => { console.log('New account created:', await account.getAddress()) }) ``` ## Environment Variables For production applications, consider using environment variables for sensitive configuration: ```javascript title="WDK environment variables Configuration" const wdk = new WDK(process.env.SEED_PHRASE) .registerWallet('ethereum', WalletManagerEvm, { provider: process.env.ETHEREUM_RPC_URL }) .registerProtocol('ethereum', 'velora', veloraProtocolEvm, { apiKey: process.env.velora_API_KEY }) ``` ## Configuration Validation The WDK Manager will validate configurations when wallets and protocols are registered: * **Wallet Registration**: Ensures the wallet class extends the required base class * **Protocol Registration**: Validates that protocol labels are unique per blockchain and protocol type * **Middleware Registration**: Validates that middleware functions have the correct signature ## Error Handling Configuration errors will be thrown during registration: ```javascript title="Configuration errors" try { wdk.registerWallet('ethereum', InvalidWalletClass, config) } catch (error) { console.error('Wallet registration failed:', error.message) } try { wdk.registerProtocol('ethereum', 'velora', veloraProtocolEvm, invalidConfig) } catch (error) { console.error('Protocol registration failed:', error.message) } ``` *** ## Next Steps Get started with WDK's usage Get started with WDK's API Explore blockchain-specific wallet modules Cross-chain USD₮0 bridges *** ### Need Help? # WDK Core (/sdk/core-module) This package serves as the main entry point and **orchestrator for all WDK wallet and protocol modules**, allowing you to register and manage different blockchain wallets through a single, unified interface. ## Next Steps Get started with WDK in a Node.js environment Get started with WDK's configuration Get started with WDK's API Get started with WDK's usage *** ## Need Help? # Usage (/sdk/core-module/usage) The WDK Core module is the central orchestrator for your wallet interactions. Install and instantiate the WDK. Connect specific blockchains (Ethereum, TON, etc.). Retrieve accounts and check balances. Transfer native tokens. Use Swap, Bridge, and Lending protocols. Add logging and failover protection. Best practices for security and stability. # Fiat Modules Overview (/sdk/fiat-modules) The Wallet Development Kit (WDK) provides fiat modules that enable on-ramp and off-ramp functionality, allowing users to seamlessly convert between fiat currencies and cryptocurrencies within your application. ## Fiat Protocol Modules On-ramp and off-ramp functionality for fiat currency integration: | Module | Provider | Status | Documentation | | ---------------------------------------------------------------------------------------------- | -------- | ------- | -------------------------------- | | [`@tetherto/wdk-protocol-fiat-moonpay`](https://github.com/tetherto/wdk-protocol-fiat-moonpay) | MoonPay | ✅ Ready | [Documentation](./fiat-moonpay/) | ## Features Fiat modules provide: * **On-Ramp**: Allow users to purchase cryptocurrency using fiat currencies (credit card, bank transfer, etc.) * **Off-Ramp**: Enable users to sell cryptocurrency and receive fiat currencies * **Multiple Payment Methods**: Support for various payment options depending on the provider * **KYC Integration**: Built-in Know Your Customer verification flows * **Multi-Currency Support**: Support for multiple fiat and cryptocurrencies ## Next Steps To get started with WDK fiat modules, follow these steps: 1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart) 2. Choose the fiat module that best fits your needs from the table above 3. Check specific documentation for the module you wish to use You can also: * Learn about key concepts in our [Concepts](../../resources/concepts) page * Explore [wallet modules](../wallet-modules/) to manage user wallets * Check our [examples](../../examples-and-starters/react-native-starter) for production-ready implementations # Lending Modules Overview (/sdk/lending-modules) The Wallet Development Kit (WDK) provides a set of modules that support connection with lending protocols on different blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations. ## Lending & Borrowing Protocol Modules DeFi lending functionality for different lending & borrowing protocols | Module | Route | Status | Documentation | | ------------------------------------------------------------------------------------------------------ | ----- | ------- | ------------------------------------ | | [`@tetherto/wdk-protocol-lending-aave-evm`](https://github.com/tetherto/wdk-protocol-lending-aave-evm) | EVM | ✅ Ready | [Documentation](./lending-aave-evm/) | ## Next Steps To get started with WDK modules, follow these steps: Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Manage wallet and protocol modules *** ## Need Help? # Swap Modules Overview (/sdk/swap-modules) The Swap Development Kit (WDK) provides a set of modules that support swap on top of multiple blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations. ## Swap Protocol Modules DeFi swap functionality for token exchanges across different DEXs: | Module | Blockchain | Status | Documentation | | ---------------------------------------------------------------------------------------------------- | ---------- | ----------- | ----------------------------------- | | [`@tetherto/wdk-protocol-swap-velora-evm`](https://github.com/tetherto/wdk-protocol-swap-velora-evm) | EVM | ✅ Ready | [Documentation](./swap-velora-evm/) | | `@tetherto/wdk-protocol-swap-stonfi-ton` | TON | In progress | Coming soon | ## Next steps To get started with WDK modules, follow these steps: 1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart) 2. Choose the modules that best fit your needs from the tables above 3. Check specific documentation for modules you wish to use You can also: * Learn about key concepts like [Account Abstraction](../../resources/concepts#account-abstraction) and other important definitions * Use one of our ready-to-use examples to be production ready # Wallet Modules Overview (/sdk/wallet-modules) The Wallet Development Kit (WDK) provides a set of modules that support multiple blockchain networks. All modules share a common interface, ensuring consistent behavior across different blockchain implementations. ## Supported Networks This package works with multiple blockchain networks through wallet registration. Bitcoin Mainnet Ethereum, Sepolia Testnet, L2s, etc. Tron Mainnet TON Mainnet Solana Mainnet Spark Mainnet ## Classic Wallet Modules Standard wallet implementations that use native blockchain tokens for transaction fees: | Module | Blockchain | Status | Documentation | | ------------------------------------------------------------------------------ | ---------- | ----------- | -------------------------------- | | [`@tetherto/wdk-wallet-evm`](https://github.com/tetherto/wdk-wallet-evm) | EVM | ✅ Ready | [Documentation](./wallet-evm) | | [`@tetherto/wdk-wallet-ton`](https://github.com/tetherto/wdk-wallet-ton) | TON | ✅ Ready | [Documentation](./wallet-ton) | | [`@tetherto/wdk-wallet-btc`](https://github.com/tetherto/wdk-wallet-btc) | Bitcoin | ✅ Ready | [Documentation](./wallet-btc) | | [`@tetherto/wdk-wallet-spark`](https://github.com/tetherto/wdk-wallet-spark) | Spark | ✅ Ready | [Documentation](./wallet-spark) | | [`@tetherto/wdk-wallet-tron`](https://github.com/tetherto/wdk-wallet-tron) | TRON | ✅ Ready | [Documentation](./wallet-tron) | | [`@tetherto/wdk-wallet-solana`](https://github.com/tetherto/wdk-wallet-solana) | Solana | ✅ Ready | [Documentation](./wallet-solana) | | `@tetherto/wdk-wallet-ark` | Ark | In progress | - | ## Account Abstraction Wallet Modules Wallet implementations that support [Account Abstraction](../../resources/concepts#account-abstraction) for gasless transactions using paymaster tokens like USD₮: | Module | Blockchain | Status | Documentation | | ------------------------------------------------------------------------------------------ | ---------- | ----------- | -------------------------------------- | | [`@tetherto/wdk-wallet-evm-erc4337`](https://github.com/tetherto/wdk-wallet-evm-erc-4337) | EVM | ✅ Ready | [Documentation](./wallet-evm-erc-4337) | | [`@tetherto/wdk-wallet-ton-gasless`](https://github.com/tetherto/wdk-wallet-ton-gasless) | TON | ✅ Ready | [Documentation](./wallet-ton-gasless) | | [`@tetherto/wdk-wallet-tron-gasfree`](https://github.com/tetherto/wdk-wallet-tron-gasfree) | TRON | ✅ Ready | [Documentation](./wallet-tron-gasfree) | | `@tetherto/wdk-wallet-solana-jupiterz` | Solana | In progress | - | ## Community Wallet Modules Wallet modules developed by the community. See the [Community Modules](../community-modules/) page for more details. Community modules are developed and maintained independently. Use your own judgment and proceed at your own risk. | Module | Blockchain | Description | Repository | | ----------------------- | ------------- | ----------------------------------------------------------------- | ---------------------------------------------------------- | | `@utexo/wdk-wallet-rgb` | Bitcoin (RGB) | RGB protocol wallet integration for Bitcoin-based smart contracts | [GitHub](https://github.com/UTEXO-Protocol/wdk-wallet-rgb) | ## Next Steps To get started with WDK modules, follow these steps: 1. Get up and running quickly with our [Quickstart Guide](../../start-building/nodejs-bare-quickstart) 2. Choose the modules that best fit your needs from the tables above 3. Check specific documentation for modules you wish to use You can also: * Learn about key concepts like [Account Abstraction](../../resources/concepts#account-abstraction) and other important definitions * Use one of our ready-to-use examples to be production ready # Bridge USD₮0 EVM API Reference (/sdk/bridge-modules/bridge-usdt0-evm/api-reference) ## Table of Contents | Class | Description | Methods | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------ | | [Usdt0ProtocolEvm](#usdt0protocolevm) | Main class for bridging USD₮0 tokens across blockchains. Extends `BridgeProtocol` from `@tetherto/wdk-wallet/protocols`. | [Constructor](#constructor), [Methods](#methods) | ## Usdt0ProtocolEvm The main class for bridging USD₮0 tokens across different blockchains using the LayerZero protocol. Extends `BridgeProtocol` from `@tetherto/wdk-wallet/protocols`. ### Constructor ```javascript new Usdt0ProtocolEvm(account, config?) ``` **Parameters:** * `account` (WalletAccountEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvm | WalletAccountReadOnlyEvmErc4337): The wallet account to use for bridge operations * `config` (BridgeProtocolConfig, optional): Configuration object * `bridgeMaxFee` (bigint, optional): Maximum total bridge cost in wei **Example:** ```javascript import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' const account = new WalletAccountEvm(seedPhrase, { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' }) const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) ``` ### Methods | Method | Description | Returns | Throws | | ------------------------------- | ---------------------------------------- | ---------------------------------------------------------- | --------------------------------- | | `bridge(options, config?)` | Bridges tokens to another blockchain | `Promise\` | If no provider or fee exceeds max | | `quoteBridge(options, config?)` | Estimates the cost of a bridge operation | `Promise\\>` | If no provider | #### `bridge(options, config?)` Bridges tokens to a different blockchain using the USD₮0 protocol. **Parameters:** * `options` (BridgeOptions): Bridge operation options * `targetChain` (string): Destination chain name * `recipient` (string): Address that will receive the bridged tokens * `token` (string): Token contract address on source chain * `amount` (bigint): Amount to bridge in token base units * `oftContractAddress` (string, optional): Override the default OFT contract address * `dstEid` (number, optional): Override the default LayerZero destination endpoint ID * `config` (`Pick & Pick`, optional): Override configuration for ERC-4337 accounts * `paymasterToken` (string, optional): Token to use for paying gas fees * `bridgeMaxFee` (bigint, optional): Override maximum bridge fee **Returns:** `Promise\` - Bridge operation result **Throws:** * Error if account is read-only * Error if no provider is configured * Error if bridge fee exceeds maximum allowed **Example:** ```javascript // Standard EVM account const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) console.log('Bridge hash:', result.hash) console.log('Approve hash:', result.approveHash) console.log('Reset allowance hash:', result.resetAllowanceHash) console.log('Total fee:', result.fee) console.log('Bridge fee:', result.bridgeFee) // ERC-4337 account const result2 = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }, { paymasterToken: '0x...', bridgeMaxFee: 1000000000000000n }) console.log('Bridge hash:', result2.hash) console.log('Total fee:', result2.fee) console.log('Bridge fee:', result2.bridgeFee) // Non-EVM destination with overrides const result3 = await bridgeProtocol.bridge({ targetChain: 'solana', recipient: 'SolanaRecipientAddress...', token: '0x...', amount: 1000000000000000000n, oftContractAddress: '0x...', dstEid: 30168 }) ``` #### `quoteBridge(options, config?)` Estimates the cost of a bridge operation without executing it. **Parameters:** * `options` (BridgeOptions): Bridge operation options (same as bridge method) * `config` (`Pick`, optional): Override configuration for ERC-4337 accounts * `paymasterToken` (string, optional): Token to use for paying gas fees **Returns:** `Promise\\>` - Bridge cost estimate **Throws:** Error if no provider is configured **Example:** ```javascript const quote = await bridgeProtocol.quoteBridge({ targetChain: 'polygon', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) console.log('Estimated fee:', quote.fee, 'wei') console.log('Bridge fee:', quote.bridgeFee, 'wei') if (quote.fee + quote.bridgeFee > 1000000000000000n) { console.log('Bridge fees too high') } else { const result = await bridgeProtocol.bridge({ targetChain: 'polygon', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) } ``` ## Types ### BridgeOptions ```typescript interface BridgeOptions { targetChain: string; recipient: string; token: string; amount: bigint; oftContractAddress?: string; // Override OFT contract address dstEid?: number; // Override LayerZero destination endpoint ID } ``` ### BridgeResult ```typescript interface BridgeResult { hash: string; fee: bigint; bridgeFee: bigint; approveHash?: string; resetAllowanceHash?: string; } ``` ### BridgeProtocolConfig ```typescript interface BridgeProtocolConfig { bridgeMaxFee?: bigint; } ``` ### EvmErc4337WalletConfig ```typescript interface EvmErc4337WalletConfig { paymasterToken?: string; } ``` ### Supported Chains The bridge protocol supports the following chains: **Source Chains (EVM):** | Chain | Chain ID | | -------------- | -------- | | Ethereum | 1 | | Arbitrum | 42161 | | Optimism | 10 | | Polygon | 137 | | Berachain | 80094 | | Ink | 57073 | | Plasma | 9745 | | Conflux eSpace | 1030 | | Corn | 21000000 | | Avalanche | 43114 | | Celo | 42220 | | Flare | 14 | | HyperEVM | 999 | | Mantle | 5000 | | MegaETH | 4326 | | Monad | 143 | | Morph | 2818 | | Rootstock | 30 | | Sei | 1329 | | Stable | 988 | | Unichain | 130 | | XLayer | 196 | **Destination Chains:** All source chains above, plus: | Chain | Endpoint ID (EID) | | ------ | ----------------- | | Solana | 30168 | | TON | 30343 | | TRON | 30420 | ## Error Handling The bridge protocol throws specific errors for different failure cases: ```javascript try { const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) } catch (error) { if (error.message.includes('not supported')) { console.error('Chain or token not supported') } if (error.message.includes('Exceeded maximum fee')) { console.error('Bridge fee too high') } if (error.message.includes('must be connected to a provider')) { console.error('Wallet not connected to blockchain') } if (error.message.includes('requires the protocol to be initialized with a non read-only account')) { console.error('Cannot bridge with read-only account') } if (error.message.includes('cannot be equal to the source chain')) { console.error('Cannot bridge to the same chain') } } ``` ## Usage Examples ### Basic Bridge Operation ```javascript import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' async function bridgeTokens() { const account = new WalletAccountEvm(seedPhrase, { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' }) const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) const quote = await bridgeProtocol.quoteBridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) console.log('Bridge quote:', quote) const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) console.log('Bridge result:', result) return result } ``` ### Multi-Chain Bridge ```javascript async function bridgeToMultipleChains(bridgeProtocol) { const chains = ['arbitrum', 'polygon', 'ethereum'] const token = '0x...' const amount = 1000000000000000000n const recipient = '0x...' const results = [] for (const chain of chains) { try { const quote = await bridgeProtocol.quoteBridge({ targetChain: chain, recipient, token, amount }) console.log(`Bridge to ${chain}:`, quote) const result = await bridgeProtocol.bridge({ targetChain: chain, recipient, token, amount }) results.push({ chain, result }) console.log(`Bridge to ${chain} successful:`, result.hash) } catch (error) { console.error(`Bridge to ${chain} failed:`, error.message) } } return results } ``` ### ERC-4337 Gasless Bridge ```javascript import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337' async function gaslessBridge() { const account = new WalletAccountEvmErc4337(seedPhrase, { provider: 'https://arb1.arbitrum.io/rpc', paymasterToken: '0x...' }) const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) const result = await bridgeProtocol.bridge({ targetChain: 'polygon', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }, { paymasterToken: '0x...' }) console.log('Gasless bridge result:', result) return result } ``` Get started with WDK in a Node.js environment Configure the Bridge USD₮0 EVM Protocol Installation, quick start, and usage examples *** ## Need Help? # Bridge USD₮0 EVM Configuration (/sdk/bridge-modules/bridge-usdt0-evm/configuration) ## Bridge Protocol Configuration The `Usdt0ProtocolEvm` accepts a configuration object that defines how the bridge protocol works: ```javascript import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' const account = new WalletAccountEvm(seedPhrase, { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' }) const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) ``` ## Account Configuration The bridge protocol uses the wallet account's configuration for blockchain access: ```javascript import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm' // Full access account const account = new WalletAccountEvm( seedPhrase, "0'/0/0", { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key', transferMaxFee: 100000000000000 } ) // Read-only account const readOnlyAccount = new WalletAccountReadOnlyEvm( '0x...', { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' } ) const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) ``` ## Configuration Options ### Bridge Max Fee The `bridgeMaxFee` option sets a maximum limit for total bridge costs to prevent unexpectedly high fees. **Type:** `bigint` (optional) **Unit:** Wei (1 ETH = 1000000000000000000 Wei) **Examples:** ```javascript const config = { bridgeMaxFee: 1000000000000000n, } try { const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) } catch (error) { if (error.message.includes('Exceeded maximum fee')) { console.error('Bridge cancelled: Fee too high') } } ``` ### Provider The `provider` option comes from the wallet account configuration and specifies how to connect to the blockchain. **Type:** `string | Eip1193Provider` **Examples:** ```javascript // Option 1: Using RPC URL const account = new WalletAccountEvm(seedPhrase, { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' }) // Option 2: Using browser provider (e.g., MetaMask) const account = new WalletAccountEvm(seedPhrase, { provider: window.ethereum }) // Option 3: Using custom JsonRpcProvider import { JsonRpcProvider } from 'ethers' const account = new WalletAccountEvm(seedPhrase, { provider: new JsonRpcProvider('https://eth-mainnet.g.alchemy.com/v2/your-api-key') }) ``` ## ERC-4337 Configuration When using ERC-4337 accounts, you can override configuration options during bridge operations: ```javascript const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }, { paymasterToken: '0x...', bridgeMaxFee: 1000000000000000n }) ``` ### Paymaster Token The `paymasterToken` option specifies which token to use for paying gas fees in ERC-4337 accounts. **Type:** `string` (optional) **Format:** Token contract address **Example:** ```javascript const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }, { paymasterToken: '0x...' }) ``` ## Network Support The bridge protocol works with EVM-compatible networks. Change the provider URL in the wallet account configuration: ```javascript // Ethereum Mainnet const ethereumAccount = new WalletAccountEvm(seedPhrase, { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' }) // Arbitrum const arbitrumAccount = new WalletAccountEvm(seedPhrase, { provider: 'https://arb1.arbitrum.io/rpc' }) // Polygon const polygonAccount = new WalletAccountEvm(seedPhrase, { provider: 'https://polygon-rpc.com' }) ``` ## Bridge Options When calling the bridge method, you need to provide bridge options: ```javascript const bridgeOptions = { targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n, oftContractAddress: '0x...', // Optional: custom OFT contract dstEid: 30110 // Optional: custom destination endpoint ID } const result = await bridgeProtocol.bridge(bridgeOptions) ``` ### Target Chain The `targetChain` option specifies which blockchain to bridge tokens to. **Type:** `string` **Supported values:** `'ethereum'`, `'arbitrum'`, `'optimism'`, `'polygon'`, `'berachain'`, `'ink'`, `'plasma'`, `'conflux'`, `'corn'`, `'avalanche'`, `'celo'`, `'flare'`, `'hyperevm'`, `'mantle'`, `'megaeth'`, `'monad'`, `'morph'`, `'rootstock'`, `'sei'`, `'stable'`, `'unichain'`, `'xlayer'`, `'solana'`, `'ton'`, `'tron'` ### Recipient The `recipient` option specifies the address that will receive the bridged tokens. **Type:** `string` **Format:** Valid address for the target chain ### Token The `token` option specifies which token contract to bridge. **Type:** `string` **Format:** Token contract address on the source chain ### Amount The `amount` option specifies how many tokens to bridge. **Type:** `bigint` **Unit:** Base units of the token (e.g., for USD₮: 1 USD₮ = 1000000n) ### OFT Contract Address The `oftContractAddress` option overrides the default OFT (Omnichain Fungible Token) contract address used for the bridge operation. **Type:** `string` (optional) **Format:** Contract address on the source chain **Example:** ```javascript const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x...', token: '0x...', amount: 1000000000000000000n, oftContractAddress: '0x1234...' // Custom OFT contract }) ``` ### Destination Endpoint ID The `dstEid` option overrides the default LayerZero destination endpoint ID for the target chain. **Type:** `number` (optional) **Example:** ```javascript const result = await bridgeProtocol.bridge({ targetChain: 'solana', recipient: 'SolanaRecipientAddress...', token: '0x...', amount: 1000000000000000000n, dstEid: 30168 // Solana endpoint ID }) ``` ## Error Handling The bridge protocol will throw errors for invalid configurations: ```javascript try { const result = await bridgeProtocol.bridge({ targetChain: 'invalid-chain', recipient: '0x...', token: '0x...', amount: 1000000000000000000n }) } catch (error) { if (error.message.includes('not supported')) { console.error('Chain or token not supported') } if (error.message.includes('Exceeded maximum fee')) { console.error('Bridge fee too high') } if (error.message.includes('must be connected to a provider')) { console.error('Wallet not connected to blockchain') } } ``` Get started with WDK in a Node.js environment Complete API documentation for the bridge protocol Installation, quick start, and usage examples *** ## Need Help? # Bridge USD₮0 EVM Overview (/sdk/bridge-modules/bridge-usdt0-evm) A simple package that lets EVM wallet accounts bridge USD₮0 tokens across different blockchains. This package provides a clean API for moving tokens between chains using the LayerZero protocol and USD₮0 bridge system. ## Features * **Cross-Chain Bridge**: Move USD₮0 tokens between supported blockchains * **LayerZero Integration**: Uses LayerZero protocol for secure cross-chain transfers * **Expanded Multi-Chain Support**: Bridge across 25+ networks including all major EVM chains * **Non-EVM Destinations**: Bridge to Solana, TON, and TRON from any supported EVM chain * **Account Abstraction**: Works with both standard EVM wallets and ERC-4337 smart accounts * **Fee Management**: Built-in fee calculation and bridge cost estimation * **Token Support**: Supports USD₮0 and XAU₮0 ecosystem tokens * **Route Overrides**: Custom OFT contract addresses and destination endpoint IDs * **TypeScript Support**: Full TypeScript definitions included * **Memory Safety**: Secure transaction handling with proper error management * **Provider Flexibility**: Works with JSON-RPC URLs and EIP-1193 browser providers ## Supported Networks ### Source Chains (EVM) | Chain | Chain ID | | -------------- | -------- | | Ethereum | 1 | | Arbitrum | 42161 | | Optimism | 10 | | Polygon | 137 | | Berachain | 80094 | | Ink | 57073 | | Plasma | 9745 | | Conflux eSpace | 1030 | | Corn | 21000000 | | Avalanche | 43114 | | Celo | 42220 | | Flare | 14 | | HyperEVM | 999 | | Mantle | 5000 | | MegaETH | 4326 | | Monad | 143 | | Morph | 2818 | | Rootstock | 30 | | Sei | 1329 | | Stable | 988 | | Unichain | 130 | | XLayer | 196 | ### Destination Chains All source chains above, plus: | Chain | Endpoint ID (EID) | | ------ | ----------------- | | Solana | 30168 | | TON | 30343 | | TRON | 30420 | Token support is determined by the contracts deployed on each chain. The protocol checks for `oftContract`, `legacyMeshContract`, and `xautOftContract` to determine available tokens. ## Next Steps Get started with WDK in a Node.js environment Configure the Bridge USD₮0 EVM Protocol Complete API documentation for the bridge protocol Installation, quick start, and usage examples *** ## Need Help? # Bridge USD₮0 EVM Usage (/sdk/bridge-modules/bridge-usdt0-evm/usage) # Usage The [@tetherto/wdk-protocol-bridge-usdt0-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-bridge-usdt0-evm) package bridges USD₮0 across EVM and selected non-EVM networks. Use the guides below for setup, standard and gasless bridging, cross-ecosystem recipients, and error handling. Install the package, attach WalletAccountEvm, and review supported chains. EVM-to-EVM bridges, quotes, fee caps, and optional OFT or endpoint overrides. Gasless bridging with WalletAccountEvmErc4337 and paymaster options. Send toward Solana, TON, or TRON recipients from EVM. Interpret bridge failures and dispose of signing material safely. Get started with WDK in a Node.js environment Configure RPC, fees, and protocol options for this bridge Constructor, methods, types, and error behavior *** # Fiat MoonPay API Reference (/sdk/fiat-modules/fiat-moonpay/api-reference) # API Reference Complete API documentation for the `@tetherto/wdk-protocol-fiat-moonpay` module. ## Constructor ### `new MoonPayProtocol(account, config)` Creates a new MoonPayProtocol instance. **Parameters:** | Name | Type | Description | | --------- | ----------------------------------------------------------- | ------------------------------- | | `account` | `IWalletAccount` \| `IWalletAccountReadOnly` \| `undefined` | Wallet account for transactions | | `config` | `MoonPayProtocolConfig` | Configuration object | **Config Options:** | Name | Type | Required | Default | Description | | ------------- | --------------------------- | -------- | ------------ | ------------------------------------------------------------------------ | | `apiKey` | string | Yes | - | Your MoonPay publishable API key | | `signUrl` | function | No | - | Callback used to sign buy and sell widget URLs through a trusted backend | | `cacheTime` | number | No | `600000` | Cache duration for currencies (ms) | | `environment` | `'production' \| 'sandbox'` | No | `production` | MoonPay widget URL endpoint set | **Example:** ```typescript import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'; const moonpay = new MoonPayProtocol(walletAccount, { apiKey: 'pk_live_xxxxx', signUrl: async (urlForSignature) => urlForSignature, environment: 'production', }); ``` *** ## Methods ### `buy(options)` Generates a MoonPay widget URL for purchasing cryptocurrency. If `signUrl` is configured, the URL is signed through that callback before being returned. **Parameters:** | Name | Type | Required | Description | | ---------------------- | ---------------- | -------- | ----------------------------------------------------- | | `options.cryptoAsset` | string | Yes | Cryptocurrency code (e.g., 'eth', 'btc') | | `options.fiatCurrency` | string | Yes | Fiat currency code (e.g., 'usd', 'eur') | | `options.cryptoAmount` | number \| bigint | No\* | Amount in smallest crypto units | | `options.fiatAmount` | number \| bigint | No\* | Amount in smallest fiat units (cents) | | `options.recipient` | string | No | Wallet address (uses account address if not provided) | | `options.config` | MoonPayBuyParams | No | Widget configuration options | \*Either `cryptoAmount` or `fiatAmount` must be provided, but not both. **Returns:** `Promise\<{ buyUrl: string }\>` *** ### `sell(options)` Generates a MoonPay widget URL for selling cryptocurrency. If `signUrl` is configured, the URL is signed through that callback before being returned. **Parameters:** | Name | Type | Required | Description | | ----------------------- | ----------------- | -------- | ------------------------------- | | `options.cryptoAsset` | string | Yes | Cryptocurrency code | | `options.fiatCurrency` | string | Yes | Fiat currency code | | `options.cryptoAmount` | number \| bigint | No\* | Amount in smallest crypto units | | `options.fiatAmount` | number \| bigint | No\* | Amount in smallest fiat units | | `options.refundAddress` | string | No | Refund wallet address | | `options.config` | MoonPaySellParams | No | Widget configuration options | **Returns:** `Promise\<{ sellUrl: string }\>` *** ### `quoteBuy(options)` Gets a price quote for a cryptocurrency purchase. **Parameters:** | Name | Type | Required | Description | | ---------------------- | --------------------- | -------- | ------------------------------- | | `options.cryptoAsset` | string | Yes | Cryptocurrency code | | `options.fiatCurrency` | string | Yes | Fiat currency code | | `options.cryptoAmount` | number \| bigint | No\* | Amount in smallest crypto units | | `options.fiatAmount` | number \| bigint | No\* | Amount in smallest fiat units | | `options.config` | MoonPayQuoteBuyParams | No | Quote parameters | **Returns:** `Promise\` ```typescript { cryptoAmount: bigint, // Crypto amount you'll receive fiatAmount: bigint, // Fiat amount to pay fee: bigint, // Total fee amount rate: string, // Exchange rate metadata: MoonPayBuyQuoteMetadata } ``` *** ### `quoteSell(options)` Gets a price quote for selling cryptocurrency. **Parameters:** | Name | Type | Required | Description | | ---------------------- | ---------------------- | -------- | ------------------------------- | | `options.cryptoAsset` | string | Yes | Cryptocurrency code | | `options.fiatCurrency` | string | Yes | Fiat currency code | | `options.cryptoAmount` | number \| bigint | Yes | Amount in smallest crypto units | | `options.config` | MoonPayQuoteSellParams | No | Quote parameters | **Returns:** `Promise\` ```typescript { cryptoAmount: bigint, // Crypto amount to sell fiatAmount: bigint, // Fiat amount you'll receive fee: bigint, // Total fee amount rate: string, // Exchange rate metadata: MoonPaySellQuoteMetadata } ``` *** ### `getSupportedCryptoAssets()` Fetches the list of supported cryptocurrencies. Results are cached. **Returns:** `Promise\` ```typescript { code: string, // Currency code (e.g., 'eth') decimals: number, // Decimal places networkCode: string, // Network identifier name: string, // Display name metadata: MoonPayCryptoCurrencyDetails } ``` *** ### `getSupportedFiatCurrencies()` Fetches the list of supported fiat currencies. Results are cached. **Returns:** `Promise\` ```typescript { code: string, // Currency code (e.g., 'usd') decimals: number, // Decimal places name: string, // Display name metadata: MoonPayFiatCurrencyDetails } ``` *** ### `getSupportedCountries()` Fetches the list of supported countries. **Returns:** `Promise\` ```typescript { code: string, // ISO country code name: string, // Country name isBuyAllowed: boolean, // Buy operations allowed isSellAllowed: boolean,// Sell operations allowed metadata: MoonPayCountryDetail } ``` *** ### `getTransactionDetail(txId, direction?)` Retrieves details of a specific transaction. **Parameters:** | Name | Type | Required | Default | Description | | ----------- | ----------------- | -------- | ------- | ---------------------- | | `txId` | string | Yes | - | MoonPay transaction ID | | `direction` | `'buy' \| 'sell'` | No | `'buy'` | Transaction type | **Returns:** `Promise\` ```typescript { status: 'completed' | 'failed' | 'in_progress', cryptoAsset: string, fiatCurrency: string, metadata: MoonPayBuyTransaction | MoonPaySellTransaction } ``` *** ## Types ### `MoonPayProtocolConfig` ```typescript interface MoonPayProtocolConfig { apiKey: string; signUrl?: (urlForSignature: string) => Promise; cacheTime?: number; environment?: 'production' | 'sandbox'; } ``` ### `MoonPayBuyParams` Widget configuration options for `buy()` operations: ```typescript interface MoonPayBuyParams { // UI options (shared with MoonPaySellParams) colorCode?: string; theme?: 'dark' | 'light'; themeId?: string; language?: string; showAllCurrencies?: boolean; showOnlyCurrencies?: string; showWalletAddressForm?: boolean; redirectURL?: string; unsupportedRegionRedirectUrl?: string; skipUnsupportedRegionScreen?: boolean; // Buy-specific options defaultCurrencyCode?: string; walletAddress?: string; walletAddressTag?: string; walletAddresses?: string; walletAddressTags?: string; contractAddress?: string; networkCode?: string; lockAmount?: boolean; email?: string; externalTransactionId?: string; externalCustomerId?: string; paymentMethod?: string; } ``` ### `MoonPaySellParams` Widget configuration options for `sell()` operations: ```typescript interface MoonPaySellParams { // UI options (shared with MoonPayBuyParams) colorCode?: string; theme?: 'dark' | 'light'; themeId?: string; language?: string; showAllCurrencies?: boolean; showOnlyCurrencies?: string; showWalletAddressForm?: boolean; redirectURL?: string; unsupportedRegionRedirectUrl?: string; skipUnsupportedRegionScreen?: boolean; // Sell-specific options defaultBaseCurrencyCode?: string; refundWalletAddresses?: string; lockAmount?: boolean; email?: string; externalTransactionId?: string; externalCustomerId?: string; paymentMethod?: string; } ``` ### `MoonPayQuoteBuyParams` ```typescript interface MoonPayQuoteBuyParams { extraFeePercentage?: number; // 0-10% paymentMethod?: string; areFeesIncluded?: boolean; walletAddress?: string; } ``` ### `MoonPayQuoteSellParams` ```typescript interface MoonPayQuoteSellParams { extraFeePercentage?: number; // 0-10% payoutMethod?: string; } ``` *** ## Next Steps * [Configuration](./configuration) - Setup and configuration options * [Usage Guide](./usage) - Common usage patterns # Fiat MoonPay Configuration (/sdk/fiat-modules/fiat-moonpay/configuration) # Configuration This page covers all configuration options for the MoonPay fiat module, including optional URL signing and environment selection. ## Prerequisites Before using this module, you need: 1. A MoonPay developer account - [Create an account on MoonPay Dashboard](https://dashboard.moonpay.com/signup) 2. A publishable API key from your dashboard 3. If you want signed widget URLs, a trusted backend signing endpoint for the `signUrl` callback ## Installation ```bash npm install @tetherto/wdk-protocol-fiat-moonpay ``` ## Basic Configuration ```typescript import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay'; const moonpay = new MoonPayProtocol(walletAccount, { apiKey: 'pk_live_xxxxx', // Your MoonPay publishable API key signUrl: async (urlForSignature) => { const response = await fetch('/api/moonpay/sign-url', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ urlForSignature }), }); if (!response.ok) { throw new Error(`Failed to sign MoonPay URL: ${response.status} ${response.statusText}`); } const { signedUrl } = await response.json(); return signedUrl; }, environment: 'sandbox', }); ``` ## Configuration Options | Option | Type | Required | Default | Description | | ------------- | --------------------------- | -------- | ----------------- | ------------------------------------------------------------------------ | | `apiKey` | string | Yes | - | Your MoonPay publishable API key | | `signUrl` | function | No | - | Callback used to sign buy and sell widget URLs through a trusted backend | | `cacheTime` | number | No | `600000` (10 min) | Duration in milliseconds to cache supported currencies | | `environment` | `'production' \| 'sandbox'` | No | `production` | MoonPay widget URL endpoint set | ## Constructor Overloads The `MoonPayProtocol` class supports three constructor patterns: ```typescript // Without account (for public read operations like fetching supported currencies) const moonpay = new MoonPayProtocol(undefined, config); // With read-only account const moonpay = new MoonPayProtocol(readOnlyAccount, config); // With full wallet account (for buy/sell operations) const moonpay = new MoonPayProtocol(walletAccount, config); ``` ## Environment Configuration ### Sandbox (Testing) Use sandbox endpoints for development and testing: ```typescript const moonpay = new MoonPayProtocol(walletAccount, { apiKey: 'pk_test_xxxxx', signUrl: async (urlForSignature) => { const response = await fetch('/api/moonpay/sign-url', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ urlForSignature }), }); return (await response.json()).signedUrl; }, environment: 'sandbox', }); ``` In sandbox mode: * No real transactions are processed * Use test card numbers provided by MoonPay * KYC verification is simulated If you do not need signed URLs, omit `signUrl` and the protocol returns unsigned widget URLs directly. ### Production For production deployments, use live API keys and the production endpoint set: ```typescript const moonpay = new MoonPayProtocol(walletAccount, { apiKey: 'pk_live_xxxxx', signUrl: async (urlForSignature) => { const response = await fetch('/api/moonpay/sign-url', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ urlForSignature }), }); return (await response.json()).signedUrl; }, environment: 'production', }); ``` ## Widget Customization When calling `buy()` or `sell()`, you can customize the MoonPay widget appearance: ```typescript const result = await moonpay.buy({ cryptoAsset: 'eth', fiatCurrency: 'usd', fiatAmount: 10000n, // $100.00 in cents config: { colorCode: '#3B82F6', // Your brand color (hex) theme: 'dark', // 'dark' or 'light' language: 'en', // ISO 639-1 language code redirectURL: 'https://yourapp.com/callback', }, }); ``` ### Available Buy Widget Options | Option | Type | Description | | ------------------------------ | ------------------- | ------------------------------------------------------- | | `colorCode` | string | Hexadecimal color for widget accent | | `theme` | `'dark' \| 'light'` | Widget appearance theme | | `themeId` | string | ID of a custom theme | | `language` | string | ISO 639-1 language code | | `showAllCurrencies` | boolean | Show all supported cryptocurrencies | | `showOnlyCurrencies` | string | Comma-separated currency codes to display | | `showWalletAddressForm` | boolean | Show wallet address input form | | `redirectURL` | string | URL to redirect after completion | | `unsupportedRegionRedirectUrl` | string | URL for unsupported regions | | `skipUnsupportedRegionScreen` | boolean | Skip unsupported region screen | | `defaultCurrencyCode` | string | Pre-selected cryptocurrency code | | `walletAddress` | string | Pre-filled wallet address | | `walletAddressTag` | string | Wallet address memo/tag (for EOS, XRP, etc.) | | `walletAddresses` | string | JSON string of wallet addresses for multiple currencies | | `walletAddressTags` | string | JSON string of address tags for multiple currencies | | `contractAddress` | string | Token contract address (DeFi Buy only) | | `networkCode` | string | Network for the token contract (DeFi Buy only) | | `lockAmount` | boolean | Prevent user from changing amount | | `email` | string | Pre-fill customer email | | `externalTransactionId` | string | Your transaction identifier | | `externalCustomerId` | string | Your customer identifier | | `paymentMethod` | string | Pre-select payment method | ### Available Sell Widget Options For `sell()`, the widget config uses `MoonPaySellParams` with different options: | Option | Type | Description | | ------------------------------ | --------------------- | ------------------------------------------- | | `colorCode` | string | Hexadecimal color for widget accent | | `theme` | `'dark'` \| `'light'` | Widget appearance theme | | `themeId` | string | ID of a custom theme | | `language` | string | ISO 639-1 language code | | `showAllCurrencies` | boolean | Show all supported cryptocurrencies | | `showOnlyCurrencies` | string | Comma-separated currency codes to display | | `showWalletAddressForm` | boolean | Show wallet address input form | | `redirectURL` | string | URL to redirect after completion | | `unsupportedRegionRedirectUrl` | string | URL for unsupported regions | | `skipUnsupportedRegionScreen` | boolean | Skip unsupported region screen | | `defaultBaseCurrencyCode` | string | Pre-selected cryptocurrency to sell | | `refundWalletAddresses` | string | JSON string of wallet addresses for refunds | | `lockAmount` | boolean | Prevent user from changing amount | | `email` | string | Pre-fill customer email | | `externalTransactionId` | string | Your transaction identifier | | `externalCustomerId` | string | Your customer identifier | | `paymentMethod` | string | Pre-select payout method | ## Next Steps * [Usage Guide](./usage) - Learn how to integrate MoonPay * [API Reference](./api-reference) - Complete API documentation # Fiat MoonPay Overview (/sdk/fiat-modules/fiat-moonpay) # @tetherto/wdk-protocol-fiat-moonpay Overview A WDK module for integrating MoonPay's fiat on-ramp and off-ramp services. This module generates signed or unsigned widget URLs that allow users to buy and sell cryptocurrency using fiat currencies directly within your application. Provide a `signUrl` callback if you want the protocol to return signed URLs from a trusted backend, or omit it to use the unsigned widget URLs directly. Get started by reading the [Usage](./usage) guide. This module requires a MoonPay developer account. [Create your account here](https://dashboard.moonpay.com/signup). If you want MoonPay to sign the widget URLs before they are returned, provide a `signUrl` callback that talks to a trusted backend signer. If you omit `signUrl`, the protocol returns unsigned widget URLs directly. ## Features * **Fiat On-Ramp**: Generate signed or unsigned widget URLs for users to buy cryptocurrency with fiat * **Fiat Off-Ramp**: Generate signed or unsigned widget URLs for users to sell cryptocurrency with fiat * **Price Quotes**: Get real-time quotes for buy and sell operations * **Transaction Tracking**: Retrieve transaction status and details * **Currency Support**: Query supported cryptocurrencies, fiat currencies, and countries * **Customizable Widget**: Configure colors, themes, language, and behavior ## Supported Payment Methods * Credit and debit cards (Visa, Mastercard, etc.) * Bank transfers (ACH, SEPA, etc.) * Apple Pay and Google Pay * Local payment methods (varies by region) For the full list of supported payment methods by country, see [MoonPay's Supported Payment Methods](https://support.moonpay.com/en/articles/380823-moonpay-s-supported-payment-methods). ## Supported Cryptocurrencies This module supports purchasing and selling cryptocurrencies on networks compatible with WDK wallet modules, including: * Ethereum and EVM-compatible chains (ETH, USD₮, etc.) * Bitcoin (BTC) * TRON (TRX, USD₮) * TON * Solana (SOL, USD₮) ## Next Steps Set up your MoonPay API key, optional signing callback, and environment Learn how to integrate MoonPay in your application Complete API documentation for the module *** ### MoonPay Resources * [MoonPay Dashboard](https://dashboard.moonpay.com/signup) - Create your developer account * [MoonPay Support Center](https://support.moonpay.com/) - Official MoonPay documentation and support * [Supported Payment Methods](https://support.moonpay.com/en/articles/380823-moonpay-s-supported-payment-methods) - Full list by country *** ### Need Help? # Fiat MoonPay Usage (/sdk/fiat-modules/fiat-moonpay/usage) # Usage The [@tetherto/wdk-protocol-fiat-moonpay](https://www.npmjs.com/package/@tetherto/wdk-protocol-fiat-moonpay) module builds signed MoonPay widget URLs and quotes for on-ramp and off-ramp flows. Use the guides below for setup, trading, and transaction follow-up. Install the package and initialize MoonPayProtocol. On-ramp, off-ramp, quotes, supported assets, widget options, recipients. Check status and load transaction details from MoonPay. Get started with WDK in a Node.js environment API keys, caching, and MoonPay configuration options Constructor, methods, and types for MoonPayProtocol # Manage Accounts (/sdk/core-module/guides/account-management) This guide explains how to access accounts from your registered wallets. An "Account" object in WDK is your interface for inspecting balances and sending transactions on a specific blockchain. ## Retrieve Accounts You can retrieve an account using a simple index or a custom derivation path. ### By Index (Recommended) The simplest way to get an account is by its index (starting at `0`). This uses the default derivation path for the specified blockchain. ```typescript title="Get Account by Index" // Get the first account (index 0) for Ethereum and TON const ethAccount = await wdk.getAccount('ethereum', 0) const tonAccount = await wdk.getAccount('ton', 0) ``` ### By Derivation Path (Advanced) If you need a specific hierarchy, you can request an account by its unique derivation path. ```typescript title="Get Account by Path" // Custom path for Ethereum const customEthAccount = await wdk.getAccountByPath('ethereum', "0'/0/1") ``` The WDK instance caches accounts. If you call `getAccount` twice using the same index, the function will return the same `Account` object instance. **Network Mismatch Warning** Ensure your WDK instance configuration matches your account environment. * If using **Testnet** keys, ensure you registered the wallet with a **Testnet RPC** (e.g., `https://sepolia.drpc.org` for ETH, `https://testnet.toncenter.com/api/v2/jsonRPC` for TON). * If using **Mainnet** keys, ensure you registered the wallet with a **Mainnet RPC** (e.g., `https://eth.drpc.org` for ETH, `https://toncenter.com/api/v2/jsonRPC` for TON). Using a Mainnet key on a Testnet RPC (or vice versa) will result in "Network not allowed" or zero balance errors. ## View Addresses Once you have an account object, you can retrieve its public blockchain address using the `getAddress` function. ```typescript title="Get Addresses" const ethAddress = await ethAccount.getAddress() console.log('Ethereum address:', ethAddress) ``` ## Check Balances You can check the native token balance of any account (e.g., ETH on Ethereum, TON on TON) by using the `getBalance()` function. ```typescript title="Get Balance" try { const balance = await ethAccount.getBalance() console.log('Balance:', balance) } catch (error) { console.error('Failed to fetch balance:', error) } ``` ### Multi-Chain Balance Check Because WDK offers a unified interface, you can easily iterate through multiple chains to fetch balances. The following example: 1. Iterates over an array of user defined chains. 2. Retrieves the first account using the respective chain's `getAccount(index)` function. 3. Retrieves the first account's balance using the `getBalance()` function. 4. Logs the balance to the console. ```typescript title="Check All Balances" const chains = ['ethereum', 'ton', 'bitcoin'] for (const chain of chains) { try { const account = await wdk.getAccount(chain, 0) const balance = await account.getBalance() console.log(`${chain} balance:`, balance) } catch (error) { console.log(`${chain}: Wallet not registered or unavailable`) } } ``` ## Next Steps Now that you can access your accounts, learn how to [send transactions](./transactions). # Error Handling (/sdk/core-module/guides/error-handling) # Error Handling & Best Practices This guide covers recommended patterns for error handling and security when using the WDK. ## Handling Common Errors When interacting with multiple chains and protocols, various runtime issues may occur. ### Missing Registration The most common error is attempting to access a wallet or protocol that hasn't been registered. ```typescript title="Check Registration Pattern" try { // This will throw if 'tron' was never registered via .registerWallet() const tronAccount = await wdk.getAccount('tron', 0) } catch (error) { console.error('Tron wallet not available:', error.message) } ``` Always use `try/catch` blocks when initializing sessions or accessing dynamic features. ## Memory Management For security, clear sensitive data from memory when a session is complete. The WDK provides [`dispose()`](../api-reference) for this purpose. ### Disposing the Instance You can clear every registered wallet using [`dispose()`](../api-reference): ```typescript title="Dispose WDK" function endSession(wdk) { // 1. Clean up sensitive data wdk.dispose() // 2. Modify app state to reflect logged-out status // ... console.log('Session ended, wallet data cleared.') } ``` ### Disposing Specific Wallets You can dispose only the wallets you no longer need using [`dispose()`](../api-reference): ```typescript title="Dispose Specific Wallets" // Keep the TON wallet registered, but dispose the Ethereum wallet wdk.dispose(['ethereum']) ``` **After Disposal:** Once a wallet is disposed, any later call that depends on that wallet registration will fail until you register it again. If you call `wdk.dispose()` without arguments, you must instantiate a new WDK instance or register fresh wallets before resuming operations. ## Security Best Practices ### Environment Variables Never hardcode API keys or seed phrases in your source code. Use environment variables (e.g., `process.env.TON_API_KEY`). ### Secure Storage If you persist a session, never store the raw seed phrase in local storage. Use secure operating system storage (like Keychain on macOS or Keystore on Android). # Getting Started (/sdk/core-module/guides/getting-started) This guide explains how to install the [`@tetherto/wdk`](https://www.npmjs.com/package/@tetherto/wdk) package and create a new instance to start managing your wallets. ## 1. Installation ### Prerequisites Before you begin, ensure you have the following installed: * **[Node.js](https://nodejs.org/)**: version 18 or higher. * **[npm](https://www.npmjs.com/)**: usually comes with Node.js. ### Install Package To install the WDK Core package, run the following command in your terminal: ```bash npm install @tetherto/wdk ``` This package allows you to manage different blockchain wallets and protocols through a single interface. ## 2. Instantiation To use WDK, you must create an instance of the `WDK` class. This instance acts as the central manager for all your wallets and protocols. ### Import the Module First, import the `WDK` class from the package: ```typescript title="Import WDK Core" import WDK from '@tetherto/wdk' ``` ### Initialize WDK You can initialize `WDK` in two ways: with a [new seed phrase](#generate-a-new-wallet) or an [existing one](#restore-an-existing-wallet). #### Generate a New Wallet If you are creating a fresh wallet for a user, use the static `getRandomSeedPhrase()` method to generate a secure mnemonic. ```typescript title="Create new WDK Instance" // 1. Generate a secure random seed phrase // Generate 24-word seed phrase for higher security const seedPhrase = WDK.getRandomSeedPhrase(24) // Or use 12-word seed phrase (default) // const seedPhrase = WDK.getRandomSeedPhrase() // 2. Initialize the WDK instance with the new seed const wdk = new WDK(seedPhrase) ``` **Secure the Seed Phrase:** You must securely store this seed phrase immediately. If it is lost, the user will permanently lose access to their funds. #### Restore an Existing Wallet If a user already has a seed phrase (e.g., from a previous session or another wallet), you can pass it directly to the constructor. ```typescript title="Restore WDK Instance" // Replace this string with the user's actual seed phrase const existingSeed = 'witch collapse practice feed shame open despair creek road again ice ...' const wdk = new WDK(existingSeed) ``` ## Next Steps With your WDK instance ready, you can now [register wallet modules](./wallet-registration) to interact with specific blockchains like [Ethereum](../../wallet-modules/wallet-evm/), [TON](../../wallet-modules/wallet-ton/), or [Bitcoin](../../wallet-modules/wallet-btc/). # Configure Middleware (/sdk/core-module/guides/middleware) Middleware allows you to intercept wallet operations. You can use this to add [logging](#logging), implement retry logic, or handle [failovers for RPC providers](#failover-protection-with-provider-failover). ## Register Middleware When registering middleware, you should reference a specific chain. The middleware function runs every time an account is instantiated or an operation is performed, depending on the implementation. ### Logging This simple middleware logs a message whenever a new account is accessed. ```typescript title="Logging Middleware" wdk.registerMiddleware('ethereum', async (account) => { const address = await account.getAddress() console.log('Accessed Ethereum account:', address) // You can also attach custom properties or wrap methods here }) ``` ## Failover Protection with Provider Failover The [`@tetherto/wdk-provider-failover`](https://www.npmjs.com/package/@tetherto/wdk-provider-failover) package provides a resilient wrapper for wallet instances. Unlike standard middleware, you wrap your wallet class instantiation directly. ### Install `@tetherto/wdk-provider-failover` You can install the `@tetherto/wdk-provider-failover` using npm with the following command: ```bash npm install @tetherto/wdk-provider-failover ``` ### Use `createFallbackWallet` You can import the `createFallbackWallet` function to ensure that if your primary RPC fails, the wallet automatically retries with the fallback providers. With this configuration, if `sendTransaction` fails due to a network error, the WDK will automatically retry using the fallback providers without throwing an error to your application. ```typescript title="Failover Wrapper Usage" import { createFallbackWallet } from '@tetherto/wdk-provider-failover' import { WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm' const wallet = createFallbackWallet( WalletAccountReadOnlyEvm, ['0x...'], // constructor args { primary: { provider: 'https://mainnet.infura.io/v3/YOUR_KEY' }, fallbacks: [ { provider: 'https://eth.llamarpc.com' }, { provider: 'https://ethereum.publicnode.com' } ] } ) // Use the wallet instance directly const balance = await wallet.getBalance() ``` ## Next Steps Learn about [error handling and best practices](./error-handling) to ensure your application is robust and secure. # Integrate Protocols (/sdk/core-module/guides/protocol-integration) The WDK Core module supports registering external protocols. This allows you to extend the basic wallet functionality with advanced features like [token swapping](#swapping-tokens), [cross-chain bridging](#bridging-assets), and lending, all through a unified interface. ## Register Protocols You can register protocols globally (for all new accounts). ### Global Registration (Recommended) Global registration ensures that every account you retrieve already has the protocol ready to use. You can do this by chaining a call to `.registerProtocol()` on the WDK instance. ### 1. Install Protocol Modules Install the [`@tetherto/wdk-protocol-swap-velora-evm`](https://www.npmjs.com/package/@tetherto/wdk-protocol-swap-velora-evm) and [`@tetherto/wdk-protocol-bridge-usdt0-evm`](https://www.npmjs.com/package/@tetherto/wdk-protocol-bridge-usdt0-evm) packages: ```bash npm install @tetherto/wdk-protocol-swap-velora-evm && npm install @tetherto/wdk-protocol-bridge-usdt0-evm ``` ### 2. Register in Code Now, import the protocol modules and register them with your WDK instance. This makes the protocol methods available to any account derived from that instance. First, import the necessary modules: ```typescript title="Import Protocols" import veloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' import usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' ``` Then, register the protocols for the specific chains they support: ```typescript title="Register Protocols" // Register protocols for specific chains const wdk = new WDK(seedPhrase) .registerWallet('ethereum', WalletManagerEvm, ethConfig) // Register Velora Swap for Ethereum .registerProtocol('ethereum', 'velora', veloraProtocolEvm, { apiKey: 'YOUR_API_KEY' }) // Register USDT0 Bridge for Ethereum .registerProtocol('ethereum', 'usdt0', usdt0ProtocolEvm, { ethereumRpcUrl: 'https://eth.drpc.org' // Configuration depends on the module }) ``` ## Use Protocols Once [registered](#register-protocols), you can access the protocol instance using the specific getter methods: `getSwapProtocol`, `getBridgeProtocol`, or `getLendingProtocol`. ### Swapping Tokens Use `getSwapProtocol` to access registered swap services on any wallet account. ```typescript title="Swap Tokens" const ethAccount = await wdk.getAccount('ethereum', 0) const velora = ethAccount.getSwapProtocol('velora') const result = await velora.swap({ tokenIn: '0x...', // Address of token to sell tokenOut: '0x...', // Address of token to buy tokenInAmount: 1000000n // Amount to swap }) ``` ### Bridging Assets 1. Use `getBridgeProtocol` to access cross-chain bridges. 2. Call `bridge` from the bridge protocol to send tokens from one protocol to another. ```typescript title="Bridge Assets" const ethAccount = await wdk.getAccount('ethereum', 0) const usdt0 = ethAccount.getBridgeProtocol('usdt0') const result = await usdt0.bridge({ targetChain: 'ton', recipient: 'UQBla...', // TON address token: '0x...', // ERC20 Token Address amount: 1000000n }) ``` **Protocol Availability:** If you try to access a protocol that hasn't been registered (e.g., `getSwapProtocol('uniswap')`), the SDK will throw an error. Always ensure registration matches the ID you request. ## Next Steps Learn how to [configure middleware](./middleware) to add logging or failover protection to your wallet interactions. # Send Transactions (/sdk/core-module/guides/transactions) You can send native tokens (like ETH, TON, or BTC) from any of your wallet accounts to another address. **Get Testnet Funds:** To test these transactions without spending real money, ensure you are on a testnet and have obtained funds. See [Testnet Funds & Faucets](../../../resources/concepts#testnet-funds--faucets) for a list of available faucets. **BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers. ## Send Native Tokens The `sendTransaction` method allows you to transfer value. It accepts a unified configuration object, though specific parameters (like `value` formatting) may vary slightly depending on the blockchain. ### Ethereum Example On EVM chains, values are typically expressed in Wei (1 ETH = 10^18 Wei). The following example will: 1. Retrieve the first Ethereum account (see [Manage Accounts](./account-management)) 2. Send 0.001 ETH (1000000000000000 wei) to an account using `sendTransaction`. ```typescript title="Send ETH" const ethAccount = await wdk.getAccount('ethereum', 0) const result = await ethAccount.sendTransaction({ to: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F', value: 1000000000000000n // 0.001 ETH (in Wei) }) console.log('Transaction sent! Hash:', result.hash) ``` ### TON Example On TON, values are expressed in Nanotons (1 TON = 10^9 Nanotons). The following example will: 1. Retrieve the first TON account 2. Send 1 TON (1000000000 nton) to an account using `sendTransaction`. ```typescript title="Send TON" // Send TON transaction const tonAccount = await wdk.getAccount('ton', 0) const tonResult = await tonAccount.sendTransaction({ to: 'UQCz5ON7jjK32HnqPushubsHxgsXgeSZDZPvh8P__oqol90r', value: 1000000000n // 1 TON (in nanotons) }) console.log('TON transaction:', tonResult.hash) ``` ## Handling Responses The `sendTransaction` method returns a [transaction result object](../api-reference). The most important field is typically `hash`, which represents the transaction ID on the blockchain. You can use this hash to track the status of your payment on a block explorer. ## Multi-Chain Transactions You can orchestrate payments across different chains in a single function by acting on multiple account objects sequentially. The following example will: 1. Retrieve an ETH and ton account using the `getAccount()` method. 2. Send ETH and `await` the transaction. 3. Send TON and `await` the transaction. ```typescript title="Multi-Chain Payment" async function sendCrossChainPayments(wdk) { const ethAccount = await wdk.getAccount('ethereum', 0) const tonAccount = await wdk.getAccount('ton', 0) // 1. Send ETH await ethAccount.sendTransaction({ to: '0x...', value: 1000000000000000000n }) // 2. Send TON await tonAccount.sendTransaction({ to: 'EQ...', value: 1000000000n }) } ``` ## Next Steps For more complex interactions like swapping tokens or bridging assets, learn how to [integrate protocols](./protocol-integration). # Register Wallets (/sdk/core-module/guides/wallet-registration) This guide explains how to register wallet modules with your WDK instance. The WDK Core module itself doesn't contain blockchain-specific logic; instead, you register separate modules for each chain you want to support (e.g., Ethereum, TON, Bitcoin). ## How it works The WDK uses a builder pattern, allowing you to chain `.registerWallet()` calls. Each call connects a blockchain-specific manager to your central WDK instance. ### Parameters The `registerWallet` method (see [API Reference](../api-reference)) requires three arguments: 1. **Symbol**: A unique string identifier for the chain (e.g., `'ethereum'`, `'ton'`). You will use this ID later to retrieve accounts. 2. **Manager Class**: The wallet manager class imported from the specific module (e.g., `WalletManagerEvm`). 3. **Configuration**: An object containing the chain-specific settings (e.g., RPC providers, API keys). ## Installation Install the [wallet managers](../../wallet-modules/) for the blockchains you want to support: ```bash npm install @tetherto/wdk-wallet-evm @tetherto/wdk-wallet-tron @tetherto/wdk-wallet-btc ``` ## Example: Registering Multiple Wallets ### Import the Wallet Manager Packages First, import the necessary wallet manager packages: ```typescript title="Import Modules" import WalletManagerEvm from '@tetherto/wdk-wallet-evm' import WalletManagerTron from '@tetherto/wdk-wallet-tron' import WalletManagerBtc from '@tetherto/wdk-wallet-btc' ``` ### Register the Wallets Then, [instantiate WDK](./getting-started#initialize-wdk) and chain the registration calls: ```typescript title="Register Wallets" const wdk = new WDK(seedPhrase) // 1. Register Ethereum .registerWallet('ethereum', WalletManagerEvm, { provider: 'https://eth.drpc.org' }) // 2. Register TRON .registerWallet('tron', WalletManagerTron, { provider: 'https://api.trongrid.io' }) // 3. Register Bitcoin .registerWallet('bitcoin', WalletManagerBtc, { provider: 'https://blockstream.info/api' }) ``` **RPC Providers:** The examples use public RPC endpoints for demonstration. We do not endorse any specific provider. * **Testnets:** You can find public RPCs for Ethereum and other EVM chains on [Chainlist](https://chainlist.org). * **Mainnet:** For production environments, we recommend using reliable, paid RPC providers to ensure stability. **TRON Networks:** Choose the correct provider for your environment. * **Mainnet:** `https://api.trongrid.io` * **Shasta (Testnet):** `https://api.shasta.trongrid.io` ## Next Steps Once your wallets are registered, you can [manage accounts and specific addresses](./account-management). # Lending Aave EVM API Reference (/sdk/lending-modules/lending-aave-evm/api-reference) # API Reference ## Class: AaveProtocolEvm Main class for Aave V3 lending on EVM. ### Constructor ```javascript new AaveProtocolEvm(account) ``` Parameters: * `account`: `WalletAccountEvm | WalletAccountReadOnlyEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvmErc4337` Example: ```javascript const aave = new AaveProtocolEvm(account) ``` ### Methods | Method | Description | Returns | | ------------------------------------------------ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `supply(options, config?)` | Add tokens to the pool | `Promise<{hash: string, fee: bigint, approveHash?: string, resetAllowanceHash?: string}>` | | `quoteSupply(options, config?)` | Estimate cost to add tokens | `Promise<{fee: bigint}>` | | `withdraw(options, config?)` | Remove tokens from the pool | `Promise<{hash: string, fee: bigint}>` | | `quoteWithdraw(options, config?)` | Estimate cost to withdraw | `Promise<{fee: bigint}>` | | `borrow(options, config?)` | Borrow tokens | `Promise<{hash: string, fee: bigint}>` | | `quoteBorrow(options, config?)` | Estimate borrowing cost | `Promise<{fee: bigint}>` | | `repay(options, config?)` | Repay borrowed tokens | `Promise<{hash: string, fee: bigint}>` | | `quoteRepay(options, config?)` | Estimate repayment cost | `Promise<{fee: bigint}>` | | `setUseReserveAsCollateral(token, use, config?)` | Toggle token as collateral | `Promise<{hash: string, fee: bigint}>` | | `setUserEMode(categoryId, config?)` | Set user eMode | `Promise<{hash: string, fee: bigint}>` | | `getAccountData(account?)` | Read account stats | `Promise<{ totalCollateralBase: bigint, totalDebtBase: bigint, availableBorrowsBase: bigint, currentLiquidationThreshold: bigint, ltv: bigint, healthFactor: bigint }>` | *** When `AaveProtocolEvm` is initialized with an ERC‑4337 smart account, the optional `config` argument on mutating and quote methods accepts the same gas-payment override families documented in [`@tetherto/wdk-wallet-evm-erc-4337`](../../wallet-modules/wallet-evm-erc-4337/api-reference): paymaster token, sponsorship policy, and native coins. ### `supply(options, config?)` Add tokens to the pool. Options: * `token` (`string`): token address * `amount` (`number | bigint`): amount in base units * `onBehalfOf` (`string`, optional) Returns: * May include `approveHash` and `resetAllowanceHash` for standard accounts (e.g., USD₮ allowance reset on Ethereum mainnet) Example: ```javascript const res = await aave.supply({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `quoteSupply(options, config?)` Estimate fee to add tokens. ```javascript const q = await aave.quoteSupply({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `withdraw(options, config?)` Remove tokens from the pool. Options: * `token` (`string`) * `amount` (`number | bigint`) * `to` (`string`, optional) ```javascript const tx = await aave.withdraw({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `quoteWithdraw(options, config?)` Estimate fee to withdraw tokens. ```javascript const q = await aave.quoteWithdraw({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `borrow(options, config?)` Borrow tokens. Options: * `token` (`string`) * `amount` (`number | bigint`) * `onBehalfOf` (`string`, optional) ```javascript const tx = await aave.borrow({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `quoteBorrow(options, config?)` Estimate fee to borrow tokens. ```javascript const q = await aave.quoteBorrow({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `repay(options, config?)` Repay borrowed tokens. Options: * `token` (`string`) * `amount` (`number | bigint`) * `onBehalfOf` (`string`, optional) ```javascript const tx = await aave.repay({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` Returns: * For standard accounts, may include `approveHash` / `resetAllowanceHash` when applicable. *** ### `quoteRepay(options, config?)` Estimate fee to repay borrowed tokens. ```javascript const q = await aave.quoteRepay({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` *** ### `setUseReserveAsCollateral(token, use, config?)` Toggle token as collateral for the user. ```javascript const tx = await aave.setUseReserveAsCollateral('TOKEN_ADDRESS', true) ``` *** ### `setUserEMode(categoryId, config?)` Set user eMode category. ```javascript const tx = await aave.setUserEMode(1) ``` *** ### `getAccountData(account?)` Read account stats like total collateral, debt, and health. ```javascript const data = await aave.getAccountData() ``` Returns the following structure: ```javascript { totalCollateralBase: bigint, totalDebtBase: bigint, availableBorrowsBase: bigint, currentLiquidationThreshold: bigint, ltv: bigint, healthFactor: bigint } ``` *** ## ERC‑4337 Config Override (optional) When the protocol uses `WalletAccountEvmErc4337` or `WalletAccountReadOnlyEvmErc4337`, the optional `config` argument on `supply`, `quoteSupply`, `withdraw`, `quoteWithdraw`, `borrow`, `quoteBorrow`, `repay`, `quoteRepay`, `setUseReserveAsCollateral`, and `setUserEMode` accepts the wallet module's per-call gas-payment overrides. * **Paymaster token mode**: `paymasterUrl`, `paymasterAddress`, `paymasterToken`, `transferMaxFee` * **Sponsorship policy mode**: `isSponsored`, `paymasterUrl`, `sponsorshipPolicyId` * **Native coin mode**: `useNativeCoins`, `transferMaxFee` Example: ```javascript const res = await aave.supply( { token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', amount: 1000000n }, { paymasterToken: { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' } } ) ``` ## Rules & Notes * `token` must be a valid (non‑zero) address * `amount` > 0 and in token base units (use BigInt) * `onBehalfOf`/`to` (if set) must be valid, non‑zero addresses * A provider is required to read/send transactions * For USD₮ on mainnet, allowance may be reset to 0 then set again before actions Get started with WDK in a Node.js environment Get started with WDK's Lending Aave EVM Protocol configuration Get started with WDK's Lending Aave EVM Protocol usage *** ### Need Help? # Lending Aave EVM Configuration (/sdk/lending-modules/lending-aave-evm/configuration) # Configuration ## Service Setup ```javascript import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' // Create wallet account first const account = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) // Create lending service const aave = new AaveProtocolEvm(account) ``` ## Account Configuration The service uses the wallet account configuration to connect to the target network and sign transactions. ```javascript import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm' // Full access account const account = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) // Read-only account (quotes, reads) const readOnly = new WalletAccountReadOnlyEvm('0xYourAddress', { provider: 'https://ethereum-rpc.publicnode.com' }) const aave = new AaveProtocolEvm(account) ``` ## ERC‑4337 (Account Abstraction) When using ERC‑4337 smart accounts, every mutating method and quote helper accepts an optional `config` override. In `v1.0.0-beta.4`, that override matches the three gas-payment families exposed by [`@tetherto/wdk-wallet-evm-erc-4337`](../../wallet-modules/wallet-evm-erc-4337/configuration): paymaster token, sponsorship policy, or native coins. Use the fields that match the gas-payment mode you want for that call. For the full field-level definitions, see the [`@tetherto/wdk-wallet-evm-erc-4337` configuration docs](../../wallet-modules/wallet-evm-erc-4337/configuration) and [`Config Override`](../../wallet-modules/wallet-evm-erc-4337/api-reference) reference. ```javascript import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337' const aa = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", { chainId: 1, provider: 'https://arb1.arbitrum.io/rpc', bundlerUrl: 'YOUR_BUNDLER_URL', paymasterUrl: 'YOUR_PAYMASTER_URL' }) const aaveAA = new AaveProtocolEvm(aa) const result = await aaveAA.supply({ token: '0xdAC17F...ec7', amount: 1000000n }, { paymasterToken: { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' } }) ``` ### Supported Override Families * **Paymaster token mode**: `paymasterUrl`, `paymasterAddress`, `paymasterToken`, `transferMaxFee` * **Sponsorship policy mode**: `isSponsored`, `paymasterUrl`, `sponsorshipPolicyId` * **Native coin mode**: `useNativeCoins`, `transferMaxFee` ## Network Support Aave V3 spans multiple EVM chains (Ethereum, Arbitrum, Base, Optimism, Polygon, Avalanche, BNB, Celo, Gnosis, Linea, Scroll, Soneium, Sonic, ZkSync, Metis). Ensure the correct RPC and token addresses for the target chain. ```javascript // Ethereum Mainnet const eth = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) // Arbitrum const arb = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://arb1.arbitrum.io/rpc' }) ``` ## Operation Options Each operation accepts a simple options object: ```javascript // Supply await aave.supply({ token: 'TOKEN_ADDRESS', amount: 1000000n }) // Withdraw await aave.withdraw({ token: 'TOKEN_ADDRESS', amount: 1000000n }) // Borrow await aave.borrow({ token: 'TOKEN_ADDRESS', amount: 1000000n }) // Repay await aave.repay({ token: 'TOKEN_ADDRESS', amount: 1000000n }) ``` ### Common Parameters * `token` (`string`): ERC‑20 token address * `amount` (`number | bigint`): token amount in base units * `onBehalfOf` (`string`, optional): another address to act for (supply/borrow/repay) * `to` (`string`, optional): destination address (withdraw) > Note: `amount` must be > 0. Addresses must be valid/non‑zero. A provider is required for any write. Get started with WDK in a Node.js environment Get started with WDK's Lending Aave EVM Protocol API Get started with WDK's Lending Aave EVM Protocol usage *** ### Need Help? # Lending Aave EVM Overview (/sdk/lending-modules/lending-aave-evm) A lightweight package that lets EVM wallet accounts interact with Aave V3: supply, withdraw, borrow, repay, and read account data. It works with both standard EVM wallets and ERC‑4337 smart accounts. ## Features * **Supply/Withdraw**: Add and remove supported assets from Aave pools * **Borrow/Repay**: Borrow assets and repay debt * **Account Data**: Read collateral, debt, health factor, and more * **Quote System**: Estimate fees before sending transactions * **AA Support**: Works with standard EVM and ERC‑4337 smart accounts * **TypeScript Support**: Full TypeScript definitions ## Supported Networks Works on Aave V3 supported EVM networks (e.g., Ethereum, Arbitrum, Base, Optimism, Polygon, Avalanche, BNB, Celo, Gnosis, Linea, Scroll, Soneium, Sonic, ZkSync, Metis). A working RPC provider and correct token addresses are required. ## Wallet Compatibility * **Standard EVM Wallets**: `@tetherto/wdk-wallet-evm` * **ERC‑4337 Smart Accounts**: `@tetherto/wdk-wallet-evm-erc-4337` * **Read‑Only Accounts**: For quoting and reading account data without sending transactions ## Key Components * **Aave V3 Integration**: Supply, withdraw, borrow, repay primitives * **Quote Helpers**: `quoteSupply`, `quoteWithdraw`, `quoteBorrow`, `quoteRepay` * **Collateral Controls**: Toggle collateral usage; set user eMode ## Next Steps How to supply, withdraw, borrow and repay with Aave Service setup, account config, ERC‑4337 options Full API for Aave Protocol Evm methods and types # Lending Aave EVM Guides (/sdk/lending-modules/lending-aave-evm/usage) # Usage The [@tetherto/wdk-protocol-lending-aave-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-lending-aave-evm) module exposes Aave V3 supply, borrow, and repayment flows for EVM accounts. Follow the guides below for setup, day-to-day operations, and error handling. Install the package, create AaveProtocolEvm, and review prerequisites. Supply, withdraw, borrow, repay, quotes, ERC-4337, and account data. Handle failures and dispose wallet secrets when finished. Get started with WDK in a Node.js environment Networks and deployment settings for the Aave lending protocol Methods and parameters for AaveProtocolEvm # API Reference (/sdk/swap-modules/swap-velora-evm/api-reference) ## Class: VeloraProtocolEvm Main class for velora token swaps on EVM. ### Constructor ```javascript new VeloraProtocolEvm(account, config?) ``` Parameters: * `account`: `WalletAccountEvm | WalletAccountReadOnlyEvm | WalletAccountEvmErc4337 | WalletAccountReadOnlyEvmErc4337` * `config` (optional): * `swapMaxFee` (`bigint`): maximum total gas fee allowed (wei) Example: ```javascript const swap = new VeloraProtocolEvm(account, { swapMaxFee: 200000000000000n }) ``` ### Methods | Method | Description | Returns | | ----------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `swap(options, config?)` | Perform a token swap | `Promise<{hash: string, fee: bigint, tokenInAmount: bigint, tokenOutAmount: bigint, approveHash?: string, resetAllowanceHash?: string}>` | | `quoteSwap(options, config?)` | Get estimated fee and amounts | `Promise<{fee: bigint, tokenInAmount: bigint, tokenOutAmount: bigint}>` | *** ### `swap(options, config?)` Execute a swap via velora. Options: * `tokenIn` (`string`): Address of the ERC‑20 token to sell * `tokenOut` (`string`): Address of the ERC‑20 token to buy * `tokenInAmount` (`bigint`, optional): Exact input amount (base units) * `tokenOutAmount` (`bigint`, optional): Exact output amount (base units) * `to` (`string`, optional): Recipient address (defaults to account address) Config (ERC‑4337 only): * `paymasterToken` (`string`, optional): Token symbol/address for fee sponsorship * `swapMaxFee` (`bigint`, optional): Per‑swap fee cap (wei) Returns: * Standard account: `{ hash, fee, tokenInAmount, tokenOutAmount, approveHash?, resetAllowanceHash? }` * ERC‑4337 account: `{ hash, fee, tokenInAmount, tokenOutAmount }` (approve may be bundled) Notes: * On Ethereum mainnet, selling USD₮ may first set allowance to 0, then approve. * Requires a provider; requires a non read‑only account to send transactions. Example: ```javascript const tx = await swap.swap({ tokenIn: '0xdAC17F...ec7', // USD₮ tokenOut: '0xC02a...6Cc2', // WETH tokenInAmount: 1000000n }) ``` *** ### `quoteSwap(options, config?)` Get estimated fee and token in/out amounts. Options are the same as `swap`. Returns: `{ fee, tokenInAmount, tokenOutAmount }` Config (ERC‑4337 only): * `paymasterToken` (`string`, optional): Token symbol/address for fee sponsorship Works with read‑only accounts. Example: ```javascript const quote = await swap.quoteSwap({ tokenIn: '0xdAC17F...ec7', // USD₮ tokenOut: '0xC02a...6Cc2', // WETH tokenOutAmount: 500000000000000000n // 0.5 WETH }) ``` *** ## Errors Common errors include: * Insufficient liquidity / no route for pair * Fee exceeds `swapMaxFee` * Read‑only account cannot send swaps * Provider/RPC errors (invalid endpoint, network mismatch) *** ## Types * `swapMaxFee: bigint` — Upper bound for gas fees (wei) * `tokenInAmount/tokenOutAmount: bigint` — ERC‑20 base units * `paymasterToken: string` — token symbol or address (AA only) Get started with WDK in a Node.js environment Get started with WDK's Swap velora EVM Protocol configuration Get started with WDK's Swap velora EVM Protocol usage *** ## Need Help? # Configuration (/sdk/swap-modules/swap-velora-evm/configuration) ## Swap Service Configuration The `VeloraProtocolEvm` accepts a configuration object that defines fee controls and behavior: ```javascript import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' // Create wallet account first const account = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) // Create swap service with configuration const swapProtocol = new VeloraProtocolEvm(account, { swapMaxFee: 200000000000000n // Optional: Max swap fee in wei }) ``` ## Account Configuration The swap service uses the wallet account configuration for network access and signing: ```javascript import { WalletAccountEvm, WalletAccountReadOnlyEvm } from '@tetherto/wdk-wallet-evm' // Full access account const account = new WalletAccountEvm( seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' } ) // Read-only account (quotes only) const readOnly = new WalletAccountReadOnlyEvm( '0xYourAddress', { provider: 'https://ethereum-rpc.publicnode.com' } ) // Create swap service const swapProtocol = new VeloraProtocolEvm(account, { swapMaxFee: 200000000000000n }) ``` ## Configuration Options ### Swap Max Fee The `swapMaxFee` option sets an upper bound for total gas costs to prevent excessive fees. **Type:** `bigint` (optional)\ **Unit:** Wei **Examples:** ```javascript const config = { // Cap total gas fee to 0.0002 ETH (in wei) swapMaxFee: 200000000000000n, } // Usage example try { const result = await swapProtocol.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USD₮ (6 decimals) tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH (18 decimals) tokenInAmount: 1000000n }) } catch (error) { if (error.message.includes('max fee')) { console.error('Swap stopped: Fee too high') } } ``` ## ERC‑4337 (Account Abstraction) Configuration When using ERC‑4337 smart accounts (`@tetherto/wdk-wallet-evm-erc-4337`), you can override fee behavior per swap and specify a paymaster token: ```javascript import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337' const aa = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", { chainId: 1, provider: 'https://arb1.arbitrum.io/rpc', bundlerUrl: 'YOUR_BUNDLER_URL', paymasterUrl: 'YOUR_PAYMASTER_URL' }) const swapAA = new VeloraProtocolEvm(aa, { swapMaxFee: 200000000000000n }) const result = await swapAA.swap({ tokenIn: '0xTokenIn', tokenOut: '0xTokenOut', tokenInAmount: 1000000n }, { paymasterToken: 'USDT', // Token used to pay for gas swapMaxFee: 200000000000000n // Per‑swap override }) ``` ### Paymaster Token (ERC‑4337) The `paymasterToken` option indicates which token the paymaster should use to sponsor gas. **Type:** `string` (optional)\ **Format:** Token symbol or address **Example:** ```javascript const result = await swapAA.swap({ tokenIn: '0xdAC17F...ec7', tokenOut: '0xC02a...6Cc2', // WETH tokenInAmount: 1000000n }, { paymasterToken: 'USDT' }) ``` ## Network Support velora supports multiple EVM networks (e.g., Ethereum, Polygon, Arbitrum). Ensure your account is configured with a valid provider for the target network. ```javascript // Ethereum Mainnet const eth = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) // Polygon const polygon = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://polygon-bor-rpc.publicnode.com' }) ``` ## Swap Options When calling `swap`, provide the swap parameters: ```javascript const swapOptions = { tokenIn: '0xTokenIn', // ERC‑20 to sell tokenOut: '0xTokenOut', // ERC‑20 to buy tokenInAmount: 1000000n, // exact input (base units) // OR // tokenOutAmount: 1000000n, // exact output (base units) to: '0xRecipient' // optional recipient (defaults to your address) } const result = await swapProtocol.swap(swapOptions) ``` ### Parameters * `tokenIn` (`string`): ERC‑20 address to sell * `tokenOut` (`string`): ERC‑20 address to buy * `tokenInAmount` (`bigint`, optional): exact input amount in token base units * `tokenOutAmount` (`bigint`, optional): exact output amount in token base units * `to` (`string`, optional): recipient address (defaults to account address) > Note: Use either `tokenInAmount` OR `tokenOutAmount`, not both. Get started with WDK in a Node.js environment Get started with WDK's velora Swap Protocol API Get started with WDK's velora Swap Protocol usage *** ## Need Help? # Swap velora EVM Overview (/sdk/swap-modules/swap-velora-evm) A lightweight package that lets EVM wallet accounts swap tokens using the velora aggregator. It provides a clean SDK for token swaps on EVM chains and works with both standard wallets and ERC‑4337 smart accounts. ## Features * **Token Swapping**: Execute token swaps through velora on supported EVM networks * **Account Abstraction**: Compatible with standard EVM accounts and ERC‑4337 smart accounts * **Fee Controls**: Optional `swapMaxFee` to cap gas costs * **Allowance Safety**: Handles USD₮ mainnet pattern (reset allowance to 0 before approve) * **Provider Flexibility**: Works with JSON‑RPC URLs and EIP‑1193 providers * **TypeScript Support**: Full TypeScript definitions included ## Supported Networks Works with EVM networks supported by velora (e.g., Ethereum, Polygon, Arbitrum, etc.). A working RPC provider is required. ## Wallet Compatibility The swap service supports multiple EVM wallet types: * **Standard EVM Wallets**: `@tetherto/wdk-wallet-evm` accounts * **ERC‑4337 Smart Accounts**: `@tetherto/wdk-wallet-evm-erc-4337` accounts with bundler/paymaster * **Read‑Only Accounts**: For quoting swaps without sending transactions ## Key Components * **velora Integration**: Uses velora aggregator for routing and quotes * **Quote System**: Pre‑transaction fee and amount estimation via `quoteSwap` * **AA Integration**: Optional paymaster token and fee cap overrides when using ERC‑4337 * **Allowance Management**: Approve flow handled automatically when required ## Next Steps Get started with WDK in a Node.js environment Get started with WDK's velora Swap Protocol configuration Get started with WDK's velora Swap Protocol API Get started with WDK's velora Swap Protocol usage *** ## Need Help? # Swap velora EVM Guides (/sdk/swap-modules/swap-velora-evm/usage) # Usage The [@tetherto/wdk-protocol-swap-velora-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-swap-velora-evm) module routes ERC-20 swaps on EVM chains through Velora. Use the guides below for setup, execution, quotes, and error handling. Install the package, create VeloraProtocolEvm, and review supported networks. Exact-input and exact-output swaps, including ERC-4337 smart accounts. Quote before swapping and compare fees to your max fee cap. Handle swap and quote failures and dispose wallet state safely. Get started with WDK in a Node.js environment RPC, fee limits, and environment settings for the Velora swap protocol Methods, options, and error notes for VeloraProtocolEvm # Wallet BTC API Reference (/sdk/wallet-modules/wallet-btc/api-reference) # API Reference ## Table of Contents | Class | Description | Methods | | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [WalletManagerBtc](#walletmanagerbtc) | Main class for managing Bitcoin wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) | | [WalletAccountBtc](#walletaccountbtc) | Individual Bitcoin wallet account implementation. Implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) | | [WalletAccountReadOnlyBtc](#walletaccountreadonlybtc) | Read-only Bitcoin wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-2), [Methods](#methods-2) | | [ElectrumTcp](#electrumtcp) | Standard TCP Electrum client. Implements `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\` | | `getAccountByPath(path)` | Returns a wallet account at the specified derivation path | `Promise\` | | `getFeeRates()` | Returns current fee rates for transactions | `Promise\<{normal: bigint, fast: bigint}\>` | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory and closing internal Electrum connections | `void` | ##### `getAccount(index)` Returns a wallet account at the specified index using BIP-84 (default) or BIP-44 derivation. **Parameters:** * `index` (number, optional): The index of the account to get (default: 0) **Returns:** `Promise\` - The wallet account **Example:** ```javascript // Returns the account with derivation path: // For mainnet (bitcoin): m/84'/0'/0'/0/1 // For testnet or regtest: m/84'/1'/0'/0/1 const account = await wallet.getAccount(1) ``` ##### `getAccountByPath(path)` Returns a wallet account at the specified derivation path. **Parameters:** * `path` (string): The derivation path (e.g., "0'/0/0") **Returns:** `Promise\` - The wallet account **Example:** ```javascript // Returns the account with derivation path: // For mainnet (bitcoin): m/84'/0'/0'/0/1 // For testnet or regtest: m/84'/1'/0'/0/1 const account = await wallet.getAccountByPath("0'/0/1") ``` ##### `getFeeRates()` Returns current fee rates from mempool.space API. **Returns:** `Promise\<{normal: bigint, fast: bigint}\>` - Object containing fee rates in sat/vB * `normal`: Standard fee rate for confirmation within \~1 hour * `fast`: Higher fee rate for faster confirmation **Example:** ```javascript const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sat/vB') console.log('Fast fee rate:', feeRates.fast, 'sat/vB') ``` ##### `dispose()` Disposes all wallet accounts, clears sensitive data from memory, and closes internal Electrum connections. **Returns:** `void` **Example:** ```javascript wallet.dispose() ``` ## WalletAccountBtc Represents an individual Bitcoin wallet account. Extends `WalletAccountReadOnlyBtc` and implements `IWalletAccount` from `@tetherto/wdk-wallet`. #### Constructor ```javascript new WalletAccountBtc(seed, path, config) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `path` (string): Derivation path suffix (e.g., "0'/0/0") * `config` (BtcWalletConfig, optional): Configuration object * `client` (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\` | | `getBalance()` | Returns the total account balance in satoshis, including unconfirmed funds when present | `Promise\` | | `sendTransaction(options, timeoutMs?)` | Sends a Bitcoin transaction and optionally polls until spent inputs disappear from unspent outputs | `Promise\<{hash: string, fee: bigint}\>` | | `quoteSendTransaction(options)` | Estimates the fee for a transaction | `Promise\<{fee: bigint}\>` | | `getTransfers(options?)` | Returns the account's transfer history | `Promise\` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | | `getMaxSpendable()` | Returns the maximum spendable amount | `Promise\` | | `sign(message)` | Signs a message with the account's private key | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `toReadOnlyAccount()` | Creates a read-only version of this account | `Promise\` | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | ##### `getAddress()` Returns the account's Bitcoin address (Native SegWit bech32 by default, or legacy if using BIP-44). **Returns:** `Promise\` - The Bitcoin address **Example:** ```javascript const address = await account.getAddress() console.log('Address:', address) // bc1q... (BIP-84) or 1... (BIP-44) ``` ##### `getBalance()` Returns the account's total balance in satoshis, including unconfirmed funds when present. **Returns:** `Promise\` - Balance in satoshis **Example:** ```javascript const balance = await account.getBalance() console.log('Balance:', balance, 'satoshis') ``` ##### `sendTransaction(options, timeoutMs?)` Sends a Bitcoin transaction to a single recipient and optionally polls after broadcast until spent inputs disappear from the unspent-output set. **Parameters:** * `options` (BtcTransaction): Transaction options * `to` (string): Recipient's Bitcoin address * `value` (number | bigint): Amount in satoshis * `feeRate` (number | bigint, optional): Fee rate in sat/vB. If provided, overrides the fee rate estimated from the blockchain. * `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1) * `timeoutMs` (number, optional): Maximum milliseconds to poll after broadcast before returning (default: 10000) **Returns:** `Promise\<{hash: string, fee: bigint}\>` * `hash`: Transaction hash * `fee`: Transaction fee in satoshis **Example:** ```javascript const result = await account.sendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 50000n }) console.log('Transaction hash:', result.hash) console.log('Fee:', result.fee, 'satoshis') ``` ##### `quoteSendTransaction(options)` Estimates the fee for a transaction without broadcasting it. **Parameters:** * `options` (BtcTransaction): Same as sendTransaction options * `to` (string): Recipient's Bitcoin address * `value` (number | bigint): Amount in satoshis * `feeRate` (number | bigint, optional): Fee rate in sat/vB. If provided, overrides the fee rate estimated from the blockchain. * `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1) **Returns:** `Promise\<{fee: bigint}\>` * `fee`: Estimated transaction fee in satoshis **Example:** ```javascript const quote = await account.quoteSendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 50000n }) console.log('Estimated fee:', quote.fee, 'satoshis') ``` ##### `getTransfers(options?)` Returns the account's transfer history with detailed transaction information. **Parameters:** * `options` (object, optional): Filter options * `direction` (string, optional): 'incoming', 'outgoing', or 'all' (default: 'all') * `limit` (number, optional): Maximum number of transfers (default: 10) * `skip` (number, optional): Number of transfers to skip (default: 0) **Returns:** `Promise\` - Array of transfer objects * `txid`: Transaction ID * `address`: Account's own address * `vout`: Output index in the transaction * `height`: Block height (0 if unconfirmed) * `value`: Transfer value in satoshis (bigint) * `direction`: 'incoming' or 'outgoing' * `fee`: Transaction fee in satoshis (bigint, for outgoing transfers) * `recipient`: Receiving address (for outgoing transfers) **Example:** ```javascript const transfers = await account.getTransfers({ direction: 'incoming', limit: 5 }) console.log('Recent incoming transfers:', transfers) ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been included in a block. **Parameters:** * `hash` (string): The transaction hash (64 hex characters) **Returns:** `Promise\` - The receipt, or null if the transaction has not been included in a block yet. **Example:** ```javascript const receipt = await account.getTransactionReceipt('abc123...') if (receipt) { console.log('Transaction confirmed') } ``` ##### `getMaxSpendable()` Returns the maximum spendable amount that can be sent in a single transaction. The maximum spendable amount can differ from the wallet's total balance for several reasons: * **Transaction fees**: Fees are subtracted from the total balance * **Uneconomic UTXOs**: Small UTXOs where the fee to spend them exceeds their value are excluded * **UTXO limit**: A transaction can include at most 200 inputs. Wallets with more UTXOs cannot spend their full balance in a single transaction. * **Dust limit**: Outputs below the dust threshold (294 sats for SegWit, 546 sats for legacy) cannot be created **Returns:** `Promise\` - Maximum spendable result * `amount`: Maximum spendable amount in satoshis (bigint) * `fee`: Estimated network fee in satoshis (bigint) * `changeValue`: Estimated change value in satoshis (bigint) **Example:** ```javascript const { amount, fee } = await account.getMaxSpendable() console.log('Max spendable:', amount, 'satoshis') console.log('Estimated fee:', fee, 'satoshis') ``` ##### `sign(message)` Signs a message using the account's private key. **Parameters:** * `message` (string): Message to sign **Returns:** `Promise\` - Signature as base64 string **Example:** ```javascript const signature = await account.sign('Hello Bitcoin!') console.log('Signature:', signature) ``` ##### `verify(message, signature)` Verifies a message signature using the account's public key. **Parameters:** * `message` (string): Original message * `signature` (string): Signature as base64 string **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const isValid = await account.verify('Hello Bitcoin!', signature) console.log('Signature valid:', isValid) ``` ##### `toReadOnlyAccount()` Creates a read-only version of this account that can query balances and transactions but cannot sign or send transactions. **Returns:** `Promise\` - Read-only account instance **Example:** ```javascript const readOnlyAccount = await account.toReadOnlyAccount() const balance = await readOnlyAccount.getBalance() ``` ##### `dispose()` Disposes the wallet account, securely erasing the private key from memory and closing the Electrum connection. **Returns:** `void` **Example:** ```javascript account.dispose() // Private key is now securely wiped from memory ``` #### Properties | Property | Type | Description | | --------- | --------- | ------------------------------------------- | | `index` | `number` | The derivation path's index of this account | | `path` | `string` | The full derivation path of this account | | `keyPair` | `KeyPair` | The account's public and private key pair | ## 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\` | | `getBalance()` | Returns the total account balance in satoshis, including unconfirmed funds when present | `Promise\` | | `quoteSendTransaction(options)` | Estimates the fee for a transaction | `Promise\<{fee: bigint}\>` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | | `getMaxSpendable()` | Returns the maximum spendable amount | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `dispose()` | Closes any internal Electrum connection | `void` | ##### `getAddress()` Returns the account's Bitcoin address. **Returns:** `Promise\` - The Bitcoin address **Example:** ```javascript const address = await readOnlyAccount.getAddress() console.log('Address:', address) ``` ##### `getBalance()` Returns the account's confirmed balance in satoshis. **Returns:** `Promise\` - Balance in satoshis **Example:** ```javascript const balance = await readOnlyAccount.getBalance() console.log('Balance:', balance, 'satoshis') ``` ##### `quoteSendTransaction(options)` Estimates the fee for a transaction without broadcasting it. **Parameters:** * `options` (BtcTransaction): Transaction options * `to` (string): Recipient's Bitcoin address * `value` (number | bigint): Amount in satoshis * `feeRate` (number | bigint, optional): Fee rate in sat/vB * `confirmationTarget` (number, optional): Target blocks for confirmation (default: 1) **Returns:** `Promise\<{fee: bigint}\>` - Estimated fee in satoshis **Example:** ```javascript const quote = await readOnlyAccount.quoteSendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 50000n }) console.log('Estimated fee:', quote.fee, 'satoshis') ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been included in a block. **Parameters:** * `hash` (string): The transaction hash **Returns:** `Promise\` - The receipt, or null if not yet included **Example:** ```javascript const receipt = await readOnlyAccount.getTransactionReceipt('abc123...') if (receipt) { console.log('Transaction confirmed') } ``` ##### `getMaxSpendable()` Returns the maximum spendable amount that can be sent in a single transaction. **Returns:** `Promise\` - Maximum spendable result * `amount`: Maximum spendable amount in satoshis (bigint) * `fee`: Estimated network fee in satoshis (bigint) * `changeValue`: Estimated change value in satoshis (bigint) **Example:** ```javascript const { amount, fee } = await readOnlyAccount.getMaxSpendable() console.log('Max spendable:', amount, 'satoshis') ``` ##### `verify(message, signature)` Verifies a message signature using the account's public key. **Parameters:** * `message` (string): Original message * `signature` (string): Signature as base64 string **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verify('Hello Bitcoin!', signature) console.log('Signature valid:', isValid) ``` ##### `dispose()` Closes any internal Electrum connection owned by this account. If a [`client`](/sdk/wallet-modules/wallet-btc/configuration#client) was provided via config, the connection is left open (the caller manages its lifecycle). **Returns:** `void` **Example:** ```javascript readOnlyAccount.dispose() ``` ## ElectrumTcp Electrum client using TCP transport. Standard for command-line and server-side environments. Implements `IElectrumClient`. #### Constructor ```javascript new ElectrumTcp(config) ``` **Parameters:** * `config` (`Omit`): Configuration options * `host` (string): Electrum server hostname * `port` (number): Electrum server port ## ElectrumTls Electrum client using TLS transport. Implements `IElectrumClient`. #### Constructor ```javascript new ElectrumTls(config) ``` **Parameters:** * `config` (`Omit`): Configuration options * `host` (string): Electrum server hostname * `port` (number): Electrum server port ## ElectrumSsl Electrum client using SSL transport. Implements `IElectrumClient`. #### Constructor ```javascript new ElectrumSsl(config) ``` **Parameters:** * `config` (`Omit`): Configuration options * `host` (string): Electrum server hostname * `port` (number): Electrum server port ## ElectrumWs Electrum client using WebSocket transport. Compatible with browser environments where TCP sockets are not available. Implements `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\` | | `close()` | Closes the connection | `Promise\` | | `reconnect()` | Recreates the underlying socket and reinitializes the session | `Promise\` | | `getBalance(scripthash)` | Returns balance for a script hash | `Promise\` | | `listUnspent(scripthash)` | Returns UTXOs for a script hash | `Promise\` | | `getHistory(scripthash)` | Returns transaction history | `Promise\` | | `getTransaction(txHash)` | Returns raw transaction hex | `Promise\` | | `broadcast(rawTx)` | Broadcasts raw transaction | `Promise\` | | `estimateFee(blocks)` | Returns estimated fee rate | `Promise\` | ## Types ### BtcTransaction ```typescript interface BtcTransaction { to: string // The transaction's recipient value: number | bigint // The amount of bitcoins to send to the recipient (in satoshis) confirmationTarget?: number // Optional confirmation target in blocks (default: 1) feeRate?: number | bigint // Optional fee rate in satoshis per virtual byte } ``` ### TransactionResult ```typescript interface TransactionResult { hash: string // Transaction hash/ID fee: bigint // Transaction fee in satoshis } ``` ### FeeRates ```typescript interface FeeRates { normal: bigint // Standard fee rate (sat/vB) for ~1 hour confirmation fast: bigint // Higher fee rate (sat/vB) for faster confirmation } ``` ### BtcTransfer ```typescript interface BtcTransfer { txid: string // The transaction's ID address: string // The user's own address vout: number // The index of the output in the transaction height: number // The block height (if unconfirmed, 0) value: bigint // The value of the transfer (in satoshis) direction: 'incoming' | 'outgoing' // The direction of the transfer fee?: bigint // The fee paid for the full transaction (in satoshis) recipient?: string // The receiving address for outgoing transfers } ``` ### BtcMaxSpendableResult ```typescript interface BtcMaxSpendableResult { amount: bigint // The maximum spendable amount in satoshis fee: bigint // The estimated network fee in satoshis changeValue: bigint // The estimated change value in satoshis } ``` ### KeyPair ```typescript interface KeyPair { publicKey: Uint8Array // Public key bytes 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 close(): Promise reconnect(): Promise getBalance(scripthash: string): Promise listUnspent(scripthash: string): Promise getHistory(scripthash: string): Promise getTransaction(txHash: string): Promise broadcast(rawTx: string): Promise estimateFee(blocks: number): Promise } ``` ### ElectrumBalance ```typescript interface ElectrumBalance { confirmed: number // Confirmed balance in satoshis unconfirmed?: number // Unconfirmed balance in satoshis } ``` ### ElectrumUtxo ```typescript interface ElectrumUtxo { tx_hash: string // The transaction hash containing this UTXO tx_pos: number // The output index within the transaction value: number // The UTXO value in satoshis height?: number // The block height (0 if unconfirmed) } ``` ### ElectrumHistoryItem ```typescript interface ElectrumHistoryItem { tx_hash: string // The transaction hash height: number // The block height (0 or negative if unconfirmed) } ``` ### MempoolElectrumConfig ```typescript interface MempoolElectrumConfig { host: string // Electrum server hostname port: number // Electrum server port protocol?: 'tcp' | 'ssl' | 'tls' // Transport protocol (default: 'tcp') maxRetry?: number // Maximum reconnection attempts (default: 2) retryPeriod?: number // Delay between reconnection attempts in ms (default: 1000) pingPeriod?: number // Delay between keep-alive pings in ms (default: 120000) callback?: (err: Error | null) => void // Called when all retries are exhausted } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Bitcoin Wallet Usage Get started with WDK's Bitcoin Wallet Configuration *** ### Need Help? # Configuration (/sdk/wallet-modules/wallet-btc/configuration) ## Wallet Configuration ```javascript import WalletManagerBtc, { 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](../../../resources/concepts#mainnet) (production) * `"testnet"` - Bitcoin [testnet](../../../resources/concepts#testnet) (development) * `"regtest"` - Bitcoin [regtest](../../../resources/concepts#regtest) (local testing) **Default:** `"bitcoin"` **Example:** ```javascript const config = { network: 'testnet' // Use testnet for development } ``` ### BIP The `bip` option specifies the address type derivation standard to use. **Type:** `number` **Values:** * `84` - [BIP-84](../../../resources/concepts#bip-84-native-segwit) (P2WPKH / Native SegWit) - addresses start with `bc1` (mainnet) or `tb1` (testnet) * `44` - [BIP-44](../../../resources/concepts#bip-44-multi-account-hierarchy) (P2PKH / Legacy) - addresses start with `1` (mainnet) or `m`/`n` (testnet) **Default:** `84` **Example:** ```javascript // Use legacy addresses const config = { bip: 44 } ``` ## Electrum Server Configuration **Important**: While the package defaults to `electrum.blockstream.info:50001` for convenience, **we strongly recommend configuring your own Electrum server** for production use. ### Recommended Approach **For Production:** * Set up your own Fulcrum server for optimal performance and reliability * Use recent Fulcrum versions that support pagination for high-transaction addresses **For Development/Testing:** * `fulcrum.frznode.com:50001` - Generally faster than default * `electrum.blockstream.info:50001` - Default fallback ### Configuration Examples ```javascript import { ElectrumTcp, ElectrumTls } from '@tetherto/wdk-wallet-btc' // Production with custom Fulcrum server const productionClient = new ElectrumTls({ host: 'your-fulcrum-server.com', port: 50002 }) const productionWallet = new WalletManagerBtc(seedPhrase, { client: productionClient, network: 'bitcoin' }) // Development with alternative public server const developmentClient = new ElectrumTcp({ host: 'fulcrum.frznode.com', port: 50001 }) const developmentWallet = new WalletManagerBtc(seedPhrase, { client: developmentClient, network: 'bitcoin' }) ``` ### Network-Specific Configuration #### Bitcoin Mainnet ```javascript import { ElectrumTcp } from '@tetherto/wdk-wallet-btc' const client = new ElectrumTcp({ host: 'electrum.blockstream.info', // Or your own server port: 50001 }) const wallet = new WalletManagerBtc(seedPhrase, { client, network: 'bitcoin' }) ``` #### Bitcoin Testnet ```javascript import { ElectrumTcp } from '@tetherto/wdk-wallet-btc' const client = new ElectrumTcp({ host: 'testnet.hsmiths.com', // Example testnet server port: 53011 }) const wallet = new WalletManagerBtc(seedPhrase, { client, network: 'testnet' }) ``` #### Bitcoin Regtest ```javascript import { ElectrumTcp } from '@tetherto/wdk-wallet-btc' const client = new ElectrumTcp({ host: 'localhost', // Local regtest node port: 50001 }) const wallet = new WalletManagerBtc(seedPhrase, { client, network: 'regtest' }) ``` ## Derivation Paths Bitcoin wallet addresses are derived using BIP-32 hierarchical deterministic paths: ### BIP-84 (Native SegWit) - Default * `m/84'/0'/0'/0/0` for mainnet account 0, address 0 * `m/84'/1'/0'/0/0` for testnet/regtest account 0, address 0 Addresses start with `bc1` (mainnet) or `tb1` (testnet). ### BIP-44 (Legacy) * `m/44'/0'/0'/0/0` for mainnet account 0, address 0 * `m/44'/1'/0'/0/0` for testnet/regtest account 0, address 0 Addresses start with `1` (mainnet) or `m`/`n` (testnet). **Default Derivation Path Change in v1.0.0-beta.4+** The default derivation path was updated in v1.0.0-beta.4 to use BIP-84 (Native SegWit) instead of BIP-44 (Legacy): * **Previous path** (\<= v1.0.0-beta.3): `m/44'/0'/0'/0/{index}` (Legacy addresses) * **Current path** (v1.0.0-beta.4+): `m/84'/0'/0'/0/{index}` (Native SegWit addresses) If you're upgrading from an earlier version, existing wallets created with the old path will generate different addresses. Make sure to migrate any existing wallets or use the old path explicitly if needed for compatibility. Use [`getAccountByPath`](./api-reference) to supply an explicit derivation path when importing or recreating legacy wallets. ## Complete Configuration Example ```javascript import WalletManagerBtc, { ElectrumTls } from '@tetherto/wdk-wallet-btc' // Create Electrum client const client = new ElectrumTls({ host: 'your-electrum-server.com', // Replace with your server port: 50002 }) // Create wallet manager with configuration const wallet = new WalletManagerBtc(seedPhrase, { client, network: 'bitcoin', bip: 84 // Native SegWit (default) }) // Get accounts (inherit configuration from manager) const account0 = await wallet.getAccount(0) const account1 = await wallet.getAccount(1) const customAccount = await wallet.getAccountByPath("0'/0/5") // Clean up when done wallet.dispose() ``` ## Performance Considerations **Electrum Server Performance:** * Public servers like Blockstream's can be significantly slower * Addresses with many transactions may cause timeouts * Custom Fulcrum servers provide better performance and reliability * Consider server location and network latency **Configuration Tips:** * Use `fulcrum.frznode.com` for better development performance * Set up your own Fulcrum server for production * Monitor connection stability and implement retry logic * Consider using multiple backup servers Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's BTC Wallet Usage Get started with WDK's BTC Wallet API *** ## Need Help? # Wallet BTC Overview (/sdk/wallet-modules/wallet-btc) A simple and secure package to manage BIP-84 (SegWit) and BIP-44 (Legacy) wallets for the Bitcoin blockchain. This package provides a clean API for creating, managing, and interacting with Bitcoin wallets using BIP-39 seed phrases and Bitcoin-specific derivation paths. **Default Derivation Path Change in v1.0.0-beta.4+** The default derivation path was updated in v1.0.0-beta.4 to use BIP-84 (Native SegWit) instead of BIP-44 (Legacy): * **Previous path** (\<= v1.0.0-beta.3): `m/44'/0'/0'/0/{index}` (Legacy addresses) * **Current path** (v1.0.0-beta.4+): `m/84'/0'/0'/0/{index}` (Native SegWit addresses) If you're upgrading from an earlier version, existing wallets created with the old path will generate different addresses. Make sure to migrate any existing wallets or use the old path explicitly if needed for compatibility. Use [`getAccountByPath`](./api-reference) to supply an explicit derivation path when importing or recreating legacy wallets. ## Features * **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases * **Bitcoin Derivation Paths**: Support for BIP-84 (Native SegWit, default) and BIP-44 (Legacy) derivation paths * **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase * **Address Types Support**: Generate Native SegWit (P2WPKH) addresses by default, with Legacy (P2PKH) support via configuration * **UTXO Management**: Track and manage unspent transaction outputs * **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 Get started with WDK in a Node.js environment Get started with WDK's Bitcoin Wallet configuration Get started with WDK's Bitcoin Wallet API Get started with WDK's Bitcoin Wallet usage *** ## Need Help? # Wallet BTC Usage (/sdk/wallet-modules/wallet-btc/usage) # Usage The `@tetherto/wdk-wallet-btc` module provides wallet management for the Bitcoin blockchain. Install the package and create your first wallet. Work with multiple accounts and custom derivation paths. Query native BTC balances for owned and read-only accounts. Send Bitcoin and estimate transaction fees. Retrieve and filter transfer history. Sign messages and verify signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Bitcoin Wallet Configuration Get started with WDK's Bitcoin Wallet API *** ### Need Help? # Wallet EVM API Reference (/sdk/wallet-modules/wallet-evm/api-reference) ## Table of Contents | Class | Description | Methods | | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [WalletManagerEvm](#walletmanagerevm) | Main class for managing EVM wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) | | [WalletAccountEvm](#walletaccountevm) | Individual EVM wallet account implementation. Extends `WalletAccountReadOnlyEvm` and implements `IWalletAccount` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) | | [WalletAccountReadOnlyEvm](#walletaccountreadonlyevm) | Read-only EVM wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-2), [Methods](#methods-2) | ## WalletManagerEvm The main class for managing EVM wallets.\ Extends `WalletManager` from `@tetherto/wdk-wallet`. ### Constructor ```javascript new WalletManagerEvm(seed, config?) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `config` (object, optional): Configuration object * `provider` (string | Eip1193Provider, 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\` | - | | `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise\` | - | | `getFeeRates()` | Returns current fee rates for transactions | `Promise\<{normal: bigint, fast: bigint}\>` | If no provider is set | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | - | ### Properties | Property | Type | Description | | -------- | ------------ | ----------------------- | | `seed` | `Uint8Array` | The wallet's seed bytes | #### `getRandomSeedPhrase(wordCount?)` (static) Returns a random BIP-39 seed phrase. **Parameters:** * `wordCount` (12 | 24, optional): The number of words in the seed phrase (default: 12) **Returns:** `string` - The seed phrase **Example:** ```javascript const seedPhrase = WalletManagerEvm.getRandomSeedPhrase() console.log('Seed phrase:', seedPhrase) // 12 words const longSeedPhrase = WalletManagerEvm.getRandomSeedPhrase(24) console.log('Long seed phrase:', longSeedPhrase) // 24 words ``` #### `isValidSeedPhrase(seedPhrase)` (static) Checks if a seed phrase is valid. **Parameters:** * `seedPhrase` (string): The seed phrase to validate **Returns:** `boolean` - True if the seed phrase is valid **Example:** ```javascript const isValid = WalletManagerEvm.isValidSeedPhrase('abandon abandon abandon ...') console.log('Valid:', isValid) ``` #### `getAccount(index?)` Returns a wallet account at the specified index following BIP-44 standard. **Parameters:** * `index` (number, optional): The index of the account to get (default: 0) **Returns:** `Promise\` - The wallet account **Example:** ```javascript // Get first account (index 0) const account = await wallet.getAccount(0) // Get second account (index 1) const account1 = await wallet.getAccount(1) // Get first account (default) const defaultAccount = await wallet.getAccount() ``` #### `getAccountByPath(path)` Returns a wallet account at the specified BIP-44 derivation path. **Parameters:** * `path` (string): The derivation path (e.g., "0'/0/0") **Returns:** `Promise\` - The wallet account **Example:** ```javascript // Full path: m/44'/60'/0'/0/1 const account = await wallet.getAccountByPath("0'/0/1") // Custom path: m/44'/60'/0'/0/5 const customAccount = await wallet.getAccountByPath("0'/0/5") ``` #### `getFeeRates()` Returns current fee rates based on network conditions with predefined multipliers. **Returns:** `Promise\<{normal: bigint, fast: bigint}\>` - Fee rates in wei * `normal`: Base fee × 1.1 (10% above base) * `fast`: Base fee × 2.0 (100% above base) **Throws:** Error if no provider is configured **Example:** ```javascript const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'wei') console.log('Fast fee rate:', feeRates.fast, 'wei') // Use in transaction const result = await account.sendTransaction({ to: '0x...', value: 1000000000000000000n, maxFeePerGas: feeRates.fast }) ``` #### `dispose()` Disposes all wallet accounts, clearing private keys from memory. **Example:** ```javascript // Clean up when done wallet.dispose() ``` ## WalletAccountEvm Represents an individual wallet account. Extends `WalletAccountReadOnlyEvm` and implements `IWalletAccount` from `@tetherto/wdk-wallet`. ### Constructor ```javascript new WalletAccountEvm(seed, path, config?) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `path` (string): BIP-44 derivation path (e.g., "0'/0/0") * `config` (object, optional): Configuration object * `provider` (string | Eip1193Provider, 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\` | - | | `sign(message)` | Signs a message using the account's private key | `Promise\` | - | | `signTypedData(typedData)` | Signs typed data according to EIP-712 | `Promise\` | - | | `verify(message, signature)` | Verifies a message signature | `Promise\` | - | | `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712) | `Promise\` | - | | `sendTransaction(tx)` | Sends an EVM transaction | `Promise\<{hash: string, fee: bigint}\>` | If no provider | | `quoteSendTransaction(tx)` | Estimates the fee for an EVM transaction | `Promise\<{fee: bigint}\>` | If no provider | | `transfer(options)` | Transfers ERC20 tokens to another address | `Promise\<{hash: string, fee: bigint}\>` | If no provider or fee exceeds max | | `quoteTransfer(options)` | Estimates the fee for an ERC20 transfer | `Promise\<{fee: bigint}\>` | If no provider | | `getBalance()` | Returns the native token balance (in wei) | `Promise\` | If no provider | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise\` | If no provider | | `getTokenBalances(tokenAddresses)` | Returns the balances of multiple ERC20 tokens in a single call | `Promise\` | If no provider | | `approve(options)` | Approves a spender to spend tokens | `Promise\<{hash: string, fee: bigint}\>` | If no provider | | `getAllowance(token, spender)` | Returns current allowance for a spender | `Promise\` | If no provider | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | If no provider | | `toReadOnlyAccount()` | Returns a read-only copy of the account | `Promise\` | - | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | - | #### `getAddress()` Returns the account's Ethereum address. **Returns:** `Promise\` - Checksummed Ethereum address **Example:** ```javascript const address = await account.getAddress() console.log('Account address:', address) // 0x... ``` #### `sign(message)` Signs a message using the account's private key. **Parameters:** * `message` (string): The message to sign **Returns:** `Promise\` - The message signature **Example:** ```javascript const message = 'Hello, Ethereum!' const signature = await account.sign(message) console.log('Signature:', signature) ``` #### `signTypedData(typedData)` Signs typed data according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712). **Parameters:** * `typedData` (TypedData): The typed data to sign * `domain` (TypedDataDomain): The domain separator (name, version, chainId, verifyingContract) * `types` (`Record`): The type definitions * `message` (`Record`): The message data **Returns:** `Promise\` - The typed data signature **Example:** ```javascript const typedData = { domain: { name: 'MyDApp', version: '1', chainId: 1, verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC' }, types: { Mail: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'contents', type: 'string' } ] }, message: { from: '0xAlice...', to: '0xBob...', contents: 'Hello Bob!' } } const signature = await account.signTypedData(typedData) console.log('EIP-712 Signature:', signature) ``` #### `verify(message, signature)` Verifies a message signature against the account's address. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const message = 'Hello, Ethereum!' const signature = await account.sign(message) const isValid = await account.verify(message, signature) console.log('Signature valid:', isValid) // true ``` #### `verifyTypedData(typedData, signature)` Verifies a typed data signature according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712). **Parameters:** * `typedData` (TypedData): The typed data that was signed * `signature` (string): The signature to verify **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const isValid = await account.verifyTypedData(typedData, signature) console.log('Typed data signature valid:', isValid) // true ``` #### `sendTransaction(tx)` Sends an EVM transaction and returns the result with hash and fee. **Parameters:** * `tx` (EvmTransaction): The transaction object * `to` (string): Recipient address * `value` (number | bigint): Amount in wei * `data` (string, optional): Transaction data in hex format * `gasLimit` (number | bigint, optional): Maximum gas units * `gasPrice` (number | bigint, optional): Legacy gas price in wei * `maxFeePerGas` (number | bigint, optional): EIP-1559 max fee per gas in wei * `maxPriorityFeePerGas` (number | bigint, optional): EIP-1559 max priority fee per gas in wei **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', // USD₮ recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000 // 1 USD₮ (6 decimals) }) console.log('Transfer hash:', result.hash) console.log('Transfer fee:', result.fee, 'wei') ``` #### `quoteTransfer(options)` Estimates the fee for an ERC20 token transfer. **Parameters:** * `options` (TransferOptions): Transfer options (same as transfer) **Returns:** `Promise\<{fee: bigint}\>` - Fee estimate in wei **Throws:** Error if no provider is configured **Example:** ```javascript const quote = await account.quoteTransfer({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000 }) console.log('Transfer fee estimate:', quote.fee, 'wei') ``` #### `getBalance()` Returns the native token balance (ETH, MATIC, BNB, etc.). **Returns:** `Promise\` - Balance in wei **Throws:** Error if no provider is configured **Example:** ```javascript const balance = await account.getBalance() console.log('Balance:', balance, 'wei') console.log('Balance in ETH:', balance / 1000000000000000000) ``` #### `getTokenBalance(tokenAddress)` Returns the balance of a specific ERC20 token using the balanceOf function. **Parameters:** * `tokenAddress` (string): The ERC20 token contract address **Returns:** `Promise\` - Token balance in base units **Throws:** Error if no provider is configured **Example:** ```javascript // Get USD₮ 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 the balances of multiple ERC20 tokens in a single call. More efficient than calling `getTokenBalance` for each token individually. **Parameters:** * `tokenAddresses` (string\[]): Array of ERC20 token contract addresses **Returns:** `Promise\` - Array of token balances in base units, in the same order as the input addresses **Throws:** Error if no provider is configured **Example:** ```javascript const balances = await account.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USD₮ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC '0x6B175474E89094C44Da98b954EedeAC495271d0F' // DAI ]) console.log('USDT balance:', balances[0]) console.log('USDC balance:', balances[1]) console.log('DAI balance:', balances[2]) ``` #### `approve(options)` Approves a specific amount of tokens to a spender. **Parameters:** * `options` (ApproveOptions): Approve options * `token` (string): Token contract address * `spender` (string): Spender address * `amount` (number | bigint): Amount to approve **Returns:** `Promise\<{hash: string, fee: bigint}\>` - Transaction result **Throws:** * Error if no provider is configured * Error if trying to re-approve USDT on Ethereum without resetting to 0 first **Example:** ```javascript const result = await account.approve({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT spender: '0xSpenderAddress...', amount: 1000000n }) console.log('Approve hash:', result.hash) ``` #### `getAllowance(token, spender)` Returns the current token allowance for the given spender. **Parameters:** * `token` (string): ERC20 token contract address * `spender` (string): The spender's address **Returns:** `Promise\` - The current allowance **Throws:** Error if no provider is configured **Example:** ```javascript const allowance = await account.getAllowance( '0xdAC17F958D2ee523a2206206994597C13D831ec7', '0xSpenderContract...' ) console.log('Current allowance:', allowance) ``` #### `getTransactionReceipt(hash)` Returns a transaction receipt by hash. **Parameters:** * `hash` (string): The transaction hash **Returns:** `Promise\` - Transaction receipt or null if not mined **Throws:** Error if no provider is configured **Example:** ```javascript const receipt = await account.getTransactionReceipt('0x...') if (receipt) { console.log('Confirmed in block:', receipt.blockNumber) console.log('Status:', receipt.status) // 1 = success, 0 = failed } ``` #### `toReadOnlyAccount()` Creates a read-only copy of the account with the same configuration. **Returns:** `Promise\` - Read-only account instance **Example:** ```javascript const readOnlyAccount = await account.toReadOnlyAccount() // Can check balances but cannot send transactions const balance = await readOnlyAccount.getBalance() // readOnlyAccount.sendTransaction() // Would throw error ``` #### `dispose()` Disposes the wallet account, erasing the private key from memory. **Example:** ```javascript // Clean up when done account.dispose() ``` ### Properties | Property | Type | Description | | --------- | --------------------------------------------------------- | -------------------------------------------------------------------------- | | `index` | `number` | The derivation path's index of this account | | `path` | `string` | The full BIP-44 derivation path of this account | | `keyPair` | `{privateKey: Uint8Array \| null, publicKey: Uint8Array}` | The account's key pair (⚠️ Contains sensitive data) | | `address` | `string` | The account's Ethereum address (inherited from `WalletAccountReadOnlyEvm`) | **Example:** ```javascript console.log('Account index:', account.index) // 0, 1, 2, etc. console.log('Account path:', account.path) // m/44'/60'/0'/0/0 // ⚠️ SENSITIVE: Handle with care const { privateKey, publicKey } = account.keyPair console.log('Public key length:', publicKey.length) // 65 bytes console.log('Private key length:', privateKey.length) // 32 bytes ``` ⚠️ **Security Note**: The `keyPair` property contains sensitive cryptographic material. Never log, display, or expose the private key. ## WalletAccountReadOnlyEvm Represents a read-only wallet account that can query balances and estimate fees but cannot send transactions. ### Constructor ```javascript new WalletAccountReadOnlyEvm(address, config?) ``` **Parameters:** * `address` (string): The account's Ethereum address * `config` (`Omit`, optional): Configuration object (same as `EvmWalletConfig` but without `transferMaxFee`, since read-only accounts cannot send transactions) * `provider` (string | Eip1193Provider, 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\` | - | | `getBalance()` | Returns the native token balance (in wei) | `Promise\` | If no provider | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise\` | If no provider | | `getTokenBalances(tokenAddresses)` | Returns the balances of multiple ERC20 tokens in a single call | `Promise\` | If no provider | | `quoteSendTransaction(tx)` | Estimates the fee for an EVM transaction | `Promise\<{fee: bigint}\>` | If no provider | | `quoteTransfer(options)` | Estimates the fee for an ERC20 transfer | `Promise\<{fee: bigint}\>` | If no provider | | `verify(message, signature)` | Verifies a message signature | `Promise\` | - | | `verifyTypedData(typedData, signature)` | Verifies a typed data signature (EIP-712) | `Promise\` | - | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | If no provider | | `getAllowance(token, spender)` | Returns current allowance for a spender | `Promise\` | If no provider | #### `getAddress()` Returns the account's Ethereum address. **Returns:** `Promise\` - Checksummed Ethereum address **Example:** ```javascript const address = await readOnlyAccount.getAddress() console.log('Account address:', address) // 0x... ``` #### `getBalance()` Returns the account's native token balance. **Returns:** `Promise\` - Balance in wei **Throws:** Error if no provider is configured **Example:** ```javascript const balance = await readOnlyAccount.getBalance() console.log('Balance:', balance, 'wei') ``` #### `getTokenBalance(tokenAddress)` Returns the balance of a specific ERC20 token. **Parameters:** * `tokenAddress` (string): The ERC20 token contract address **Returns:** `Promise\` - Token balance in base units **Throws:** Error if no provider is configured **Example:** ```javascript const tokenBalance = await readOnlyAccount.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7') console.log('USDT balance:', tokenBalance) ``` #### `getTokenBalances(tokenAddresses)` Returns the balances of multiple ERC20 tokens in a single call. More efficient than calling `getTokenBalance` for each token individually. **Parameters:** * `tokenAddresses` (string\[]): Array of ERC20 token contract addresses **Returns:** `Promise\` - Array of token balances in base units, in the same order as the input addresses **Throws:** Error if no provider is configured **Example:** ```javascript const balances = await readOnlyAccount.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USD₮ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC ]) console.log('USDT balance:', balances[0]) console.log('USDC balance:', balances[1]) ``` #### `quoteSendTransaction(tx)` Estimates the fee for an EVM transaction. **Parameters:** * `tx` (EvmTransaction): The transaction object **Returns:** `Promise\<{fee: bigint}\>` - Fee estimate in wei **Throws:** Error if no provider is configured **Example:** ```javascript const quote = await readOnlyAccount.quoteSendTransaction({ to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', value: 1000000000000000000 }) console.log('Estimated fee:', quote.fee, 'wei') ``` #### `quoteTransfer(options)` Estimates the fee for an ERC20 token transfer. **Parameters:** * `options` (TransferOptions): Transfer options **Returns:** `Promise\<{fee: bigint}\>` - Fee estimate in wei **Throws:** Error if no provider is configured **Example:** ```javascript const quote = await readOnlyAccount.quoteTransfer({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000 }) console.log('Transfer fee estimate:', quote.fee, 'wei') ``` #### `verify(message, signature)` Verifies a message signature against the account's address. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const message = 'Hello, Ethereum!' const signature = await account.sign(message) const readOnlyAccount = new WalletAccountReadOnlyEvm('0x...', { provider: '...' }) const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) // true ``` #### `verifyTypedData(typedData, signature)` Verifies a typed data signature according to [EIP-712](https://eips.ethereum.org/EIPS/eip-712). **Parameters:** * `typedData` (TypedData): The typed data that was signed * `signature` (string): The signature to verify **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verifyTypedData(typedData, signature) console.log('Typed data signature valid:', isValid) // true ``` #### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been mined. **Parameters:** * `hash` (string): The transaction hash **Returns:** `Promise\` - Transaction receipt or null if not yet mined **Throws:** Error if no provider is configured **Example:** ```javascript const receipt = await readOnlyAccount.getTransactionReceipt('0x...') if (receipt) { console.log('Transaction confirmed in block:', receipt.blockNumber) console.log('Gas used:', receipt.gasUsed) console.log('Status:', receipt.status) // 1 = success, 0 = failed } else { console.log('Transaction not yet mined') } ``` #### `getAllowance(token, spender)` Returns the current allowance for the given token and spender. **Parameters:** * `token` (string): The token's address * `spender` (string): The spender's address **Returns:** `Promise\` - The allowance **Example:** ```javascript const allowance = await readOnlyAccount.getAllowance( '0xdAC17F958D2ee523a2206206994597C13D831ec7', '0xSpenderAddress...' ) console.log('Allowance:', allowance) ``` ## Types ### EvmTransaction ```typescript interface EvmTransaction { to: string; // The transaction's recipient address value: number | bigint; // The amount of ethers to send (in wei) data?: string; // The transaction's data in hex format (optional) gasLimit?: number | bigint; // Maximum amount of gas this transaction can use (optional) gasPrice?: number | bigint; // Legacy gas price in wei (optional) maxFeePerGas?: number | bigint; // EIP-1559 max fee per gas in wei (optional) maxPriorityFeePerGas?: number | bigint; // EIP-1559 priority fee in wei (optional) } ``` ### TransferOptions ```typescript interface TransferOptions { token: string; // ERC20 token contract address recipient: string; // Recipient's Ethereum address amount: number | bigint; // Amount in token's base units } ``` ### TransactionResult ```typescript interface TransactionResult { hash: string; // Transaction hash fee: bigint; // Transaction fee paid in wei } ``` ### TransferResult ```typescript interface TransferResult { hash: string; // Transfer transaction hash fee: bigint; // Transfer fee paid in wei } ``` ### FeeRates ```typescript interface FeeRates { normal: bigint; // Normal priority fee rate (base fee × 1.1) fast: bigint; // Fast priority fee rate (base fee × 2.0) } ``` ### KeyPair ```typescript interface KeyPair { privateKey: Uint8Array | null; // Private key as Uint8Array (32 bytes, null after dispose) publicKey: Uint8Array; // Public key as Uint8Array (65 bytes) } ``` ### TypedData ```typescript interface TypedData { domain: TypedDataDomain; // The domain separator types: Record; // The type definitions message: Record; // The message data } ``` ### TypedDataDomain ```typescript interface TypedDataDomain { name?: string; // The domain name (e.g., the DApp name) version?: string; // The domain version chainId?: number | bigint; // The chain ID verifyingContract?: string; // The verifying contract address salt?: string; // An optional salt } ``` ### TypedDataField ```typescript interface TypedDataField { name: string; // The field name type: string; // The field type (e.g., 'address', 'uint256', 'string') } ``` ### EvmWalletConfig ```typescript interface EvmWalletConfig { provider?: string | Eip1193Provider; // 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; // Event logs blockNumber: number; // Block number confirmations: number; // Number of confirmations cumulativeGasUsed: bigint; // Cumulative gas used in block effectiveGasPrice: bigint; // Effective gas price paid status: number; // Transaction status (1 = success, 0 = failed) type: number; // Transaction type (0 = legacy, 2 = EIP-1559) } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's EVM Wallet Usage Get started with WDK's EVM Wallet Configuration *** ## Need Help? # Configuration (/sdk/wallet-modules/wallet-evm/configuration) ## Wallet Configuration The `WalletManagerEvm` accepts a configuration object that defines how the wallet interacts with the blockchain: ```javascript import WalletManagerEvm from '@tetherto/wdk-wallet-evm' const config = { // Recommended: RPC endpoint URL or EIP-1193 provider (required for blockchain operations) provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key', // 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-mainnet.g.alchemy.com/v2/your-api-key', transferMaxFee: 100000000000000 } ) // Read-only account const readOnlyAccount = new WalletAccountReadOnlyEvm( '0x...', // Ethereum address { provider: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key' } ) ``` ## 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-mainnet.g.alchemy.com/v2/your-api-key' } // 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-mainnet.g.alchemy.com/v2/your-api-key') } ``` ### 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-mainnet.g.alchemy.com/v2/your-api-key' } // Polygon (Matic) const polygonConfig = { provider: 'https://polygon-rpc.com' } // Arbitrum const arbitrumConfig = { provider: 'https://arb1.arbitrum.io/rpc' } // BSC (Binance Smart Chain) const bscConfig = { provider: 'https://bsc-dataseed.binance.org' } // Avalanche C-Chain const avalancheConfig = { provider: 'https://avalanche-c-chain-rpc.publicnode.com', } // Plasma const plasmaConfig = { provider: 'https://plasma.drpc.org', } // Stable (uses USD₮ as native gas token) // No need for ERC-4337 paymaster/bundler setup. const stableConfig = { provider: 'https://rpc.stable.xyz', } // Sepolia Testnet const sepoliaConfig = { provider: 'https://sepolia.drpc.org', } ``` ## Next Steps Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's EVM Wallet Usage Get started with WDK's EVM Wallet API *** ## Need Help? # Wallet EVM Overview (/sdk/wallet-modules/wallet-evm) A simple and secure package to manage BIP-44 wallets for EVM (Ethereum Virtual Machine) blockchains. This package provides a clean API for creating, managing, and interacting with Ethereum-compatible wallets using BIP-39 seed phrases and BIP-44 derivation paths. ## Features * **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases * **EVM Derivation Paths**: Support for BIP-44 standard derivation paths for Ethereum (m/44'/60') * **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase * **EVM Address Support**: Generate and manage Ethereum-compatible addresses using ethers.js * **Message Signing**: Sign and verify messages using EVM cryptography * **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**: Query multiple ERC20 token balances in a single 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 Get started with WDK in a Node.js environment Get started with WDK's EVM Wallet configuration Get started with WDK's EVM Wallet API Get started with WDK's EVM Wallet usage *** ## Need Help? # Usage (/sdk/wallet-modules/wallet-evm/usage) The `@tetherto/wdk-wallet-evm` module provides wallet management for Ethereum and EVM-compatible blockchains. Install the package and create your first wallet. Work with multiple accounts and custom derivation paths. Query native and ERC-20 token balances. Send native tokens with EIP-1559 or legacy gas settings. Transfer ERC-20 tokens and estimate fees. Sign messages and verify signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's EVM Wallet Configuration Get started with WDK's EVM Wallet API *** ### Need Help? # Wallet EVM ERC-4337 API Reference (/sdk/wallet-modules/wallet-evm-erc-4337/api-reference) ## 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`. ### Fee Rate Behavior Internally, `getFeeRates()` applies these multipliers to the base fee: * **Normal**: base fee × 110% * **Fast**: base fee × 200% These multipliers are internal (`protected static`) and cannot be imported or overridden. ### 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): 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' // USD₮ }, transferMaxFee: 100000 // Optional: max fee in token units }) ``` 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 }) ``` 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 }) ``` ### Methods | Method | Description | Returns | Throws | | --------------------------------- | ---------------------------------------------------------------- | ------------------------------------------- | -------------- | | `getRandomSeedPhrase(wordCount?)` | (static) Returns a random BIP-39 seed phrase | `string` | - | | `isValidSeedPhrase(seedPhrase)` | (static) Checks if a seed phrase is valid | `boolean` | - | | `getAccount(index?)` | Returns a wallet account at the specified index | `Promise\` | - | | `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise\` | - | | `getFeeRates()` | Returns current fee rates for transactions | `Promise\<{normal: bigint, fast: bigint}\>` | If no provider | | `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\` - 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\` - 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`. ### Constants The following constant is used internally for Safe account address derivation: ```javascript // Internal: used by predictSafeAddress() for deterministic address generation const SALT_NONCE = '0x69b348339eea4ed93f9d11931c3b894c8f9d8c7663a053024b11cb7eb4e5a1f6' ``` > **Note:** This constant is not re-exported from the package entry point. Use `predictSafeAddress()` instead of referencing it directly. ### 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\` | - | | `sign(message)` | Signs a message using the account's private key | `Promise\` | - | | `verify(message, signature)` | Verifies a message signature | `Promise\` | - | | `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\` | - | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise\` | - | | `getPaymasterTokenBalance()` | Returns the paymaster token balance | `Promise\` | - | | `getAllowance(token, spender)` | Returns current token allowance for a spender | `Promise\` | - | | `getTransactionReceipt(hash)` | Returns a transaction receipt | `Promise\` | - | | `getUserOperationReceipt(hash)` | Returns a UserOperation receipt | `Promise\` | - | | `signTypedData(typedData)` | Signs EIP-712 typed structured data | `Promise\` | - | | `verifyTypedData(typedData, signature)` | Verifies an EIP-712 typed data signature | `Promise\` | - | | `getTokenBalances(tokenAddresses)` | Returns balances for multiple ERC20 tokens | `Promise\\>` | - | | `toReadOnlyAccount()` | Returns a read-only copy of the account | `Promise\` | - | | `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\` - 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\` - The message signature **Example:** ```javascript const message = 'Hello, ERC-4337!' const signature = await account.sign(message) console.log('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\` - True if signature is valid **Example:** ```javascript const isValid = await account.verify(message, signature) console.log('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', // USD₮ recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000 // 1 USD₮ (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\` - 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\` - Token balance in base units **Example:** ```javascript const tokenBalance = await account.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7') console.log('USDT balance:', tokenBalance) // In 6 decimal units ``` ##### `getPaymasterTokenBalance()` Returns the balance of the configured paymaster token used for paying fees. **Returns:** `Promise\` - 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 USD₮ }) 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\` - 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\` - 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\` - UserOperation receipt or null if not processed **Example:** ```javascript const receipt = await account.getUserOperationReceipt('0x...') if (receipt) { console.log('UserOp receipt:', receipt) } ``` ##### `signTypedData(typedData)` Signs EIP-712 typed structured data using the underlying EOA private key. **Parameters:** * `typedData` (TypedData): The typed data object containing domain, types, primaryType, and message **Returns:** `Promise\` - The typed data signature **Example:** ```javascript const typedData = { domain: { name: 'MyDApp', version: '1', chainId: 1, verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC' }, types: { Transfer: [ { name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' } ] }, primaryType: 'Transfer', message: { to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000n } } const signature = await account.signTypedData(typedData) console.log('Typed data signature:', signature) ``` ##### `verifyTypedData(typedData, signature)` Verifies an EIP-712 typed data signature against the underlying EOA address. **Parameters:** * `typedData` (TypedData): The original typed data object * `signature` (string): The signature to verify **Returns:** `Promise\` - True if the signature is valid **Example:** ```javascript const isValid = await account.verifyTypedData(typedData, signature) console.log('Typed data signature valid:', isValid) ``` ##### `getTokenBalances(tokenAddresses)` Returns balances for multiple ERC20 tokens in a single call. **Parameters:** * `tokenAddresses` (string\[]): Array of ERC20 token contract addresses **Returns:** `Promise\\>` - Map of token address to balance in base units **Example:** ```javascript const balances = await account.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC ]) for (const [address, balance] of balances) { console.log(`Token ${address}: ${balance}`) } ``` ##### `toReadOnlyAccount()` Creates a read-only copy of the account with the same Safe address and configuration. **Returns:** `Promise\` - Read-only account instance **Example:** ```javascript const readOnlyAccount = await account.toReadOnlyAccount() // Can check balances but cannot send transactions const balance = await readOnlyAccount.getBalance() // readOnlyAccount.sendTransaction() // Would 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. ### Constants The following constant is used internally for Safe account address derivation: ```javascript // Internal: used by predictSafeAddress() for deterministic address generation const SALT_NONCE = '0x69b348339eea4ed93f9d11931c3b894c8f9d8c7663a053024b11cb7eb4e5a1f6' ``` > **Note:** This constant is not re-exported from the package entry point. Use `predictSafeAddress()` instead of referencing it directly. ### Constructor ```javascript new WalletAccountReadOnlyEvmErc4337(address, config) ``` **Parameters:** * `address` (string): The EOA address (owner address) * `config` (`Omit`): 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\` | - | | `verify(message, signature)` | Verifies a message signature | `Promise\` | - | | `getBalance()` | Returns the native token balance (in wei) | `Promise\` | - | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific ERC20 token | `Promise\` | - | | `getPaymasterTokenBalance()` | Returns the paymaster token balance | `Promise\` | - | | `getAllowance(token, spender)` | Returns current token allowance for a spender | `Promise\` | - | | `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\` | - | | `getUserOperationReceipt(hash)` | Returns a UserOperation receipt | `Promise\` | - | | `signTypedData(typedData)` | Signs EIP-712 typed structured data | `Promise\` | - | | `verifyTypedData(typedData, signature)` | Verifies an EIP-712 typed data signature | `Promise\` | - | | `getTokenBalances(tokenAddresses)` | Returns balances for multiple ERC20 tokens | `Promise\\>` | - | ##### `getAddress()` Returns the Safe smart contract wallet address. **Returns:** `Promise\` - 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\` - True if signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` ##### `getBalance()` Returns the Safe account's native token balance. **Returns:** `Promise\` - 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\` - Token balance in base units **Example:** ```javascript const tokenBalance = await readOnlyAccount.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7') console.log('USDT balance:', tokenBalance) ``` ##### `getPaymasterTokenBalance()` Returns the balance of the configured paymaster token. **Returns:** `Promise\` - 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\` - 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\` - 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\` - UserOperation receipt or null if not processed **Example:** ```javascript const receipt = await readOnlyAccount.getUserOperationReceipt('0x...') if (receipt) { console.log('UserOp receipt:', receipt) } ``` ##### `signTypedData(typedData)` Signs EIP-712 typed structured data using the underlying EOA address. **Parameters:** * `typedData` (TypedData): The typed data object containing domain, types, primaryType, and message **Returns:** `Promise\` - The typed data signature **Example:** ```javascript const typedData = { domain: { name: 'MyDApp', version: '1', chainId: 1, verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC' }, types: { Transfer: [ { name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' } ] }, primaryType: 'Transfer', message: { to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000n } } const signature = await readOnlyAccount.signTypedData(typedData) console.log('Typed data signature:', signature) ``` ##### `verifyTypedData(typedData, signature)` Verifies an EIP-712 typed data signature against the underlying EOA address. **Parameters:** * `typedData` (TypedData): The original typed data object * `signature` (string): The signature to verify **Returns:** `Promise\` - True if the signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verifyTypedData(typedData, signature) console.log('Typed data signature valid:', isValid) ``` ##### `getTokenBalances(tokenAddresses)` Returns balances for multiple ERC20 tokens in a single call. **Parameters:** * `tokenAddresses` (string\[]): Array of ERC20 token contract addresses **Returns:** `Promise\\>` - Map of token address to balance in base units **Example:** ```javascript const balances = await readOnlyAccount.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC ]) for (const [address, balance] of balances) { console.log(`Token ${address}: ${balance}`) } ``` ## Types ### 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 } ``` ### TypedData ```typescript interface TypedData { domain: TypedDataDomain; // EIP-712 domain separator types: Record; // Type definitions primaryType: string; // Primary type name message: Record; // Structured message data } ``` ### TypedDataDomain ```typescript interface TypedDataDomain { name?: string; // DApp or protocol name version?: string; // Domain version chainId?: number; // Blockchain ID verifyingContract?: string; // Contract address salt?: string; // Optional salt } ``` ### TypedDataField ```typescript interface TypedDataField { name: string; // Field name type: string; // Solidity type (e.g., 'address', 'uint256') } ``` ### 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% ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's EVM with ERC-4337 Wallet Usage Get started with WDK's EVM with ERC-4337 Wallet Configuration *** ## Need Help? # Configuration (/sdk/wallet-modules/wallet-evm-erc-4337/configuration) ## 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 } // Avalanche C-Chain const config = { chainId: 43114 } ``` ### 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 ### Ethereum Mainnet **Supported Paymaster Tokens** The following tokens are supported for gas payments on Ethereum Mainnet: * **USD₮**: `0xdAC17F958D2ee523a2206206994597C13D831ec7` * **USA₮**: `0x07041776f5007aca2a54844f50503a18a72a8b68` * **XAU₮**: `0x68749665ff8d2d112fa859aa293f07a622782f38` ```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-rpc.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 } ``` ### Avalanche C-Chain ```javascript const avalancheConfig = { chainId: 43114, provider: 'https://avalanche-c-chain-rpc.publicnode.com', bundlerUrl: "https://public.pimlico.io/v2/43114/rpc", paymasterUrl: "https://public.pimlico.io/v2/43114/rpc", paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba', entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', safeModulesVersion: '0.3.0', paymasterToken: { address: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7' // USDT }, transferMaxFee: 100000 // 100,000 paymaster token units (e.g., 0.1 USDT if 6 decimals) } ``` ### Plasma ```javascript // Plasma (example Layer 2) const plasmaConfig = { chainId: 9745, provider: 'https://plasma.drpc.org', // For ERC-4337 support, optional fields: 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) Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's EVM with ERC-4337 Wallet Usage Get started with WDK's EVM with ERC-4337 Wallet API *** ## Need Help? # Wallet EVM ERC-4337 Overview (/sdk/wallet-modules/wallet-evm-erc-4337) 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 * **ERC20 Support**: Query native token and ERC20 token balances using smart contract interactions * **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 * **EIP-712 Typed Data Support**: Sign and verify EIP-712 structured typed data * **Batch Token Balance Queries**: Query multiple ERC20 token balances in a single call ## Supported Networks This package works with any EVM-compatible blockchain, including: * **Ethereum Mainnet** * **Ethereum Testnets** (Sepolia) * **Other EVM Chains** (Polygon, Arbitrum, Avalanche C-chain, Plasma etc.) ## Next Steps Get started with WDK in a Node.js environment Get started with WDK's EVM with ERC-4337 Wallet configuration Get started with WDK's EVM with ERC-4337 Wallet API Get started with WDK's EVM with ERC-4337 Wallet usage *** ## Need Help? # Wallet EVM ERC-4337 Usage (/sdk/wallet-modules/wallet-evm-erc-4337/usage) # Usage The `@tetherto/wdk-wallet-evm-erc-4337` module provides account abstraction wallet management for EVM-compatible blockchains using the ERC-4337 standard. Install the package and create your first smart account. Work with multiple smart accounts and custom derivation paths. Query native, ERC-20, and paymaster token balances. Send gasless transactions and estimate fees. Transfer ERC-20 tokens with gasless transactions. Sign messages and EIP-712 typed data. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's EVM ERC-4337 Wallet Configuration Get started with WDK's EVM ERC-4337 Wallet API *** ### Need Help? # Wallet Solana API Reference (/sdk/wallet-modules/wallet-solana/api-reference) # API Reference ### 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 | string\[]): RPC endpoint URL or an ordered list of endpoints for failover * `commitment` (string, optional): Commitment level ('processed', 'confirmed', or 'finalized') * `retries` (number, optional): Retry count for failover requests (default: 3) * `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\` | | `getAccountByPath(path)` | Returns a wallet account at the specified SLIP-0010 derivation path | `Promise\` | | `getFeeRates()` | Returns current fee rates for transactions | `Promise\<{normal: bigint, fast: bigint}\>` | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `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\` - The wallet account **Example:** ```javascript const account = await wallet.getAccount(0) ``` ##### `getAccountByPath(path)` Returns a wallet account at the specified SLIP-0010 derivation path. **Parameters:** * `path` (string): The derivation path (e.g., "0'/0'/0'"). On Solana, every child segment must be hardened. **Returns:** `Promise\` - 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): SLIP-0010 derivation path (e.g., "0'/0'/0'") * `config` (SolanaWalletConfig, optional): Configuration object #### Methods | Method | Description | Returns | | ----------------------------- | -------------------------------------------------------------- | --------------------------------------------- | | `getAddress()` | Returns the account's Solana address | `Promise\` | | `sign(message)` | Signs a message using the account's private key | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `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\` | | `getTokenBalance(tokenMint)` | Returns the balance of a specific SPL token | `Promise\` | | `getTransactionReceipt(hash)` | Gets the transaction receipt for a given transaction hash | `Promise\` | | `toReadOnlyAccount()` | Returns a read-only copy of the account | `Promise\` | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | ##### `getAddress()` Returns the account's Solana address. **Returns:** `Promise\` - 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\` - 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\` - 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): A simple transfer object or a prebuilt `TransactionMessage` * `to` (string): Recipient's Solana address (base58-encoded) * `value` (number | bigint): Amount in lamports When `tx` is a `TransactionMessage`, WDK preserves an existing recent blockhash or durable nonce lifetime. If no lifetime is present, WDK fetches the latest blockhash before quoting or sending. If you set an explicit `feePayer`, it must match the wallet address. **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 | bigint): 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\` - 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\` - 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\` - 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\` - 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\` | | `getBalance()` | Returns the native SOL balance (in lamports) | `Promise\` | | `getTokenBalance(tokenMint)` | Returns the balance of a specific SPL token | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `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\` - 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\` - 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\` - 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\` - 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 ### SolanaWalletConfig ```typescript interface SolanaWalletConfig { rpcUrl?: string | string[]; commitment?: 'processed' | 'confirmed' | 'finalized'; retries?: number; transferMaxFee?: number | bigint; } ``` ### TransferOptions ```typescript interface TransferOptions { token: string; recipient: string; amount: number | bigint; } ``` ### KeyPair ```typescript interface KeyPair { publicKey: Uint8Array privateKey: Uint8Array } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Solana Wallet Usage Get started with WDK's Solana Wallet Configuration *** ### Need Help? # Wallet Solana Configuration (/sdk/wallet-modules/wallet-solana/configuration) # Configuration ## 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 one Solana RPC endpoint or an ordered list of endpoints for blockchain interactions. **Type:** `string | string[]` (optional) **Default:** If not provided, wallet functionality that requires RPC will throw an error **Examples:** ```javascript // Single endpoint const config = { rpcUrl: 'https://api.mainnet-beta.solana.com' } // Devnet const config = { rpcUrl: 'https://api.devnet.solana.com' } // Failover across multiple endpoints const config = { rpcUrl: [ 'https://api.mainnet-beta.solana.com', 'https://rpc.ankr.com/solana' ] } // Custom RPC const config = { rpcUrl: 'https://your-custom-rpc-endpoint.com' } ``` When `rpcUrl` is an array, WDK initializes a failover provider and tries the next RPC when the current provider fails. ### retries The `retries` option controls how many times the failover provider retries a request before moving on to the next RPC entry. **Type:** `number` (optional) **Default:** `3` **Example:** ```javascript const config = { rpcUrl: [ 'https://api.mainnet-beta.solana.com', 'https://rpc.ankr.com/solana' ], retries: 5 } ``` ### 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 SLIP-0010 derivation paths. The default derivation path follows ecosystem conventions: * Default path: `m/44'/501'/{index}'/0'` (where `{index}` is the account index) * Custom child paths must keep every segment hardened, for example `0'/0'/5'` **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`](./api-reference) to supply an explicit derivation path when importing or recreating legacy wallets. ## Security Considerations * Always use HTTPS URLs for RPC endpoints * Use RPC endpoints that serve the same Solana network when enabling failover * 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 Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Solana Wallet Usage Get started with WDK's Solana Wallet API *** ### Need Help? # Wallet Solana Overview (/sdk/wallet-modules/wallet-solana) # @tetherto/wdk-wallet-solana Overview A simple and secure package to manage SLIP-0010 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. **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`](./api-reference) to supply an explicit derivation path when importing or recreating legacy wallets. On Solana, every child segment in a custom path must be hardened. ## Features * **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases * **Solana Derivation Paths**: Support for SLIP-0010 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 a single Solana RPC endpoint, plus runtime failover support for ordered RPC URL lists * **Transaction Message Support**: Quote or send prebuilt `TransactionMessage` flows with recent blockhash or durable nonce lifetimes * **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 Get started with WDK in a Node.js environment Get started with WDK's Solana Wallet configuration Get started with WDK's Solana Wallet API Get started with WDK's with Solana Wallet usage *** ### Need Help? # Usage (/sdk/wallet-modules/wallet-solana/usage) The `@tetherto/wdk-wallet-solana` module provides wallet management for the Solana blockchain. Install the package and create your first wallet. Work with multiple accounts and custom derivation paths. Query SOL and SPL token balances. Send native SOL and estimate transaction fees. Transfer SPL tokens and estimate fees. Sign messages and verify Ed25519 signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Solana Wallet Configuration Get started with WDK's Solana Wallet API *** ## Need Help? # API Reference (/sdk/wallet-modules/wallet-ton/api-reference) ## 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): Configuration object * `tonClient` (object | TonClient): TON client configuration or instance * `url` (string): TON Center API URL (e.g., '[https://toncenter.com/api/v3](https://toncenter.com/api/v3)') * `secretKey` (string, optional): API key for TON Center * `transferMaxFee` (number, 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\` | | `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise\` | | `getFeeRates()` | Returns current fee rates for transactions | `Promise\<{normal: number, fast: number}\>` | | `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\` - 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\` - 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\` - Object containing normal and fast fee rates **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 phrase. **Type:** `string | Uint8Array` **Example:** ```javascript console.log('Seed phrase:', 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): Configuration object * `tonClient` (object | TonClient): TON client configuration or instance * `url` (string): TON Center API URL * `secretKey` (string, optional): API key for TON Center * `transferMaxFee` (number, 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\` | | `sign(message)` | Signs a message using the account's private key | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `sendTransaction(tx)` | Sends a TON transaction | `Promise\<{hash: string, fee: number}\>` | | `quoteSendTransaction(tx)` | Estimates the fee for a TON transaction | `Promise\<{fee: number}\>` | | `transfer(options)` | Transfers Jetton tokens to another address | `Promise\<{hash: string, fee: number}\>` | | `quoteTransfer(options)` | Estimates the fee for a Jetton transfer | `Promise\<{fee: number}\>` | | `getBalance()` | Returns the native TON balance (in nanotons) | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific Jetton token | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | ##### `verify(message, signature)` Verifies a message signature. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify **Returns:** `Promise\` - True if the signature is valid **Example:** ```javascript const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, { tonClient: { url: '...' } }) const isValid = await readOnlyAccount.verify('Hello, World!', signature) console.log('Signature valid:', isValid) ``` ##### `getAddress()` Returns the account's address. **Returns:** `Promise\` - 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\` - The message signature **Example:** ```javascript const signature = await account.sign('Hello, World!') console.log('Signature:', signature) ``` ##### `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): Amount in nanotons (1 TON = 1,000,000,000 nanotons) * `bounceable` (boolean, optional): Whether the address is bounceable (TON-specific, optional) **Returns:** `Promise\<{hash: string, fee: number}\>` - 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): Amount in nanotons (1 TON = 1,000,000,000 nanotons) * `bounceable` (boolean, optional): Whether the address is bounceable (TON-specific, optional) **Returns:** `Promise\<{fee: number}\>` - 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): Amount in Jetton's base units **Returns:** `Promise\<{hash: string, fee: number}\>` - 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): Amount in Jetton's base units **Returns:** `Promise\<{fee: number}\>` - 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\` - 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\` - 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\` - Transaction receipt or null if not yet mined **Example:** ```javascript const receipt = await account.getTransactionReceipt('EQ...') console.log('Transaction confirmed:', receipt.success) ``` ##### `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 public and private key pair as buffers | **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. #### Constructor ```javascript new WalletAccountReadOnlyTon(publicKey, config) ``` **Parameters:** * `publicKey` (string): The account's public key (hex or base64) * `config` (object): Configuration object (same as WalletManagerTon) #### Methods | Method | Description | Returns | | ------------------------------- | ---------------------------------------- | ------------------------------------------ | | `getAddress()` | Returns the account's TON address | `Promise\` | | `getBalance()` | Returns the native TON balance | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific Jetton | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | ##### `getAddress()` Returns the account's address. **Returns:** `Promise\` - The account's TON address ##### `getBalance()` Returns the native TON balance. **Returns:** `Promise\` - Balance in nanotons ##### `getTokenBalance(tokenAddress)` Returns the balance of a specific Jetton. **Parameters:** * `tokenAddress` (string): The Jetton master contract address **Returns:** `Promise\` - Token balance ##### `verify(message, signature)` Verifies a message signature. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify **Returns:** `Promise\` - True if the signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verify('Hello, World!', signature) console.log('Signature valid:', isValid) ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been mined. **Parameters:** * `hash` (string): The transaction hash **Returns:** `Promise\` - Transaction receipt or null if not yet mined **Example:** ```javascript const receipt = await readOnlyAccount.getTransactionReceipt('EQ...') console.log('Transaction confirmed:', receipt.success) ``` ## 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; /** * Whether the destination address is bounceable * @default true */ bounceable?: boolean; /** * Optional message payload */ payload?: string; /** * Optional contract initialization state */ stateInit?: Cell | null; } ``` ### 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; } ``` ### TransactionResult ```typescript interface TransactionResult { /** * Transaction hash in base64 format * @example 'EQD4FPq...' */ hash: string; /** * Transaction fee in nanotons * @example 100000 // 0.0001 TON */ fee: number; } ``` ### FeeRates ```typescript interface FeeRates { /** * Fee rate for normal priority transactions (in nanotons) * @example 100000000 // 0.1 TON */ normal: number; /** * Fee rate for high priority transactions (in nanotons) * @example 200000000 // 0.2 TON */ fast: number; } ``` ### KeyPair ```typescript interface KeyPair { /** * Ed25519 public key */ publicKey: Buffer; /** * Ed25519 private key (sensitive data) * @security Never expose or log this value */ privateKey: Buffer; } ``` ### TonWalletConfig ```typescript interface TonWalletConfig { /** * TON Center client configuration */ tonClient?: { /** * TON Center API endpoint * @example 'https://toncenter.com/api/v3' */ url: string; /** * Optional API key for higher rate limits */ secretKey?: string; }; /** * Maximum allowed fee for transfers (in nanotons) * @example 1000000000 // 1 TON */ transferMaxFee?: number; } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's TON Wallet Usage Get started with WDK's TON Wallet Configuration *** ## Need Help? # Configuration (/sdk/wallet-modules/wallet-ton/configuration) ## 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: 1000000000 // Optional: Maximum fee in nanotons (1 TON) } const wallet = new WalletManagerTon(seedPhrase, config) ``` ## 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: 1000000000 // Optional: Maximum fee in nanotons } const account = new WalletAccountTon(seedPhrase, "0'/0/0", accountConfig) ``` ## Configuration Options ### tonClient The `tonClient` option configures the TON Center API client for blockchain interactions. **Type:** ```typescript interface TonClientConfig { /** * TON Center API endpoint URL */ url: string; /** * Optional API key for TON Center * Required for higher rate limits */ secretKey?: string; } ``` **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` (nanotons) **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) **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`](./api-reference) to supply an explicit derivation path when importing or recreating legacy wallets. ## 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 Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's TON Wallet Usage Get started with WDK's TON Wallet API *** ## Need Help? # Wallet TON Overview (/sdk/wallet-modules/wallet-ton) 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. **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`](./api-reference) to supply an explicit derivation path when importing or recreating legacy wallets. ## Features * **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases * **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 Get started with WDK in a Node.js environment Get started with WDK's TON Wallet configuration Get started with WDK's TON Wallet API Get started with WDK's TON Wallet usage *** ## Need Help? # Usage (/sdk/wallet-modules/wallet-ton/usage) The `@tetherto/wdk-wallet-ton` module provides wallet management for the TON blockchain. Install the package and create your first wallet. Work with multiple accounts and custom derivation paths. Query native TON and Jetton token balances. Send native TON and estimate transaction fees. Transfer Jetton tokens and estimate fees. Sign messages and verify signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's TON Wallet Configuration Get started with WDK's TON Wallet API *** ### Need Help? # Wallet Spark API Reference (/sdk/wallet-modules/wallet-spark/api-reference) # API Reference ### Table of Contents | Class | Description | Methods | | --------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [WalletManagerSpark](#walletmanagerspark) | Main class for managing Spark wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) | | [WalletAccountSpark](#walletaccountspark) | Individual Spark wallet account implementation. Implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) | | [WalletAccountReadOnlySpark](#walletaccountreadonlyspark) | Read-only Spark wallet account. | [Constructor](#constructor-1), [Methods](#methods-2) | ## WalletManagerSpark The main class for managing Spark wallets.\ Extends `WalletManager` from `@tetherto/wdk-wallet`. #### Constructor ```javascript new WalletManagerSpark(seed, config) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `config` (object, optional): Configuration object * `network` (string, optional): 'MAINNET', 'SIGNET', or 'REGTEST' (default: 'MAINNET') * `sparkscan` (`SparkScanConfig`, optional): SparkScan configuration for balance polling * `syncAndRetry` (boolean, optional): When true, failed sends and Lightning payments sync wallet state and retry once ### Methods | Method | Description | Returns | | ------------------------ | ------------------------------------------------------------------ | ------------------------------------------- | | `getAccount(index)` | Returns a wallet account at the specified index | `Promise\` | | `getAccountByPath(path)` | Returns a wallet account at a specific BIP-44 derivation path | `Promise\` | | `getFeeRates()` | Returns current fee rates for transactions (always zero for Spark) | `Promise\<{normal: bigint, fast: bigint}\>` | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | ##### `getAccount(index)` Returns a wallet account at the specified index using BIP-44 derivation path. **Parameters:** * `index` (number, optional): The index of the account to get (default: 0) **Returns:** `Promise\` - The wallet account **Example:** ```javascript const account = await wallet.getAccount(0) const account1 = await wallet.getAccount(1) ``` **Note:** Uses derivation path pattern `m/44'/998'/{networkNumber}'/0/{index}` where 998 is the coin type for Spark and networkNumber is 0 for MAINNET, 2 for SIGNET, or 3 for REGTEST. ##### `getFeeRates()` Returns current fee rates for transactions. On Spark network, transactions have zero fees. **Returns:** `Promise\<{normal: bigint, fast: bigint}\>` - Object containing fee rates (always `{normal: 0n, fast: 0n}`) **Example:** ```javascript const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal) // Always 0n console.log('Fast fee rate:', feeRates.fast) // Always 0n ``` ##### `dispose()` Disposes all wallet accounts and clears sensitive data from memory. **Returns:** `void` **Example:** ```javascript wallet.dispose() ``` ##### `getAccountByPath(path)` Returns a wallet account at a specific BIP-44 derivation path. **Parameters:** * `path` (string): The derivation path segment (e.g. `"0'/0/0"`) **Returns:** `Promise\` - 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\` | | `sign(message)` | Signs a message using the account's identity key | `Promise\` | | `getIdentityKey()` | Returns the account's identity public key | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `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\` | | `getTokenBalance(tokenAddress)` | Returns the balance for a specific token | `Promise\` | | `getTransactionReceipt(hash)` | Returns a Spark transfer by its ID | `Promise\` | | `getTransfers(options?)` | Returns the account's transfer history | `Promise\` | | `getSingleUseDepositAddress()` | Generates a single-use Bitcoin deposit address | `Promise\` | | `getUnusedDepositAddresses(options?)` | Returns unused single-use deposit addresses | `Promise\<{depositAddresses: DepositAddressQueryResult[], offset: number}\>` | | `getStaticDepositAddress()` | Gets or creates a reusable static deposit address | `Promise\` | | `getStaticDepositAddresses()` | Returns all existing static deposit addresses | `Promise\` | | `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\` | | `claimStaticDeposit(txId)` | Claims a static Bitcoin deposit to the wallet | `Promise\` | | `refundStaticDeposit(options)` | Refunds a static deposit back to a Bitcoin address | `Promise\` | | `quoteWithdraw(options)` | Gets a fee quote for withdrawing funds | `Promise\` | | `withdraw(options)` | Withdraws funds to a Bitcoin address | `Promise\` | | `createLightningInvoice(options)` | Creates a Lightning invoice | `Promise\` | | `getLightningReceiveRequest(invoiceId)` | Gets Lightning receive request by id | `Promise\` | | `getLightningSendRequest(requestId)` | Gets Lightning send request by id | `Promise\` | | `payLightningInvoice(options)` | Pays a Lightning invoice | `Promise\` | | `quotePayLightningInvoice(options)` | Gets fee estimate for Lightning payments | `Promise\` | | `createSparkSatsInvoice(options)` | Creates a Spark invoice for receiving sats | `Promise\` | | `createSparkTokensInvoice(options)` | Creates a Spark invoice for receiving tokens | `Promise\` | | `paySparkInvoice(invoices)` | Pays one or more Spark invoices | `Promise\` | | `syncWalletBalance()` | Reconciles wallet state and waits for any triggered optimization to complete | `Promise\` | | `getSparkInvoices(params)` | Queries the status of Spark invoices | `Promise\<{invoiceStatuses: InvoiceResponse[], offset: number}\>` | | `toReadOnlyAccount()` | Creates a read-only version of this account | `Promise\` | | `cleanupConnections()` | Cleans up network connections and resources | `Promise\` | | `dispose()` | Disposes the wallet account, clearing private keys | `void` | ##### `getAddress()` Returns the account's Spark network address. **Returns:** `Promise\` - 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\` - 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\` - The identity public key **Example:** ```javascript const identityKey = await account.getIdentityKey() console.log('Identity key:', identityKey) // 02eda8... ``` ##### `sendTransaction({to, value})` Sends a Spark transaction. When `syncAndRetry` is enabled, the wallet syncs state and retries once after a failure. **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. When `sparkscan` is configured, this uses SparkScan's `btcSoftBalanceSats` value. **Returns:** `Promise\` - 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\` - 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\` - 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\` - 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\` - 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\, 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\` - 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\` - 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\` - 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\` - 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\` - 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\` - 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\`) * `onchainAddress` (string): Bitcoin address to withdraw to * `amountSats` (number): Amount in satoshis to withdraw **Returns:** `Promise\` - 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\` - 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\` - 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\` - 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. When `syncAndRetry` is enabled, the wallet syncs state and retries once after a failure. **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\` - 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\` - 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\` - 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\` - 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\` - 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\` - Response containing transaction results and errors **Example:** ```javascript const result = await account.paySparkInvoice([ { invoice: 'spark1...', amount: BigInt(100000) } ]) console.log('Payment result:', result) ``` ##### `syncWalletBalance()` Reconciles the wallet's internal state with the server and waits for any triggered optimization to complete. **Returns:** `Promise\` **Example:** ```javascript await account.syncWalletBalance() ``` ##### `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\` - 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\` **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\` | | `getIdentityKey()` | Returns the account's identity public key | `Promise\` | | `getBalance()` | Returns the native token balance in satoshis | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance for a specific token | `Promise\` | | `getTransactionReceipt(hash)` | Returns a Spark transfer by its ID | `Promise\` | | `getTransfers(options?)` | Returns the account's Spark transfer history | `Promise\` | | `getUnusedDepositAddresses(options?)` | Returns unused single-use deposit addresses | `Promise\<{depositAddresses: DepositAddressQueryResult[], offset: number}\>` | | `getStaticDepositAddresses()` | Returns all existing static deposit addresses | `Promise\` | | `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\` - 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\` - 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. When `sparkscan` is configured, this uses SparkScan's `btcSoftBalanceSats` value. **Returns:** `Promise\` - 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\` - 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\` - 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\` - 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\, 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\` - 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 ### SparkScanConfig ```typescript interface SparkScanConfig { baseUrl?: string // Optional SparkScan URL (default: "https://api.sparkscan.io") network?: 'MAINNET' | 'SIGNET' | 'REGTEST' // Spark network, SparkScan only accepts MAINNET and REGTEST at runtime apiKey?: string // Optional API key for SparkScan requests } ``` ### SparkWalletConfig ```typescript interface SparkWalletConfig { network?: 'MAINNET' | 'SIGNET' | 'REGTEST' // The network (default: "MAINNET") sparkscan?: SparkScanConfig // Optional SparkScan configuration for balance polling syncAndRetry?: boolean // When true, failed sends and Lightning payments sync wallet state and retry once } ``` ### 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 } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Spark Wallet Usage Get started with WDK's Spark Wallet Configuration *** ### Need Help? # Wallet Spark Configuration (/sdk/wallet-modules/wallet-spark/configuration) # Configuration ## Wallet Configuration ```javascript const config = { network: 'MAINNET', // 'MAINNET', 'SIGNET', or 'REGTEST' sparkscan: { apiKey: 'your-api-key-here' }, syncAndRetry: true } 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 } ``` ### SparkScan Balance Polling The `sparkscan` option configures SparkScan-backed balance polling for [`getBalance()`](./api-reference). **Type:** `SparkScanConfig` (optional) **Fields:** * `baseUrl` - Optional SparkScan URL, default: `https://api.sparkscan.io` * `network` - Optional Spark network. SparkScan supports `MAINNET` and `REGTEST` * `apiKey` - Optional SparkScan API key **Example:** ```javascript const config = { network: 'MAINNET', sparkscan: { apiKey: 'your-api-key-here' } } ``` When `sparkscan` is configured, [`getBalance()`](./api-reference) returns SparkScan's soft balance from `btcSoftBalanceSats`. ### Automatic Retry The `syncAndRetry` option tells [`sendTransaction()`](./api-reference) and [`payLightningInvoice()`](./api-reference) to sync wallet state and retry once after a failure. **Type:** `boolean` (optional) **Default:** `false` **Example:** ```javascript const config = { network: 'MAINNET', syncAndRetry: true } ``` You can also call [`syncWalletBalance()`](./api-reference) directly when you want to reconcile wallet state before retrying an operation. ## 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](../../../resources/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](../../../resources/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', sparkscan: { apiKey: 'your-api-key-here' }, syncAndRetry: true }) // Get accounts (no additional configuration needed) const account0 = await wallet.getAccount(0) const account1 = await wallet.getAccount(1) // Clean up when done wallet.dispose() ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Spark Wallet Usage Get started with WDK's Spark Wallet API *** ### Need Help? # Wallet Spark Overview (/sdk/wallet-modules/wallet-spark) # @tetherto/wdk-wallet-spark Overview 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](/resources/concepts#bip-39-mnemonic-seed-phrases), [BIP-44 derivation paths](/resources/concepts#bip-44-multi-account-hierarchy), and the Spark SDK for Bitcoin [layer 2](/resources/concepts#layer-2-solutions) functionality including [Lightning Network](/resources/concepts#lightning-network) integration. ## Features * **Spark Blockchain Support**: Full integration with the Spark Bitcoin [layer 2](/resources/concepts#layer-2-solutions) network * **Lightning Network Integration**: Create and pay [Lightning Network](/resources/concepts#lightning-network) invoices directly * **Spark Invoices**: Create and pay Spark invoices for receiving sats and tokens directly on the Spark network * **SparkScan Balance Polling**: Use SparkScan-backed balance polling in [`getBalance()`](./api-reference) when `sparkscan` is configured * **Sync and Retry**: Optionally sync wallet state and retry failed [`sendTransaction()`](./api-reference) and [`payLightningInvoice()`](./api-reference) calls once * **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](/resources/concepts#bip-44-multi-account-hierarchy)**: Support for standard BIP-44 derivation paths with Spark-specific coin type (998) * **[BIP-39 Seed Phrase Support](/resources/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](/resources/concepts#mainnet) and [regtest](/resources/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 **Regtest Faucet** You can obtain test funds for your Regtest environment from the [Lightspark Regtest Faucet](https://app.lightspark.com/regtest-faucet). ## Next Steps Get started with WDK in a Node.js environment Get started with WDK's Spark Wallet configuration Get started with WDK's Spark Wallet API Get started with WDK's with Spark Wallet usage *** ### Need Help? # Wallet Spark Usage (/sdk/wallet-modules/wallet-spark/usage) # Usage The `@tetherto/wdk-wallet-spark` module provides wallet management for the Spark network. Install the package and create your first Spark wallet. Retrieve accounts by index and iterate over them. Query native Spark balances and read-only accounts. Send native Spark, transfer tokens, and estimate fees. Create and pay Lightning invoices and inspect payment status. Fund from Bitcoin layer 1 and withdraw on-chain. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Spark Wallet Configuration Get started with WDK's Spark Wallet API *** ### Need Help? # API Reference (/sdk/wallet-modules/wallet-ton-gasless/api-reference) ## Table of Contents | Class | Description | Methods | | ------------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------- | | [WalletManagerTonGasless](#walletmanagertongasless) | Main class for managing gasless TON wallets | [Constructor](#constructor), [Methods](#methods) | | [WalletAccountTonGasless](#walletaccounttongasless) | Individual gasless TON wallet account implementation | [Constructor](#constructor-1), [Methods](#methods-1) | | [WalletAccountReadOnlyTonGasless](#walletaccountreadonlytongasless) | Read-only gasless TON wallet account | [Constructor](#constructor-2), [Methods](#methods-2) | ### WalletManagerTonGasless The main class for managing gasless TON wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. #### Constructor ```javascript new WalletManagerTonGasless(seed, config) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `config` (TonGaslessWalletConfig): Configuration object * `tonClient` (object | TonClient): TON client configuration or instance * `url` (string): TON Center API URL (e.g., '[https://toncenter.com/api/v3](https://toncenter.com/api/v3)') * `secretKey` (string, optional): API key for TON Center * `tonApiClient` (object | TonApiClient): TON API client configuration or instance * `url` (string): TON API URL (e.g., '[https://tonapi.io/v2](https://tonapi.io/v2)') * `secretKey` (string, optional): API key for TON API * `paymasterToken` (object): Paymaster token configuration * `address` (string): Paymaster token contract address * `transferMaxFee` (number, optional): Maximum fee for transfer operations **Example:** ```javascript const wallet = new WalletManagerTonGasless(seedPhrase, { tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' }, tonApiClient: { url: 'https://tonapi.io/v2', secretKey: 'your-tonapi-key' }, paymasterToken: { address: 'EQ...' }, transferMaxFee: 1000000000 }) ``` #### Methods | Method | Description | Returns | | ------------------------ | ------------------------------------------------------------------------ | ------------------------------------------- | | `getAccount(index)` | Returns a gasless wallet account at the specified index | `Promise\` | | `getAccountByPath(path)` | Returns a gasless wallet account at the specified BIP-44 derivation path | `Promise\` | | `getFeeRates()` | Returns current fee rates for transactions | `Promise\<{normal: number, fast: number}\>` | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | ##### `getAccount(index)` Returns a gasless wallet account at the specified index. **Parameters:** * `index` (number, optional): The index of the account to get (default: 0) **Returns:** `Promise\` - The wallet account **Example:** ```javascript const account = await wallet.getAccount(0) ``` ##### `getAccountByPath(path)` Returns a gasless wallet account at the specified BIP-44 derivation path. **Parameters:** * `path` (string): The derivation path (e.g., "0'/0/0") **Returns:** `Promise\` - The wallet account **Example:** ```javascript const account = await wallet.getAccountByPath("0'/0/1") ``` ##### `getFeeRates()` Returns current fee rates for transactions based on blockchain config. **Returns:** `Promise\<{normal: number, fast: number}\>` - Object containing fee rates **Example:** ```javascript const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal) console.log('Fast fee rate:', feeRates.fast) ``` ##### `dispose()` Disposes all wallet accounts, clearing private keys from memory. **Example:** ```javascript wallet.dispose() ``` ### WalletAccountTonGasless Individual gasless TON wallet account implementation. Extends `WalletAccountReadOnlyTonGasless` and implements `IWalletAccount`. #### Constructor ```javascript new WalletAccountTonGasless(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` (TonGaslessWalletConfig): Configuration object (same as WalletManagerTonGasless) #### Methods | Method | Description | Returns | | --------------------------------- | -------------------------------------------------------------- | -------------------------------------------- | | `getAddress()` | Returns the account's TON address | `Promise\` | | `sign(message)` | Signs a message using the account's private key | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `transfer(options, config?)` | Transfers tokens using gasless transactions | `Promise\<{hash: string, fee: number}\>` | | `quoteTransfer(options, config?)` | Estimates the fee for a token transfer | `Promise\<{fee: number}\>` | | `getBalance()` | Returns the native TON balance (in nanotons) | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific token | `Promise\` | | `getPaymasterTokenBalance()` | Returns the balance of the paymaster token | `Promise\` | | `toReadOnlyAccount()` | Returns a read-only copy of the account | `Promise\` | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | ##### `getAddress()` Returns the account's address. **Returns:** `Promise\` - 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\` - 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\` - True if the signature is valid **Example:** ```javascript const isValid = await account.verify('Hello, World!', signature) console.log('Signature valid:', isValid) ``` ##### `transfer(options, config?)` Transfers tokens using gasless transactions. **Note:** `sendTransaction()` is not supported and will throw an error. **Parameters:** * `options` (TransferOptions): Transfer options * `token` (string): Token contract address * `recipient` (string): Recipient TON address * `amount` (number): Amount in token's base units * `config` (object, optional): Override configuration * `paymasterToken` (object, optional): Override default paymaster token * `address` (string): Paymaster token address * `transferMaxFee` (number, optional): Override maximum fee **Returns:** `Promise\<{hash: string, fee: number}\>` - Transfer result **Example:** ```javascript const result = await account.transfer({ token: 'EQ...', recipient: 'EQ...', amount: 1000000000 }, { paymasterToken: { address: 'EQ...' }, transferMaxFee: 2000000000 }) ``` ##### `quoteTransfer(options)` Estimates the fee for a Jetton (TON token) transfer. **Parameters:** * `options` (TransferOptions): Transfer options * `token` (string): Token contract address * `recipient` (string): Recipient TON address * `amount` (number): Amount in token's base units * `config` (object, optional): Override configuration * `paymasterToken` (object, optional): Override default paymaster token **Returns:** `Promise\<{fee: number}\>` - Object containing fee estimate (in paymaster token base units) **Example:** ```javascript const quote = await account.quoteTransfer({ token: 'EQ...', recipient: 'EQ...', amount: 1000000000 }); console.log('Transfer fee estimate:', quote.fee, 'paymaster token units'); ``` ##### `getPaymasterTokenBalance()` Returns the balance of the paymaster Jetton (used for gasless fees). **Returns:** `Promise\` - Paymaster Jetton balance in base units **Example:** ```javascript const paymasterBalance = await account.getPaymasterTokenBalance(); console.log('Paymaster Jetton balance:', paymasterBalance); ``` ##### `getBalance()` Returns the native TON balance (in nanotons). **Returns:** `Promise\` - 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 token contract address **Returns:** `Promise\` - Token balance in base units **Example:** ```javascript const tokenBalance = await account.getTokenBalance('EQ...'); console.log('Token balance:', tokenBalance, 'token base units'); ``` ##### `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 public and private key pair as buffers | **Example:** ```javascript const { publicKey, privateKey } = account.keyPair console.log('Public key length:', publicKey.length) console.log('Private key length:', privateKey.length) ``` ### WalletAccountReadOnlyTonGasless Read-only gasless TON wallet account. #### Constructor ```javascript new WalletAccountReadOnlyTonGasless(publicKey, config) ``` **Parameters:** * `publicKey` (string | Uint8Array): The account's public key * `config` (TonGaslessWalletConfig): Configuration object #### Methods | Method | Description | Returns | | --------------------------------- | ------------------------------------------ | ------------------------------------------ | | `getAddress()` | Returns the account's TON address | `Promise\` | | `getBalance()` | Returns the native TON balance | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific token | `Promise\` | | `getPaymasterTokenBalance()` | Returns the balance of the paymaster token | `Promise\` | | `quoteTransfer(options, config?)` | Estimates the fee for a token transfer | `Promise\<{fee: number}\>` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | ##### `getAddress()` Returns the account's TON address. **Returns:** `Promise\` - The account's TON address **Example:** ```javascript const address = await readOnlyAccount.getAddress() console.log('Account address:', address) ``` ##### `getBalance()` Returns the native TON balance (in nanotons). **Returns:** `Promise\` - Balance in nanotons **Example:** ```javascript const balance = await readOnlyAccount.getBalance() console.log('TON balance:', balance, 'nanotons') ``` ##### `getTokenBalance(tokenAddress)` Returns the balance of a specific token. **Parameters:** * `tokenAddress` (string): The token contract address **Returns:** `Promise\` - Token balance in base units **Example:** ```javascript const tokenBalance = await readOnlyAccount.getTokenBalance('EQ...') console.log('Token balance:', tokenBalance, 'token base units') ``` ##### `getPaymasterTokenBalance()` Returns the balance of the paymaster token (used for gasless fees). **Returns:** `Promise\` - Paymaster token balance in base units **Example:** ```javascript const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance() console.log('Paymaster token balance:', paymasterBalance) ``` ##### `quoteTransfer(options, config?)` Estimates the fee for a token transfer. **Parameters:** * `options` (TransferOptions): Transfer options * `token` (string): Token contract address * `recipient` (string): Recipient TON address * `amount` (number): Amount in token's base units * `config` (object, optional): Override configuration * `paymasterToken` (object, optional): Override default paymaster token **Returns:** `Promise\<{fee: number}\>` - Object containing fee estimate (in paymaster token base units) **Example:** ```javascript const quote = await readOnlyAccount.quoteTransfer({ token: 'EQ...', recipient: 'EQ...', amount: 1000000000 }) console.log('Transfer fee estimate:', quote.fee, 'paymaster token units') ``` ##### `verify(message, signature)` Verifies a message signature. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify **Returns:** `Promise\` - True if the signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verify('Hello, World!', signature) console.log('Signature valid:', isValid) ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt. **Parameters:** * `hash` (string): The transaction's hash **Returns:** `Promise\` - The receipt, or null if the transaction has not been included in a block yet **Example:** ```javascript const receipt = await readOnlyAccount.getTransactionReceipt('transaction-hash') if (receipt) { console.log('Transaction receipt:', receipt) } else { console.log('Transaction not yet included in a block') } ``` ## Types ### TonGaslessWalletConfig ```typescript interface TonGaslessWalletConfig { /** * TON client configuration */ tonClient: { /** * TON Center API URL * @example 'https://toncenter.com/api/v3' */ url: string; /** * Optional API key for TON Center */ secretKey?: string; }; /** * TON API client configuration */ tonApiClient: { /** * TON API URL * @example 'https://tonapi.io/v2' */ url: string; /** * Optional API key for TON API */ secretKey?: string; }; /** * Paymaster token configuration */ paymasterToken: { /** * Paymaster token contract address * @example 'EQ...' */ address: string; }; /** * Maximum fee for transfer operations * @optional */ transferMaxFee?: number; } ``` ### TransferOptions ```typescript interface TransferOptions { /** * Token contract address * @example 'EQ...' */ token: string; /** * Recipient's TON address * @example 'EQ...' */ recipient: string; /** * Amount in token's base units */ amount: number; } ``` ### TransferResult ```typescript interface TransferResult { /** * Transaction hash */ hash: string; /** * Fee paid in paymaster token units */ fee: number; } ``` ### KeyPair ```typescript interface KeyPair { /** * Public key as buffer */ publicKey: Buffer; /** * Private key as buffer (sensitive data) */ privateKey: Buffer; } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's TON Gasless Wallet Usage Get started with WDK's TON Gasless Wallet Configuration *** ## Need Help? # Configuration (/sdk/wallet-modules/wallet-ton-gasless/configuration) ## Wallet Configuration ```javascript import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless' const config = { // Required parameters tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' // Optional }, gasFreeProvider: 'https://your-gasfree-provider.com', gasFreeApiKey: 'your-gasfree-api-key', gasFreeApiSecret: 'your-gasfree-api-secret', serviceProvider: 'EQ...', // Service provider's TON address verifyingContract: 'EQ...', // Verifying contract address chainId: '1', // TON chain ID // Optional parameters transferMaxFee: 10000000 // Maximum fee in token base units } const wallet = new WalletManagerTonGasless(seedPhrase, config) ``` ## Account Configuration ```javascript import { WalletAccountTonGasless } from '@tetherto/wdk-wallet-ton-gasless' const accountConfig = { // Required parameters tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' // Optional }, gasFreeProvider: 'https://your-gasfree-provider.com', gasFreeApiKey: 'your-gasfree-api-key', gasFreeApiSecret: 'your-gasfree-api-secret', serviceProvider: 'EQ...', // Service provider's TON address verifyingContract: 'EQ...', // Verifying contract address chainId: '1', // TON chain ID // Optional parameters transferMaxFee: 10000000 // Maximum fee in token base units } const account = new WalletAccountTonGasless(seedPhrase, "0'/0/0", accountConfig) ``` ## Configuration Options ### tonClient The `tonClient` option configures the TON Center API client for blockchain interactions. **Type:** ```typescript 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; } ``` ### gasFreeProvider The `gasFreeProvider` option specifies the gas-free service endpoint. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { gasFreeProvider: 'https://your-gasfree-provider.com' } ``` ### gasFreeApiKey and gasFreeApiSecret API credentials for the gas-free service. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { gasFreeApiKey: 'your-gasfree-api-key', gasFreeApiSecret: 'your-gasfree-api-secret' } ``` ### serviceProvider The TON address of the service provider that handles gas-free transactions. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { serviceProvider: 'EQ...' // TON address } ``` ### verifyingContract The TON address of the contract that verifies gas-free transactions. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { verifyingContract: 'EQ...' // TON address } ``` ### chainId The blockchain's identifier. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { chainId: '1' // TON mainnet } ``` ### transferMaxFee The `transferMaxFee` option sets the maximum allowed fee in token base units for transfer operations. **Type:** `number` **Required:** No **Example:** ```javascript const config = { transferMaxFee: 10000000 // Maximum fee in token base units } ``` ## Complete Configuration Example Here's a complete configuration example with all options: ```javascript const config = { // TON Client (Required) tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' }, // Gas-free Service (Required) gasFreeProvider: 'https://your-gasfree-provider.com', gasFreeApiKey: 'your-gasfree-api-key', gasFreeApiSecret: 'your-gasfree-api-secret', // Contract Addresses (Required) serviceProvider: 'EQ...', // Service provider's address verifyingContract: 'EQ...', // Verifying contract address // Chain Configuration (Required) chainId: '1', // TON mainnet // Fee Limits (Optional) transferMaxFee: 10000000 // Maximum fee in token base units } ``` ## Security Considerations * Keep API keys and secrets secure and never expose them in client-side code * Use environment variables for sensitive configuration values * Always use HTTPS URLs for API endpoints * Set appropriate `transferMaxFee` limits to prevent excessive fees * Validate contract addresses before using them in configuration Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's TON Gasless Wallet Usage Get started with WDK's TON Gasless Wallet API *** ## Need Help? # Wallet TON Gasless Overview (/sdk/wallet-modules/wallet-ton-gasless) 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 Get started with WDK in a Node.js environment Get started with WDK's TON Gasless Wallet configuration Get started with WDK's TON Gasless Wallet API Get started with WDK's with TON Gasless Wallet usage *** ## Need Help? # Usage (/sdk/wallet-modules/wallet-ton-gasless/usage) 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. Install the package and create your first gasless wallet. Work with multiple accounts and custom derivation paths. Query native TON, Jetton, and paymaster token balances. Send native TON transactions. Transfer Jetton tokens gaslessly with paymaster fees. Sign messages and verify signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's TON Gasless Wallet Configuration Get started with WDK's TON Gasless Wallet API *** ## Need Help? # API Reference (/sdk/wallet-modules/wallet-tron/api-reference) ## Table of Contents | Class | Description | Methods | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [WalletManagerTron](#walletmanagertron) | Main class for managing Tron wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. | [Constructor](#constructor), [Methods](#methods) | | [WalletAccountTron](#walletaccounttron) | Individual Tron wallet account implementation. Extends `WalletAccountReadOnlyTron` and implements `IWalletAccount`. | [Constructor](#constructor-1), [Methods](#methods-1), [Properties](#properties) | | [WalletAccountReadOnlyTron](#walletaccountreadonlytron) | Read-only Tron wallet account. Extends `WalletAccountReadOnly` from `@tetherto/wdk-wallet`. | [Constructor](#constructor-2), [Methods](#methods-2) | ## WalletManagerTron The main class for managing Tron wallets. Extends `WalletManager` from `@tetherto/wdk-wallet`. ### Fee Rate Constants ```javascript const FEE_RATE_NORMAL_MULTIPLIER = 1.1 const FEE_RATE_FAST_MULTIPLIER = 2.0 ``` ### Constructor ```javascript new WalletManagerTron(seed, config?) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `config` (TronWalletConfig, optional): Configuration object * `provider` (string | TronWeb, optional): Tron RPC endpoint URL or TronWeb instance * `transferMaxFee` (number, optional): Maximum fee amount for transfer operations (in sun) **Example:** ```javascript const wallet = new WalletManagerTron(seedPhrase, { provider: 'https://api.trongrid.io', // Tron RPC endpoint transferMaxFee: 10000000 // 10 TRX in sun }) // Or with TronWeb instance const tronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io' }) const wallet2 = new WalletManagerTron(seedPhrase, { provider: tronWeb, transferMaxFee: 10000000 }) ``` ### Methods | Method | Description | Returns | Throws | | ------------------------ | ---------------------------------------------------------------- | ------------------------------------------- | -------------- | | `getAccount(index?)` | Returns a wallet account at the specified index | `Promise\` | - | | `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise\` | - | | `getFeeRates()` | Returns current fee rates from Tron network | `Promise\<{normal: number, fast: number}\>` | If no provider | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | - | ##### `getAccount(index?)` Returns a wallet account at the specified index using Tron's BIP-44 derivation (m/44'/195'). **Parameters:** * `index` (number, optional): The index of the account to get (default: 0) **Returns:** `Promise\` - The wallet account **Example:** ```javascript // Get first account (m/44'/195'/0'/0/0) const account = await wallet.getAccount(0) // Get second account (m/44'/195'/0'/0/1) const account1 = await wallet.getAccount(1) ``` ##### `getAccountByPath(path)` Returns a wallet account at the specified BIP-44 derivation path. **Parameters:** * `path` (string): The derivation path (e.g., "0'/0/0") **Returns:** `Promise\` - The wallet account **Example:** ```javascript // Full path: m/44'/195'/0'/0/1 const account = await wallet.getAccountByPath("0'/0/1") ``` ##### `getFeeRates()` Returns current fee rates from Tron network chain parameters. **Returns:** `Promise\<{normal: number, fast: number}\>` - Fee rates in sun * `normal`: Base fee × 1.1 * `fast`: Base fee × 2.0 **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sun') console.log('Fast fee rate:', feeRates.fast, 'sun') ``` ##### `dispose()` Disposes all wallet accounts, clearing private keys from memory. **Example:** ```javascript wallet.dispose() ``` ## WalletAccountTron Represents an individual Tron wallet account. Extends `WalletAccountReadOnlyTron` and implements `IWalletAccount`. ### Constants ```javascript const BIP_44_TRON_DERIVATION_PATH_PREFIX = "m/44'/195'" const BANDWIDTH_PRICE = 1_000 ``` ### Constructor ```javascript new WalletAccountTron(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` (TronWalletConfig, optional): Configuration object **Throws:** Error if seed phrase is invalid (BIP-39 validation fails) **Example:** ```javascript const account = new WalletAccountTron(seedPhrase, "0'/0/0", { provider: 'https://api.trongrid.io', transferMaxFee: 10000000 // 10 TRX in sun }) ``` ### Methods | Method | Description | Returns | Throws | | ------------------------------- | -------------------------------------------------------------- | ------------------------------------------- | --------------------------------- | | `getAddress()` | Returns the account's Tron address | `Promise\` | - | | `sign(message)` | Signs a message using the account's private key | `Promise\` | - | | `verify(message, signature)` | Verifies a message signature | `Promise\` | - | | `sendTransaction(tx)` | Sends a Tron transaction | `Promise\<{hash: string, fee: number}\>` | If no provider or fee exceeds max | | `quoteSendTransaction(tx)` | Estimates the fee for a Tron transaction | `Promise\<{fee: number}\>` | If no provider | | `transfer(options)` | Transfers TRC20 tokens to another address | `Promise\<{hash: string, fee: number}\>` | If no provider or fee exceeds max | | `quoteTransfer(options)` | Estimates the fee for a TRC20 transfer | `Promise\<{fee: number}\>` | If no provider | | `getBalance()` | Returns the native TRX balance (in sun) | `Promise\` | If no provider | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific TRC20 token | `Promise\` | If no provider | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | If no provider | | `toReadOnlyAccount()` | Returns a read-only copy of the account | `Promise\` | - | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | - | ##### `getAddress()` Returns the account's Tron address (starts with 'T'). **Returns:** `Promise\` - The account's Tron address **Example:** ```javascript const address = await account.getAddress() console.log('Account address:', address) // T... ``` ##### `sign(message)` Signs a message using Keccak-256 hash and secp256k1 signature. **Parameters:** * `message` (string): The message to sign (UTF-8 encoded) **Returns:** `Promise\` - The message signature (hex string) **Example:** ```javascript const message = 'Hello, Tron!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ##### `verify(message, signature)` Verifies a message signature using secp256k1. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify (hex string) **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const isValid = await account.verify('Hello, Tron!', signature) console.log('Signature valid:', isValid) ``` ##### `sendTransaction(tx)` Sends a TRX transaction and returns the result with hash and fee. **Parameters:** * `tx` (TronTransaction): The transaction object * `to` (string): Recipient Tron address (e.g., 'T...') * `value` (number): Amount in sun (1 TRX = 1,000,000 sun) **Returns:** `Promise\<{hash: string, fee: number}\>` - Transaction hash and fee in sun **Throws:** * Error if no TronWeb provider is configured * Error if fee exceeds `transferMaxFee` **Example:** ```javascript const result = await account.sendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', // Tron address value: 1000000 // 1 TRX in sun }) console.log('Transaction hash:', result.hash) console.log('Transaction fee:', result.fee, 'sun') ``` ##### `quoteSendTransaction(tx)` Estimates the bandwidth cost for a TRX transaction. **Parameters:** * `tx` (TronTransaction): The transaction object (same as sendTransaction) **Returns:** `Promise\<{fee: number}\>` - Fee estimate in sun **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const quote = await account.quoteSendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 }) console.log('Estimated fee:', quote.fee, 'sun') ``` ##### `transfer(options)` Transfers TRC20 tokens using smart contract call. **Parameters:** * `options` (TransferOptions): Transfer options * `token` (string): TRC20 contract address (e.g., 'T...') * `recipient` (string): Recipient Tron address (e.g., 'T...') * `amount` (number | bigint): Amount in token's base units **Returns:** `Promise\<{hash: string, fee: number}\>` - Transaction hash and fee in sun **Throws:** * Error if no TronWeb provider is configured * Error if fee exceeds `transferMaxFee` **Example:** ```javascript const result = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT TRC20 recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 // 1 USDT (6 decimals) }) console.log('Transfer hash:', result.hash) console.log('Transfer fee:', result.fee, 'sun') ``` ##### `quoteTransfer(options)` Estimates the energy and bandwidth cost for a TRC20 token transfer. **Parameters:** * `options` (TransferOptions): Transfer options (same as transfer) **Returns:** `Promise\<{fee: number}\>` - Fee estimate in sun (energy + bandwidth costs) **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const quote = await account.quoteTransfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }) console.log('Transfer fee estimate:', quote.fee, 'sun') ``` ##### `getBalance()` Returns the native TRX balance. **Returns:** `Promise\` - Balance in sun **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const balance = await account.getBalance() console.log('TRX balance:', balance, 'sun') ``` ##### `getTokenBalance(tokenAddress)` Returns the balance of a specific TRC20 token. **Parameters:** * `tokenAddress` (string): The TRC20 contract address (e.g., 'T...') **Returns:** `Promise\` - Token balance in base units **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const tokenBalance = await account.getTokenBalance('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t') console.log('USDT balance:', tokenBalance) // In 6 decimal units ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been processed. **Parameters:** * `hash` (string): The transaction hash **Returns:** `Promise\` - Transaction receipt or null **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const receipt = await account.getTransactionReceipt('0x...') console.log('Transaction confirmed:', receipt.success) ``` ##### `toReadOnlyAccount()` Creates a read-only copy of the account. **Returns:** `Promise\` - Read-only account instance **Example:** ```javascript const readOnlyAccount = await account.toReadOnlyAccount() // Can check balances but cannot send transactions const balance = await readOnlyAccount.getBalance() ``` ##### `dispose()` Disposes the wallet account, clearing private keys from memory using sodium\_memzero. **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: Buffer, publicKey: Buffer}` | 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'/195'/0'/0/0 // ⚠️ SENSITIVE: Handle with care const { privateKey, publicKey } = account.keyPair console.log('Public key length:', publicKey.length) // 33 bytes (compressed) 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. ## WalletAccountReadOnlyTron Represents a read-only Tron wallet account that can query balances and estimate fees but cannot send transactions. ### Constructor ```javascript new WalletAccountReadOnlyTron(address, config?) ``` **Parameters:** * `address` (string): The account's Tron address * `config` (`Omit`, optional): Configuration object without transferMaxFee **Example:** ```javascript const readOnlyAccount = new WalletAccountReadOnlyTron('TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', { provider: 'https://api.trongrid.io' }) ``` ### Methods | Method | Description | Returns | Throws | | ------------------------------- | --------------------------------------------- | ------------------------------------------- | -------------- | | `getBalance()` | Returns the native TRX balance (in sun) | `Promise\` | If no provider | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific TRC20 token | `Promise\` | If no provider | | `quoteSendTransaction(tx)` | Estimates the fee for a TRX transaction | `Promise\<{fee: number}\>` | If no provider | | `quoteTransfer(options)` | Estimates the fee for a TRC20 transfer | `Promise\<{fee: number}\>` | If no provider | | `verify(message, signature)` | Verifies a message signature | `Promise\` | - | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | If no provider | ##### `getBalance()` Returns the native TRX balance. **Returns:** `Promise\` - Balance in sun **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const balance = await readOnlyAccount.getBalance() console.log('TRX balance:', balance, 'sun') ``` ##### `getTokenBalance(tokenAddress)` Returns the balance of a specific TRC20 token. **Parameters:** * `tokenAddress` (string): The TRC20 contract address **Returns:** `Promise\` - Token balance in base units **Throws:** Error if no TronWeb provider is configured **Example:** ```javascript const tokenBalance = await readOnlyAccount.getTokenBalance('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t') console.log('USDT balance:', tokenBalance) ``` ##### `quoteSendTransaction(tx)` Estimates the bandwidth cost for a TRX transaction. **Parameters:** * `tx` (TronTransaction): The transaction object **Returns:** `Promise\<{fee: number}\>` - Fee estimate in sun **Throws:** Error if no TronWeb provider is configured ##### `quoteTransfer(options)` Estimates the energy and bandwidth cost for a TRC20 transfer. **Parameters:** * `options` (TransferOptions): Transfer options **Returns:** `Promise\<{fee: number}\>` - Fee estimate in sun **Throws:** Error if no TronWeb provider is configured ##### `verify(message, signature)` Verifies a message signature using secp256k1. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify (hex string) **Returns:** `Promise\` - True if signature is valid **Example:** ```javascript const readOnlyAccount = new WalletAccountReadOnlyTron('T...', { provider: '...' }) const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been processed. **Parameters:** * `hash` (string): The transaction hash **Returns:** `Promise\` - Transaction receipt or null **Throws:** Error if no TronWeb provider is configured ## Types ### TronWalletConfig ```typescript interface TronWalletConfig { provider?: string | TronWeb; // Tron RPC URL or TronWeb instance transferMaxFee?: number; // Maximum fee in sun } ``` ### TronTransaction ```typescript interface TronTransaction { to: string; // Recipient Tron address value: number; // Amount in sun (1 TRX = 1,000,000 sun) } ``` ### TransferOptions ```typescript interface TransferOptions { token: string; // TRC20 contract address recipient: string; // Recipient Tron address amount: number | bigint; // Amount in token base units } ``` ### TransactionResult ```typescript interface TransactionResult { hash: string; // Transaction hash fee: number; // Fee paid in sun } ``` ### TransferResult ```typescript interface TransferResult { hash: string; // Transaction hash fee: number; // Fee paid in sun } ``` ### Constants ```typescript // Tron-specific constants const BIP_44_TRON_DERIVATION_PATH_PREFIX: string = "m/44'/195'"; const BANDWIDTH_PRICE: number = 1_000; // Fee rate multipliers const FEE_RATE_NORMAL_MULTIPLIER: number = 1.1; const FEE_RATE_FAST_MULTIPLIER: number = 2.0; ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Tron Wallet Usage Get started with WDK's Tron Wallet Configuration *** ## Need Help? # Configuration (/sdk/wallet-modules/wallet-tron/configuration) ## Wallet Configuration ```javascript import WalletManagerTron from '@tetherto/wdk-wallet-tron' const config = { provider: 'https://api.trongrid.io', // Tron RPC endpoint transferMaxFee: 10000000 // Maximum fee in sun (optional) } const wallet = new WalletManagerTron(seedPhrase, config) ``` ## Account Configuration ```javascript import { WalletAccountTron } from '@tetherto/wdk-wallet-tron' const accountConfig = { provider: 'https://api.trongrid.io', transferMaxFee: 10000000 // Maximum fee in sun (optional) } const account = new WalletAccountTron(seedPhrase, "0'/0/0", accountConfig) ``` ## Configuration Options ### Provider The `provider` option specifies the Tron RPC endpoint or TronWeb instance for blockchain interactions. **Type:** `string | TronWeb` **Example:** ```javascript const config = { provider: 'https://api.trongrid.io' } ``` ### Transfer Max Fee The `transferMaxFee` option sets the maximum fee amount (in sun) for transfer operations. This helps prevent transactions from being sent with unexpectedly high fees. **Type:** `number` (optional)\ **Unit:** Sun (1 TRX = 1,000,000 Sun) **Example:** ```javascript const config = { transferMaxFee: 10000000 // 10 TRX in sun } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Tron Wallet Usage Get started with WDK's Tron Wallet API *** ## Need Help? # Wallet Tron Overview (/sdk/wallet-modules/wallet-tron) A simple and secure package to manage BIP-44 wallets for the Tron blockchain. This package provides a clean API for creating, managing, and interacting with Tron wallets using BIP-39 seed phrases and Tron-specific derivation paths. ## Features * **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases * **Tron Derivation Paths**: Support for BIP-44 standard derivation paths for Tron * **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase * **Tron Address Support:** Generate and manage Tron addresses * **Message Signing:** Sign and verify messages using Tron cryptography * **Transaction Management**: Send transactions and get fee estimates * **TRC20 Support:** Query native TRX and TRC20 token balances. * **TypeScript Support**: Full TypeScript definitions included * **Memory Safety**: Secure private key management with automatic memory cleanup * **Provider Flexibility:** Support for custom Tron RPC endpoints ## Supported Networks This package works with the Tron blockchain, including: * **Tron Mainnet** * **Tron Shasta Testnet** ## Next Steps Get started with WDK in a Node.js environment Get started with WDK's Tron Wallet configuration Get started with WDK's Tron Wallet API Get started with WDK's with Tron Wallet usage *** ## Need Help? # Usage (/sdk/wallet-modules/wallet-tron/usage) The `@tetherto/wdk-wallet-tron` module provides wallet management for the Tron blockchain. Install the package and create your first wallet. Work with multiple accounts and custom derivation paths. Query native TRX and TRC20 token balances. Send native TRX and estimate transaction fees. Transfer TRC20 tokens and estimate fees. Sign messages and verify secp256k1 signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Tron Wallet Configuration Get started with WDK's Tron Wallet API *** ## Need Help? # API Reference (/sdk/wallet-modules/wallet-tron-gasfree/api-reference) ## Table of Contents | Class | Description | Methods | | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | [WalletManagerTronGasfree](#walletmanagertrongasfree) | Main class for managing gas-free Tron wallets. Extends `WalletManagerTron`. | [Constructor](#constructor), [Methods](#methods) | | [WalletAccountTronGasfree](#walletaccounttrongasfree) | Individual gas-free Tron wallet account implementation. Extends `WalletAccountReadOnlyTronGasfree`. | [Constructor](#constructor-1), [Methods](#methods-1) | | [WalletAccountReadOnlyTronGasfree](#walletaccountreadonlytrongasfree) | Read-only gas-free Tron wallet account. | [Constructor](#constructor-2), [Methods](#methods-2) | ### WalletManagerTronGasfree The main class for managing gas-free Tron wallets. #### Constructor ```javascript new WalletManagerTronGasfree(seed, config) ``` **Parameters:** * `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes * `config` (object): Configuration object * `chainId` (string): The blockchain's id * `provider` (string): Tron RPC endpoint URL * `gasFreeProvider` (string): Gas-free service endpoint * `gasFreeApiKey` (string): API key for gas-free provider * `gasFreeApiSecret` (string): API secret for gas-free provider * `serviceProvider` (string): Service provider Tron address * `verifyingContract` (string): Gas-free verifying contract address * `transferMaxFee` (number, optional): Maximum fee for transfer operations **Example:** ```javascript const wallet = new WalletManagerTronGasfree(seedPhrase, { chainId: '728126428', provider: 'https://api.trongrid.io', gasFreeProvider: 'https://gasfree.provider.url', gasFreeApiKey: 'your-api-key', gasFreeApiSecret: 'your-api-secret', serviceProvider: 'T...', verifyingContract: 'T...', transferMaxFee: 10000000 // Optional }) ``` #### Methods | Method | Description | Returns | | ------------------------ | ---------------------------------------------------------------- | ------------------------------------------- | | `getAccount(index)` | Returns a wallet account at the specified index | `Promise\` | | `getAccountByPath(path)` | Returns a wallet account at the specified BIP-44 derivation path | `Promise\` | | `getFeeRates()` | Returns current fee rates for normal and fast transactions | `Promise\<{normal: number, fast: number}\>` | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | ##### `getAccount(index)` Returns a gas-free wallet account at the specified index. **Parameters:** * `index` (number, optional): The index of the account to get (default: 0) **Returns:** `Promise\` - The wallet account **Example:** ```javascript const account = await wallet.getAccount(0) ``` ##### `getAccountByPath(path)` Returns a gas-free wallet account at the specified BIP-44 derivation path. **Parameters:** * `path` (string): The derivation path (e.g., "0'/0/0") **Returns:** `Promise\` - The wallet account **Example:** ```javascript const account = await wallet.getAccountByPath("0'/0/1") ``` ##### `getFeeRates()` Returns current fee rates for normal and fast transactions. **Returns:** `Promise\<{normal: number, fast: number}\>` - Object containing fee rates in sun * `normal`: Fee rate for normal priority transactions * `fast`: Fee rate for high priority transactions **Example:** ```javascript const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sun') console.log('Fast fee rate:', feeRates.fast, 'sun') ``` ##### `dispose()` Disposes all wallet accounts, clearing private keys from memory. This method should be called when you're done using the wallet to ensure sensitive data is removed. **Example:** ```javascript wallet.dispose() ``` ### WalletAccountTronGasfree Individual gas-free Tron wallet account implementation. #### Constructor ```javascript new WalletAccountTronGasfree(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): Same configuration object as WalletManagerTronGasfree #### Methods | Method | Description | Returns | | ------------------------------- | -------------------------------------------------------------- | ---------------------------------------- | | `getAddress()` | Returns the account's address | `Promise\` | | `getBalance()` | Returns the native TRX balance (in sun) | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific TRC20 token | `Promise\` | | `transfer(options)` | Transfers TRC20 tokens to another address | `Promise\<{hash: string, fee: number}\>` | | `quoteTransfer(options)` | Estimates the fee for a TRC20 transfer | `Promise\<{fee: number}\>` | | `sign(message)` | Signs a message using the account's private key | `Promise\` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `dispose()` | Disposes the wallet account, clearing private keys from memory | `void` | ##### `getAddress()` Returns the account's gas-free Tron address. **Returns:** `Promise\` - The account's Tron address **Example:** ```javascript const address = await account.getAddress() console.log('Account address:', address) ``` ##### `getBalance()` Returns the native TRX balance in sun units. **Returns:** `Promise\` - Balance in sun **Example:** ```javascript const balance = await account.getBalance() console.log('TRX Balance:', balance, 'sun') ``` ##### `getTokenBalance(tokenAddress)` Returns the balance of a specific TRC20 token. **Parameters:** * `tokenAddress` (string): The TRC20 contract address (e.g., 'T...') **Returns:** `Promise\` - Token balance in base units **Example:** ```javascript const tokenBalance = await account.getTokenBalance('T...') console.log('Token balance:', tokenBalance) ``` ##### `transfer(options)` Transfers TRC20 tokens to another address using the gas-free service. **Parameters:** * `options` (TransferOptions): Transfer options * `token` (string): TRC20 contract address * `recipient` (string): Recipient's Tron address * `amount` (number): Amount in token base units **Returns:** `Promise\<{hash: string, fee: number}\>` - Object containing transaction hash and fee paid in token base units **Example:** ```javascript const result = await account.transfer({ token: 'T...', // TRC20 contract address recipient: 'T...', // Recipient's address amount: 1000000 // Amount in token base units }) console.log('Transaction hash:', result.hash) console.log('Fee paid:', result.fee, 'token base units') ``` ##### `quoteTransfer(options)` Estimates the fee for a TRC20 token transfer. **Parameters:** * `options` (TransferOptions): Transfer options (same as transfer method) **Returns:** `Promise\<{fee: number}\>` - Estimated fee in token base units **Example:** ```javascript const quote = await account.quoteTransfer({ token: 'T...', recipient: 'T...', amount: 1000000 }) console.log('Estimated fee:', quote.fee, 'token base units') ``` ##### `sign(message)` Signs a message using the account's private key. **Parameters:** * `message` (string): The message to sign **Returns:** `Promise\` - The message signature **Example:** ```javascript const 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\` - True if the signature is valid **Example:** ```javascript const isValid = await account.verify('Hello, World!', signature) console.log('Signature valid:', isValid) ``` ##### `dispose()` Disposes the wallet account, clearing private keys from memory. **Example:** ```javascript account.dispose() ``` ### WalletAccountReadOnlyTronGasfree Read-only gas-free Tron wallet account. #### Constructor ```javascript new WalletAccountReadOnlyTronGasfree(address, config) ``` **Parameters:** * `address` (string): The account's Tron address * `config` (object): Configuration object * `chainId` (string): The blockchain's id * `provider` (string): Tron RPC endpoint URL * `gasFreeProvider` (string): Gas-free service endpoint * `gasFreeApiKey` (string): API key for gas-free provider * `gasFreeApiSecret` (string): API secret for gas-free provider * `serviceProvider` (string): Service provider Tron address * `verifyingContract` (string): Gas-free verifying contract address #### Methods | Method | Description | Returns | | ------------------------------- | --------------------------------------------- | -------------------------- | | `getAddress()` | Returns the account's address | `Promise\` | | `getBalance()` | Returns the native TRX balance (in sun) | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific TRC20 token | `Promise\` | | `quoteTransfer(options)` | Estimates the fee for a TRC20 transfer | `Promise\<{fee: number}\>` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | ##### `getAddress()` Returns the account's gas-free Tron address. **Returns:** `Promise\` - The account's Tron address **Example:** ```javascript const address = await readOnlyAccount.getAddress() console.log('Account address:', address) ``` ##### `getBalance()` Returns the native TRX balance in sun units. **Returns:** `Promise\` - Balance in sun **Example:** ```javascript const balance = await readOnlyAccount.getBalance() console.log('TRX Balance:', balance, 'sun') ``` ##### `getTokenBalance(tokenAddress)` Returns the balance of a specific TRC20 token. **Parameters:** * `tokenAddress` (string): The TRC20 contract address (e.g., 'T...') **Returns:** `Promise\` - Token balance in base units **Example:** ```javascript const tokenBalance = await readOnlyAccount.getTokenBalance('T...') console.log('Token balance:', tokenBalance) ``` ##### `quoteTransfer(options)` Estimates the fee for a TRC20 token transfer without requiring private keys. **Parameters:** * `options` (TransferOptions): Transfer options * `token` (string): TRC20 contract address * `recipient` (string): Recipient's Tron address * `amount` (number): Amount in token base units **Returns:** `Promise\<{fee: number}\>` - Estimated fee in token base units **Example:** ```javascript const quote = await readOnlyAccount.quoteTransfer({ token: 'T...', recipient: 'T...', amount: 1000000 }) console.log('Estimated fee:', quote.fee, 'token base units') ``` ##### `verify(message, signature)` Verifies a message signature. **Parameters:** * `message` (string): The original message * `signature` (string): The signature to verify **Returns:** `Promise\` - True if the signature is valid **Example:** ```javascript const isValid = await readOnlyAccount.verify('Hello, World!', signature) console.log('Signature valid:', isValid) ``` ## Types ### TransferOptions Configuration options for token transfers. ```typescript interface TransferOptions { /** * The TRC20 token contract address * @example 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' // USDT contract */ token: string; /** * The recipient's Tron address * @example 'TJYeasTPa6gpEEfQa7s9CqqqgvYh6JtpAR' */ recipient: string; /** * Amount to transfer in token base units * @example 1000000 // 1 USDT (6 decimals) */ amount: number; } ``` ### TransferResult Result object returned by transfer operations. ```typescript interface TransferResult { /** * The transaction hash * @example '0x123...' */ hash: string; /** * Fee paid in token base units * @example 1000 // Fee in token base units */ fee: number; } ``` ### FeeRates Fee rate information for transactions. ```typescript interface FeeRates { /** * Fee rate for normal priority transactions (in sun) * @example 1000 */ normal: number; /** * Fee rate for high priority transactions (in sun) * @example 2000 */ fast: number; } ``` ### TronGasfreeWalletConfig Configuration options for wallet initialization. ```typescript interface TronGasfreeWalletConfig { /** * The blockchain's ID * @example '728126428' // Tron Mainnet */ chainId: string; /** * Tron RPC endpoint URL or TronWeb instance * @example 'https://api.trongrid.io' */ provider: string | TronWeb; /** * Gas-free service endpoint * @example 'https://gasfree.trongrid.io' */ gasFreeProvider: string; /** * API key for gas-free provider */ gasFreeApiKey: string; /** * API secret for gas-free provider */ gasFreeApiSecret: string; /** * Service provider Tron address * @example 'T...' */ serviceProvider: string; /** * Gas-free verifying contract address * @example 'T...' */ verifyingContract: string; /** * Maximum fee for transfer operations (in token base units) * @optional * @example 10000000 */ transferMaxFee?: number; } ``` ### KeyPair Account key pair information. ```typescript interface KeyPair { /** * Public key as buffer */ publicKey: Buffer; /** * Private key as buffer (sensitive data) */ privateKey: Buffer; } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Tron Gasfree Wallet Usage Get started with WDK's Tron Gasfree Wallet Configuration *** ## Need Help? # Configuration (/sdk/wallet-modules/wallet-tron-gasfree/configuration) ## Network & Service Providers | Service | Provider | URL (Mainnet) | URL (Testnet) | | :------------------- | :--------- | :------------------------------ | :----------------------------------- | | **RPC Provider** | TronGrid | `https://api.trongrid.io` | `https://nile.trongrid.io` | | **Gas-Free Service** | GasFree.io | `https://open.gasfree.io/tron/` | `https://open-test.gasfree.io/nile/` | > **Note:** For the latest connection parameters and contract addresses, please refer to the official [GasFree Specification](https://gasfree.io/specification?lang=en-US). ## Wallet Configuration ```javascript import WalletManagerTronGasfree from '@tetherto/wdk-wallet-tron-gasfree' import TronWeb from 'tronweb' // Option 1: Using RPC URL const config = { // Required parameters chainId: '728126428', // Blockchain ID provider: 'https://api.trongrid.io', // Tron RPC endpoint gasFreeProvider: 'https://open.gasfree.io/tron/', // Gas-free service URL gasFreeApiKey: 'your-api-key', // Gas-free API key gasFreeApiSecret: 'your-api-secret', // Gas-free API secret serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', // Service provider address verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', // Verifying contract address // Optional parameter transferMaxFee: 10000000 // Maximum fee in token base units } const wallet = new WalletManagerTronGasfree(seedPhrase, config) // Option 2: Using TronWeb instance const tronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io' }) const config2 = { chainId: '728126428', provider: tronWeb, gasFreeProvider: 'https://open.gasfree.io/tron/', gasFreeApiKey: 'your-api-key', gasFreeApiSecret: 'your-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH' } ``` ## Account Configuration Both `WalletAccountTronGasfree` and `WalletAccountReadOnlyTronGasfree` share similar configuration requirements: ```javascript import { WalletAccountTronGasfree, WalletAccountReadOnlyTronGasfree } from '@tetherto/wdk-wallet-tron-gasfree' // Full access account const account = new WalletAccountTronGasfree( seedPhrase, "0'/0/0", // BIP-44 derivation path { chainId: '728126428', provider: 'https://api.trongrid.io', gasFreeProvider: 'https://open.gasfree.io/tron/', gasFreeApiKey: 'your-api-key', gasFreeApiSecret: 'your-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', transferMaxFee: 10000000 // Optional } ) // Read-only account (transferMaxFee not needed) const readOnlyAccount = new WalletAccountReadOnlyTronGasfree( 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', // Tron address { chainId: '728126428', provider: 'https://api.trongrid.io', gasFreeProvider: 'https://open.gasfree.io/tron/', gasFreeApiKey: 'your-api-key', gasFreeApiSecret: 'your-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH' } ) ``` ## Configuration Options ### Provider The `provider` option specifies how to connect to the Tron network. **Type:** `string | TronWeb` **Required:** Yes **Examples:** ```javascript // Option 1: Using RPC URL const config = { provider: 'https://api.trongrid.io' } // Option 2: Using TronWeb instance const tronWeb = new TronWeb({ fullHost: 'https://api.trongrid.io' }) const config = { provider: tronWeb } ``` ### Chain ID The `chainId` option specifies the blockchain's ID. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { chainId: '728126428' // Tron Mainnet } ``` ### Gas-Free Provider The `gasFreeProvider` option specifies the URL of the gas-free service. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { gasFreeProvider: 'https://open.gasfree.io/tron/' } ``` ### Gas-Free API Key The `gasFreeApiKey` option is your API key for the gas-free service. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { gasFreeApiKey: 'your-api-key' } ``` ### Gas-Free API Secret The `gasFreeApiSecret` option is your API secret for the gas-free service. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { gasFreeApiSecret: 'your-api-secret' } ``` ### Service Provider The `serviceProvider` option is the Tron address of the gas-free service provider. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH' } ``` ### Verifying Contract The `verifyingContract` option is the Tron address of the contract that verifies gas-free transactions. **Type:** `string` **Required:** Yes **Example:** ```javascript const config = { verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH' } ``` ### Transfer Max Fee The `transferMaxFee` option sets a maximum limit for transaction fees to prevent unexpectedly high costs. **Type:** `number` **Required:** No (optional) **Unit:** Token base units **Example:** ```javascript const config = { transferMaxFee: 10000000 // Maximum fee in token base units } // Usage with error handling try { const result = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }, { transferMaxFee: 5000 // Override default max fee }) } catch (error) { if (error.message.includes('exceeds the transfer max fee')) { console.error('Transfer cancelled: Fee too high') } } ``` ## Network-Specific Configurations ### Tron Mainnet ```javascript const mainnetConfig = { chainId: '728126428', provider: 'https://api.trongrid.io', gasFreeProvider: 'https://open.gasfree.io/tron/', gasFreeApiKey: 'your-api-key', gasFreeApiSecret: 'your-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TFFAMLQZybALab4uxHA9RBE7pxhUAjfF3U' // Official Mainnet Contract } ``` ### Tron Nile Testnet ```javascript const nileConfig = { chainId: '3448148188', // Nile Testnet (Specific ID required for GasFree) provider: 'https://nile.trongrid.io', gasFreeProvider: 'https://open-test.gasfree.io/nile/', gasFreeApiKey: 'your-testnet-api-key', gasFreeApiSecret: 'your-testnet-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'THQGuFzL87ZqhxkgqYEryRAd7gqFqL5rdc' // Official Testnet Contract } ``` Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Tron Gasfree Wallet Usage Get started with WDK's Tron Gasfree Wallet API *** ## Need Help? # Wallet Tron Gas-Free Overview (/sdk/wallet-modules/wallet-tron-gasfree) A simple and secure package to manage BIP-44 wallets for the Tron blockchain with **gas-free TRC20 token transfers**. This package provides a clean API for creating, managing, and interacting with Tron wallets using BIP-39 seed phrases and Tron-specific derivation paths, with support for gas-free operations via a service provider. ## Features * **Gas-Free Transactions**: Support for gas-free transactions using TRC20 tokens. * **BIP-39 Seed Phrase Support**: Generate and validate BIP-39 mnemonic seed phrases. * **Tron Derivation Paths**: Support for BIP-44 standard derivation paths for Tron. * **Multi-Account Management**: Create and manage multiple accounts from a single seed phrase. * **Tron Address Support**: Generate and manage Tron addresses. * **Message Signing**: Sign and verify messages using Tron cryptography. * **Transaction Management**: Send transactions and get fee estimates. * **TRC20 Support**: Query native TRX and TRC20 token balances. * **TypeScript Support**: Full TypeScript definitions included. * **Memory Safety**: Secure private key management with automatic memory cleanup. * **Provider Flexibility**: Support for custom Tron RPC endpoints. ## Supported Networks This package works with the Tron blockchain, including: * **Tron Mainnet** * **Tron Nile Testnet** ## Next Steps Get started with WDK in a Node.js environment Get started with WDK's Tron Gasfree Wallet configuration Get started with WDK's Tron Gasfree Wallet API Get started with WDK's with Tron Gasfree Wallet usage *** ## Need Help? # Usage (/sdk/wallet-modules/wallet-tron-gasfree/usage) The `@tetherto/wdk-wallet-tron-gasfree` module provides wallet management for the Tron blockchain with gas-free transaction support, where TRC20 transfer fees are handled by the gas-free service. Install the package and create your first gas-free wallet. Work with multiple accounts and custom derivation paths. Query native TRX and TRC20 token balances. Send native TRX transactions. Transfer TRC20 tokens gas-free. Sign messages and verify signatures. Handle errors, manage fees, and dispose of sensitive data. Get started with WDK in a Node.js environment Build mobile wallets with React Native Expo Get started with WDK's Tron Gasfree Wallet Configuration Get started with WDK's Tron Gasfree Wallet API *** ## Need Help? # Bridge Cross-Ecosystem (/sdk/bridge-modules/bridge-usdt0-evm/guides/bridge-cross-ecosystem) This guide covers [prerequisites](#prerequisites) and how to [bridge to Solana](#bridge-to-solana), [bridge to TON](#bridge-to-ton), and [bridge to TRON](#bridge-to-tron) using [`bridge()`](../api-reference). The same [`Usdt0ProtocolEvm`](../api-reference) instance you use for EVM destinations applies; only `targetChain` and `recipient` formats change. ## Prerequisites A [`Usdt0ProtocolEvm`](../api-reference) backed by a non-read-only EVM account, with enough USD₮ (and native gas for non-4337 accounts) on the source chain. Recipient strings must match each network’s address encoding. ## Bridge to Solana You can set `targetChain` to `solana` and pass a base58 Solana address as `recipient` when calling [`bridge()`](../api-reference): ```javascript title="Bridge toward Solana" const solanaResult = await bridgeProtocol.bridge({ targetChain: 'solana', recipient: 'HyXJcgYpURfDhgzuyRL7zxP4FhLg7LZQMeDrR4MXZcMN', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }) console.log('Solana bridge hash:', solanaResult.hash) console.log('Bridge fee:', solanaResult.bridgeFee) ``` Validate Solana addresses (length and base58 alphabet) before bridging. A malformed `recipient` fails the operation. ## Bridge to TON You can set `targetChain` to `ton` and supply a TON user-friendly or raw address string as `recipient` in [`bridge()`](../api-reference): ```javascript title="Bridge toward TON" const tonResult = await bridgeProtocol.bridge({ targetChain: 'ton', recipient: 'EQAd31gAUhdO0d0NZsNb_cGl_Maa9PSuNhVLE9z8bBSjX6Gq', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }) console.log('TON bridge hash:', tonResult.hash) ``` ## Bridge to TRON You can set `targetChain` to `tron` and pass a base58Check TRON address (typically starting with `T`) to [`bridge()`](../api-reference): ```javascript title="Bridge toward TRON" const tronResult = await bridgeProtocol.bridge({ targetChain: 'tron', recipient: 'TFG4wBaDQ8sHWWP1ACeSGnoNR6RRzevLPt', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }) console.log('TRON bridge hash:', tronResult.hash) ``` LayerZero endpoint IDs for these destinations are listed under [Supported chains](../api-reference) in the API reference. ## Next Steps Harden integrations with [Handle errors](./handle-errors), or return to [Bridge tokens](./bridge-tokens) for EVM-only flows and quotes. # Bridge Tokens (/sdk/bridge-modules/bridge-usdt0-evm/guides/bridge-tokens) This guide covers [prerequisites](#prerequisites), how to [run a standard EVM-to-EVM bridge](#run-a-standard-evm-to-evm-bridge), [quote bridge fees](#quote-bridge-fees), [override OFT routing](#override-oft-contract-and-destination-endpoint), and [set `bridgeMaxFee`](#cap-fees-with-bridgemaxfee) on the protocol. ## Prerequisites Complete [Get Started](./get-started): an account from [`new WalletAccountEvm(seed, path, config?)`](../../../wallet-modules/wallet-evm/api-reference) and a bridge from [`new Usdt0ProtocolEvm(account, config?)`](../api-reference). The source chain RPC must match the account network. ## Run a standard EVM-to-EVM bridge You can move USD₮ on the source chain toward another EVM chain by calling [`bridge()`](../api-reference) with `targetChain`, `recipient`, `token`, and `amount` (token base units). Amount `1000000n` is 1 USD₮ when the token uses 6 decimals. ```javascript title="Standard EVM bridge" const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }) console.log('Bridge transaction hash:', result.hash) console.log('Approve hash:', result.approveHash) console.log('Reset allowance hash:', result.resetAllowanceHash) console.log('Total fee:', result.fee, 'wei') console.log('Bridge fee:', result.bridgeFee, 'wei') ``` `resetAllowanceHash` appears for USD₮ on Ethereum when the implementation requires a zero allowance reset before a new approval. ## Quote bridge fees You can estimate gas and protocol fees without sending transactions using [`quoteBridge()`](../api-reference): ```javascript title="Quote before bridging" const quote = await bridgeProtocol.quoteBridge({ targetChain: 'polygon', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }) console.log('Estimated fee:', quote.fee, 'wei') console.log('Bridge fee:', quote.bridgeFee, 'wei') ``` Compare `quote.fee` and `quote.bridgeFee` to your risk limits before calling [`bridge()`](../api-reference). ## Override OFT contract and destination endpoint You can point [`bridge()`](../api-reference) at a specific OFT contract and LayerZero destination endpoint ID when auto-resolution is not enough. Supply values from your deployment or integration configuration (environment variables shown for illustration): ```javascript title="Custom OFT and dstEid on bridge" const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n, oftContractAddress: process.env.USDT0_OFT_ADDRESS, dstEid: Number(process.env.CUSTOM_DST_EID) }) console.log('Bridge transaction hash:', result.hash) ``` You can obtain matching fee estimates with [`quoteBridge()`](../api-reference) using the same `oftContractAddress` and `dstEid` fields: ```javascript title="Quote with OFT overrides" const customQuote = await bridgeProtocol.quoteBridge({ targetChain: 'arbitrum', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n, oftContractAddress: process.env.USDT0_OFT_ADDRESS, dstEid: Number(process.env.CUSTOM_DST_EID) }) console.log('Custom route quote fee:', customQuote.fee, 'wei') ``` Invalid pairings of `oftContractAddress` and `dstEid` fail at execution time. Validate addresses and endpoint IDs against LayerZero and your token deployment. ## Cap fees with bridgeMaxFee You can pass `bridgeMaxFee` into the [`new Usdt0ProtocolEvm(account, config?)`](../api-reference) constructor so [`bridge()`](../api-reference) rejects operations whose cost exceeds the cap: ```javascript title="Protocol-level bridgeMaxFee" import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' const cappedBridge = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) ``` If the quote exceeds `bridgeMaxFee`, [`bridge()`](../api-reference) throws (for example when the message includes `Exceeded maximum fee`). ERC-4337 accounts can also pass `bridgeMaxFee` in the second argument to [`bridge()`](../api-reference); see [Bridge with ERC-4337](./bridge-with-4337). ## Next Steps Bridge to Solana, TON, or TRON in [Bridge cross-ecosystem](./bridge-cross-ecosystem), or switch to a smart account in [Bridge with ERC-4337](./bridge-with-4337). # Bridge with ERC-4337 (/sdk/bridge-modules/bridge-usdt0-evm/guides/bridge-with-4337) This guide covers [prerequisites](#prerequisites), how to [create an ERC-4337 account](#create-a-walletaccountevmerc4337-account), and how to [call the bridge with paymaster configuration](#run-a-gasless-bridge-with-paymaster-options). ## Prerequisites * `@tetherto/wdk-wallet-evm-erc-4337` installed alongside [@tetherto/wdk-protocol-bridge-usdt0-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-bridge-usdt0-evm). * Bundler and paymaster endpoints for your chain (example uses Arbitrum public URLs from the API reference). ## Create a WalletAccountEvmErc4337 account You can construct an ERC-4337 signing account using [`new WalletAccountEvmErc4337(seed, path, config)`](../../../wallet-modules/wallet-evm-erc-4337/api-reference) with chain, provider, bundler, entry point, and paymaster settings: ```javascript title="ERC-4337 account on Arbitrum" import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337' const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' const account = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", { chainId: 42161, provider: 'https://arb1.arbitrum.io/rpc', bundlerUrl: 'https://api.candide.dev/public/v3/arbitrum', entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', safeModulesVersion: '0.3.0', paymasterUrl: 'https://api.candide.dev/public/v3/arbitrum', paymasterAddress: '0x8b1f6cb5d062aa2ce8d581942bbb960420d875ba', paymasterToken: { address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' } }) ``` You can wrap that account with the [`new Usdt0ProtocolEvm(account, config?)`](../api-reference) constructor: ```javascript title="Usdt0ProtocolEvm with ERC-4337 account" import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) ``` ## Run a gasless bridge with paymaster options You can execute [`bridge()`](../api-reference) with a second argument that includes `paymasterToken` (and optional `bridgeMaxFee` override) as described in the [methods table](../api-reference). User operations bundle approvals and the bridge into a single user-op hash on the result. ```javascript title="Gasless bridge with paymasterToken" const result = await bridgeProtocol.bridge( { targetChain: 'polygon', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }, { paymasterToken: { address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' }, bridgeMaxFee: 1000000000000000n } ) console.log('Bridge hash:', result.hash) console.log('Total fee:', result.fee) console.log('Bridge fee:', result.bridgeFee) ``` Unlike the standard EVM account path, the bundled flow returns a single `hash` for the user operation rather than separate approve and bridge transaction hashes. Paymaster policies, token addresses, and URLs are service-specific. Confirm supported tokens and networks with your bundler or paymaster provider before production use. ## Next Steps Bridge to non-EVM chains in [Bridge cross-ecosystem](./bridge-cross-ecosystem). For failure modes and cleanup, read [Handle errors](./handle-errors). # Get Started (/sdk/bridge-modules/bridge-usdt0-evm/guides/get-started) This guide shows how to [install the package](#install-the-package), [create an EVM account](#create-an-evm-account), [instantiate the bridge protocol](#instantiate-the-bridge-protocol), and review [supported chains](#supported-chains). ## Install the package ### Prerequisites * **[Node.js](https://nodejs.org/)**: version 18 or higher. * **[npm](https://www.npmjs.com/)**: usually bundled with Node.js. You can add the published package to your project from npm: [@tetherto/wdk-protocol-bridge-usdt0-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-bridge-usdt0-evm). ```bash title="Install @tetherto/wdk-protocol-bridge-usdt0-evm" npm install @tetherto/wdk-protocol-bridge-usdt0-evm ``` ## Create an EVM account You can construct a signing account using [`new WalletAccountEvm(seed, path, config?)`](../../../wallet-modules/wallet-evm/api-reference) from `@tetherto/wdk-wallet-evm` with an RPC `provider`: ```javascript title="Create WalletAccountEvm" import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' const account = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://eth.drpc.org' }) ``` **Seed phrase:** Store the mnemonic securely. Anyone with the phrase controls the funds on derived accounts. ## Instantiate the bridge protocol You can create a [`Usdt0ProtocolEvm`](../api-reference) instance with the [`new Usdt0ProtocolEvm(account, config?)`](../api-reference) constructor. Optional `bridgeMaxFee` caps the total bridge cost in wei (see [BridgeProtocolConfig](../api-reference)): ```javascript title="Construct Usdt0ProtocolEvm" import Usdt0ProtocolEvm from '@tetherto/wdk-protocol-bridge-usdt0-evm' const bridgeProtocol = new Usdt0ProtocolEvm(account, { bridgeMaxFee: 1000000000000000n }) ``` The account must not be read-only. Read-only accounts cannot call [`bridge()`](../api-reference). ## Supported chains Bridge operations use EVM source chains listed in the [API reference](../api-reference). Destination routes include the same EVM set where USD₮0 contracts are deployed, plus Solana (EID 30168), TON (EID 30343), and TRON (EID 30420). **Source chains (EVM, `targetChain` keys)** | Chain | Key | Chain ID | | -------------- | ----------- | -------- | | Ethereum | `ethereum` | 1 | | Arbitrum | `arbitrum` | 42161 | | Optimism | `optimism` | 10 | | Polygon | `polygon` | 137 | | Berachain | `berachain` | 80094 | | Ink | `ink` | 57073 | | Plasma | `plasma` | 9745 | | Conflux eSpace | `conflux` | 1030 | | Corn | `corn` | 21000000 | | Avalanche | `avalanche` | 43114 | | Celo | `celo` | 42220 | | Flare | `flare` | 14 | | HyperEVM | `hyperevm` | 999 | | Mantle | `mantle` | 5000 | | MegaETH | `megaeth` | 4326 | | Monad | `monad` | 143 | | Morph | `morph` | 2818 | | Rootstock | `rootstock` | 30 | | Sei | `sei` | 1329 | | Stable | `stable` | 988 | | Unichain | `unichain` | 130 | | XLayer | `xlayer` | 196 | Arbitrum supports ERC-4337 workflows (see [Bridge with ERC-4337](./bridge-with-4337)). **Non-EVM destinations** | Network | `targetChain` | Endpoint ID | | ------- | ------------- | ----------- | | Solana | `solana` | 30168 | | TON | `ton` | 30343 | | TRON | `tron` | 30420 | ## Next Steps Run a standard EVM-to-EVM transfer with [Bridge tokens](./bridge-tokens), or use [Bridge with ERC-4337](./bridge-with-4337) for gasless flows on supported networks. # Handle Errors (/sdk/bridge-modules/bridge-usdt0-evm/guides/handle-errors) This guide describes [errors thrown by the bridge](#errors-from-the-bridge-protocol), [how to catch and branch on messages](#catch-and-branch-on-error-messages), and [best practices](#best-practices) for clearing sensitive material from memory. ## Errors from the bridge protocol Calls to [`bridge()`](../api-reference) and [`quoteBridge()`](../api-reference) throw when the account is read-only, no provider is configured, the route is invalid, fees exceed [`bridgeMaxFee`](../api-reference), or the destination matches the source chain. The [API reference](../api-reference) lists representative `error.message` substrings. ## Catch and branch on error messages You can wrap [`bridge()`](../api-reference) in `try/catch` and inspect `error.message` for stable substrings: ```javascript title="Handle bridge errors" try { const result = await bridgeProtocol.bridge({ targetChain: 'arbitrum', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', token: '0xdac17f958d2ee523a2206206994597c13d831ec7', amount: 1000000n }) console.log('Bridge successful:', result.hash) } catch (error) { console.error('Bridge failed:', error.message) if (error.message.includes('not supported')) { console.error('Chain or token not supported') } if (error.message.includes('Exceeded maximum fee')) { console.error('Bridge fee above bridgeMaxFee') } if (error.message.includes('insufficient funds')) { console.error('Not enough tokens or gas') } if (error.message.includes('must be connected to a provider')) { console.error('Wallet not connected to blockchain') } if ( error.message.includes( 'requires the protocol to be initialized with a non read-only account' ) ) { console.error('Cannot bridge with read-only account') } if (error.message.includes('cannot be equal to the source chain')) { console.error('Source and destination chain must differ') } } ``` Prefer [`quoteBridge()`](../api-reference) before [`bridge()`](../api-reference) when you want to fail early on fee or route issues without broadcasting. ## Best practices You can clear private key material from memory when a session ends by calling [`account.dispose()`](../../../wallet-modules/wallet-evm/api-reference) on [`WalletAccountEvm`](../../../wallet-modules/wallet-evm/api-reference), or [`account.dispose()`](../../../wallet-modules/wallet-evm-erc-4337/api-reference) on [`WalletAccountEvmErc4337`](../../../wallet-modules/wallet-evm-erc-4337/api-reference): ```javascript title="Dispose EVM account after use" account.dispose() ``` Call dispose only when you no longer need signing for that account instance. Create a new account object for later sessions. Combine quoting, fee caps via [`new Usdt0ProtocolEvm(account, config?)`](../api-reference), and user-facing validation of `targetChain` and `recipient` to reduce avoidable failures. ## Next Steps Review configuration defaults in [WDK Bridge USD₮0 EVM Protocol Configuration](../configuration) or return to [Get Started](./get-started) for setup. # Buy and Sell (/sdk/fiat-modules/fiat-moonpay/guides/buy-and-sell) This guide explains [buying crypto (on-ramp)](#buy-crypto-on-ramp), [selling crypto (off-ramp)](#sell-crypto-off-ramp), [quotes](#get-price-quotes), [supported currencies](#supported-currencies-and-countries), [widget customization](#widget-customization), and [custom recipients](#custom-recipient-addresses). It assumes a [`MoonPayProtocol`](../api-reference) instance named `moonpay`. Amounts use smallest units: fiat in minor units (cents), crypto in on-chain base units (for example wei for ETH). ## Buy crypto (on-ramp) You can build a signed purchase URL with [`buy()`](../api-reference) when you know the fiat spend: ```typescript title="Buy with fiat amount" const result = await moonpay.buy({ cryptoAsset: 'usdt', fiatCurrency: 'usd', fiatAmount: 10000n }) window.open(result.buyUrl, '_blank') ``` You can request a fixed crypto amount instead by passing `cryptoAmount` to [`buy()`](../api-reference): ```typescript title="Buy with crypto amount" const result = await moonpay.buy({ cryptoAsset: 'eth', fiatCurrency: 'usd', cryptoAmount: 100000000000000000n }) window.open(result.buyUrl, '_blank') ``` ## Sell crypto (off-ramp) You can generate a sell widget URL with [`sell()`](../api-reference): ```typescript title="Sell ETH for USD" const result = await moonpay.sell({ cryptoAsset: 'eth', fiatCurrency: 'usd', cryptoAmount: 500000000000000000n }) window.open(result.sellUrl, '_blank') ``` ## Get price quotes You can preview economics before opening the widget using [`quoteBuy()`](../api-reference): ```typescript title="Buy quote" const buyQuote = await moonpay.quoteBuy({ cryptoAsset: 'eth', fiatCurrency: 'usd', fiatAmount: 10000n }) console.log('Crypto amount:', buyQuote.cryptoAmount) console.log('Fee:', buyQuote.fee) console.log('Exchange rate:', buyQuote.rate) ``` You can estimate proceeds for a sell with [`quoteSell()`](../api-reference): ```typescript title="Sell quote" const sellQuote = await moonpay.quoteSell({ cryptoAsset: 'eth', fiatCurrency: 'usd', cryptoAmount: 500000000000000000n }) console.log('Fiat amount:', sellQuote.fiatAmount) ``` ## Supported currencies and countries You can list tradable assets with [`getSupportedCryptoAssets()`](../api-reference): ```typescript title="Supported crypto" const cryptoAssets = await moonpay.getSupportedCryptoAssets() console.log(cryptoAssets) ``` You can list fiat currencies with [`getSupportedFiatCurrencies()`](../api-reference): ```typescript title="Supported fiat" const fiatCurrencies = await moonpay.getSupportedFiatCurrencies() console.log(fiatCurrencies) ``` You can check regional availability with [`getSupportedCountries()`](../api-reference): ```typescript title="Supported countries" const countries = await moonpay.getSupportedCountries() console.log(countries) ``` ## Widget customization You can pass UI options under `config` to [`buy()`](../api-reference) (see [`MoonPayBuyParams`](../api-reference)): ```typescript title="Themed buy widget" const result = await moonpay.buy({ cryptoAsset: 'usdt', fiatCurrency: 'eur', fiatAmount: 5000n, config: { colorCode: '#1f2937', theme: 'dark', language: 'de', redirectURL: 'https://yourapp.com/payment-complete', lockAmount: true, email: 'user@example.com', externalCustomerId: 'user_123' } }) window.open(result.buyUrl, '_blank') ``` ## Custom recipient addresses By default [`buy()`](../api-reference) credits the connected wallet. You can override the destination with `recipient`: ```typescript title="Custom buy recipient" const result = await moonpay.buy({ cryptoAsset: 'eth', fiatCurrency: 'usd', fiatAmount: 10000n, recipient: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' }) window.open(result.buyUrl, '_blank') ``` You can set a refund destination on sells with `refundAddress` on [`sell()`](../api-reference): ```typescript title="Custom sell refund address" const result = await moonpay.sell({ cryptoAsset: 'eth', fiatCurrency: 'usd', cryptoAmount: 500000000000000000n, refundAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' }) window.open(result.sellUrl, '_blank') ``` ## Next Steps * [Manage transactions](manage-transactions) * [Get started](get-started) * [API reference](../api-reference) # Get Started (/sdk/fiat-modules/fiat-moonpay/guides/get-started) This guide covers [installation](#installation) and [initializing the protocol](#initialize-moonpayprotocol). You need [Node.js](https://nodejs.org/), [npm](https://www.npmjs.com/), and MoonPay API keys from your MoonPay dashboard. ## Installation Run the following to install [@tetherto/wdk-protocol-fiat-moonpay](https://www.npmjs.com/package/@tetherto/wdk-protocol-fiat-moonpay): ```bash title="Install with npm" npm install @tetherto/wdk-protocol-fiat-moonpay ``` ## Initialize MoonPayProtocol You can create a fiat ramp client with [`new MoonPayProtocol(account, config)`](../api-reference): ```typescript title="Construct MoonPayProtocol" import MoonPayProtocol from '@tetherto/wdk-protocol-fiat-moonpay' const moonpay = new MoonPayProtocol(walletAccount, { apiKey: process.env.MOONPAY_PUBLISHABLE_KEY, secretKey: process.env.MOONPAY_SECRET_KEY }) ``` Never ship a secret key to browsers. Run server-side signing where your architecture allows, and rotate keys if they leak. See [Configuration](../configuration) for `cacheTime` and related options. ## Next Steps * [Buy and sell](buy-and-sell) * [Manage transactions](manage-transactions) # Manage Transactions (/sdk/fiat-modules/fiat-moonpay/guides/manage-transactions) This guide shows how to [check transaction status](#check-transaction-status) and [read transaction details](#read-transaction-details) with [`getTransactionDetail()`](../api-reference). Pass the identifier MoonPay returns after checkout (for example from your redirect URL or webhook payload). ## Check transaction status You can read the high-level state of a buy with [`getTransactionDetail()`](../api-reference): ```typescript title="Buy transaction status" const buyTx = await moonpay.getTransactionDetail(moonpayTransactionId, 'buy') console.log('Status:', buyTx.status) ``` `status` is one of `completed`, `failed`, or `in_progress` as described in the API reference. ## Read transaction details You can load the same record to inspect assets and currencies using [`getTransactionDetail()`](../api-reference): ```typescript title="Buy transaction fields" const buyTx = await moonpay.getTransactionDetail(moonpayTransactionId, 'buy') console.log('Crypto asset:', buyTx.cryptoAsset) console.log('Fiat currency:', buyTx.fiatCurrency) console.log('Metadata:', buyTx.metadata) ``` You can query a sell the same way by passing `sell` as the direction to [`getTransactionDetail()`](../api-reference): ```typescript title="Sell transaction details" const sellTx = await moonpay.getTransactionDetail(moonpayTransactionId, 'sell') console.log('Status:', sellTx.status) console.log('Crypto asset:', sellTx.cryptoAsset) console.log('Fiat currency:', sellTx.fiatCurrency) ``` The second argument defaults to `buy` when omitted; set it explicitly for sell flows. ## Next Steps * [Buy and sell](buy-and-sell) * [Get started](get-started) * [Configuration](../configuration) # Get Started (/sdk/lending-modules/lending-aave-evm/guides/get-started) This guide covers [installation](#installation), [creating the lending client](#create-the-lending-client), and [prerequisites](#prerequisites). Use [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/) on your machine. ## Installation Run the following to install [@tetherto/wdk-protocol-lending-aave-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-lending-aave-evm): ```bash title="Install with npm" npm install @tetherto/wdk-protocol-lending-aave-evm ``` ## Create the lending client You can attach Aave V3 actions to an EVM account from [`WalletAccountEvm`](/sdk/wallet-modules/wallet-evm/api-reference) with [`new AaveProtocolEvm(account)`](../api-reference) on [`AaveProtocolEvm`](../api-reference): ```javascript title="Create AaveProtocolEvm" import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' const account = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) const aave = new AaveProtocolEvm(account) ``` ## Prerequisites **Token balance:** To supply or repay, hold the ERC-20 in the wallet. **Gas:** Keep native balance (ETH on Ethereum, and so on) for transaction fees unless you use sponsored ERC-4337 flows. **Networks:** This module targets mainnet deployments; confirm your RPC matches [supported networks](../configuration). Use contract addresses for Aave-supported reserves. On Ethereum mainnet, USD₮ uses `0xdAC17F958D2ee523a2206206994597C13D831ec7` (use `USDT` in code identifiers and literals). ## Next Steps * [Lending operations](lending-operations) * [Handle errors](handle-errors) # Handle Errors (/sdk/lending-modules/lending-aave-evm/guides/handle-errors) This guide explains how to [handle operation errors](#operation-errors) and follow [best practices](#best-practices) for disposing wallet state. ## Operation errors You can catch failures from [`supply()`](../api-reference), [`withdraw()`](../api-reference), [`borrow()`](../api-reference), and [`repay()`](../api-reference) with `try/catch`: ```javascript title="Handle a failed supply" try { await aave.supply({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', amount: 0n }) } catch (e) { console.error('Lending failed:', e.message) if (e.message.includes('zero')) { console.log('Amount must be greater than zero') } } ``` You can isolate quote failures from [`quoteSupply()`](../api-reference) (or the other `quote*` methods) when you only need an estimate: ```javascript title="Handle quote errors" try { const q = await aave.quoteBorrow({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', amount: 1000000n }) console.log('Borrow fee (wei):', q.fee) } catch (e) { console.error('Quote failed:', e.message) } ``` See [Rules & Notes](../api-reference) for address and amount validation expectations. ## Best Practices You can wipe private keys after lending work by calling [`dispose()`](/sdk/wallet-modules/wallet-evm/api-reference) on [`WalletAccountEvm`](/sdk/wallet-modules/wallet-evm/api-reference), or [`dispose()`](/sdk/wallet-modules/wallet-evm/api-reference) on [`WalletManagerEvm`](/sdk/wallet-modules/wallet-evm/api-reference): ```javascript title="Dispose after lending session" try { await aave.supply({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', amount: 1000000n }) } finally { account.dispose() } ``` For ERC-4337 accounts, use [`dispose()`](/sdk/wallet-modules/wallet-evm-erc-4337/api-reference) on the smart-account type. Clear references to [`AaveProtocolEvm`](../api-reference) when the session ends. ## Next Steps * [Lending operations](lending-operations) * [Get started](get-started) * [API reference](../api-reference) # Lending Operations (/sdk/lending-modules/lending-aave-evm/guides/lending-operations) This guide walks through [supply](#supply), [withdraw](#withdraw), [borrow](#borrow), [repay](#repay), [quotes](#quotes-before-sending), [ERC-4337 usage](#erc-4337-smart-accounts), and [reading account data](#reading-account-data). It assumes an [`AaveProtocolEvm`](../api-reference) instance named `aave` and the USD₮ contract on Ethereum mainnet `0xdAC17F958D2ee523a2206206994597C13D831ec7`. ## Supply You can deposit reserves into the pool using [`supply()`](../api-reference): ```javascript title="Supply USDT" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const tx = await aave.supply({ token: USDT, amount: 1000000n }) console.log('Supply tx hash:', tx.hash) ``` ## Withdraw You can remove supplied liquidity using [`withdraw()`](../api-reference): ```javascript title="Withdraw USDT" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const tx = await aave.withdraw({ token: USDT, amount: 1000000n }) console.log('Withdraw tx hash:', tx.hash) ``` ## Borrow You can draw debt against your collateral using [`borrow()`](../api-reference): ```javascript title="Borrow USDT" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const tx = await aave.borrow({ token: USDT, amount: 1000000n }) console.log('Borrow tx hash:', tx.hash) ``` ## Repay You can pay down debt using [`repay()`](../api-reference): ```javascript title="Repay USDT" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const tx = await aave.repay({ token: USDT, amount: 1000000n }) console.log('Repay tx hash:', tx.hash) ``` ## Quotes before sending You can estimate the supply fee with [`quoteSupply()`](../api-reference): ```javascript title="Quote supply fee" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const supplyQuote = await aave.quoteSupply({ token: USDT, amount: 1000000n }) console.log('Supply fee (wei):', supplyQuote.fee) ``` You can estimate the withdraw fee with [`quoteWithdraw()`](../api-reference): ```javascript title="Quote withdraw fee" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const withdrawQuote = await aave.quoteWithdraw({ token: USDT, amount: 1000000n }) console.log('Withdraw fee (wei):', withdrawQuote.fee) ``` You can estimate the borrow fee with [`quoteBorrow()`](../api-reference): ```javascript title="Quote borrow fee" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const borrowQuote = await aave.quoteBorrow({ token: USDT, amount: 1000000n }) console.log('Borrow fee (wei):', borrowQuote.fee) ``` You can estimate the repay fee with [`quoteRepay()`](../api-reference): ```javascript title="Quote repay fee" const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7' const repayQuote = await aave.quoteRepay({ token: USDT, amount: 1000000n }) console.log('Repay fee (wei):', repayQuote.fee) ``` Health factor and collateralization limits still apply. A quote does not guarantee the transaction will succeed if on-chain state changes. ## ERC-4337 smart accounts You can run the same methods through [`WalletAccountEvmErc4337`](/sdk/wallet-modules/wallet-evm-erc-4337/api-reference) and pass a second `config` argument to override per-call gas payment settings. In `v1.0.0-beta.4`, the lending methods accept the same override families as the wallet module: paymaster token, sponsorship policy, and native coins. See the [ERC-4337 config override](../api-reference) section for the full field list. ```javascript title="Supply with paymaster" import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337' import AaveProtocolEvm from '@tetherto/wdk-protocol-lending-aave-evm' const aa = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", { chainId: 42161, provider: 'https://arb1.arbitrum.io/rpc', bundlerUrl: process.env.BUNDLER_URL, paymasterUrl: process.env.PAYMASTER_URL }) const aaveAA = new AaveProtocolEvm(aa) const result = await aaveAA.supply( { token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', amount: 1000000n }, { paymasterToken: { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' } } ) console.log('Supply hash:', result.hash) ``` You can use the same second argument to: * override paymaster-token mode with `paymasterUrl`, `paymasterAddress`, `paymasterToken`, or `transferMaxFee` * switch one call to sponsorship mode with `isSponsored`, `paymasterUrl`, and `sponsorshipPolicyId` * switch one call to native-coin gas mode with `useNativeCoins` and `transferMaxFee` Use token addresses that exist on the same chain as the smart account RPC. ## Reading account data You can inspect collateral, debt, and health using [`getAccountData()`](../api-reference): ```javascript title="Read Aave account data" const data = await aave.getAccountData() console.log({ totalCollateralBase: data.totalCollateralBase, totalDebtBase: data.totalDebtBase, availableBorrowsBase: data.availableBorrowsBase, currentLiquidationThreshold: data.currentLiquidationThreshold, ltv: data.ltv, healthFactor: data.healthFactor }) ``` ## Next Steps * [Handle errors](handle-errors) * [Get started](get-started) * [API reference](../api-reference) # Execute Swaps (/sdk/swap-modules/swap-velora-evm/guides/execute-swaps) This guide explains how to run a [basic exact-input swap](#basic-exact-input-swap), an [exact-output swap](#exact-output-swap), and a [swap from an ERC-4337 smart account](#swap-with-erc-4337). You should already have a [`VeloraProtocolEvm`](../api-reference) instance. Swaps spend tokens and gas on-chain. Use amounts you control and an RPC you trust. ## Basic exact-input swap You can sell an exact amount of the input token using [`swap()`](../api-reference): ```javascript title="Exact input: USDT to WETH" const result = await swapProtocol.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) console.log('Swap transaction hash:', result.hash) console.log('Total fee (wei):', result.fee) console.log('Tokens sold (base units):', result.tokenInAmount) console.log('Tokens bought (base units):', result.tokenOutAmount) ``` ## Exact output swap You can receive an exact amount of the output token by passing `tokenOutAmount` to [`swap()`](../api-reference): ```javascript title="Exact output amount" const result = await swapProtocol.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenOutAmount: 500000000000000000n }) console.log('Swap hash:', result.hash) console.log('Tokens sold (base units):', result.tokenInAmount) console.log('Tokens bought (base units):', result.tokenOutAmount) ``` ## Swap with ERC-4337 You can perform a user-operation-backed swap by constructing [`VeloraProtocolEvm`](../api-reference) with [`WalletAccountEvmErc4337`](../../../wallet-modules/wallet-evm-erc-4337/api-reference) and passing paymaster options to [`swap()`](../api-reference): ```javascript title="Swap with smart account and paymaster" import { WalletAccountEvmErc4337 } from '@tetherto/wdk-wallet-evm-erc-4337' import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' const aa = new WalletAccountEvmErc4337(seedPhrase, "0'/0/0", { chainId: 42161, provider: 'https://arb1.arbitrum.io/rpc', bundlerUrl: process.env.BUNDLER_URL, paymasterUrl: process.env.PAYMASTER_URL }) const swapAA = new VeloraProtocolEvm(aa, { swapMaxFee: 200000000000000n }) const result = await swapAA.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }, { paymasterToken: 'USDT', swapMaxFee: 200000000000000n }) console.log('Swap hash:', result.hash) console.log('Total fee (wei):', result.fee) ``` Token addresses must match the chain your account uses (for example, mainnet USD₮ addresses differ from Arbitrum). ## Next Steps * [Get swap quotes](get-swap-quotes) before sending * [Handle errors](handle-errors) * [Get started](get-started) if you still need setup # Get Started (/sdk/swap-modules/swap-velora-evm/guides/get-started) This guide covers [installation](#installation), [create the swap protocol](#create-the-swap-protocol), and [supported networks](#supported-networks). You need [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/) to follow along. ## Installation Run the following to install [@tetherto/wdk-protocol-swap-velora-evm](https://www.npmjs.com/package/@tetherto/wdk-protocol-swap-velora-evm): ```bash title="Install with npm" npm install @tetherto/wdk-protocol-swap-velora-evm ``` You also need an EVM wallet account from [`@tetherto/wdk-wallet-evm`](https://www.npmjs.com/package/@tetherto/wdk-wallet-evm) (or an ERC-4337 account from [`@tetherto/wdk-wallet-evm-erc-4337`](https://www.npmjs.com/package/@tetherto/wdk-wallet-evm-erc-4337)) on the same chain as your RPC provider. ## Create the swap protocol You can construct a swap client with [`new VeloraProtocolEvm(account, config?)`](../api-reference) on top of [`VeloraProtocolEvm`](../api-reference): ```javascript title="Create VeloraProtocolEvm" import VeloraProtocolEvm from '@tetherto/wdk-protocol-swap-velora-evm' import { WalletAccountEvm } from '@tetherto/wdk-wallet-evm' const account = new WalletAccountEvm(seedPhrase, "0'/0/0", { provider: 'https://ethereum-rpc.publicnode.com' }) const swapProtocol = new VeloraProtocolEvm(account, { swapMaxFee: 200000000000000n }) ``` Optional `swapMaxFee` caps the total gas fee in wei for swaps. See [configuration](../configuration) for environment-specific settings. ## Supported networks Velora routing works on EVM networks the aggregator supports, including **Ethereum**, **Polygon**, **Arbitrum**, and other chains where Velora exposes liquidity. Use an RPC endpoint for the network your [`WalletAccountEvm`](../../../wallet-modules/wallet-evm/api-reference) is configured for so [`swap()`](../api-reference) and [`quoteSwap()`](../api-reference) target the correct chain. ## Next Steps * [Execute swaps](execute-swaps) * [Get swap quotes](get-swap-quotes) * [Handle errors](handle-errors) # Get Swap Quotes (/sdk/swap-modules/swap-velora-evm/guides/get-swap-quotes) This guide shows how to [quote before swapping](#quote-before-swapping) and use quotes for [fee estimation](#fee-estimation). Quotes use [`quoteSwap()`](../api-reference), which works with read-only accounts as well as signing accounts. ## Quote before swapping You can preview fee and token amounts for the same parameters you would pass to [`swap()`](../api-reference) using [`quoteSwap()`](../api-reference): ```javascript title="Quote exact input swap" const quote = await swapProtocol.quoteSwap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) console.log('Estimated fee (wei):', quote.fee) console.log('Tokens in (base units):', quote.tokenInAmount) console.log('Tokens out (base units):', quote.tokenOutAmount) ``` You can quote an exact-output style trade the same way by passing `tokenOutAmount` instead of `tokenInAmount` to [`quoteSwap()`](../api-reference): ```javascript title="Quote exact output swap" const quote = await swapProtocol.quoteSwap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenOutAmount: 500000000000000000n }) console.log('Estimated fee (wei):', quote.fee) console.log('Required token in (base units):', quote.tokenInAmount) ``` ## Fee estimation You can read `quote.fee` from [`quoteSwap()`](../api-reference) as the estimated total swap fee in wei before calling [`swap()`](../api-reference): ```javascript title="Quote fee before deciding" const quote = await swapProtocol.quoteSwap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) const maxFee = 200000000000000n console.log('Quoted fee (wei):', quote.fee, 'cap:', maxFee) ``` You can compare that estimate to `swapMaxFee` on [`VeloraProtocolEvm`](../api-reference) and only then call [`swap()`](../api-reference) when the quote is within your cap: ```javascript title="Swap when fee is under cap" const maxFee = 200000000000000n const quote = await swapProtocol.quoteSwap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) if (quote.fee <= maxFee) { const result = await swapProtocol.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) console.log('Swap hash:', result.hash) } ``` On-chain conditions can change between quote and execution. The executed [`swap()`](../api-reference) may still differ slightly from the last [`quoteSwap()`](../api-reference) result. ## Next Steps * [Execute swaps](execute-swaps) * [Handle errors](handle-errors) * [Get started](get-started) # Handle Errors (/sdk/swap-modules/swap-velora-evm/guides/handle-errors) This guide covers [swap errors](#swap-errors), [quote errors](#quote-errors), and [best practices](#best-practices) for clearing wallet material after use. ## Swap errors You can detect failed swaps by wrapping [`swap()`](../api-reference) in `try/catch` and inspecting `error.message`: ```javascript title="Handle swap failures" try { const result = await swapProtocol.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) console.log('Swap successful:', result.hash) } catch (error) { console.error('Swap failed:', error.message) if (error.message.includes('liquidity')) { console.log('No route or insufficient liquidity for this pair') } if (error.message.includes('max fee')) { console.log('Swap fee exceeds swapMaxFee') } if (error.message.includes('read-only')) { console.log('Read-only account cannot swap') } } ``` Match string fragments only as a convenience; production apps should prefer stable error codes from your runtime when available. ## Quote errors You can handle failures from [`quoteSwap()`](../api-reference) the same way, including provider or routing errors: ```javascript title="Handle quote failures" try { const quote = await swapProtocol.quoteSwap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) console.log('Quoted fee (wei):', quote.fee) } catch (error) { console.error('Quote failed:', error.message) } ``` Common causes are listed under [Errors](../api-reference) in the API reference (liquidity, fee cap, read-only send attempts, RPC issues). ## Best Practices You can clear signing material when a session ends by calling [`dispose()`](../../../wallet-modules/wallet-evm/api-reference) on each [`WalletAccountEvm`](../../../wallet-modules/wallet-evm/api-reference), or [`dispose()`](../../../wallet-modules/wallet-evm/api-reference) on [`WalletManagerEvm`](../../../wallet-modules/wallet-evm/api-reference) if you use a manager: ```javascript title="Dispose wallet accounts" try { await swapProtocol.swap({ tokenIn: '0xdAC17F958D2ee523a2206206994597C13D831ec7', tokenOut: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', tokenInAmount: 1000000n }) } finally { account.dispose() } ``` If you use an ERC-4337 account, call [`dispose()`](../../../wallet-modules/wallet-evm-erc-4337/api-reference) on that account type per its API reference. Drop references to your [`VeloraProtocolEvm`](../api-reference) instance when you no longer need it. ## Next Steps * [Get swap quotes](get-swap-quotes) * [Execute swaps](execute-swaps) * [API reference](../api-reference) # Check Balances (/sdk/wallet-modules/wallet-btc/guides/check-balances) 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()`](../api-reference): ```javascript title="Get Native BTC Balance" const balance = await account.getBalance() console.log('Total balance:', balance, 'satoshis') ``` On Bitcoin, balances are expressed in satoshis (1 BTC = 100,000,000 satoshis). The [`getBalance()`](../api-reference) method returns the total balance, including unconfirmed funds when present. ## Maximum Spendable Amount You can check the maximum amount available to send in a single transaction using [`account.getMaxSpendable()`](../api-reference): ```javascript title="Get Maximum Spendable" const { amount, fee } = await account.getMaxSpendable() console.log('Max spendable:', amount, 'satoshis') console.log('Estimated fee:', fee, 'satoshis') ``` 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). ## Read-Only Account Balances You can check balances for any Bitcoin address without a seed phrase using [`WalletAccountReadOnlyBtc`](../api-reference): ```javascript title="Create Read-Only Account" 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' }) ``` You can retrieve the balance from a read-only account using [`readOnlyAccount.getBalance()`](../api-reference): ```javascript title="Read-Only Balance" const balance = await readOnlyAccount.getBalance() console.log('Read-only account balance:', balance, 'satoshis') ``` Read-only accounts follow the same balance behavior as owned accounts: [`getBalance()`](../api-reference) includes unconfirmed funds when present. You can also create a read-only account from an existing owned account using [`account.toReadOnlyAccount()`](../api-reference). ## Next Steps With balance checks in place, learn how to [send BTC](./send-transactions). # Get Started (/sdk/wallet-modules/wallet-btc/guides/get-started) 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. ```bash title="Install @tetherto/wdk-wallet-btc" npm install @tetherto/wdk-wallet-btc ``` ## 2. Create a Wallet You can create a new wallet instance using the [`WalletManagerBtc`](../api-reference) constructor with a BIP-39 seed phrase and an Electrum client: ```javascript title="Create Bitcoin Wallet" 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' }) ``` **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. **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. ## 3. Get Your First Account You can retrieve an account at a given index using [`wallet.getAccount()`](../api-reference): ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Wallet address:', address) ``` 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. ## 4. (optional) Convert to Read-Only You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Transaction History (/sdk/wallet-modules/wallet-btc/guides/get-transaction-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()`](../api-reference): ```javascript title="Get All Transfers" const transfers = await account.getTransfers() console.log('Recent transfers:', transfers) ``` The default limit is 10 transfers. Change outputs are automatically filtered out. Transfers are sorted by block height (newest first). ## Filter by Direction You can filter transfers by direction using the `direction` option in [`account.getTransfers()`](../api-reference): ```javascript title="Incoming Transfers" const incoming = await account.getTransfers({ direction: 'incoming' }) console.log('Incoming transfers:', incoming) ``` You can retrieve outgoing transfers with a custom limit using [`account.getTransfers()`](../api-reference): ```javascript title="Outgoing Transfers" const outgoing = await account.getTransfers({ direction: 'outgoing', limit: 5 }) console.log('Outgoing transfers:', outgoing) ``` ## Paginate Results You can paginate through transfer history using the `limit` and `skip` options in [`account.getTransfers()`](../api-reference): ```javascript title="Paginate Transfers" const page = await account.getTransfers({ direction: 'all', limit: 20, skip: 10 }) console.log('Transfers 11-30:', page) ``` ## Check Transaction Receipts You can check whether a specific transaction has been confirmed using [`account.getTransactionReceipt()`](../api-reference): ```javascript title="Get Transaction Receipt" const receipt = await account.getTransactionReceipt('abc123...') if (receipt) { console.log('Transaction confirmed') } ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages). # Handle Errors (/sdk/wallet-modules/wallet-btc/guides/handle-errors) 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()`](../api-reference) can fail for several reasons. Wrap transaction calls in a `try/catch` block to handle specific error types: ```javascript title="Handle Transaction Errors" 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) } } ``` ## Connection Errors Network issues with the Electrum server can cause failures across all operations. Handle connection errors at a higher level: ```javascript title="Handle Connection Errors" 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) } } ``` ## Best Practices ### Fee Management You can retrieve current network fee rates using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sat/vB') console.log('Fast fee rate:', feeRates.fast, 'sat/vB') ``` [`wallet.getFeeRates()`](../api-reference) fetches rates from the mempool.space API, while [`account.sendTransaction()`](../api-reference) estimates fees from the connected Electrum server. Use [`getFeeRates()`](../api-reference) for display purposes. ### Dispose of Sensitive Data For security, clear sensitive data from memory when a session is complete. Use [`account.dispose()`](../api-reference) and [`wallet.dispose()`](../api-reference) to securely wipe private keys: ```javascript title="Dispose Resources" try { const result = await account.sendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 100000n }) console.log('Transaction hash:', result.hash) } finally { account.dispose() wallet.dispose() } ``` Always call [`dispose()`](../api-reference) when finished with accounts. Private keys are securely wiped from memory using `sodium_memzero`. Electrum connections are automatically closed. Disposal is irreversible. # Manage Accounts (/sdk/wallet-modules/wallet-btc/guides/manage-accounts) 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()`](../api-reference) with different index values: ```javascript title="Retrieve Multiple Accounts" 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) ``` You can iterate through multiple accounts using [`wallet.getAccount()`](../api-reference) to inspect addresses and balances in bulk: ```javascript title="Iterate Over Accounts" 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)`) } ``` ## Retrieve Account by Custom Derivation Path You can retrieve an account at a specific derivation path using [`wallet.getAccountByPath()`](../api-reference): ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` 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}`. ## Next Steps With accounts set up, learn how to [check balances](./check-balances). # Send Transactions (/sdk/wallet-modules/wallet-btc/guides/send-transactions) 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()`](../api-reference): ```javascript title="Send BTC" 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') ``` 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). ## Extend Post-Broadcast Polling If you want [`account.sendTransaction()`](../api-reference) to keep polling after broadcast until spent inputs disappear from the unspent-output set, pass the optional `timeoutMs` argument: ```javascript title="Send BTC With Extended Polling" const result = await account.sendTransaction( { to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 100000n, }, 30000 ) console.log('Transaction hash:', result.hash) ``` If you omit `timeoutMs`, the wallet uses the default post-broadcast polling window before returning. ## Estimate Fees You can estimate the fee for a transaction without broadcasting it using [`account.quoteSendTransaction()`](../api-reference): ```javascript title="Estimate Fee" const quote = await account.quoteSendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 100000n }) console.log('Estimated fee:', quote.fee, 'satoshis') ``` ## Send with Custom Fee Rate You can override automatic fee estimation by providing a `feeRate` in sat/vB to [`account.sendTransaction()`](../api-reference): ```javascript title="Custom Fee Rate" const result = await account.sendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 100000n, feeRate: 10n // sat/vB }) ``` When `feeRate` is provided, the `confirmationTarget` parameter is ignored. ## Send with Confirmation Target You can target a specific number of blocks for confirmation using the `confirmationTarget` parameter in [`account.sendTransaction()`](../api-reference): ```javascript title="Confirmation Target" const result = await account.sendTransaction({ to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', value: 100000n, confirmationTarget: 6 // target 6 blocks (~1 hour) }) ``` ## Next Steps Learn how to [view transaction history](./get-transaction-history). # Sign and Verify Messages (/sdk/wallet-modules/wallet-btc/guides/sign-verify-messages) 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()`](../api-reference): ```javascript title="Sign Message" const message = 'Hello, Bitcoin!' const signature = await account.sign(message) console.log('Signature:', signature) ``` The signature is returned as a base64-encoded string. ## Verify a Signature You can verify that a signature was produced by the corresponding private key using [`account.verify()`](../api-reference): ```javascript title="Verify Signature" const isValid = await account.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also verify signatures using a [read-only account](../api-reference). Use [`account.toReadOnlyAccount()`](../api-reference) to create one from an owned account, then call [`readOnlyAccount.verify()`](../api-reference): ```javascript title="Verify with Read-Only Account" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verify('Hello, Bitcoin!', signature) console.log('Verified with read-only account:', isValid) ``` ## Next Steps Learn how to [handle errors and manage resources](./handle-errors). # Check Balances (/sdk/wallet-modules/wallet-evm/guides/check-balances) 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`](/sdk/wallet-modules/wallet-evm/api-reference) to query balances. ### Native Token Balance You can retrieve the native token balance from an `Account` object using [`account.getBalance()`](/sdk/wallet-modules/wallet-evm/api-reference): ```javascript title="Get Native Balance" const balance = await account.getBalance() console.log('Native balance:', balance, 'wei') ``` ### Single ERC-20 Token Balance You can retrieve a single ERC-20 token balance from an `Account` object using [`account.getTokenBalance(tokenAddress)`](/sdk/wallet-modules/wallet-evm/api-reference#gettokenbalancetokenaddress): ```javascript title="Get ERC-20 Balance" const tokenAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT const tokenBalance = await account.getTokenBalance(tokenAddress) console.log('Token balance:', tokenBalance) ``` ### Multiple ERC-20 Token Balances You can retrieve multiple ERC-20 token balances from an `Account` object using [`account.getTokenBalances(tokenAddresses)`](/sdk/wallet-modules/wallet-evm/api-reference#gettokenbalancestokenaddresses), where `tokenAddresses` is an array of ERC-20 tokens: ```javascript title="Get Multiple Token Balances" const tokenBalances = await account.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT '0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT ]) console.log('Multi-token balances:', tokenBalances) ``` ## Read-Only Account Balances Use [`WalletAccountReadOnlyEvm`](/sdk/wallet-modules/wallet-evm/api-reference) to check balances for any public address without a seed phrase. ### Native Balance ```javascript title="Read-Only Native Balance" 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') ``` ### Single Token Balance ```javascript title="Read-Only Token Balance" const tokenBalance = await readOnlyAccount.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7') console.log('Token balance:', tokenBalance) ``` ### Multiple Token Balances ```javascript title="Read-Only Multiple Token Balances" const tokenBalances = await readOnlyAccount.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT '0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT ]) console.log('Multi-token balances:', tokenBalances) ``` You can also create a read-only account from an existing owned account using [`await account.toReadOnlyAccount()`](/sdk/wallet-modules/wallet-evm/api-reference). ## Next Steps With balance checks in place, learn how to [send transactions](./send-transactions). # Error Handling (/sdk/wallet-modules/wallet-evm/guides/error-handling) 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. ```javascript title="Transaction Error Handling" 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') } } ``` ## Handle Token Transfer Errors Token transfers can fail for additional reasons such as invalid addresses or insufficient token balances. ```javascript title="Token Transfer Error Handling" 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') } } ``` ## Manage Fee Limits Set `transferMaxFee` when creating the wallet to prevent transactions from exceeding a maximum gas cost. Retrieve current network rates with [`getFeeRates()`](/sdk/wallet-modules/wallet-evm/api-reference) to make informed decisions. ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'wei') console.log('Fast fee rate:', feeRates.fast, 'wei') ``` ## Dispose of Sensitive Data Call [`dispose()`](/sdk/wallet-modules/wallet-evm/api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed. ```javascript title="Memory Cleanup" account.dispose() wallet.dispose() ``` Always call [`dispose()`](/sdk/wallet-modules/wallet-evm/api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. # Getting Started (/sdk/wallet-modules/wallet-evm/guides/getting-started) 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 ```bash title="Install @tetherto/wdk-wallet-evm" npm install @tetherto/wdk-wallet-evm ``` ## 2. Create a Wallet Import the module and create a [`WalletManagerEvm`](/sdk/wallet-modules/wallet-evm/api-reference) instance with a BIP-39 seed phrase and an RPC provider. ```javascript title="Create EVM Wallet" 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 }) ``` **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. You can also pass an EIP-1193 provider (e.g., from a browser wallet) instead of an RPC URL: ```javascript title="Use EIP-1193 Provider" const wallet = new WalletManagerEvm(seedPhrase, { provider: window.ethereum, transferMaxFee: 100000000000000 }) ``` ## 3. Get Your First Account Retrieve an account from the wallet and inspect its address. ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Wallet address:', address) const readOnlyAccount = await account.toReadOnlyAccount() ``` **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. To use test/mock tokens instead of real funds, see the [configuration section](../configuration#network-support). ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Manage Accounts (/sdk/wallet-modules/wallet-evm/guides/manage-accounts) 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}`). ```javascript title="Get Accounts by Index" 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) ``` ## Retrieve Account by Custom Derivation Path Use `getAccountByPath()` when you need a specific hierarchy beyond the default sequential index. ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` ## Iterate Over Multiple Accounts You can loop through accounts to inspect addresses and balances in bulk. ```javascript title="Multi-Account Iteration" 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 } ``` ## Next Steps Now that you can access your accounts, learn how to [check balances](./check-balances). # Send Transactions (/sdk/wallet-modules/wallet-evm/guides/send-transactions) This guide explains how to send native tokens (ETH, MATIC, BNB, etc.) on EVM chains, estimate fees, and configure gas parameters. **BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers. ## Send with EIP-1559 Gas Parameters You can use [`account.sendTransaction()`](/sdk/wallet-modules/wallet-evm/api-reference#sendtransactiontx) to send an EIP-1559 transaction. EIP-1559 transactions provide more predictable gas fees and faster inclusion times. ```javascript title="EIP-1559 Transaction" 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') ``` ## Send with Legacy Gas Parameters You can also use [`account.sendTransaction()`](/sdk/wallet-modules/wallet-evm/api-reference#sendtransactiontx) with legacy gas settings for chains that do not support EIP-1559. ```javascript title="Legacy Transaction" const legacyResult = await account.sendTransaction({ to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', value: 1000000000000000000n, gasPrice: 20000000000n, gasLimit: 21000 }) console.log('Transaction hash:', legacyResult.hash) ``` ## Estimate Transaction Fees Use [`account.quoteSendTransaction()`](/sdk/wallet-modules/wallet-evm/api-reference#quotesendtransactiontx) to get a fee estimate before sending. ```javascript title="Quote Transaction Fee" const quote = await account.quoteSendTransaction({ to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', value: 1000000000000000000n }) console.log('Estimated fee:', quote.fee, 'wei') ``` ## Use Dynamic Fee Rates Retrieve current fee rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-evm/api-reference) and apply them to your transaction. ```javascript title="Dynamic Fee Rates" 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') ``` **Gas Estimation:** The `maxFeePerGas` and `maxPriorityFeePerGas` fields enable EIP-1559 transactions, ensuring more predictable gas fees and faster inclusion times. ## Next Steps To transfer ERC-20 tokens instead of native tokens, see [Transfer ERC-20 Tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-evm/guides/sign-verify-messages) 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()`](/sdk/wallet-modules/wallet-evm/api-reference#signmessage) to produce a cryptographic signature for any string message. ```javascript title="Sign a Message" const message = 'Hello, Ethereum!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ## Verify a Signature You can get a [read-only account](/sdk/wallet-modules/wallet-evm/api-reference#walletaccountreadonlyevm) from any `Account` object by calling [`account.toReadOnlyAccount()`](/sdk/wallet-modules/wallet-evm/api-reference#toreadonlyaccount). Use a read-only account to [`verify()`](/sdk/wallet-modules/wallet-evm/api-reference#verifymessage-signature-1) that a signature was produced by the corresponding private key. ```javascript title="Verify a Signature" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also create a [`WalletAccountReadOnlyEvm`](/sdk/wallet-modules/wallet-evm/api-reference) from any public address to verify signatures without access to the private key. ## Next Steps For best practices on handling errors, managing fees, and cleaning up memory, see [Error Handling](./error-handling). # Transfer ERC-20 Tokens (/sdk/wallet-modules/wallet-evm/guides/transfer-tokens) 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()`](/sdk/wallet-modules/wallet-evm/api-reference#transferoptions) to send ERC-20 tokens to a recipient address. ```javascript title="Transfer ERC-20 Tokens" 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') ``` ## Estimate Transfer Fees Use [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-evm/api-reference#quotetransferoptions) to get a fee estimate before executing the transfer. ```javascript title="Quote Token Transfer" const transferQuote = await account.quoteTransfer({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000000000000000n }) console.log('Transfer fee estimate:', transferQuote.fee, 'wei') ``` ## Transfer with Validation You can use `transferTokenWithValidation()` to validate addresses and check balances before transferring to catch errors early. ### 1. Validate Addresses ```javascript title="Address Validation" 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') } ``` ### 2. Check Balances Use [`account.getTokenBalance()`](/sdk/wallet-modules/wallet-evm/api-reference#gettokenbalancetokenaddress) and [`account.getBalance()`](/sdk/wallet-modules/wallet-evm/api-reference#getbalance) to verify sufficient funds: ```javascript title="Balance Check" 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') } ``` ### 3. Quote and Execute Transfer Use [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-evm/api-reference#quotetransferoptions) to estimate fees, then [`account.transfer()`](/sdk/wallet-modules/wallet-evm/api-reference#transferoptions) to execute: ```javascript title="Quote and Execute" 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') ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages) with your EVM account. # Check Balances (/sdk/wallet-modules/wallet-evm-erc-4337/guides/check-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()`](../api-reference): ```javascript title="Get Native Balance" const balance = await account.getBalance() console.log('Native balance:', balance, 'wei') ``` ## ERC-20 Token Balance You can check the balance of a specific ERC-20 token using [`account.getTokenBalance()`](../api-reference): ```javascript title="Get ERC-20 Balance" const tokenBalance = await account.getTokenBalance('0xdAC17F958D2ee523a2206206994597C13D831ec7') // USDT console.log('USDT balance:', tokenBalance) ``` ## Multiple Token Balances You can check balances for multiple ERC-20 tokens in a single call using [`account.getTokenBalances()`](../api-reference): ```javascript title="Get Multiple Token Balances" const tokenBalances = await account.getTokenBalances([ '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT '0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT ]) console.log('Multi-token balances:', tokenBalances) ``` ## Paymaster Token Balance You can check the paymaster token balance used for paying gas fees using [`account.getPaymasterTokenBalance()`](../api-reference): ```javascript title="Get Paymaster Token Balance" const paymasterBalance = await account.getPaymasterTokenBalance() console.log('Paymaster token balance:', paymasterBalance) ``` The paymaster token balance determines how many gasless transactions you can execute. Ensure the paymaster has sufficient token balance before initiating gasless operations. ## Read-Only Account Balances You can check balances for any smart account address without a seed phrase using [`WalletAccountReadOnlyEvmErc4337`](../api-reference): ```javascript title="Read-Only Balance" 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') ``` ## Next Steps With balance checks in place, learn how to [send gasless transactions](./send-transactions). # Get Started (/sdk/wallet-modules/wallet-evm-erc-4337/guides/get-started) 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. ```bash title="Install @tetherto/wdk-wallet-evm-erc-4337" npm install @tetherto/wdk-wallet-evm-erc-4337 ``` ## 2. Create a Wallet You can create a new wallet instance using the [`WalletManagerEvmErc4337`](../api-reference) constructor with a BIP-39 seed phrase and ERC-4337 configuration: ```javascript title="Create ERC-4337 Wallet" 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 } }) ``` **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. To use test/mock tokens instead of real funds, see the [testnet configuration section](../configuration#network-specific-configurations). ## 3. Get Your First Account You can retrieve a smart account at a given index using [`wallet.getAccount()`](../api-reference): ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Smart account address:', address) ``` ## 4. (optional) Convert to Read-Only You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Handle Errors (/sdk/wallet-modules/wallet-evm-erc-4337/guides/handle-errors) 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()`](../api-reference) can fail when the paymaster token balance is insufficient. Wrap calls in a `try/catch` block: ```javascript title="Handle Transaction Errors" 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) } } ``` ## Transfer Errors Token transfers via [`account.transfer()`](../api-reference) can fail due to insufficient balance or exceeding the maximum fee limit: ```javascript title="Handle Transfer Errors" 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) } } ``` ## Best Practices ### Fee Management You can retrieve current network fee rates using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal) console.log('Fast fee rate:', feeRates.fast) ``` ### Dispose of Sensitive Data For security, clear sensitive data from memory when a session is complete. Use [`account.dispose()`](../api-reference) and [`wallet.dispose()`](../api-reference) to securely wipe private keys: ```javascript title="Dispose Resources" try { const result = await account.sendTransaction({ to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', value: 1000000000000000n }) console.log('Transaction hash:', result.hash) } finally { account.dispose() wallet.dispose() } ``` Always call [`dispose()`](../api-reference) when finished with accounts. Private keys are securely wiped from memory. Disposal is irreversible. # Manage Accounts (/sdk/wallet-modules/wallet-evm-erc-4337/guides/manage-accounts) 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()`](../api-reference) with different index values: ```javascript title="Retrieve Multiple Accounts" 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) ``` ## Retrieve Account by Custom Derivation Path You can retrieve an account at a specific derivation path using [`wallet.getAccountByPath()`](../api-reference): ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` ## Next Steps With accounts set up, learn how to [check balances](./check-balances). # Send Transactions (/sdk/wallet-modules/wallet-evm-erc-4337/guides/send-transactions) 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()`](../api-reference): ```javascript title="Send Gasless Transaction" 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) ``` 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₮). ## Estimate Fees You can estimate the fee for a transaction without broadcasting it using [`account.quoteSendTransaction()`](../api-reference): ```javascript title="Estimate Fee" const quote = await account.quoteSendTransaction({ to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', value: 1000000000000000n }) console.log('Estimated fee:', quote.fee) ``` ## Send with Custom Paymaster Token You can override the default paymaster token for a specific transaction by passing a config object to [`account.sendTransaction()`](../api-reference): ```javascript title="Custom Paymaster Token" const result = await account.sendTransaction({ to: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', value: 1000000000000000n }, { paymasterToken: { address: '0x68749665FF8D2d112Fa859AA293F07A622782F38' // XAUT } }) ``` ## Next Steps Learn how to [transfer ERC-20 tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-evm-erc-4337/guides/sign-verify-messages) 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()`](../api-reference): ```javascript title="Sign Message" const signature = await account.sign('Hello, ERC-4337!') console.log('Signature:', signature) ``` ## Verify a Signature You can verify a signature using a read-only account. Use [`account.toReadOnlyAccount()`](../api-reference) to create one, then call [`readOnlyAccount.verify()`](../api-reference): ```javascript title="Verify Signature" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verify('Hello, ERC-4337!', signature) console.log('Signature valid:', isValid) ``` ## Sign Typed Data (EIP-712) You can sign EIP-712 structured data using [`account.signTypedData()`](../api-reference): ```javascript title="Sign Typed Data" 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) ``` You can verify typed data signatures using [`readOnlyAccount.verifyTypedData()`](../api-reference): ```javascript title="Verify Typed Data" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verifyTypedData(typedData, typedDataSignature) console.log('Typed data signature valid:', isValid) ``` ## Next Steps Learn how to [handle errors and manage resources](./handle-errors). # Transfer Tokens (/sdk/wallet-modules/wallet-evm-erc-4337/guides/transfer-tokens) 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()`](../api-reference): ```javascript title="Transfer ERC-20 Tokens" 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) ``` ## Estimate Transfer Fees You can estimate the fee for a token transfer without executing it using [`account.quoteTransfer()`](../api-reference): ```javascript title="Estimate Transfer Fee" const quote = await account.quoteTransfer({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000 }) console.log('Estimated transfer fee:', quote.fee) ``` ## 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()`](../api-reference): ```javascript title="Transfer with Fee Limit" const result = await account.transfer({ token: '0xdAC17F958D2ee523a2206206994597C13D831ec7', recipient: '0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6', amount: 1000000 }, { transferMaxFee: 100000 }) ``` If the estimated fee exceeds `transferMaxFee`, the transfer is cancelled with an "Exceeded maximum fee" error. ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages). # Manage Accounts (/sdk/wallet-modules/wallet-solana/guides/account-management) This guide explains how to retrieve multiple accounts from your Solana wallet and use custom derivation paths. ## Retrieve Accounts by Index Use [`getAccount()`](/sdk/wallet-modules/wallet-solana/api-reference#getaccountindex) with a zero-based index to access accounts derived from the default derivation path. ```javascript title="Get Accounts by Index" 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) ``` ## Retrieve Account by Custom Derivation Path Use [`getAccountByPath()`](/sdk/wallet-modules/wallet-solana/api-reference#getaccountbypathpath) when you need a specific hierarchy beyond the default sequential index. ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0'/5'") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` Solana uses SLIP-0010 derivation paths. Every child segment in a custom path must be hardened, for example `0'/0'/5'`. All accounts inherit the provider configuration from the wallet manager. ## Iterate Over Multiple Accounts You can loop through accounts to inspect addresses and balances in bulk. ```javascript title="Multi-Account Iteration" 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 } ``` ## Next Steps Now that you can access your accounts, learn how to [check balances](./check-balances). # Check Balances (/sdk/wallet-modules/wallet-solana/guides/check-balances) 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`](/sdk/wallet-modules/wallet-solana/api-reference) to query balances. ### Native SOL Balance You can retrieve the native SOL balance from an `Account` object using [`account.getBalance()`](/sdk/wallet-modules/wallet-solana/api-reference): ```javascript title="Get SOL Balance" const balance = await account.getBalance() console.log('Native SOL balance:', balance, 'lamports') ``` ### SPL Token Balance You can retrieve an SPL token balance from an `Account` object using [`account.getTokenBalance(tokenMint)`](/sdk/wallet-modules/wallet-solana/api-reference#gettokenbalancetokenmint): ```javascript title="Get SPL Token Balance" const splTokenAddress = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB' // USDT mint address const splTokenBalance = await account.getTokenBalance(splTokenAddress) console.log('SPL token balance:', splTokenBalance) ``` Token balances are returned in the token's smallest units. Adjust for the token's decimals when displaying (e.g., USD₮ has 6 decimals). ## Read-Only Account Balances Use [`WalletAccountReadOnlySolana`](/sdk/wallet-modules/wallet-solana/api-reference) to check balances for any public key without a seed phrase. ### Native Balance ```javascript title="Read-Only SOL Balance" 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') ``` ### Token Balance ```javascript title="Read-Only Token Balance" const tokenBalance = await readOnlyAccount.getTokenBalance('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB') console.log('Token balance:', tokenBalance) ``` You can also create a read-only account from an existing owned account using [`await account.toReadOnlyAccount()`](/sdk/wallet-modules/wallet-solana/api-reference). ## Next Steps With balance checks in place, learn how to [send SOL](./send-transactions). # Error Handling (/sdk/wallet-modules/wallet-solana/guides/error-handling) 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. ```javascript title="Transaction Error Handling" 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') } } ``` ## Handle SOL Transfer Errors Native SOL transfers can fail for reasons including insufficient balance or invalid recipient addresses. ```javascript title="SOL Transfer Error Handling" 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({ to: '11111111111111111111111111111112', value: transferAmount }) console.log('Estimated fee:', quote.fee, 'lamports') const result = await account.sendTransaction({ to: '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() } } ``` ## Handle Prebuilt TransactionMessage Errors If you pass a prebuilt `TransactionMessage`, make sure it already has a recent blockhash or durable nonce lifetime, or let WDK inject the latest blockhash for you. If you set `feePayer`, it must match the wallet address. Durable nonce flows still need a valid nonce account and signer setup in the message you provide. WDK preserves that lifetime instead of replacing it. ## Manage Fee Limits Set `transferMaxFee` when creating the wallet to prevent transactions from exceeding a maximum cost. Retrieve current network rates with [`getFeeRates()`](/sdk/wallet-modules/wallet-solana/api-reference) to make informed decisions. ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'lamports') console.log('Fast fee rate:', feeRates.fast, 'lamports') ``` ## Dispose of Sensitive Data Call [`dispose()`](/sdk/wallet-modules/wallet-solana/api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed. ```javascript title="Memory Cleanup" account.dispose() wallet.dispose() ``` Always call [`dispose()`](/sdk/wallet-modules/wallet-solana/api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. # Getting Started (/sdk/wallet-modules/wallet-solana/guides/getting-started) 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 ```bash title="Install @tetherto/wdk-wallet-solana" npm install @tetherto/wdk-wallet-solana ``` ## 2. Create a Wallet Import the module and create a [`WalletManagerSolana`](/sdk/wallet-modules/wallet-solana/api-reference) instance with a BIP-39 seed phrase and a Solana RPC endpoint. ```javascript title="Create Solana Wallet" 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 }) ``` To enable RPC failover, pass `rpcUrl` as an ordered array of endpoints and set `retries` to control how many times WDK retries each provider before moving to the next one. **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. ## 3. Get Your First Account Retrieve an account from the wallet and inspect its address. ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Wallet address:', address) const readOnlyAccount = await account.toReadOnlyAccount() ``` All Solana addresses are base58-encoded public keys. Accounts inherit the provider configuration from the wallet manager. ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./account-management). # Send SOL (/sdk/wallet-modules/wallet-solana/guides/send-transactions) This guide explains how to send native SOL, estimate transaction fees, and use dynamic fee rates. **BigInt Usage:** Always use `BigInt` (the `n` suffix) for monetary values to avoid precision loss with large numbers. On Solana, values are expressed in lamports (1 SOL = 10^9 lamports). Fees are calculated based on the recent blockhash and instruction count. ## Send Native SOL Use [`account.sendTransaction()`](/sdk/wallet-modules/wallet-solana/api-reference#sendtransactiontx) to transfer SOL to a recipient address. ```javascript title="Send SOL" const result = await account.sendTransaction({ to: 'publicKey', // Recipient's base58-encoded public key value: 1000000000n // 1 SOL in lamports }) console.log('Transaction hash:', result.hash) console.log('Transaction fee:', result.fee, 'lamports') ``` ## Estimate Transaction Fees Use [`account.quoteSendTransaction()`](/sdk/wallet-modules/wallet-solana/api-reference#quotesendtransactiontx) to get a fee estimate before sending. ```javascript title="Quote Transaction Fee" const quote = await account.quoteSendTransaction({ to: 'publicKey', value: 1000000000n }) console.log('Estimated fee:', quote.fee, 'lamports') ``` ## Quote or Send a TransactionMessage Use a prebuilt `TransactionMessage` when you need custom instructions or a durable nonce flow. If the transaction message already includes a recent blockhash or durable nonce lifetime, WDK preserves it. If it does not, WDK fetches the latest blockhash before quoting or sending. When you set `feePayer`, it must match the wallet address. ```javascript title="Quote and Send a TransactionMessage" const quote = await account.quoteSendTransaction(txMessage) console.log('Estimated fee:', quote.fee, 'lamports') const result = await account.sendTransaction(txMessage) console.log('Transaction hash:', result.hash) ``` ## Use Dynamic Fee Rates Retrieve current fee rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-solana/api-reference). Rates are calculated based on the recent blockhash and compute unit prices. ```javascript title="Dynamic Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'lamports') console.log('Fast fee rate:', feeRates.fast, 'lamports') ``` ## Complete Example ```javascript title="Full SOL Transfer Flow" 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({ to: '11111111111111111111111111111112', value: transferAmount }) console.log('Estimated fee:', quote.fee, 'lamports') const result = await account.sendTransaction({ to: '11111111111111111111111111111112', value: transferAmount }) console.log('Transaction hash:', result.hash) console.log('Fee paid:', result.fee, 'lamports') return result } ``` ## Next Steps To transfer SPL tokens instead of native SOL, see [Transfer SPL Tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-solana/guides/sign-verify-messages) 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()`](/sdk/wallet-modules/wallet-solana/api-reference#signmessage) to produce an Ed25519 signature for any string message. ```javascript title="Sign a Message" const message = 'Hello, Solana!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ## Verify a Signature You can get a [read-only account](/sdk/wallet-modules/wallet-solana/api-reference#walletaccountreadonlysolana) from any `Account` object by calling [`account.toReadOnlyAccount()`](/sdk/wallet-modules/wallet-solana/api-reference#toreadonlyaccount). Use a read-only account to [`verify()`](/sdk/wallet-modules/wallet-solana/api-reference#verifymessage-signature) that a signature was produced by the corresponding private key. ```javascript title="Verify a Signature" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also create a [`WalletAccountReadOnlySolana`](/sdk/wallet-modules/wallet-solana/api-reference) from any public key to verify signatures without access to the private key. ## Next Steps For best practices on handling errors, managing fees, and cleaning up memory, see [Error Handling](./error-handling). # Transfer SPL Tokens (/sdk/wallet-modules/wallet-solana/guides/transfer-tokens) This guide explains how to transfer SPL tokens (such as USD₮), estimate fees, and validate inputs before executing. ## Transfer Tokens Use [`account.transfer()`](/sdk/wallet-modules/wallet-solana/api-reference#transferoptions) to send SPL tokens to a recipient address. If the recipient does not have a token account, one is created automatically. ```javascript title="Transfer SPL Tokens" 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) }) console.log('Transfer hash:', transferResult.hash) console.log('Transfer fee:', transferResult.fee, 'lamports') ``` ## Estimate Transfer Fees Use [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-solana/api-reference#quotetransferoptions) to get a fee estimate before executing the transfer. ```javascript title="Quote Token Transfer" const transferQuote = await account.quoteTransfer({ token: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', recipient: 'publicKey', amount: 1000000n }) console.log('Transfer fee estimate:', transferQuote.fee, 'lamports') ``` ## Transfer with Validation You can validate addresses and check balances before transferring to catch errors early. ### 1. Validate Addresses ```javascript title="Address Validation" 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') } ``` ### 2. Check Balance Use [`account.getTokenBalance()`](/sdk/wallet-modules/wallet-solana/api-reference#gettokenbalancetokenmint) to verify sufficient funds: ```javascript title="Balance Check" const balance = await account.getTokenBalance(splTokenMint) if (balance < amount) { throw new Error('Insufficient SPL token balance') } ``` ### 3. Quote and Execute Transfer Use [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-solana/api-reference#quotetransferoptions) to estimate fees, then [`account.transfer()`](/sdk/wallet-modules/wallet-solana/api-reference#transferoptions) to execute: ```javascript title="Quote and Execute" 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') ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages) with your Solana account. # Check Balances (/sdk/wallet-modules/wallet-ton/guides/check-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()`](../api-reference): ```javascript title="Get Native TON Balance" const balance = await account.getBalance() console.log('Native TON balance:', balance, 'nanotons') ``` On TON, values are expressed in nanotons (1 TON = 10^9 nanotons). ## Jetton Token Balance You can check the balance of a specific Jetton token using [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress): ```javascript title="Get Jetton Token Balance" const jettonAddress = 'EQ...' // Jetton contract address const jettonBalance = await account.getTokenBalance(jettonAddress) console.log('Jetton token balance:', jettonBalance) ``` ## Read-Only Account Balances You can check balances for any public key without a seed phrase using [`WalletAccountReadOnlyTon`](../api-reference): ```javascript title="Create Read-Only Account" import { WalletAccountReadOnlyTon } from '@tetherto/wdk-wallet-ton' const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, { tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' // Optional } }) ``` You can retrieve the native balance from a read-only account using [`readOnlyAccount.getBalance()`](../api-reference): ```javascript title="Read-Only Native Balance" const balance = await readOnlyAccount.getBalance() console.log('Read-only account balance:', balance) ``` You can also create a read-only account from an existing owned account using [`account.toReadOnlyAccount()`](../api-reference). ## Next Steps With balance checks in place, learn how to [send TON](./send-transactions). # Get Started (/sdk/wallet-modules/wallet-ton/guides/get-started) 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. ```bash title="Install @tetherto/wdk-wallet-ton" npm install @tetherto/wdk-wallet-ton ``` ## 2. Create a Wallet You can create a new wallet instance using the [`WalletManagerTon`](../api-reference) constructor with a BIP-39 seed phrase and a TON Center client configuration: ```javascript title="Create TON Wallet" 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 } }) ``` **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. ## 3. Get Your First Account You can retrieve an account at a given index using [`wallet.getAccount()`](../api-reference#getaccountindex): ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Wallet address:', address) ``` ## 4. (optional) Convert to Read-Only You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Handle Errors (/sdk/wallet-modules/wallet-ton/guides/handle-errors) 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()`](../api-reference#sendtransactiontx) with proper error handling: ```javascript title="Transaction Error Handling" 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) } } ``` ## Handle Token Transfer Errors Jetton transfers can fail for multiple reasons, such as insufficient token balances. Use [`account.transfer()`](../api-reference#transferoptions) with error handling: ```javascript title="Token Transfer Error Handling" 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') } } ``` ## 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()`](../api-reference): ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` ### Dispose of Sensitive Data Call [`dispose()`](../api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed: ```javascript title="Memory Cleanup" account.dispose() wallet.dispose() ``` Always call [`dispose()`](../api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. # Manage Accounts (/sdk/wallet-modules/wallet-ton/guides/manage-accounts) 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()`](../api-reference#getaccountindex): ```javascript title="Get Accounts by Index" 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) ``` ## Retrieve Account by Custom Derivation Path You can request an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](../api-reference#getaccountbypathpath): ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` ## Iterate Over Multiple Accounts You can loop through multiple accounts using [`wallet.getAccount()`](../api-reference#getaccountindex) to inspect addresses and balances in bulk: ```javascript title="Multi-Account Iteration" 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 } ``` ## Next Steps Now that you can access your accounts, learn how to [check balances](./check-balances). # Send TON (/sdk/wallet-modules/wallet-ton/guides/send-transactions) 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). On TON, values are expressed in nanotons (1 TON = 10^9 nanotons). Transactions support an optional `bounceable` parameter specific to the TON network. ## Send Native TON You can transfer TON to a recipient address using [`account.sendTransaction()`](../api-reference#sendtransactiontx): ```javascript title="Send TON" 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') ``` ## Estimate Transaction Fees You can get a fee estimate before sending using [`account.quoteSendTransaction()`](../api-reference#quotesendtransactiontx): ```javascript title="Quote Transaction Fee" const quote = await account.quoteSendTransaction({ to: 'EQ...', value: 1000000000, bounceable: true }) console.log('Estimated fee:', quote.fee, 'nanotons') ``` ## Use Dynamic Fee Rates You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` ## Next Steps To transfer Jetton tokens instead of native TON, see [Transfer Jetton Tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-ton/guides/sign-verify-messages) 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()`](../api-reference#signmessage): ```javascript title="Sign a Message" const message = 'Hello, TON!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ## Verify a Signature You can verify that a signature was produced by the corresponding private key using [`readOnlyAccount.verify()`](../api-reference#verifymessage-signature): ```javascript title="Verify a Signature" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also create a [`WalletAccountReadOnlyTon`](../api-reference) from any public key to verify signatures without access to the private key. ## Next Steps For best practices on handling errors, managing fees, and cleaning up memory, see [Handle Errors](./handle-errors). # Transfer Jetton Tokens (/sdk/wallet-modules/wallet-ton/guides/transfer-tokens) 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()`](../api-reference#transferoptions): ```javascript title="Transfer Jetton Tokens" 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') ``` ## Estimate Transfer Fees You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](../api-reference#quotetransferoptions): ```javascript title="Quote Token Transfer" 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') ``` ## Transfer with Validation Validate addresses and check balances before transferring to catch errors early: 1. Use [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress) to verify sufficient funds. 2. Use [`account.quoteTransfer()`](../api-reference#quotetransferoptions) to confirm fees. 3. Execute the transfer with [`account.transfer()`](../api-reference#transferoptions): ```javascript title="Validated Jetton Transfer" 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 } ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages) with your TON account. # Check Balances (/sdk/wallet-modules/wallet-spark/guides/check-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()`](../api-reference): ```javascript title="Native Spark Balance" const balance = await account.getBalance() console.log('Balance:', balance, 'satoshis') console.log('Balance in BTC:', Number(balance) / 100000000) ``` Balances are in satoshis (1 BTC = 100,000,000 satoshis). If you configure [`sparkscan`](../configuration#sparkscan-balance-polling), [`account.getBalance()`](../api-reference) returns SparkScan's `btcSoftBalanceSats` value instead of the Spark SDK balance: ```javascript title="SparkScan Balance Polling" const wallet = new WalletManagerSpark(seedPhrase, { network: 'MAINNET', sparkscan: { apiKey: 'your-api-key-here', }, }) const account = await wallet.getAccount(0) const balance = await account.getBalance() console.log('SparkScan balance:', balance) ``` ## Token Balance You can read a specific token balance using [`account.getTokenBalance()`](../api-reference): ```javascript title="Token Balance" const tokenBalance = await account.getTokenBalance('token_address...') console.log('Token balance:', tokenBalance) ``` ## Read-Only Account Balances 1. Construct a [`WalletAccountReadOnlySpark`](../api-reference) instance with the Spark address and optional config. 2. Call [`readOnlyAccount.getBalance()`](../api-reference). You can create a read-only account from a Spark address using the [`WalletAccountReadOnlySpark`](../api-reference) constructor: ```javascript title="Read-Only Account" import { WalletAccountReadOnlySpark } from '@tetherto/wdk-wallet-spark' const readOnlyAccount = new WalletAccountReadOnlySpark('spark1...', { network: 'MAINNET' }) ``` You can read the native balance from that account using [`readOnlyAccount.getBalance()`](../api-reference): ```javascript title="Read-Only Native Balance" const balance = await readOnlyAccount.getBalance() console.log('Read-only balance:', balance, 'satoshis') ``` The same [`sparkscan`](../configuration#sparkscan-balance-polling) behavior applies to read-only accounts. You can read a token balance on a read-only account using [`readOnlyAccount.getTokenBalance()`](../api-reference): ```javascript title="Read-Only Token Balance" const tokenBalance = await readOnlyAccount.getTokenBalance('token_address...') console.log('Read-only token balance:', tokenBalance) ``` You can also obtain a read-only handle from an owned account with [`account.toReadOnlyAccount()`](../api-reference). ## Next Steps With balances verified, learn how to [send Spark and transfer tokens](./send-and-transfer). # Deposits and Withdrawals (/sdk/wallet-modules/wallet-spark/guides/deposits-and-withdrawals) 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()`](../api-reference). 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()`](../api-reference): ```javascript title="Single-Use Deposit Address" const depositAddress = await account.getSingleUseDepositAddress() console.log('Send Bitcoin to:', depositAddress) ``` ## Claim Deposits 1. Identify the Bitcoin transaction id that funded the deposit. 2. Call [`account.claimDeposit()`](../api-reference) with that id. You can credit the wallet after the deposit confirms using [`account.claimDeposit()`](../api-reference): ```javascript title="Claim Single-Use Deposit" const txId = 'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16' const walletLeaves = await account.claimDeposit(txId) console.log('Deposit claimed:', walletLeaves) ``` ### 1. (optional) Use a static deposit address You can reuse one on-chain deposit address using [`account.getStaticDepositAddress()`](../api-reference), then credit the wallet with [`account.claimStaticDeposit()`](../api-reference) after the Bitcoin transaction confirms: ```javascript title="Static Deposit Flow" const staticAddress = await account.getStaticDepositAddress() console.log('Static deposit address:', staticAddress) const staticLeaves = await account.claimStaticDeposit( 'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16' ) console.log('Static deposit claimed:', staticLeaves) ``` You can list unused single-use addresses with [`account.getUnusedDepositAddresses()`](../api-reference). The method returns a paginated result with `depositAddresses` and `offset` fields. ## Query Static Deposit Addresses You can list all existing static deposit addresses using [`account.getStaticDepositAddresses()`](../api-reference): ```javascript title="Query Static Deposit Addresses" const addresses = await account.getStaticDepositAddresses() console.log('Static deposit addresses:', addresses) ``` ## Query UTXOs for a Deposit Address You can check confirmed UTXOs for a specific deposit address using [`account.getUtxosForDepositAddress()`](../api-reference): ```javascript title="Query UTXOs" const result = await account.getUtxosForDepositAddress({ depositAddress: 'bc1q...' }) console.log('Confirmed UTXOs:', result.utxos) console.log('Offset:', result.offset) ``` ## Withdraw to Bitcoin Layer 1 1. Choose a Bitcoin `onchainAddress` and `amountSats`. 2. Request a cooperative exit quote with [`account.quoteWithdraw()`](../api-reference). 3. Call [`account.withdraw()`](../api-reference) with the destination and amount. You can request a withdrawal fee quote using [`account.quoteWithdraw()`](../api-reference): ```javascript title="Quote Withdrawal" const feeQuote = await account.quoteWithdraw({ withdrawalAddress: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', amountSats: 100000 }) console.log('Withdrawal fee quote:', feeQuote) ``` You can initiate the withdrawal using [`account.withdraw()`](../api-reference): ```javascript title="Withdraw to On-Chain Bitcoin" const withdrawal = await account.withdraw({ onchainAddress: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', amountSats: 100000 }) console.log('Withdrawal request:', withdrawal) ``` [`withdraw()`](../api-reference) accepts `onchainAddress` and `amountSats`. Run [`quoteWithdraw()`](../api-reference) first to understand the cooperative exit costs before initiating the withdrawal. ## Next Steps Learn how to [handle errors and follow operational best practices](./handle-errors). # Get Started (/sdk/wallet-modules/wallet-spark/guides/get-started) 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): ```bash title="Install @tetherto/wdk-wallet-spark" npm install @tetherto/wdk-wallet-spark ``` The WDK Spark wallet module uses ES Modules (`import` / `export`). Set `"type": "module"` in `package.json`, or run in an environment that supports ESM. ## 2. Create a Wallet You can create a wallet manager using the [`WalletManagerSpark`](../api-reference) constructor with a BIP-39 seed phrase: ```javascript title="Create Spark Wallet" 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' }) ``` **Secure the seed phrase:** Store this seed phrase securely. If it is lost, the user will permanently lose access to their funds. For development on **REGTEST**, you can request test funds from the [Lightspark Regtest Faucet](https://app.lightspark.com/regtest-faucet). The Spark wallet uses `@buildonspark/spark-sdk`. Network options are `MAINNET`, `SIGNET`, or `REGTEST`. There is no custom RPC provider option. ## 3. Get Your First Account 1. Call [`wallet.getAccount()`](../api-reference) with index `0`. 2. Call [`account.getAddress()`](../api-reference) to read the Spark address. You can retrieve the first account using [`wallet.getAccount()`](../api-reference): ```javascript title="Get First Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Account address:', address) ``` ## 4. (optional) Convert to Read-Only You can create a read-only view of the account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Handle Errors (/sdk/wallet-modules/wallet-spark/guides/handle-errors) 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()`](../api-reference), [`account.transfer()`](../api-reference), [`account.payLightningInvoice()`](../api-reference), and [`account.withdraw()`](../api-reference) can throw. Wrap each call in `try/catch` and branch on `message` or error type when your runtime allows it: ```javascript title="Handle Transaction Errors" try { const result = await account.sendTransaction({ to: 'spark1...', value: 1000000 }) console.log('Transaction hash:', result.hash) } catch (error) { console.error('Send failed:', error.message) } ``` You can isolate Lightning failures by wrapping [`account.payLightningInvoice()`](../api-reference): ```javascript title="Handle Lightning Errors" 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) } ``` ## 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: ```javascript title="Handle Connection Errors" 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) } } ``` ## Best Practices ### Fee management Native Spark sends and token transfers report zero fees, but withdrawals and Lightning payments can charge fees. Use [`wallet.getFeeRates()`](../api-reference) for wallet-level rate placeholders and [`account.quotePayLightningInvoice()`](../api-reference) for Lightning sends: ```javascript title="Inspect Spark Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal) console.log('Fast fee rate:', feeRates.fast) ``` ```javascript title="Quote Lightning Fee Before Paying" const lightningFee = await account.quotePayLightningInvoice({ encodedInvoice: 'lnbc500u1p...' }) console.log('Estimated Lightning fee:', Number(lightningFee), 'satoshis') ``` [`quoteWithdraw()`](../api-reference) should run before [`withdraw()`](../api-reference) so you understand cooperative exit costs. ### Dispose of sensitive data Clear keys from memory when a session ends. Call [`account.dispose()`](../api-reference) for each account and [`wallet.dispose()`](../api-reference) on the manager: ```javascript title="Dispose Wallet Resources" try { const result = await account.sendTransaction({ to: 'spark1...', value: 1000000 }) console.log('Transaction hash:', result.hash) } finally { account.dispose() wallet.dispose() } ``` After [`dispose()`](../api-reference), the account cannot sign new operations. Call disposal when the wallet UI or job is finished. ## Next Steps Return to the [Spark wallet usage overview](../usage) or open the [API Reference](../api-reference) for full method signatures. # Lightning Payments (/sdk/wallet-modules/wallet-spark/guides/lightning-payments) 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()`](../api-reference). You can create a BOLT11 invoice using [`account.createLightningInvoice()`](../api-reference): ```javascript title="Create Lightning Invoice" const invoice = await account.createLightningInvoice({ amountSats: 50000, memo: 'Payment for services' }) console.log('Lightning invoice:', invoice.invoice) ``` ## Pay a Lightning Invoice 1. Obtain a BOLT11 `encodedInvoice` string. 2. Set `maxFeeSats` to cap routing fees. 3. Call [`account.payLightningInvoice()`](../api-reference). You can pay an invoice using [`account.payLightningInvoice()`](../api-reference): ```javascript title="Pay Lightning Invoice" const payment = await account.payLightningInvoice({ encodedInvoice: 'lnbc500u1p...', maxFeeSats: 1000 }) console.log('Payment result:', payment) ``` If you enable [`syncAndRetry`](../configuration#automatic-retry), the wallet syncs state and retries [`account.payLightningInvoice()`](../api-reference) once after a failure: ```javascript title="Retry Lightning Payment Once" const wallet = new WalletManagerSpark(seedPhrase, { network: 'MAINNET', syncAndRetry: true, }) const account = await wallet.getAccount(0) await account.payLightningInvoice({ encodedInvoice: 'lnbc500u1p...', maxFeeSats: 1000, }) ``` ## Estimate Lightning Fees You can estimate the routing fee before paying using [`account.quotePayLightningInvoice()`](../api-reference): ```javascript title="Quote Lightning Payment Fee" const feeEstimate = await account.quotePayLightningInvoice({ encodedInvoice: 'lnbc500u1p...' }) console.log('Fee estimate:', Number(feeEstimate), 'satoshis') ``` Older references to `getLightningSendFeeEstimate()` map to [`quotePayLightningInvoice()`](../api-reference). ## Fetch a Lightning Send Request You can load a prior send request by id using [`account.getLightningSendRequest()`](../api-reference): ```javascript title="Get Lightning Send Request" const sendRequest = await account.getLightningSendRequest(payment.id) if (sendRequest) { console.log('Payment status:', sendRequest.status) } ``` Use the `id` from the object returned by [`payLightningInvoice()`](../api-reference). ## Next Steps Learn how to [handle Bitcoin layer 1 deposits and withdrawals](./deposits-and-withdrawals). # Manage Accounts (/sdk/wallet-modules/wallet-spark/guides/manage-accounts) 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()`](../api-reference) with the account index. 2. Call [`account.getAddress()`](../api-reference) for each account. You can retrieve multiple accounts using [`wallet.getAccount()`](../api-reference) with different index values: ```javascript title="Retrieve Accounts by Index" 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) ``` 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. ## Retrieve Accounts by Derivation Path You can retrieve an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](../api-reference): ```javascript title="Retrieve Account by Path" const account = await wallet.getAccountByPath("0'/0/0") const address = await account.getAddress() console.log('Account address:', address) ``` 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()`](../api-reference) in the API reference. ## Iterate Over Accounts You can walk a range of indices using [`wallet.getAccount()`](../api-reference) inside a loop: ```javascript title="Iterate Over Accounts" 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)`) } ``` ## Next Steps With accounts set up, learn how to [check balances](./check-balances). # Send and Transfer (/sdk/wallet-modules/wallet-spark/guides/send-and-transfer) 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()`](../api-reference). You can send native Spark (satoshis) using [`account.sendTransaction()`](../api-reference): ```javascript title="Send Native Spark" const result = await account.sendTransaction({ to: 'spark1...', value: 1000000 }) console.log('Transaction hash:', result.hash) console.log('Transaction fee:', result.fee) ``` On-chain Spark transfers report `fee` as `0`. Memos are not supported on [`sendTransaction()`](../api-reference). Use valid Spark network addresses. If you enable [`syncAndRetry`](../configuration#automatic-retry), the wallet syncs its state and retries [`account.sendTransaction()`](../api-reference) once after a failure: ```javascript title="Retry Failed Sends Once" const wallet = new WalletManagerSpark(seedPhrase, { network: 'MAINNET', syncAndRetry: true, }) const account = await wallet.getAccount(0) await account.sendTransaction({ to: 'spark1...', value: 1000000, }) ``` ## Transfer Tokens You can move tokens to another Spark address using [`account.transfer()`](../api-reference): ```javascript title="Transfer Tokens" 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)) ``` Token identifiers use Bech32m (for example `btkn1...`). Amounts use the token’s base units. ## Estimate Fees ### Spark native and token transfer quotes You can preview the fee for a native send using [`account.quoteSendTransaction()`](../api-reference): ```javascript title="Quote Native Send" const quote = await account.quoteSendTransaction({ to: 'spark1...', value: 1000000 }) console.log('Estimated fee:', quote.fee) ``` You can preview the fee for a token transfer using [`account.quoteTransfer()`](../api-reference): ```javascript title="Quote Token Transfer" const transferQuote = await account.quoteTransfer({ token: 'btkn1...', amount: BigInt(1000000), recipient: 'spark1...' }) console.log('Estimated transfer fee:', Number(transferQuote.fee)) ``` ### Wallet-level fee rates You can read wallet-level fee rate placeholders using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Wallet Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal:', feeRates.normal) console.log('Fast:', feeRates.fast) ``` Spark network fees for native sends and token transfers are zero; [`wallet.getFeeRates()`](../api-reference) returns `{ normal: 0n, fast: 0n }`. Lightning flows can still incur fees; see [Lightning payments](./lightning-payments). If you want to reconcile wallet state before retrying manually, call [`account.syncWalletBalance()`](../api-reference): ```javascript title="Sync Wallet Balance" await account.syncWalletBalance() ``` ## Next Steps Learn how to [create and pay Lightning invoices](./lightning-payments). # Check Balances (/sdk/wallet-modules/wallet-ton-gasless/guides/check-balances) This guide explains how to check [native TON balances](#native-ton-balance), [Jetton token balances](#jetton-token-balance), [paymaster token balances](#paymaster-token-balance), and [read-only account balances](#read-only-account-balances). ## Native TON Balance You can retrieve the native TON balance using [`account.getBalance()`](../api-reference): ```javascript title="Get Native TON Balance" const balance = await account.getBalance() console.log('Native TON balance:', balance, 'nanotons') ``` ## Jetton Token Balance You can check the balance of a specific Jetton token using [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress): ```javascript title="Get Jetton Token Balance" const jettonAddress = 'EQ...' // Jetton contract address const jettonBalance = await account.getTokenBalance(jettonAddress) console.log('Jetton token balance:', jettonBalance) ``` ## Paymaster Token Balance You can check the balance of the configured paymaster token using [`account.getPaymasterTokenBalance()`](../api-reference): ```javascript title="Get Paymaster Token Balance" const paymasterBalance = await account.getPaymasterTokenBalance() console.log('Paymaster Jetton balance:', paymasterBalance) ``` The paymaster token balance determines how many gasless transfers you can execute. Ensure the paymaster has sufficient token balance before initiating gasless transfers. ## Read-Only Account Balances You can check balances for any public key without a seed phrase using [`WalletAccountReadOnlyTonGasless`](../api-reference): ```javascript title="Create Read-Only Account" import { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasless' const readOnlyAccount = new WalletAccountReadOnlyTonGasless(publicKey, { tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' // Optional }, tonApiClient: { url: 'https://tonapi.io/v2', secretKey: 'your-ton-api-key' // Optional }, paymasterToken: { address: 'EQ...' // Paymaster Jetton contract address } }) ``` You can retrieve balances from a read-only account using [`readOnlyAccount.getBalance()`](../api-reference) and [`readOnlyAccount.getPaymasterTokenBalance()`](../api-reference): ```javascript title="Read-Only Balances" const balance = await readOnlyAccount.getBalance() console.log('Native TON balance:', balance) const paymasterBalance = await readOnlyAccount.getPaymasterTokenBalance() console.log('Paymaster token balance:', paymasterBalance) ``` ## Next Steps With balance checks in place, learn how to [send TON](./send-transactions). # Get Started (/sdk/wallet-modules/wallet-ton-gasless/guides/get-started) This guide explains how to [install the package](#1-install-the-package), [create a gasless wallet](#2-create-a-gasless-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. ```bash title="Install @tetherto/wdk-wallet-ton-gasless" npm install @tetherto/wdk-wallet-ton-gasless ``` ## 2. Create a Gasless Wallet You can create a new gasless wallet instance using the [`WalletManagerTonGasless`](../api-reference) constructor with a BIP-39 seed phrase, TON client endpoints, and a paymaster token configuration: ```javascript title="Create Gasless TON Wallet" import WalletManagerTonGasless, { WalletAccountTonGasless, WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasless' const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' const wallet = new WalletManagerTonGasless(seedPhrase, { tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' // Optional }, tonApiClient: { url: 'https://tonapi.io/v2', secretKey: 'your-ton-api-key' // Optional }, paymasterToken: { address: 'EQ...' // Paymaster Jetton master contract address }, transferMaxFee: 10000000 // Optional: maximum fee in paymaster Jetton base units }) ``` **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. ## 3. Get Your First Account You can retrieve an account at a given index using [`wallet.getAccount()`](../api-reference#getaccountindex): ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Wallet address:', address) ``` ## 4. (optional) Convert to Read-Only You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Handle Errors (/sdk/wallet-modules/wallet-ton-gasless/guides/handle-errors) This guide covers how to [handle gasless transfer errors](#handle-gasless-transfer-errors) and [handle native TON transaction errors](#handle-native-ton-transaction-errors), plus [best practices](#best-practices) for fee management and memory cleanup. ## Handle Gasless Transfer Errors Gasless transfers can fail for reasons specific to the paymaster model. Wrap calls to [`account.transfer()`](../api-reference#transferoptions-config) in `try/catch` blocks: ```javascript title="Gasless Transfer Error Handling" try { const result = await account.transfer({ token: 'EQ...', recipient: 'EQ...', amount: 1000000000 }) console.log('Transfer hash:', result.hash) } catch (error) { if (error.message.includes('insufficient jetton balance')) { console.error('Please add more Jetton tokens to your wallet') } else if (error.message.includes('insufficient paymaster balance')) { console.error('Please add more paymaster tokens for gas fees') } 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('Transfer failed:', error.message) } } ``` ## Handle Native TON Transaction Errors Native TON transactions sent via [`account.sendTransaction()`](../api-reference) can fail for standard reasons: ```javascript title="Transaction Error Handling" try { const result = await account.sendTransaction({ to: 'EQ...', value: 1000000000 }) console.log('Transaction hash:', result.hash) } catch (error) { if (error.message.includes('insufficient balance')) { console.error('Not enough TON to complete transaction') } else { console.error('Transaction failed:', error.message) } } ``` ## Best Practices ### Manage Fee Limits Set `transferMaxFee` when creating the wallet to prevent gasless transfers from exceeding a maximum cost. You can retrieve current network rates using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` ### Dispose of Sensitive Data Call [`dispose()`](../api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed: ```javascript title="Memory Cleanup" account.dispose() wallet.dispose() ``` Always call [`dispose()`](../api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. # Manage Accounts (/sdk/wallet-modules/wallet-ton-gasless/guides/manage-accounts) 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()`](../api-reference#getaccountindex): ```javascript title="Get Accounts by Index" 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) ``` ## Retrieve Account by Custom Derivation Path You can request an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](../api-reference#getaccountbypathpath): ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` ## Iterate Over Multiple Accounts You can loop through multiple accounts using [`wallet.getAccount()`](../api-reference#getaccountindex) to inspect addresses and balances in bulk: ```javascript title="Multi-Account Iteration" 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() const paymasterBalance = await account.getPaymasterTokenBalance() accounts.push({ index: i, address, balance, paymasterBalance }) } return accounts } ``` ## Next Steps Now that you can access your accounts, learn how to [check balances](./check-balances). # Send TON (/sdk/wallet-modules/wallet-ton-gasless/guides/send-transactions) This guide explains how to [send native TON](#send-native-ton) and [use dynamic fee rates](#use-dynamic-fee-rates). Native TON sends are not gasless; for gasless Jetton token transfers, see [Transfer Jetton Tokens](./transfer-tokens). On TON, values are expressed in nanotons (1 TON = 10^9 nanotons). ## Send Native TON You can transfer TON to a recipient address using [`account.sendTransaction()`](../api-reference): ```javascript title="Send TON" const result = await account.sendTransaction({ to: 'EQ...', value: 1000000000 // 1 TON in nanotons }) console.log('Transaction hash:', result.hash) console.log('Transaction fee:', result.fee, 'nanotons') ``` ## Use Dynamic Fee Rates You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` ## Next Steps To transfer Jetton tokens with gasless fees (paid in paymaster tokens), see [Transfer Jetton Tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-ton-gasless/guides/sign-verify-messages) This guide explains how to [sign messages](#sign-a-message) with an owned account and [verify signatures](#verify-a-signature). ## Sign a Message You can produce a cryptographic signature for any string message using [`account.sign()`](../api-reference#signmessage): ```javascript title="Sign a Message" const message = 'Hello, TON!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ## Verify a Signature You can verify that a signature is valid using [`account.verify()`](../api-reference#verifymessage-signature): ```javascript title="Verify a Signature" const isValid = await account.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also create a [`WalletAccountReadOnlyTonGasless`](../api-reference) from any public key to verify signatures without access to the private key: ```javascript title="Verify with Read-Only Account" import { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasless' const readOnlyAccount = new WalletAccountReadOnlyTonGasless(publicKey, { tonClient: { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' }, tonApiClient: { url: 'https://tonapi.io/v2', secretKey: 'your-ton-api-key' }, paymasterToken: { address: 'EQ...' } }) const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` ## Next Steps For best practices on handling errors, managing fees, and cleaning up memory, see [Handle Errors](./handle-errors). # Transfer Jetton Tokens (/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens) This guide explains how to [transfer Jetton tokens gaslessly](#transfer-tokens-gasless), [override paymaster configuration](#override-paymaster-configuration), [estimate transfer fees](#estimate-transfer-fees), and [validate inputs before executing](#transfer-with-validation). ## Transfer Tokens (Gasless) You can send Jetton tokens gaslessly using [`account.transfer()`](../api-reference#transferoptions-config). Fees are deducted from the configured paymaster token: ```javascript title="Gasless Jetton Transfer" 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, 'paymaster token units') ``` ## Override Paymaster Configuration You can override the default paymaster token and maximum fee on a per-transfer basis by passing a second configuration argument to [`account.transfer()`](../api-reference#transferoptions-config): ```javascript title="Transfer with Config Override" const result = await account.transfer({ token: 'EQ...', recipient: 'EQ...', amount: 1000000000 }, { paymasterToken: { address: 'EQ...' // Override default paymaster token }, transferMaxFee: 2000000000 // Override maximum allowed fee }) console.log('Transfer hash:', result.hash) console.log('Transfer fee:', result.fee, 'paymaster token units') ``` ## Estimate Transfer Fees You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](../api-reference#quotetransferoptions): ```javascript title="Quote Gasless Transfer" const quote = await account.quoteTransfer({ token: 'EQ...', recipient: 'EQ...', amount: 1000000 }) console.log('Transfer fee estimate:', quote.fee, 'paymaster token units') ``` ## Transfer with Validation Validate balances before transferring: 1. Use [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress) to check Jetton balance. 2. Use [`account.getPaymasterTokenBalance()`](../api-reference#getpaymastertokenbalance) to verify sufficient paymaster funds. 3. Use [`account.quoteTransfer()`](../api-reference#quotetransferoptions) to estimate fees. 4. Execute the transfer with [`account.transfer()`](../api-reference#transferoptions-config): ```javascript title="Validated Gasless Transfer" async function transferWithValidation(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 paymasterBalance = await account.getPaymasterTokenBalance() console.log('Paymaster token balance:', paymasterBalance) const quote = await account.quoteTransfer({ token: jettonAddress, recipient, amount }) console.log('Estimated fee (paymaster token):', quote.fee) const result = await account.transfer({ token: jettonAddress, recipient, amount }) console.log('Transfer hash:', result.hash) console.log('Actual fee (paymaster token):', result.fee) return result } ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages) with your gasless TON account. # Check Balances (/sdk/wallet-modules/wallet-tron/guides/check-balances) This guide explains how to check [native TRX balances](#native-trx-balance), [TRC20 token balances](#trc20-token-balance), and [read-only account balances](#read-only-account-balances). ## Native TRX Balance You can retrieve the native TRX balance using [`account.getBalance()`](../api-reference): ```javascript title="Get Native TRX Balance" const balance = await account.getBalance() console.log('Native TRX balance:', balance, 'sun') ``` On Tron, values are expressed in sun (1 TRX = 1,000,000 sun). ## TRC20 Token Balance You can check the balance of a specific TRC20 token using [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress): ```javascript title="Get TRC20 Token Balance" const trc20Address = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' // USDT const trc20Balance = await account.getTokenBalance(trc20Address) console.log('TRC20 token balance:', trc20Balance) ``` ## Read-Only Account Balances You can check balances for any Tron address without a seed phrase using [`WalletAccountReadOnlyTron`](../api-reference): ```javascript title="Create Read-Only Account" import { WalletAccountReadOnlyTron } from '@tetherto/wdk-wallet-tron' const readOnlyAccount = new WalletAccountReadOnlyTron('TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', { provider: 'https://api.trongrid.io' }) ``` You can retrieve the native balance from a read-only account using [`readOnlyAccount.getBalance()`](../api-reference): ```javascript title="Read-Only Native Balance" const balance = await readOnlyAccount.getBalance() console.log('Read-only account balance:', balance) ``` You can also create a read-only account from an existing owned account using [`account.toReadOnlyAccount()`](../api-reference). ## Next Steps With balance checks in place, learn how to [send TRX](./send-transactions). # Get Started (/sdk/wallet-modules/wallet-tron/guides/get-started) 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. ```bash title="Install @tetherto/wdk-wallet-tron" npm install @tetherto/wdk-wallet-tron ``` ## 2. Create a Wallet You can create a new wallet instance using the [`WalletManagerTron`](../api-reference) constructor with a BIP-39 seed phrase and a Tron RPC provider: ```javascript title="Create Tron Wallet" import WalletManagerTron, { WalletAccountTron, WalletAccountReadOnlyTron } from '@tetherto/wdk-wallet-tron' const seedPhrase = 'your twelve word seed phrase here' const wallet = new WalletManagerTron(seedPhrase, { provider: 'https://api.trongrid.io' }) ``` **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. ## 3. Get Your First Account You can retrieve an account at a given index using [`wallet.getAccount()`](../api-reference#getaccountindex): ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Wallet address:', address) ``` ## 4. (optional) Convert to Read-Only You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` All Tron addresses start with `T` and are 34 characters long. ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Handle Errors (/sdk/wallet-modules/wallet-tron/guides/handle-errors) 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()`](../api-reference#sendtransactiontx) with proper error handling: ```javascript title="Transaction Error Handling" try { const result = await account.sendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 // 1 TRX in sun }) console.log('Transaction hash:', result.hash) console.log('Fee paid:', result.fee, 'sun') } catch (error) { if (error.message.toLowerCase().includes('insufficient')) { console.error('Not enough TRX to complete transaction') } else if (error.message.toLowerCase().includes('max fee')) { console.error('The transfer fee exceeds your configured maximum') } else { console.error('Transaction failed:', error.message) } } ``` ## Handle Token Transfer Errors TRC20 transfers can fail for additional reasons such as insufficient token balances. Use [`account.transfer()`](../api-reference#transferoptions) with error handling: ```javascript title="Token Transfer Error Handling" try { const result = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }) console.log('Transfer successful:', result.hash) console.log('Fee paid (sun):', result.fee) } catch (error) { console.error('Transfer failed:', error.message) if (error.message.toLowerCase().includes('insufficient')) { console.log('Please add more TRC20 tokens to your wallet') } else if (error.message.toLowerCase().includes('max fee')) { console.log('The transfer fee exceeds your configured maximum') } } ``` ## 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()`](../api-reference): ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sun') console.log('Fast fee rate:', feeRates.fast, 'sun') ``` ### Dispose of Sensitive Data Call [`dispose()`](../api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed: ```javascript title="Memory Cleanup" account.dispose() wallet.dispose() ``` Always call [`dispose()`](../api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. # Manage Accounts (/sdk/wallet-modules/wallet-tron/guides/manage-accounts) 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 (`m/44'/195'`) using [`wallet.getAccount()`](../api-reference#getaccountindex): ```javascript title="Get Accounts by Index" 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) ``` ## Retrieve Account by Custom Derivation Path You can request an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](../api-reference#getaccountbypathpath): ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` ## Iterate Over Multiple Accounts You can loop through multiple accounts using [`wallet.getAccount()`](../api-reference#getaccountindex) to inspect addresses and balances in bulk: ```javascript title="Multi-Account Iteration" 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 } ``` ## Next Steps Now that you can access your accounts, learn how to [check balances](./check-balances). # Send TRX (/sdk/wallet-modules/wallet-tron/guides/send-transactions) This guide explains how to [send native TRX](#send-native-trx), [estimate transaction fees](#estimate-transaction-fees), and [use dynamic fee rates](#use-dynamic-fee-rates). On Tron, values are expressed in sun (1 TRX = 1,000,000 sun). ## Send Native TRX You can transfer TRX to a recipient address using [`account.sendTransaction()`](../api-reference#sendtransactiontx): ```javascript title="Send TRX" const result = await account.sendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 // 1 TRX in sun }) console.log('Transaction hash:', result.hash) console.log('Transaction fee:', result.fee, 'sun') ``` ## Estimate Transaction Fees You can get a fee estimate before sending using [`account.quoteSendTransaction()`](../api-reference#quotesendtransactiontx): ```javascript title="Quote Transaction Fee" const quote = await account.quoteSendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 }) console.log('Estimated fee:', quote.fee, 'sun') ``` ## Use Dynamic Fee Rates You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sun') console.log('Fast fee rate:', feeRates.fast, 'sun') ``` ## Next Steps To transfer TRC20 tokens instead of native TRX, see [Transfer TRC20 Tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-tron/guides/sign-verify-messages) 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. Tron uses secp256k1 cryptography for signing. ## Sign a Message You can produce a cryptographic signature for any string message using [`account.sign()`](../api-reference#signmessage): ```javascript title="Sign a Message" const message = 'Hello, Tron!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ## Verify a Signature You can verify that a signature was produced by the corresponding private key using [`readOnlyAccount.verify()`](../api-reference#verifymessage-signature): ```javascript title="Verify a Signature" const readOnlyAccount = await account.toReadOnlyAccount() const isValid = await readOnlyAccount.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also create a [`WalletAccountReadOnlyTron`](../api-reference) from any Tron address to verify signatures without access to the private key. ## Next Steps For best practices on handling errors, managing fees, and cleaning up memory, see [Handle Errors](./handle-errors). # Transfer TRC20 Tokens (/sdk/wallet-modules/wallet-tron/guides/transfer-tokens) This guide explains how to [transfer TRC20 tokens](#transfer-tokens), [estimate transfer fees](#estimate-transfer-fees), and [validate inputs before executing](#transfer-with-validation). ## Transfer Tokens You can send TRC20 tokens to a recipient address using [`account.transfer()`](../api-reference#transferoptions): ```javascript title="Transfer TRC20 Tokens" const transferResult = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 // Amount in TRC20's base units }) console.log('Transfer hash:', transferResult.hash) console.log('Transfer fee:', transferResult.fee, 'sun') ``` ## Estimate Transfer Fees You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](../api-reference#quotetransferoptions): ```javascript title="Quote Token Transfer" const transferQuote = await account.quoteTransfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }) console.log('Transfer fee estimate:', transferQuote.fee, 'sun') ``` ## Transfer with Validation Validate addresses and check balances before transferring to catch errors early: 1. Use [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress) to verify sufficient funds. 2. Use [`account.quoteTransfer()`](../api-reference#quotetransferoptions) to confirm fees. 3. Execute the transfer with [`account.transfer()`](../api-reference#transferoptions): ```javascript title="Validated TRC20 Transfer" async function transferTRC20WithValidation(account, trc20Address, recipient, amount) { if (!trc20Address.startsWith('T') || trc20Address.length !== 34) { throw new Error('Invalid TRC20 contract address') } if (!recipient.startsWith('T') || recipient.length !== 34) { throw new Error('Invalid recipient address') } const balance = await account.getTokenBalance(trc20Address) if (balance < amount) { throw new Error('Insufficient TRC20 token balance') } const quote = await account.quoteTransfer({ token: trc20Address, recipient, amount }) console.log('Transfer fee estimate (sun):', quote.fee) const result = await account.transfer({ token: trc20Address, recipient, amount }) console.log('Transfer completed:', result.hash) console.log('Fee paid (sun):', result.fee) return result } ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages) with your Tron account. # Check Balances (/sdk/wallet-modules/wallet-tron-gasfree/guides/check-balances) This guide explains how to check [native TRX balances](#native-trx-balance), [TRC20 token balances](#trc20-token-balance), and [read-only account balances](#read-only-account-balances). ## Native TRX Balance You can retrieve the native TRX balance using [`account.getBalance()`](../api-reference): ```javascript title="Get Native TRX Balance" const balance = await account.getBalance() console.log('Native TRX balance:', balance, 'sun') ``` On Tron, values are expressed in sun (1 TRX = 1,000,000 sun). ## TRC20 Token Balance You can check the balance of a specific TRC20 token using [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress): ```javascript title="Get TRC20 Token Balance" const trc20Address = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' // USDT const trc20Balance = await account.getTokenBalance(trc20Address) console.log('TRC20 token balance:', trc20Balance) ``` ## Read-Only Account Balances You can check balances for any Tron address without a seed phrase using [`WalletAccountReadOnlyTronGasfree`](../api-reference): ```javascript title="Create Read-Only Account" import { WalletAccountReadOnlyTronGasfree } from '@tetherto/wdk-wallet-tron-gasfree' const readOnlyAccount = new WalletAccountReadOnlyTronGasfree('TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', { chainId: 728126428, provider: 'https://api.trongrid.io', gasFreeProvider: 'https://gasfree.provider.url', gasFreeApiKey: 'your-api-key', gasFreeApiSecret: 'your-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH' }) ``` You can retrieve the native balance from a read-only account using [`readOnlyAccount.getBalance()`](../api-reference): ```javascript title="Read-Only Native Balance" const balance = await readOnlyAccount.getBalance() console.log('Read-only account balance:', balance) ``` You can also create a read-only account from an existing owned account using [`account.toReadOnlyAccount()`](../api-reference). ## Next Steps With balance checks in place, learn how to [send TRX](./send-transactions). # Get Started (/sdk/wallet-modules/wallet-tron-gasfree/guides/get-started) This guide explains how to [install the package](#1-install-the-package), [create a gas-free wallet](#2-create-a-gas-free-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. ```bash title="Install @tetherto/wdk-wallet-tron-gasfree" npm install @tetherto/wdk-wallet-tron-gasfree ``` ## 2. Create a Gas-Free Wallet You can create a new gas-free wallet instance using the [`WalletManagerTronGasfree`](../api-reference) constructor with a BIP-39 seed phrase, Tron RPC provider, and gas-free service configuration: ```javascript title="Create Gas-Free Tron Wallet" import WalletManagerTronGasfree, { WalletAccountTronGasfree, WalletAccountReadOnlyTronGasfree } from '@tetherto/wdk-wallet-tron-gasfree' const seedPhrase = 'your twelve word seed phrase here' const wallet = new WalletManagerTronGasfree(seedPhrase, { chainId: 728126428, provider: 'https://api.trongrid.io', gasFreeProvider: 'https://gasfree.provider.url', gasFreeApiKey: 'your-gasfree-api-key', gasFreeApiSecret: 'your-gasfree-api-secret', serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', transferMaxFee: 10000000 // Optional: maximum fee in token base units }) ``` **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. ## 3. Get Your First Account You can retrieve an account at a given index using [`wallet.getAccount()`](../api-reference#getaccountindex): ```javascript title="Get Account" const account = await wallet.getAccount(0) const address = await account.getAddress() console.log('Gas-free account address:', address) ``` ## 4. (optional) Convert to Read-Only You can convert an owned account to a read-only account using [`account.toReadOnlyAccount()`](../api-reference): ```javascript title="Convert to Read-Only" const readOnlyAccount = await account.toReadOnlyAccount() ``` All Tron addresses start with `T` and are 34 characters long. ## Next Steps With your wallet ready, learn how to [manage multiple accounts](./manage-accounts). # Handle Errors (/sdk/wallet-modules/wallet-tron-gasfree/guides/handle-errors) This guide covers how to [handle gas-free transfer errors](#handle-gas-free-transfer-errors) and [handle native TRX transaction errors](#handle-native-trx-transaction-errors), plus [best practices](#best-practices) for fee management and memory cleanup. ## Handle Gas-Free Transfer Errors Gas-free transfers can fail for reasons including exceeded fee limits or insufficient token balances. Wrap calls to [`account.transfer()`](../api-reference) in `try/catch` blocks: ```javascript title="Gas-Free Transfer Error Handling" try { const result = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }) console.log('Transfer successful:', result.hash) console.log('Fee paid:', result.fee, 'token units') } catch (error) { console.error('Transfer failed:', error.message) if (error.message.includes('exceeds the transfer max fee')) { console.log('Transfer cancelled: fee too high') } else if (error.message.toLowerCase().includes('insufficient')) { console.log('Please add more TRC20 tokens to your wallet') } } ``` ## Handle Native TRX Transaction Errors Native TRX sends via [`account.sendTransaction()`](../api-reference) can fail for standard reasons: ```javascript title="Transaction Error Handling" try { const result = await account.sendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 }) console.log('Transaction hash:', result.hash) } catch (error) { if (error.message.toLowerCase().includes('insufficient')) { console.error('Not enough TRX to complete transaction') } else { console.error('Transaction failed:', error.message) } } ``` ## Best Practices ### Manage Fee Limits Set `transferMaxFee` when creating the wallet or per-transfer to prevent gas-free transfers from exceeding a maximum cost. You can retrieve current network rates using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sun') console.log('Fast fee rate:', feeRates.fast, 'sun') ``` ### Dispose of Sensitive Data Call [`dispose()`](../api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed: ```javascript title="Memory Cleanup" account.dispose() wallet.dispose() ``` Always call [`dispose()`](../api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. # Manage Accounts (/sdk/wallet-modules/wallet-tron-gasfree/guides/manage-accounts) 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 (`m/44'/195'`) using [`wallet.getAccount()`](../api-reference#getaccountindex): ```javascript title="Get Accounts by Index" 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) ``` ## Retrieve Account by Custom Derivation Path You can request an account at a specific BIP-44 derivation path using [`wallet.getAccountByPath()`](../api-reference#getaccountbypathpath): ```javascript title="Custom Derivation Path" const customAccount = await wallet.getAccountByPath("0'/0/5") const customAddress = await customAccount.getAddress() console.log('Custom account address:', customAddress) ``` ## Iterate Over Multiple Accounts You can iterate through multiple accounts using [`wallet.getAccount()`](../api-reference#getaccountindex) to inspect addresses and balances in bulk: ```javascript title="Multi-Account Iteration" 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 }) console.log(`Account ${i}:`, address) } return accounts } ``` ## Next Steps Now that you can access your accounts, learn how to [check balances](./check-balances). # Send TRX (/sdk/wallet-modules/wallet-tron-gasfree/guides/send-transactions) This guide explains how to [send native TRX](#send-native-trx), [estimate transaction fees](#estimate-transaction-fees), and [use dynamic fee rates](#use-dynamic-fee-rates). Native TRX sends are not gas-free; for gas-free TRC20 token transfers, see [Transfer TRC20 Tokens](./transfer-tokens). On Tron, values are expressed in sun (1 TRX = 1,000,000 sun). ## Send Native TRX You can transfer TRX to a recipient address using [`account.sendTransaction()`](../api-reference): ```javascript title="Send TRX" const result = await account.sendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 // 1 TRX in sun }) console.log('Transaction hash:', result.hash) console.log('Fee paid:', result.fee, 'sun') ``` ## Estimate Transaction Fees You can get a fee estimate before sending using [`account.quoteSendTransaction()`](../api-reference): ```javascript title="Quote Transaction Fee" const quote = await account.quoteSendTransaction({ to: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', value: 1000000 }) console.log('Estimated fee:', quote.fee, 'sun') ``` ## Use Dynamic Fee Rates You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](../api-reference): ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() console.log('Normal fee rate:', feeRates.normal, 'sun') console.log('Fast fee rate:', feeRates.fast, 'sun') ``` ## Next Steps To transfer TRC20 tokens with gas-free fees, see [Transfer TRC20 Tokens](./transfer-tokens). # Sign and Verify Messages (/sdk/wallet-modules/wallet-tron-gasfree/guides/sign-verify-messages) This guide explains how to [sign messages](#sign-a-message) with an owned account and [verify signatures](#verify-a-signature). ## Sign a Message You can produce a cryptographic signature for any string message using [`account.sign()`](../api-reference#signmessage): ```javascript title="Sign a Message" const message = 'Hello, Tron!' const signature = await account.sign(message) console.log('Signature:', signature) ``` ## Verify a Signature You can verify that a signature is valid using [`account.verify()`](../api-reference#verifymessage-signature): ```javascript title="Verify a Signature" const isValid = await account.verify(message, signature) console.log('Signature valid:', isValid) ``` You can also create a [`WalletAccountReadOnlyTronGasfree`](../api-reference) from any Tron address to verify signatures without access to the private key. ## Next Steps For best practices on handling errors, managing fees, and cleaning up memory, see [Handle Errors](./handle-errors). # Transfer TRC20 Tokens (/sdk/wallet-modules/wallet-tron-gasfree/guides/transfer-tokens) This guide explains how to [transfer TRC20 tokens gas-free](#transfer-tokens-gas-free), [override the fee limit](#override-fee-limit), [estimate transfer fees](#estimate-transfer-fees), and [validate inputs before executing](#transfer-with-validation). ## Transfer Tokens (Gas-Free) You can send TRC20 tokens gas-free using [`account.transfer()`](../api-reference). The gas-free service handles the fee payment: ```javascript title="Gas-Free TRC20 Transfer" const transferResult = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 // Amount in TRC20's base units }) console.log('Transfer hash:', transferResult.hash) console.log('Transfer fee:', transferResult.fee, 'token units') ``` ## Override Fee Limit You can set a maximum fee for a specific transfer by passing a second configuration object specifying a `transferMaxFee` to [`account.transfer()`](../api-reference): ```javascript title="Transfer with Fee Limit" const result = await account.transfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }, { transferMaxFee: 1000 // Maximum fee allowed in token units }) console.log('Transfer hash:', result.hash) console.log('Transfer fee:', result.fee, 'token units') ``` ## Estimate Transfer Fees You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](../api-reference#quotetransferoptions): ```javascript title="Quote Gas-Free Transfer" const transferQuote = await account.quoteTransfer({ token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 }) console.log('Transfer fee estimate:', transferQuote.fee, 'token units') ``` ## Transfer with Validation Validate addresses and check balances before transferring: 1. Use [`account.getTokenBalance()`](../api-reference#gettokenbalancetokenaddress) to verify sufficient funds. 2. Use [`account.quoteTransfer()`](../api-reference#quotetransferoptions) to confirm fees. 3. Execute the transfer with [`account.transfer()`](../api-reference): ```javascript title="Validated Gas-Free Transfer" async function transferWithValidation(account, tokenAddress, recipient, amount) { if (!tokenAddress.startsWith('T') || tokenAddress.length !== 34) { throw new Error('Invalid TRC20 contract address') } if (!recipient.startsWith('T') || recipient.length !== 34) { throw new Error('Invalid recipient address') } const balance = await account.getTokenBalance(tokenAddress) if (balance < amount) { throw new Error('Insufficient TRC20 token balance') } const quote = await account.quoteTransfer({ token: tokenAddress, recipient, amount }) console.log('Transfer fee estimate:', quote.fee, 'token units') const result = await account.transfer({ token: tokenAddress, recipient, amount }) console.log('Transfer completed:', result.hash) console.log('Fee paid:', result.fee, 'token units') return result } ``` ## Next Steps Learn how to [sign and verify messages](./sign-verify-messages) with your gas-free Tron account.