diff --git a/content/docs/overview/changelog.mdx b/content/docs/overview/changelog.mdx index a6efd257..a405cf96 100644 --- a/content/docs/overview/changelog.mdx +++ b/content/docs/overview/changelog.mdx @@ -10,6 +10,30 @@ Stay up to date with the latest improvements, new features, and bug fixes across --- +### July 09, 2026 + +**What's New** +- **pear-wrk-wdk** ([v1.0.0-beta.9](https://github.com/tetherto/pear-wrk-wdk/releases/tag/v1.0.0-beta.9)): Add HRPC-only generic-module construction, method calls, lifecycle handling, and host events, plus a separate length-prefixed JSON-RPC server entrypoint for native hosts. JSON-RPC supports the existing WDK, wallet, protocol, and secret operations but not wallet resets or generic modules in this release. Production logging now defaults to ERROR, JSC object logging is serialized safely, and temporary secret-buffer cleanup is improved. +- **wdk-utils** ([v1.0.0-beta.9](https://github.com/tetherto/wdk-utils/releases/tag/v1.0.0-beta.9)): Add `deriveSeedKey()` for domain-separated HKDF-SHA256 byte keys and `deriveSeedKeyPair()` for deterministic Ed25519 keypairs. Both require caller-supplied `salt` and `info` values and expect high-entropy seed bytes rather than mnemonic words. + +**Changes** +- **wallet-tron-gasfree** ([v1.0.0-beta.8](https://github.com/tetherto/wdk-wallet-tron-gasfree/releases/tag/v1.0.0-beta.8)): Add `transactionMaxFee` to the shared config type while native quote, sign, and send methods remain unsupported, so the field has no runtime enforcement path. GasFree TRC20 transfers continue to use per-call `transferMaxFee`, and provider transfer and activation fee fields are converted to `bigint` before addition. + +--- + +### July 08, 2026 + +**What's New** +- **wdk-wallet** ([v1.0.0-beta.14](https://github.com/tetherto/wdk-wallet/releases/tag/v1.0.0-beta.14)): Add optional `minAmountOut` to shared swap and swidge options, in destination-token base units, and forward it through the Swidge swap adapters. The base package does not validate or enforce the minimum; concrete provider behavior remains provider-defined. +- **wallet-btc** ([v1.0.0-beta.11](https://github.com/tetherto/wdk-wallet-btc/releases/tag/v1.0.0-beta.11)): Let writable Bitcoin accounts quote and broadcast signed raw transaction hex. Signed-hex quotes fetch referenced previous transactions through the configured client without broadcasting, while signed-hex sends broadcast the exact payload and apply `transactionMaxFee` when configured. Read-only accounts still quote transaction objects only. An updated descriptor dependency raises the Node.js minimum to 20.19.0. +- **react-native-core** ([v1.0.0-beta.13](https://github.com/tetherto/wdk-react-native-core/releases/tag/v1.0.0-beta.13)): Add the `useModule()` hook, `ModuleService`, generic-module event subscriptions, and runtime `WdkConfigs.modules`. The published package still pins Pear Worklet beta.8, which lacks the required module HRPC methods, so the new API is not runnable through the default dependency graph. The React Native source entry is present, but the declared default JavaScript and type outputs under `dist/` are missing from this tag. +- **worklet-bundler** ([v1.0.0-beta.5](https://github.com/tetherto/wdk-worklet-bundler/releases/tag/v1.0.0-beta.5)): Restore the built CLI and API files missing from beta.4, making the published HRPC/JSON-RPC transport, HRPC generic-module config, native addon linking, `addons.yml`, and ESM-to-CJS options available. Native linking now includes `bare-posix` automatically. + +**Fixes** +- **wdk-core** ([v1.0.0-beta.14](https://github.com/tetherto/wdk/releases/tag/v1.0.0-beta.14)): Export the type-only `WdkAccount` intersection and use it as the declared return type of `getAccount()` and `getAccountByPath()`, so writable wallet and protocol methods are represented together. Runtime account behavior is unchanged. + +--- + ### July 07, 2026 **What's New** diff --git a/content/docs/resources/concepts.mdx b/content/docs/resources/concepts.mdx index cdb06bcd..bfb8ff93 100644 --- a/content/docs/resources/concepts.mdx +++ b/content/docs/resources/concepts.mdx @@ -15,7 +15,7 @@ Account Abstraction is a blockchain technology that separates the concept of a u WDK provides Account Abstraction support through specialized wallet modules: - `@tetherto/wdk-wallet-evm-erc4337` - EVM chains with ERC-4337 standard -- `@tetherto/wdk-wallet-ton-gasless` - TON blockchain with gasless transactions +- `@tetherto/wdk-wallet-ton-gasless` - TON blockchain with gasless Jetton transfers - `@tetherto/wdk-wallet-tron-gasfree` - TRON blockchain with gas-free transactions These modules allow developers to implement gasless transaction flows where users can pay fees in tokens like USD₮ or XAU₮ instead of native blockchain tokens. diff --git a/content/docs/sdk/all-modules.mdx b/content/docs/sdk/all-modules.mdx index 45d896e2..e8f4c0a5 100644 --- a/content/docs/sdk/all-modules.mdx +++ b/content/docs/sdk/all-modules.mdx @@ -26,7 +26,7 @@ Wallet modules provide blockchain-specific wallet functionality for managing add | [`@tetherto/wdk-wallet-evm-erc4337`](https://github.com/tetherto/wdk-wallet-evm-erc-4337) | EVM | ERC-4337 Account Abstraction for EVM chains | [Docs](/sdk/wallet-modules/wallet-evm-erc-4337/) | | [`@tetherto/wdk-wallet-evm-7702-gasless`](https://github.com/tetherto/wdk-wallet-evm-7702-gasless) | EVM | EIP-7702 gasless account abstraction for EVM chains | [Docs](/sdk/wallet-modules/wallet-evm-7702-gasless/) | | [`@tetherto/wdk-wallet-ton`](https://github.com/tetherto/wdk-wallet-ton) | TON | TON blockchain wallet | [Docs](/sdk/wallet-modules/wallet-ton/) | -| [`@tetherto/wdk-wallet-ton-gasless`](https://github.com/tetherto/wdk-wallet-ton-gasless) | TON | Gasless transactions on TON | [Docs](/sdk/wallet-modules/wallet-ton-gasless/) | +| [`@tetherto/wdk-wallet-ton-gasless`](https://github.com/tetherto/wdk-wallet-ton-gasless) | TON | Gasless Jetton transfers on TON | [Docs](/sdk/wallet-modules/wallet-ton-gasless/) | | [`@tetherto/wdk-wallet-tron`](https://github.com/tetherto/wdk-wallet-tron) | TRON | TRON blockchain wallet | [Docs](/sdk/wallet-modules/wallet-tron/) | | [`@tetherto/wdk-wallet-tron-gasfree`](https://github.com/tetherto/wdk-wallet-tron-gasfree) | TRON | Gas-free transactions on TRON | [Docs](/sdk/wallet-modules/wallet-tron-gasfree/) | | [`@tetherto/wdk-wallet-solana`](https://github.com/tetherto/wdk-wallet-solana) | Solana | Solana blockchain wallet | [Docs](/sdk/wallet-modules/wallet-solana/) | diff --git a/content/docs/sdk/core-module/api-reference.mdx b/content/docs/sdk/core-module/api-reference.mdx index e5aaded8..4953c100 100644 --- a/content/docs/sdk/core-module/api-reference.mdx +++ b/content/docs/sdk/core-module/api-reference.mdx @@ -12,7 +12,8 @@ icon: Code |-------|-------------|---------| | [WDK](#wdk) | Main class for managing wallets across multiple blockchains. Orchestrates wallet managers, protocols, middleware, and local transaction policies. | [Constructor](#constructor), [Methods](#methods) | | [IWalletAccount](#iwalletaccount) | Base writable wallet account interface from `@tetherto/wdk-wallet`. | [Methods](#methods-1) | -| [IWalletAccountWithProtocols](#iwalletaccountwithprotocols) | Extended wallet account interface that supports protocol registration and access. Extends `IWalletAccount`. | [Methods](#methods-2) | +| [IWalletAccountWithProtocols](#iwalletaccountwithprotocols) | Protocol registration and access surface added to a wallet account. | [Methods](#methods-2) | +| [WdkAccount](#wdkaccount) | Consumer-facing account type returned by `getAccount()` and `getAccountByPath()`. | Type alias | ## WDK @@ -47,8 +48,8 @@ const wdk2 = new WDK(seedBytes) | `registerProtocol(blockchain, label, protocol, config)` | Registers a protocol globally for a blockchain | `WDK` | - | | `registerMiddleware(blockchain, middleware)` | Registers middleware for account decoration | `WDK` | - | | `registerPolicy(policies, options?)` | Registers local transaction policies for wallet account and protocol write methods | `WDK` | If policy configuration is invalid | -| `getAccount(blockchain, index?)` | Returns a wallet account for a blockchain and index | `Promise` | If wallet not registered | -| `getAccountByPath(blockchain, path)` | Returns a wallet account for a blockchain and derivation path | `Promise` | If wallet not registered | +| `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(blockchain)` | Returns current fee rates for a registered blockchain | `Promise` | If wallet not registered | | `dispose(blockchains?)` | Disposes all registered wallets, or only the named blockchains, and clears keys and account state managed by WDK | `void` | - | @@ -259,7 +260,7 @@ Returns a wallet account for a specific blockchain and index using BIP-44 deriva - `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. When a registered policy targets the account, the returned runtime account is policy-enforced and exposes matching `simulate` helpers. +**Returns:** `Promise` - The writable wallet account with protocol support. When a registered policy targets the account, the returned runtime account is policy-enforced and exposes matching `simulate` helpers. **Throws:** Error if no wallet has been registered for the given blockchain. Throws `PolicyConfigurationError` if a registered policy applies but the wallet account does not expose a read-only account view. @@ -289,7 +290,7 @@ Returns a wallet account for a specific blockchain and BIP-44 derivation path. - `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. When a registered policy targets the account, the returned runtime account is policy-enforced and exposes matching `simulate` helpers. +**Returns:** `Promise` - The writable wallet account with protocol support. When a registered policy targets the account, the returned runtime account is policy-enforced and exposes matching `simulate` helpers. **Throws:** Error if no wallet has been registered for the given blockchain. Throws `PolicyConfigurationError` if a registered policy applies but the wallet account does not expose a read-only account view. @@ -419,7 +420,7 @@ console.log('Signed transaction:', signedTransaction) ## IWalletAccountWithProtocols -Extended wallet account interface that supports protocol registration and access. Extends `IWalletAccount` from `@tetherto/wdk-wallet`. +Protocol registration and access surface that WDK adds to a wallet account. The consumer-facing [`WdkAccount`](#wdkaccount) type combines this interface with `IWalletAccount` from `@tetherto/wdk-wallet`. ### Methods @@ -666,6 +667,20 @@ wdk.dispose() ## Types +### WdkAccount + +`WdkAccount` is the exported type returned by `getAccount()` and `getAccountByPath()`. It combines the writable wallet methods with the protocol registration and lookup surface. This is a type-only export; there is no runtime `WdkAccount` value. + +```typescript title="Use WdkAccount" +import WDK, { type WdkAccount } from '@tetherto/wdk' + +async function getBitcoinAccount(wdk: WDK): Promise { + return wdk.getAccount('bitcoin') +} +``` + +The published definition is `IWalletAccount & IWalletAccountWithProtocols`. Concrete wallet packages can expose additional methods beyond this shared shape. The declared return type of `IWalletAccountWithProtocols.registerProtocol()` remains `IWalletAccountWithProtocols`, so assigning the result of that chained call can narrow away the writable-account methods in TypeScript. + ### FeeRates ```typescript title="Type: FeeRates" @@ -832,6 +847,7 @@ type SwidgeOptions = { recipient?: string; refundAddress?: string; slippage?: number; // decimal, e.g. 0.01 for 1% + minAmountOut?: number | bigint; // destination-token base units; provider-defined enforcement } & ( | { fromTokenAmount: number | bigint } // exact-in | { toTokenAmount: number | bigint } // exact-out diff --git a/content/docs/sdk/swidge-modules/index.mdx b/content/docs/sdk/swidge-modules/index.mdx index c30b1db2..7779b044 100644 --- a/content/docs/sdk/swidge-modules/index.mdx +++ b/content/docs/sdk/swidge-modules/index.mdx @@ -112,9 +112,14 @@ console.log('Fees:', quote.fees) | `recipient` | `string` | Optional recipient for the output tokens. | | `refundAddress` | `string` | Optional address that receives refunds if the transaction cannot complete. | | `slippage` | `number` | Optional decimal slippage tolerance, for example `0.01` for 1%. | +| `minAmountOut` | `number \| bigint` | Optional minimum destination amount, in destination-token base units, passed to the provider. | | `fromTokenAmount` | `number \| bigint` | Exact source amount to spend. Do not pass with `toTokenAmount`. | | `toTokenAmount` | `number \| bigint` | Exact destination amount to receive. Do not pass with `fromTokenAmount`. | + +The shared WDK wallet package passes `minAmountOut` to the concrete provider but does not validate or enforce it. Confirm provider-specific support before relying on this field as an execution guard. + + ## Execute a route Call `quoteSwidge()` first, show the quote to the user, then call `swidge()` with the same route options after explicit confirmation. Apply fee caps with `SwidgeProtocolConfig` where supported by the provider. diff --git a/content/docs/sdk/wallet-modules/wallet-btc/api-reference.mdx b/content/docs/sdk/wallet-modules/wallet-btc/api-reference.mdx index c5b98935..72901fdf 100644 --- a/content/docs/sdk/wallet-modules/wallet-btc/api-reference.mdx +++ b/content/docs/sdk/wallet-modules/wallet-btc/api-reference.mdx @@ -127,9 +127,9 @@ new WalletAccountBtc(seed, path, config) |--------|-------------|---------| | `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}>` | +| `sendTransaction(tx, timeoutMs?)` | Signs and sends transaction options, or broadcasts signed raw transaction hex, then optionally polls spent inputs | `Promise<{hash: string, fee: bigint}>` | | `signTransaction(options)` | Signs a Bitcoin transaction without broadcasting it | `Promise` | -| `quoteSendTransaction(options)` | Estimates the fee for a transaction | `Promise<{fee: bigint}>` | +| `quoteSendTransaction(tx)` | Estimates an unsigned transaction fee or calculates the fee of signed raw transaction hex | `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` | @@ -160,10 +160,10 @@ 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. +Accepts either transaction options or signed raw Bitcoin transaction hex. With transaction options, the wallet builds, signs, and broadcasts a single-recipient transaction. With signed hex, it broadcasts the exact supplied transaction without rebuilding or signing it. Both paths can poll after broadcast until spent inputs disappear from the unspent-output set. **Parameters:** -- `options` (BtcTransaction): Transaction options +- `options` (`BtcTransaction | string`): Transaction options or signed raw transaction hex - `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. @@ -174,7 +174,7 @@ Sends a Bitcoin transaction to a single recipient and optionally polls after bro - `hash`: Transaction hash - `fee`: Transaction fee in satoshis -**Throws:** Error if the estimated transaction fee exceeds `transactionMaxFee` when configured. +**Throws:** Error if the transaction fee exceeds `transactionMaxFee` when configured. Invalid raw transaction data, unavailable previous transactions, and broadcast rejection errors propagate from the configured client. **Example:** ```javascript @@ -212,10 +212,10 @@ console.log('Signed transaction:', signedTransaction) ``` ##### `quoteSendTransaction(options)` -Estimates the fee for a transaction without broadcasting it. +Estimates the fee for transaction options or calculates the fee encoded by signed raw transaction hex, without broadcasting it. **Parameters:** -- `options` (BtcTransaction): Same as sendTransaction options +- `options` (`BtcTransaction | string`): Transaction options or signed raw transaction hex - `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. @@ -233,6 +233,8 @@ const quote = await account.quoteSendTransaction({ console.log('Estimated fee:', quote.fee, 'satoshis') ``` +For signed hex, the wallet parses the transaction and fetches every referenced previous transaction through the configured client to calculate input value minus output value. This path requires network access, does not validate signatures before broadcast, does not broadcast, and does not apply `transactionMaxFee`. + ##### `getTransfers(options?)` Returns the account's transfer history with detailed transaction information. diff --git a/content/docs/sdk/wallet-modules/wallet-btc/configuration.mdx b/content/docs/sdk/wallet-modules/wallet-btc/configuration.mdx index 42add2d4..be14821b 100644 --- a/content/docs/sdk/wallet-modules/wallet-btc/configuration.mdx +++ b/content/docs/sdk/wallet-modules/wallet-btc/configuration.mdx @@ -234,7 +234,7 @@ const config = { ### Transaction Max Fee -The `transactionMaxFee` option sets the maximum fee, in satoshis, for BTC `sendTransaction()` and `signTransaction()` operations. Use it to stop a native BTC send or signed transaction from being created when the estimated fee is higher than your app allows. +The `transactionMaxFee` option sets the maximum fee, in satoshis, for BTC `sendTransaction()` and `signTransaction()` operations. It blocks building or signing a transaction above the cap and also blocks `sendTransaction(signedHex)` from broadcasting externally supplied signed hex when its calculated fee is above the cap. **Type:** `number | bigint` (optional) diff --git a/content/docs/sdk/wallet-modules/wallet-btc/guides/get-started.mdx b/content/docs/sdk/wallet-modules/wallet-btc/guides/get-started.mdx index 3aaf87d4..766555fa 100644 --- a/content/docs/sdk/wallet-modules/wallet-btc/guides/get-started.mdx +++ b/content/docs/sdk/wallet-modules/wallet-btc/guides/get-started.mdx @@ -9,7 +9,7 @@ This guide explains how to [install the package](#1-install-the-package), [creat ### Prerequisites -* **[Node.js](https://nodejs.org/)**: version 18 or higher. +* **[Node.js](https://nodejs.org/)**: version 20.19.0 or higher. Wallet BTC beta.11 depends on `@bitcoinerlab/descriptors` 3.1.7, which sets this minimum. * **[npm](https://www.npmjs.com/)**: usually comes with Node.js. ```bash title="Install @tetherto/wdk-wallet-btc" diff --git a/content/docs/sdk/wallet-modules/wallet-btc/guides/send-transactions.mdx b/content/docs/sdk/wallet-modules/wallet-btc/guides/send-transactions.mdx index 6f134564..406a9a88 100644 --- a/content/docs/sdk/wallet-modules/wallet-btc/guides/send-transactions.mdx +++ b/content/docs/sdk/wallet-modules/wallet-btc/guides/send-transactions.mdx @@ -3,7 +3,7 @@ title: Send Transactions description: Send BTC and estimate transaction fees. --- -This guide explains how to [send BTC](#send-btc), [extend post-broadcast polling](#extend-post-broadcast-polling), [sign without broadcasting](#sign-without-broadcasting), [estimate fees before sending](#estimate-fees), [cap transaction fees](#cap-transaction-fees), [use a custom fee rate](#send-with-custom-fee-rate), and [target a specific confirmation time](#send-with-confirmation-target). +This guide explains how to [send BTC](#send-btc), [extend post-broadcast polling](#extend-post-broadcast-polling), [sign without broadcasting](#sign-without-broadcasting), [quote and broadcast signed hex](#quote-and-broadcast-signed-hex), [estimate fees before sending](#estimate-fees), [cap transaction fees](#cap-transaction-fees), [use a custom fee rate](#send-with-custom-fee-rate), and [target a specific confirmation time](#send-with-confirmation-target). ## Send BTC @@ -60,6 +60,26 @@ console.log('Signed transaction:', signedTransaction) `signTransaction()` returns the signed transaction hex. Use `sendTransaction()` when WDK should sign, broadcast, and return the transaction hash. +## Quote and Broadcast Signed Hex + +A writable Bitcoin account can quote and broadcast a previously signed raw transaction. The wallet broadcasts the supplied hex without rebuilding or signing it again. + +```javascript title="Quote And Broadcast Signed BTC" +const signedTransaction = await account.signTransaction({ + to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', + value: 100000n, + feeRate: 10n +}) + +const quote = await account.quoteSendTransaction(signedTransaction) +console.log('Signed transaction fee:', quote.fee, 'satoshis') + +const result = await account.sendTransaction(signedTransaction) +console.log('Transaction hash:', result.hash) +``` + +Signed-hex quoting parses the transaction and fetches its referenced previous transactions through the configured client. It requires network access and does not broadcast. Broadcasting applies `transactionMaxFee` when configured, but signature validity is ultimately checked by the Bitcoin network rather than pre-validated by this method. + ## Estimate Fees You can estimate the fee for a transaction without broadcasting it using [`account.quoteSendTransaction()`](/sdk/wallet-modules/wallet-btc/api-reference#quotesendtransactionoptions): diff --git a/content/docs/sdk/wallet-modules/wallet-btc/index.mdx b/content/docs/sdk/wallet-modules/wallet-btc/index.mdx index 06876bf5..a298cde8 100644 --- a/content/docs/sdk/wallet-modules/wallet-btc/index.mdx +++ b/content/docs/sdk/wallet-modules/wallet-btc/index.mdx @@ -28,7 +28,7 @@ Use [`getAccountByPath`](/sdk/wallet-modules/wallet-btc/api-reference#getaccount - **Address Types Support**: Generate Native SegWit (P2WPKH) addresses by default, with Legacy (P2PKH) support via configuration - **UTXO Management**: Track and manage unspent transaction outputs - **Offline Transaction Signing**: Sign Bitcoin transactions with `signTransaction()` without broadcasting them -- **Transaction Management**: Create, sign, and broadcast Bitcoin transactions (single recipient per transaction) +- **Transaction Management**: Create, sign, and broadcast single-recipient Bitcoin transactions, or separately quote and broadcast signed raw transaction hex - **Fee Estimation**: Dynamic fee calculation via mempool.space API - **Provider Failover**: Configure ordered Electrum, WebSocket, Blockbook, or custom client fallbacks - **TypeScript Support**: Full TypeScript definitions included diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/api-reference.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/api-reference.mdx index f9f6e043..31492249 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/api-reference.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/api-reference.mdx @@ -28,13 +28,13 @@ new WalletManagerTonGasless(seed, config) - `seed` (string | Uint8Array): BIP-39 mnemonic seed phrase or seed bytes - `config` (TonGaslessWalletConfig): Configuration object - `tonClient` (object | TonClient | array): TON client configuration, instance, or an array of configurations or instances for failover - - `url` (string): TON Center API URL (e.g., 'https://toncenter.com/api/v3') + - `url` (string): TON Center v2 JSON-RPC URL (e.g., 'https://toncenter.com/api/v2/jsonRPC') - `secretKey` (string, optional): API key for TON Center - `tonApiClient` (object | TonApiClient | array): TON API client configuration, instance, or an array of configurations or instances for failover - - `url` (string): TON API URL (e.g., 'https://tonapi.io/v2') + - `url` (string): TON API base URL (e.g., 'https://tonapi.io') - `secretKey` (string, optional): API key for TON API - `paymasterToken` (object): Paymaster token configuration - - `address` (string): Paymaster Jetton master contract address + - `address` (string): Supported paymaster Jetton master contract address - `retries` (number, optional): Failover retries used when `tonClient` and `tonApiClient` are arrays (default: 3) - `transferMaxFee` (number | bigint, optional): Maximum fee for gasless transfer operations - `transactionMaxFee` (number | bigint, optional): Shared wallet config option; native `sendTransaction()`, `quoteSendTransaction()`, and `signTransaction()` are unsupported on this module @@ -43,11 +43,11 @@ new WalletManagerTonGasless(seed, config) ```javascript const wallet = new WalletManagerTonGasless(seedPhrase, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, tonApiClient: { - url: 'https://tonapi.io/v2', + url: 'https://tonapi.io', secretKey: 'your-tonapi-key' }, paymasterToken: { @@ -64,8 +64,8 @@ const wallet = new WalletManagerTonGasless(seedPhrase, { |--------|-------------|---------| | `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` | +| `getFeeRates()` | Returns fee rates from the mainnet TON API configuration | `Promise\<{normal: bigint, fast: bigint}\>` | +| `dispose()` | Disposes cached accounts and signers; the manager seed remains in memory | `void` | ##### `getAccount(index)` Returns a gasless wallet account at the specified index. Index `n` derives the account at `m/44'/607'/n'`. @@ -96,9 +96,9 @@ const account = await wallet.getAccountByPath("1'") ``` ##### `getFeeRates()` -Returns current fee rates for transactions based on blockchain config. +Returns fee rates from the mainnet TON API configuration. In `1.0.0-beta.7`, this method always requests `https://tonapi.io/v2`, does not follow the configured client network, and returns the same calculated value for both fields. -**Returns:** `Promise\<{normal: number, fast: number}\>` - Object containing fee rates +**Returns:** `Promise\<{normal: bigint, fast: bigint}\>` - Object containing fee rates **Example:** ```javascript @@ -108,7 +108,7 @@ console.log('Fast fee rate:', feeRates.fast) ``` ##### `dispose()` -Disposes all wallet accounts, clearing private keys from memory. +Disposes cached wallet accounts and signers, clearing their derived private keys. In the current beta, this method does not zero or unset the wallet manager's seed bytes. **Example:** ```javascript @@ -140,8 +140,8 @@ new WalletAccountTonGasless(seed, path, config) | `sendTransaction(tx)` | Not supported on gasless; always rejects | `Promise\` | | `quoteSendTransaction(tx)` | Not supported on gasless; always rejects | `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}\>` | +| `transfer(options, config?)` | Transfers tokens using gasless transactions | `Promise\<{hash: string, fee: bigint}\>` | +| `quoteTransfer(options, config?)` | Estimates the fee for a token transfer | `Promise\<{fee: bigint}\>` | | `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\` | @@ -174,7 +174,7 @@ console.log('Signature:', signature) ``` ##### `signTransaction(tx)` -Not supported on the gasless module. This method always throws. The gasless module only supports paymaster-funded Jetton transfers through [`transfer()`](#transferoptions-config). Use the standard `@tetherto/wdk-wallet-ton` module for offline transaction signing. +Not supported on the gasless module. This method always throws. The gasless module only supports paymaster-funded Jetton transfers through [`transfer()`](#transferoptions-config). Use the standard `@tetherto/wdk-wallet-ton` module to build signed native transaction bodies. **Parameters:** - `tx` (TonTransaction): The transaction @@ -202,7 +202,7 @@ await account.sendTransaction({ to: 'EQ...', value: 1000000000n }) ``` ##### `quoteSendTransaction(tx)` -Not supported on the gasless module. This method is inherited for wallet-interface compatibility and always rejects at runtime. Use [`quoteTransfer()`](#quotetransferoptions) to estimate gasless Jetton transfer fees. +Not supported on the gasless module. This method is inherited for wallet-interface compatibility and always rejects at runtime. Use [`quoteTransfer()`](#quotetransferoptions-config) to estimate gasless Jetton transfer fees. **Parameters:** - `tx` (TonTransaction): The transaction @@ -237,13 +237,13 @@ Transfers a Jetton using a gasless transaction, paying the fee with the configur - `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 + - `amount` (number | bigint): Amount in token's base units +- `config` (object, optional): Per-call configuration. When supplied, it replaces the wallet-level transfer configuration for this call. + - `paymasterToken` (object, required when `config` is supplied): Paymaster token for this transfer - `address` (string): Paymaster token address - `transferMaxFee` (number | bigint, optional): Override maximum fee. Transfers throw only when the estimated fee is greater than this cap, so an equal estimate is allowed. -**Returns:** `Promise\<{hash: string, fee: number}\>` - Transfer result +**Returns:** `Promise\<{hash: string, fee: bigint}\>` - The signed transfer body hash as lowercase hex and the fee in paymaster Jetton base units **Example:** ```javascript @@ -257,18 +257,21 @@ const result = await account.transfer({ }) ``` -##### `quoteTransfer(options)` +##### `quoteTransfer(options, config?)` 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 + - `amount` (number | bigint): Amount in token's base units +- `config` (object, optional): Per-call configuration. When supplied, it replaces the wallet-level quote configuration for this call. + - `paymasterToken` (object, required when `config` is supplied): Paymaster token for this quote + - `address` (string): Paymaster token address -**Returns:** `Promise\<{fee: number}\>` - Object containing fee estimate (in paymaster token base units) +**Returns:** `Promise\<{fee: bigint}\>` - Object containing fee estimate (in paymaster token base units) + +`quoteTransfer()` returns a fee estimate only. It does not submit a transfer or return a transaction hash. **Example:** ```javascript @@ -362,8 +365,8 @@ new WalletAccountReadOnlyTonGasless(publicKey, config) ``` **Parameters:** -- `publicKey` (string | Uint8Array): The account's public key -- `config` (TonGaslessWalletConfig): Configuration object +- `publicKey` (string | Uint8Array): The account's public key. String values must be hex encoded. +- `config` (object): Client, retry, and paymaster configuration. `transferMaxFee` and `transactionMaxFee` are not accepted by the read-only constructor. #### Methods @@ -374,7 +377,7 @@ new WalletAccountReadOnlyTonGasless(publicKey, config) | `getTokenBalance(tokenAddress)` | Returns the balance of a specific token | `Promise\` | | `getPaymasterTokenBalance()` | Returns the balance of the paymaster token | `Promise\` | | `quoteSendTransaction(tx)` | Not supported on gasless; always rejects | `Promise\\>` | -| `quoteTransfer(options, config?)` | Estimates the fee for a token transfer | `Promise\<{fee: number}\>` | +| `quoteTransfer(options, config?)` | Estimates the fee for a token transfer | `Promise\<{fee: bigint}\>` | | `verify(message, signature)` | Verifies a message signature | `Promise\` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | @@ -446,11 +449,14 @@ Estimates the fee for a token transfer. - `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 + - `amount` (number | bigint): Amount in token's base units +- `config` (object, optional): Per-call configuration. When supplied, it replaces the account's wallet-level quote configuration for this call. + - `paymasterToken` (object, required when `config` is supplied): Paymaster token for this quote + - `address` (string): Paymaster token address + +**Returns:** `Promise\<{fee: bigint}\>` - Object containing fee estimate (in paymaster token base units) -**Returns:** `Promise\<{fee: number}\>` - Object containing fee estimate (in paymaster token base units) +`quoteTransfer()` returns a fee estimate only. It does not submit a transfer or return a transaction hash. **Example:** ```javascript @@ -480,8 +486,10 @@ console.log('Signature valid:', isValid) ##### `getTransactionReceipt(hash)` Returns a transaction's receipt. +In `1.0.0-beta.7`, the inherited initial receipt lookup always queries mainnet TON Center v3. Do not rely on this method for testnet receipts; see [Network Selection](/sdk/wallet-modules/wallet-ton-gasless/configuration#network-selection). + **Parameters:** -- `hash` (string): The transaction's hash +- `hash` (string): The signed transfer body hash returned by `transfer()` **Returns:** `Promise\` - The receipt, or null if the transaction has not been included in a block yet @@ -501,14 +509,14 @@ if (receipt) { ```typescript type TonClientConfig = { - /** TON Center API URL @example 'https://toncenter.com/api/v3' */ + /** TON Center v2 JSON-RPC URL @example 'https://toncenter.com/api/v2/jsonRPC' */ url: string; /** Optional API key for TON Center */ secretKey?: string; }; type TonApiClientConfig = { - /** TON API URL @example 'https://tonapi.io/v2' */ + /** TON API base URL @example 'https://tonapi.io' */ url: string; /** Optional API key for TON API */ secretKey?: string; @@ -575,7 +583,7 @@ interface TransferOptions { /** * Amount in token's base units */ - amount: number; + amount: number | bigint; } ``` @@ -584,14 +592,15 @@ interface TransferOptions { ```typescript interface TransferResult { /** - * Transaction hash + * Signed transfer body hash as a lowercase hex string; pass it to getTransactionReceipt() + * @example '7f83b1657ff1fc53b92dc18148a1d65dfa13501404a55e63ddfde593f4f5f9d8' */ hash: string; /** * Fee paid in paymaster token units */ - fee: number; + fee: bigint; } ``` diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/configuration.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/configuration.mdx index 27273c4c..d2bc0826 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/configuration.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/configuration.mdx @@ -14,11 +14,11 @@ import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless' const config = { // Required parameters tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional }, tonApiClient: { - url: 'https://tonapi.io/v2', + url: 'https://tonapi.io', secretKey: 'your-ton-api-key' // Optional }, paymasterToken: { @@ -33,6 +33,10 @@ const config = { const wallet = new WalletManagerTonGasless(seedPhrase, config) ``` + +`tonClient.url` must be a TON Center v2 JSON-RPC endpoint because the module passes it to `@ton/ton`'s `TonClient`. Set `tonApiClient.url` to the TON API base URL without `/v2`; the generated TON API client appends `/v2/gasless/...` to the base URL. + + ## Account Configuration ```javascript @@ -41,11 +45,11 @@ import { WalletAccountTonGasless } from '@tetherto/wdk-wallet-ton-gasless' const accountConfig = { // Required parameters tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional }, tonApiClient: { - url: 'https://tonapi.io/v2', + url: 'https://tonapi.io', secretKey: 'your-ton-api-key' // Optional }, paymasterToken: { @@ -64,14 +68,14 @@ const account = new WalletAccountTonGasless(seedPhrase, "0'", accountConfig) ### tonClient -The `tonClient` option configures the TON Center API client for blockchain interactions. You can pass a single configuration object, a `TonClient` instance, or an array of configurations or instances to enable failover. +The `tonClient` option configures the TON Center v2 JSON-RPC client for blockchain interactions. You can pass a single configuration object, a `TonClient` instance, or an array of configurations or instances to enable failover. **Type:** ```typescript type TonClientConfig = { /** - * TON Center API endpoint URL - * @example 'https://toncenter.com/api/v3' + * TON Center v2 JSON-RPC endpoint URL + * @example 'https://toncenter.com/api/v2/jsonRPC' */ url: string; @@ -88,18 +92,18 @@ type TonClient = TonClientConfig | TonClientInstance | Array +Do not include `/v2` in `tonApiClient.url`. Use `https://tonapi.io`, not `https://tonapi.io/v2`; otherwise the generated client requests `/v2/v2/gasless/...`. + + ### paymasterToken -The `paymasterToken` option specifies the Jetton used to pay gasless transfer fees instead of native TON. +The `paymasterToken` option specifies the Jetton used to pay gasless transfer fees instead of native TON. Its address must match a `gas_jettons[].master_id` value returned by the configured TON API service's raw `/v2/gasless/config` endpoint. The generated `@ton-api/client` exposes the same values as `gasJettons[].masterId`. **Type:** ```typescript @@ -129,6 +137,10 @@ type PaymasterToken = { **Required:** Yes + +`paymasterToken` must be an object with an `address` field, not a raw address string. + + **Example:** ```javascript const config = { @@ -150,12 +162,12 @@ The `retries` option sets the number of additional failover attempts after the i ```javascript const config = { tonClient: [ - { url: 'https://toncenter.com/api/v3' }, - { url: 'https://backup.toncenter.com/api/v3', secretKey: 'your-api-key' } + { url: 'https://toncenter.com/api/v2/jsonRPC' }, + { url: 'https://your-secondary-toncenter.example/api/v2/jsonRPC', secretKey: 'your-secondary-api-key' } // Replace with a real independent provider ], tonApiClient: [ - { url: 'https://tonapi.io/v2' }, - { url: 'https://backup.tonapi.io/v2' } + { url: 'https://tonapi.io' }, + { url: 'https://your-secondary-tonapi.example' } // Replace with a real independent provider ], retries: 3 } @@ -192,14 +204,14 @@ Here's a complete configuration example with required clients, failover, and gas const config = { // TON Client (Required) - array enables failover tonClient: [ - { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' }, - { url: 'https://backup.toncenter.com/api/v3' } + { url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, + { url: 'https://your-secondary-toncenter.example/api/v2/jsonRPC' } // Replace with a real independent provider ], // TON API Client (Required) - array enables failover tonApiClient: [ - { url: 'https://tonapi.io/v2', secretKey: 'your-ton-api-key' }, - { url: 'https://backup.tonapi.io/v2' } + { url: 'https://tonapi.io', secretKey: 'your-ton-api-key' }, + { url: 'https://your-secondary-tonapi.example' } // Replace with a real independent provider ], // Paymaster Token (Required) @@ -215,6 +227,19 @@ const config = { } ``` +## Network Selection + +Use TON Center and TON API endpoints for the same network: + +- Mainnet: `https://toncenter.com/api/v2/jsonRPC` and `https://tonapi.io` +- Testnet: `https://testnet.toncenter.com/api/v2/jsonRPC` and `https://testnet.tonapi.io` + +Do not mix mainnet and testnet clients in one wallet configuration or failover list. + + +In `@tetherto/wdk-wallet-ton-gasless` `1.0.0-beta.7`, the inherited `getTransactionReceipt()` implementation starts its lookup against a hard-coded mainnet TON Center v3 endpoint. `getFeeRates()` likewise always reads mainnet TON API configuration. Do not rely on these methods for testnet-specific receipts or fee rates. + + The default derivation path changed in `1.0.0-beta.5`. Accounts now derive at `m/44'/607'/{index}'` to align with `@tetherto/wdk-wallet-ton`. Wallets created with `1.0.0-beta.4` or earlier derived `getAccount(index)` at `m/44'/607'/0'/0/{index}`, so the same seed produces different addresses after upgrading. Migrate existing accounts using [`getAccountByPath()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#getaccountbypathpath) with the old path if you need to keep prior addresses. diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/check-balances.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/check-balances.mdx index b906bf4b..5a244413 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/check-balances.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/check-balances.mdx @@ -36,7 +36,7 @@ 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. +The account pays gasless fees from its balance of the configured paymaster Jetton. If that is also the Jetton being transferred, the same balance must cover both the transfer amount and the final fee. ## Read-Only Account Balances @@ -48,11 +48,11 @@ import { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasles const readOnlyAccount = new WalletAccountReadOnlyTonGasless(publicKey, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional }, tonApiClient: { - url: 'https://tonapi.io/v2', + url: 'https://tonapi.io', secretKey: 'your-ton-api-key' // Optional }, paymasterToken: { @@ -73,4 +73,4 @@ console.log('Paymaster token balance:', paymasterBalance) ## Next Steps -With balance checks in place, learn how to [send TON](/sdk/wallet-modules/wallet-ton-gasless/guides/send-transactions). +With balance checks in place, learn how to [transfer Jetton tokens gaslessly](/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens). diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/get-started.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/get-started.mdx index 0473db1c..efbf7d27 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/get-started.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/get-started.mdx @@ -28,15 +28,16 @@ import WalletManagerTonGasless, { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasless' -const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about' +const seedPhrase = process.env.WDK_SEED_PHRASE +if (!seedPhrase) throw new Error('WDK_SEED_PHRASE is required') const wallet = new WalletManagerTonGasless(seedPhrase, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional }, tonApiClient: { - url: 'https://tonapi.io/v2', + url: 'https://tonapi.io', secretKey: 'your-ton-api-key' // Optional }, paymasterToken: { @@ -47,7 +48,7 @@ const wallet = new WalletManagerTonGasless(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. +**Secure the Seed Phrase:** Load seed phrases from secure storage; never hardcode or log them. This server-side example uses an environment variable. If the seed phrase is lost, the user will permanently lose access to their funds. ## 3. Get Your First Account diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/handle-errors.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/handle-errors.mdx index fdbdbeaa..2345aebc 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/handle-errors.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/handle-errors.mdx @@ -1,11 +1,11 @@ --- title: Handle Errors -description: Handle errors, manage fees, and dispose of sensitive data in gasless TON wallets. +description: Handle errors, manage fees, and clean up derived account keys in gasless TON wallets. docType: how-to schemaType: TechArticle --- -This guide covers how to [handle gasless transfer errors](#handle-gasless-transfer-errors) and [handle unsupported method errors](#handle-unsupported-method-errors), plus [best practices](#best-practices) for fee management and memory cleanup. +This guide covers how to [handle gasless transfer errors](#handle-gasless-transfer-errors) and [handle unsupported method errors](#handle-unsupported-method-errors), plus [best practices](#best-practices) for fee management and derived key cleanup. ## Handle Gasless Transfer Errors @@ -18,7 +18,7 @@ try { recipient: 'EQ...', amount: 1000000000 }) - console.log('Transfer hash:', result.hash) + console.log('Signed transfer body hash:', result.hash) } catch (error) { if (error.message.includes('insufficient jetton balance')) { console.error('Please add more Jetton tokens to your wallet') @@ -26,7 +26,7 @@ try { 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.toLowerCase().includes('fee')) { + } else if (error.message === 'The transfer operation exceeds the transfer max fee.') { console.error('The transfer fee exceeds your configured maximum') } else { console.error('Transfer failed:', error.message) @@ -54,7 +54,7 @@ try { ### Manage Fee Limits -Set `transferMaxFee` when creating the wallet to prevent gasless transfers from exceeding a maximum cost. Fee caps reject estimates greater than the configured limit, so an estimate equal to the cap is allowed. Native `sendTransaction()`, `quoteSendTransaction()`, and `signTransaction()` are unsupported on this module, so `transactionMaxFee` does not cap gasless transfers. You can retrieve current network rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#getfeerates): +Set `transferMaxFee` when creating the wallet to prevent gasless transfers from exceeding a maximum cost. Fee caps reject estimates greater than the configured limit, so an estimate equal to the cap is allowed. Native `sendTransaction()`, `quoteSendTransaction()`, and `signTransaction()` are unsupported on this module, so `transactionMaxFee` does not cap gasless transfers. You can retrieve mainnet TON API rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#getfeerates). In `1.0.0-beta.7`, this method does not follow configured testnet clients and returns the same calculated value for `normal` and `fast`: ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() @@ -62,9 +62,9 @@ console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` -### Dispose of Sensitive Data +### Dispose Derived Account Keys -Call [`dispose()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#dispose-1) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed: +Call [`dispose()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#dispose-1) on accounts and wallet managers to clear cached accounts' derived private keys when they are no longer needed: ```javascript title="Memory Cleanup" account.dispose() @@ -73,5 +73,5 @@ wallet.dispose() ``` -Always call [`dispose()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#dispose-1) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. +Call [`dispose()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#dispose-1) in a `finally` block or cleanup handler so derived account keys are cleared even if an error occurs. In the current beta, `wallet.dispose()` does not zero or unset `wallet.seed`; manage the seed lifecycle separately and release all manager references when finished. diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/send-transactions.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/send-transactions.mdx index fca1d4e0..a295013b 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/send-transactions.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/send-transactions.mdx @@ -1,11 +1,11 @@ --- -title: Send Transactions +title: Native Sends Unsupported description: Why native TON sends are unsupported on the gasless module and what to use instead. docType: how-to schemaType: TechArticle --- -This guide explains why [native TON sends are not supported](#native-ton-sends-are-not-supported) on the gasless module and how to [check current fee rates](#check-current-fee-rates). +This guide explains why [native TON sends are not supported](#native-ton-sends-are-not-supported) on the gasless module and how to [check mainnet fee rates](#check-mainnet-fee-rates). ## Native TON Sends Are Not Supported @@ -23,9 +23,9 @@ await account.sendTransaction({ To send native TON, use the standard `@tetherto/wdk-wallet-ton` module. For gasless Jetton transfers, see [Transfer Jetton Tokens](/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens). -## Check Current Fee Rates +## Check Mainnet Fee Rates -You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#getfeerates): +You can retrieve mainnet TON API fee rates from the wallet manager using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#getfeerates). In `1.0.0-beta.7`, this method does not follow configured testnet clients and returns the same calculated value for `normal` and `fast`: ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/sign-verify-messages.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/sign-verify-messages.mdx index a7c406cc..4af049b4 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/sign-verify-messages.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/sign-verify-messages.mdx @@ -33,11 +33,11 @@ import { WalletAccountReadOnlyTonGasless } from '@tetherto/wdk-wallet-ton-gasles const readOnlyAccount = new WalletAccountReadOnlyTonGasless(publicKey, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, tonApiClient: { - url: 'https://tonapi.io/v2', + url: 'https://tonapi.io', secretKey: 'your-ton-api-key' }, paymasterToken: { diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens.mdx index 32d976f1..231a7a0c 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/guides/transfer-tokens.mdx @@ -5,7 +5,7 @@ docType: how-to schemaType: TechArticle --- -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). +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 [run preflight checks](#preflight-transfer-checks). ## Transfer Tokens (Gasless) @@ -17,7 +17,7 @@ const result = await account.transfer({ recipient: 'EQ...', // Recipient's TON address amount: 1000000000 // Amount in Jetton's base units }) -console.log('Transfer hash:', result.hash) +console.log('Signed transfer body hash:', result.hash) console.log('Transfer fee:', result.fee, 'paymaster token units') ``` @@ -36,7 +36,7 @@ const result = await account.transfer({ }, transferMaxFee: 2000000000 // Override maximum allowed fee }) -console.log('Transfer hash:', result.hash) +console.log('Signed transfer body hash:', result.hash) console.log('Transfer fee:', result.fee, 'paymaster token units') ``` @@ -44,7 +44,7 @@ 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()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#quotetransferoptions): +You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#quotetransferoptions-config): ```javascript title="Quote Gasless Transfer" const quote = await account.quoteTransfer({ @@ -55,46 +55,70 @@ const quote = await account.quoteTransfer({ console.log('Transfer fee estimate:', quote.fee, 'paymaster token units') ``` -## Transfer with Validation +## Preflight Transfer Checks -Validate balances before transferring: +Inspect balances and fees before transferring: 1. Use [`account.getTokenBalance()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#gettokenbalancetokenaddress) to check Jetton balance. -2. Use [`account.getPaymasterTokenBalance()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#getpaymastertokenbalance) to verify sufficient paymaster funds. -3. Use [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#quotetransferoptions) to estimate fees. -4. Execute the transfer with [`account.transfer()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#transferoptions-config): +2. Use [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#quotetransferoptions-config) with the intended paymaster to estimate the fee. +3. Query that paymaster Jetton explicitly with `getTokenBalance(paymasterJettonAddress)`. `getPaymasterTokenBalance()` always reads the wallet-level paymaster, so do not use it to preflight a per-call override. +4. If the transferred Jetton is also the paymaster Jetton, require one balance to cover the transfer amount plus the fee. Compare parsed TON addresses because different string encodings can identify the same Jetton master. +5. Reject a quote above your application's fee policy, then execute [`account.transfer()`](/sdk/wallet-modules/wallet-ton-gasless/api-reference#transferoptions-config) with `transferMaxFee` set to that quote. The method obtains a fresh estimate and aborts before relay if it has risen. This explicit policy check matters because a per-call configuration replaces, rather than merges with, the wallet-level transfer configuration: -```javascript title="Validated Gasless Transfer" -async function transferWithValidation(account, jettonAddress, recipient, amount) { +This example imports `Address` from `@ton/ton` for canonical address comparison. Add `@ton/ton` as a direct dependency in your application before using it. + +```javascript title="Gasless Transfer with Preflight Checks" +import { Address } from '@ton/ton' + +async function transferWithChecks(account, jettonAddress, paymasterJettonAddress, recipient, amount, maxFee) { if (typeof jettonAddress !== 'string' || jettonAddress.length === 0) { throw new Error('Invalid Jetton address format') } + if (typeof paymasterJettonAddress !== 'string' || paymasterJettonAddress.length === 0) { + throw new Error('Invalid paymaster 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 amountBaseUnits = BigInt(amount) + const maxFeeBaseUnits = BigInt(maxFee) + const transferOptions = { + token: jettonAddress, + recipient, + amount: amountBaseUnits } + const paymasterToken = { address: paymasterJettonAddress } - const paymasterBalance = await account.getPaymasterTokenBalance() - console.log('Paymaster token balance:', paymasterBalance) + const transferBalance = await account.getTokenBalance(jettonAddress) + if (transferBalance < amountBaseUnits) { + throw new Error('Insufficient Jetton balance') + } - const quote = await account.quoteTransfer({ - token: jettonAddress, - recipient, - amount - }) + const quote = await account.quoteTransfer(transferOptions, { paymasterToken }) console.log('Estimated fee (paymaster token):', quote.fee) - const result = await account.transfer({ - token: jettonAddress, - recipient, - amount + if (quote.fee > maxFeeBaseUnits) { + throw new Error('Quoted fee exceeds application policy') + } + + const paymasterBalance = await account.getTokenBalance(paymasterJettonAddress) + const sameJetton = Address.parse(jettonAddress).equals(Address.parse(paymasterJettonAddress)) + const requiredPaymasterBalance = sameJetton + ? amountBaseUnits + quote.fee + : quote.fee + + if (paymasterBalance < requiredPaymasterBalance) { + throw new Error('Insufficient paymaster Jetton balance') + } + + const result = await account.transfer(transferOptions, { + paymasterToken, + transferMaxFee: quote.fee }) - console.log('Transfer hash:', result.hash) + console.log('Signed transfer body hash:', result.hash) console.log('Actual fee (paymaster token):', result.fee) return result diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/index.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/index.mdx index d42b410f..7a7d736a 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/index.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/index.mdx @@ -14,11 +14,11 @@ Use the gasless TON wallet module when your app needs Jetton transfers without r - **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 +- **Gasless Jetton Transfers**: Transfer Jettons with fees paid in a supported paymaster Jetton - **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 +- **Derived Key Cleanup**: Account disposal zeroes derived private key bytes with sodium-universal - **Provider Flexibility**: Support for both TON Center and TON API endpoints ## Supported Networks @@ -41,7 +41,7 @@ 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 +Get started with WDK's TON Gasless Wallet usage diff --git a/content/docs/sdk/wallet-modules/wallet-ton-gasless/usage.mdx b/content/docs/sdk/wallet-modules/wallet-ton-gasless/usage.mdx index f8348c1d..de8b9134 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton-gasless/usage.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton-gasless/usage.mdx @@ -6,7 +6,7 @@ schemaType: TechArticle icon: BookOpen --- -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. +The `@tetherto/wdk-wallet-ton-gasless` module provides wallet management for the TON blockchain with gasless Jetton transfer support, where transfer fees are paid using a configured paymaster token instead of native TON. @@ -28,7 +28,7 @@ Transfer Jetton tokens gaslessly with paymaster fees. Sign messages and verify signatures. -Handle errors, manage fees, and dispose of sensitive data. +Handle errors, manage fees, and clean up derived account keys. diff --git a/content/docs/sdk/wallet-modules/wallet-ton/api-reference.mdx b/content/docs/sdk/wallet-modules/wallet-ton/api-reference.mdx index 8befa2e0..5d4d18ea 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/api-reference.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/api-reference.mdx @@ -33,9 +33,9 @@ new WalletManagerTon(seed, config) - `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') + - `url` (string): TON Center v2 JSON-RPC URL (e.g., 'https://toncenter.com/api/v2/jsonRPC') - `secretKey` (string, optional): API key for TON Center - - `transferMaxFee` (number, optional): Maximum fee amount for transfer operations (in nanotons) + - `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations (in nanotons) - `transactionMaxFee` (number | bigint, optional): Maximum fee amount for native `sendTransaction()` and `signTransaction()` operations (in nanotons) @@ -43,7 +43,7 @@ new WalletManagerTon(seed, config) ```javascript const wallet = new WalletManagerTon(seedPhrase, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, transferMaxFee: 1000000000, // Maximum Jetton transfer fee in nanotons @@ -58,8 +58,8 @@ const wallet = new WalletManagerTon(seedPhrase, { |--------|-------------|---------| | `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` | +| `getFeeRates()` | Returns fee rates from the mainnet TON API configuration | `Promise\<{normal: bigint, fast: bigint}\>` | +| `dispose()` | Disposes cached accounts and signers; the manager seed remains in memory | `void` | ##### `getAccount(index)` @@ -89,7 +89,7 @@ const account = await wallet.getAccountByPath("0'/0/1") ``` ##### `getFeeRates()` -Returns current fee rates for normal and fast transactions. +Returns normal and fast fee rates from the mainnet TON API configuration. In `1.0.0-beta.10`, this method always requests `https://tonapi.io/v2`, does not follow the configured `tonClient` network, and returns the same calculated value for both fields. **Returns:** `Promise\` - Object containing normal and fast fee rates @@ -101,7 +101,7 @@ console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` ##### `dispose()` -Disposes all wallet accounts, clearing private keys from memory. +Disposes cached wallet accounts and signers, clearing their derived private keys. In the current beta, this method does not zero or unset the wallet manager's seed bytes. **Example:** ```javascript @@ -111,14 +111,13 @@ wallet.dispose() #### Properties ##### `seed` -The wallet's seed phrase. +The wallet manager's sensitive raw seed bytes. A manager created with a seed phrase converts it to bytes before storing it; a signer-backed manager returns `undefined`. -**Type:** `string | Uint8Array` +**Type:** `Uint8Array | undefined` -**Example:** -```javascript -console.log('Seed phrase:', wallet.seed) -``` + +Do not log, serialize, or expose this property. In the current beta, [`wallet.dispose()`](#dispose) does not zero or unset these bytes; release all manager references and manage the original seed lifecycle separately. + ### WalletAccountTon @@ -136,9 +135,9 @@ new WalletAccountTon(seed, path, config) - `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 + - `url` (string): TON Center v2 JSON-RPC URL - `secretKey` (string, optional): API key for TON Center - - `transferMaxFee` (number, optional): Maximum fee amount for transfer operations + - `transferMaxFee` (number | bigint, optional): Maximum fee amount for transfer operations - `transactionMaxFee` (number | bigint, optional): Maximum fee amount for native `sendTransaction()` and `signTransaction()` operations @@ -146,7 +145,7 @@ new WalletAccountTon(seed, path, config) ```javascript const account = new WalletAccountTon(seedPhrase, "0'/0/0", { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, transferMaxFee: 10000000, // Maximum Jetton transfer fee in nanotons @@ -161,11 +160,11 @@ const account = new WalletAccountTon(seedPhrase, "0'/0/0", { | `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\` | -| `signTransaction(tx)` | Signs a transaction offline without broadcasting it | `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}\>` | +| `signTransaction(tx)` | Builds a signed external-message body using current chain state, without broadcasting it | `Promise\` | +| `sendTransaction(tx)` | Sends a TON transaction | `Promise\<{hash: string, fee: bigint}\>` | +| `quoteSendTransaction(tx)` | Estimates the fee for a TON transaction | `Promise\<{fee: bigint}\>` | +| `transfer(options)` | Transfers Jetton tokens to another address | `Promise\<{hash: string, fee: bigint}\>` | +| `quoteTransfer(options)` | Estimates the fee for a Jetton transfer | `Promise\<{fee: bigint}\>` | | `getBalance()` | Returns the native TON balance (in nanotons) | `Promise\` | | `getTokenBalance(tokenAddress)` | Returns the balance of a specific Jetton token | `Promise\` | | `getTransactionReceipt(hash)` | Returns a transaction's receipt | `Promise\` | @@ -214,7 +213,7 @@ console.log('Signature:', signature) ``` ##### `signTransaction(tx)` -Signs a transaction offline and returns the signed external-message body without broadcasting it. Use this to build a transaction on a signing device and broadcast it elsewhere. Added in v1.0.0-beta.8. +Builds and signs an external-message body without broadcasting it. This is not an offline operation: it requires a configured TON client to read the wallet's current sequence number and, when `transactionMaxFee` is set, to estimate the fee. Added in v1.0.0-beta.8. **Parameters:** - `tx` (object): The transaction object (same shape as `sendTransaction`) @@ -223,7 +222,7 @@ Signs a transaction offline and returns the signed external-message body without - `bounceable` (boolean, optional): Whether the destination address is bounceable - `body` (string | Cell, optional): Optional message body -**Returns:** `Promise\` - The signed external-message body as a TON `Cell`. Call `cell.toBoc().toString('base64')` to obtain a wire-format payload ready for broadcast. +**Returns:** `Promise\` - The signed body as a TON `Cell`. It is the body accepted by the matching opened `WalletContractV5R1.send()` call, not a complete external-message BOC that can be posted directly to TON Center. **Throws:** Error if the estimated transaction fee exceeds `transactionMaxFee` when configured. @@ -233,21 +232,20 @@ const cell = await account.signTransaction({ to: 'EQ...', // TON address value: 1000000000 // 1 TON in nanotons }); -const boc = cell.toBoc().toString('base64'); -console.log('Signed payload:', boc); +// `cell` is not broadcast by signTransaction(). ``` ##### `sendTransaction(tx)` -Sends a TON transaction and returns the result with hash and fee. +Sends a TON transaction and returns its signed transfer body 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) + - `value` (number | bigint): 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) +**Returns:** `Promise\<{hash: string, fee: bigint}\>` - Object containing the signed transfer body hash as lowercase hex and the fee in nanotons **Throws:** Error if the estimated transaction fee exceeds `transactionMaxFee` when configured. @@ -257,7 +255,7 @@ const result = await account.sendTransaction({ to: 'EQ...', // TON address value: 1000000000 // 1 TON in nanotons }); -console.log('Transaction hash:', result.hash); +console.log('Signed transfer body hash:', result.hash); console.log('Transaction fee:', result.fee, 'nanotons'); ``` @@ -267,10 +265,10 @@ 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) + - `value` (number | bigint): 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) +**Returns:** `Promise\<{fee: bigint}\>` - Object containing fee estimate (in nanotons) **Example:** ```javascript @@ -288,9 +286,9 @@ Transfers Jettons (TON tokens) to another address. - `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 + - `amount` (number | bigint): Amount in Jetton's base units -**Returns:** `Promise\<{hash: string, fee: number}\>` - Object containing hash and fee (in nanotons) +**Returns:** `Promise\<{hash: string, fee: bigint}\>` - Object containing the signed transfer body hash as lowercase hex and the fee in nanotons **Example:** ```javascript @@ -299,7 +297,7 @@ const result = await account.transfer({ recipient: 'EQ...', // Recipient's TON address amount: 1000000000 // Amount in Jetton's base units }); -console.log('Transfer hash:', result.hash); +console.log('Signed transfer body hash:', result.hash); console.log('Transfer fee:', result.fee, 'nanotons'); ``` @@ -310,9 +308,9 @@ Estimates the fee for a Jetton (TON token) transfer. - `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 + - `amount` (number | bigint): Amount in Jetton's base units -**Returns:** `Promise\<{fee: number}\>` - Object containing fee estimate (in nanotons) +**Returns:** `Promise\<{fee: bigint}\>` - Object containing fee estimate (in nanotons) **Example:** ```javascript @@ -346,21 +344,32 @@ Returns the balance of a specific Jetton (TON token). **Example:** ```javascript const tokenBalance = await account.getTokenBalance('EQ...'); -console.log('Token balance:', tokenBalance, 'nanotons'); +console.log('Token balance:', tokenBalance, 'Jetton base units'); ``` ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been mined. +In `1.0.0-beta.10`, the initial receipt lookup always queries mainnet TON Center v3. Do not rely on this method for testnet receipts; see [Network Selection](/sdk/wallet-modules/wallet-ton/configuration#network-selection). + **Parameters:** -- `hash` (string): The transaction hash +- `hash` (string): The signed transfer body hash returned by `sendTransaction()` or `transfer()` **Returns:** `Promise\` - Transaction receipt or null if not yet mined **Example:** ```javascript -const receipt = await account.getTransactionReceipt('EQ...') -console.log('Transaction confirmed:', receipt.success) +const result = await account.sendTransaction({ + to: 'EQ...', + value: 1000000000n +}) +const receipt = await account.getTransactionReceipt(result.hash) + +if (receipt) { + console.log('Transaction receipt:', receipt) +} else { + console.log('Transaction not yet included in a block') +} ``` ##### `toReadOnlyAccount()` @@ -410,7 +419,7 @@ new WalletAccountReadOnlyTon(publicKey, config) ``` **Parameters:** -- `publicKey` (string): The account's public key (hex or base64) +- `publicKey` (string | Uint8Array): The account's public key. String values must be hex encoded. - `config` (object): TON client and retry configuration without send-only fee caps #### Methods @@ -459,15 +468,24 @@ console.log('Signature valid:', isValid) ##### `getTransactionReceipt(hash)` Returns a transaction's receipt if it has been mined. +In `1.0.0-beta.10`, the initial receipt lookup always queries mainnet TON Center v3. Do not rely on this method for testnet receipts; see [Network Selection](/sdk/wallet-modules/wallet-ton/configuration#network-selection). + **Parameters:** -- `hash` (string): The transaction hash +- `hash` (string): The signed transfer body hash returned by `sendTransaction()` or `transfer()` **Returns:** `Promise\` - Transaction receipt or null if not yet mined **Example:** ```javascript -const receipt = await readOnlyAccount.getTransactionReceipt('EQ...') -console.log('Transaction confirmed:', receipt.success) +async function logTransactionReceipt(readOnlyAccount, transactionHash) { + const receipt = await readOnlyAccount.getTransactionReceipt(transactionHash) + + if (receipt) { + console.log('Transaction receipt:', receipt) + } else { + console.log('Transaction not yet included in a block') + } +} ``` ## Types @@ -520,7 +538,7 @@ interface TransferOptions { * Amount in Jetton's base units * @example 1000000000 // Amount depends on token decimals */ - amount: number; + amount: number | bigint; } ``` @@ -529,16 +547,16 @@ interface TransferOptions { ```typescript interface TransactionResult { /** - * Transaction hash in base64 format - * @example 'EQD4FPq...' + * Signed transfer body hash as a lowercase hex string; pass it to getTransactionReceipt() + * @example '7f83b1657ff1fc53b92dc18148a1d65dfa13501404a55e63ddfde593f4f5f9d8' */ hash: string; /** * Transaction fee in nanotons - * @example 100000 // 0.0001 TON + * @example 100000n // 0.0001 TON */ - fee: number; + fee: bigint; } ``` @@ -547,16 +565,16 @@ interface TransactionResult { ```typescript interface FeeRates { /** - * Fee rate for normal priority transactions (in nanotons) - * @example 100000000 // 0.1 TON + * Mainnet-derived fee rate in nanotons + * @example 100000000n // 0.1 TON */ - normal: number; + normal: bigint; /** - * Fee rate for high priority transactions (in nanotons) - * @example 200000000 // 0.2 TON + * Same mainnet-derived fee rate as `normal` in v1.0.0-beta.10 + * @example 100000000n // 0.1 TON */ - fast: number; + fast: bigint; } ``` @@ -583,8 +601,8 @@ interface KeyPair { interface TonWalletConfig { /** * TON Center client configuration, a TonClient instance, or an array of - * either. When an array is provided, connection errors cause the wallet to - * fail over to the next client in the list. + * either. When an array is provided, any thrown Error causes the wallet to + * retry on the next client by default. */ tonClient?: TonClientConfig | TonClient | Array; @@ -611,7 +629,7 @@ interface TonWalletConfig { interface TonClientConfig { /** * TON Center API endpoint - * @example 'https://toncenter.com/api/v3' + * @example 'https://toncenter.com/api/v2/jsonRPC' */ url: string; diff --git a/content/docs/sdk/wallet-modules/wallet-ton/configuration.mdx b/content/docs/sdk/wallet-modules/wallet-ton/configuration.mdx index 3f309c59..909715bb 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/configuration.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/configuration.mdx @@ -15,7 +15,7 @@ import WalletManagerTon from '@tetherto/wdk-wallet-ton' const config = { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional }, transferMaxFee: 1000000000, // Optional: Maximum Jetton transfer fee in nanotons @@ -32,7 +32,7 @@ import { WalletAccountTon } from '@tetherto/wdk-wallet-ton' const accountConfig = { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional }, transferMaxFee: 1000000000, // Optional: Maximum Jetton transfer fee in nanotons @@ -46,13 +46,13 @@ const account = new WalletAccountTon(seedPhrase, "0'/0/0", accountConfig) ### tonClient -The `tonClient` option configures the TON Center API client for blockchain interactions. It accepts a single client configuration, a `TonClient` instance, or an array of either for endpoint failover. +The `tonClient` option configures the TON Center v2 JSON-RPC client for blockchain interactions. It accepts a single client configuration, a `TonClient` instance, or an array of either for endpoint failover. **Type:** ```typescript interface TonClientConfig { /** - * TON Center API endpoint URL + * TON Center v2 JSON-RPC endpoint URL */ url: string; @@ -75,22 +75,26 @@ type TonClientOption = // Basic configuration const config = { tonClient: { - url: 'https://toncenter.com/api/v3' + url: 'https://toncenter.com/api/v2/jsonRPC' } } // With API key for higher rate limits const config = { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' } } ``` + +Provide the full v2 JSON-RPC endpoint. The module passes this URL to `@ton/ton`'s `TonClient`, which posts JSON-RPC requests directly to it. + + ### tonClient (array) and retries -Since v1.0.0-beta.8, `tonClient` also accepts an array of configurations or instances. When a connection error occurs, the wallet automatically fails over to the next client in the list. The `retries` option sets the number of additional retry attempts after the initial call fails. +Since v1.0.0-beta.8, `tonClient` also accepts an array of configurations or instances. When a client call throws an `Error`, the wallet automatically retries on the next client. By default, this includes application errors as well as connection errors. The `retries` option sets the number of additional attempts after the initial call fails. **Type:** `retries` is `number` (optional) @@ -101,8 +105,8 @@ The total number of attempts is `1 + retries`. For example, `retries: 3` with fo ```javascript const config = { tonClient: [ - { url: 'https://toncenter.com/api/v3', secretKey: 'your-api-key' }, - { url: 'https://toncenter.com/api/v3' } + { url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, + { url: 'https://your-secondary-toncenter.example/api/v2/jsonRPC' } // Replace with a real independent provider ], retries: 3 // Optional: additional retry attempts after the first failure } @@ -112,7 +116,7 @@ const config = { The `transferMaxFee` option sets the maximum allowed fee, in nanotons, for Jetton `transfer()` operations. -**Type:** `number` (nanotons) +**Type:** `number | bigint` (nanotons) **Default:** No maximum (undefined) @@ -125,7 +129,7 @@ const config = { // Example with both options const config = { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, transferMaxFee: 1000000000 @@ -144,7 +148,7 @@ The `transactionMaxFee` option sets the maximum allowed fee, in nanotons, for na ```javascript const config = { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, transactionMaxFee: 1000000000 // 1 TON in nanotons @@ -160,7 +164,7 @@ import { WalletAccountReadOnlyTon } from '@tetherto/wdk-wallet-ton' const readOnlyConfig = { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional } } @@ -170,10 +174,14 @@ const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, readOnlyConfig) ## Network Selection -The TON network (mainnet or testnet) is determined by the TON Center API endpoint URL: +For client-backed balance and transaction operations, the TON network is determined by the TON Center API endpoint URL: -- Mainnet: `https://toncenter.com/api/v3` -- Testnet: `https://testnet.toncenter.com/api/v3` +- Mainnet: `https://toncenter.com/api/v2/jsonRPC` +- Testnet: `https://testnet.toncenter.com/api/v2/jsonRPC` + + +In `@tetherto/wdk-wallet-ton` `1.0.0-beta.10`, `getTransactionReceipt()` starts its lookup against a hard-coded mainnet TON Center v3 endpoint, even when `tonClient` points to testnet. `getFeeRates()` likewise always reads mainnet TON API configuration. Do not rely on these methods for testnet-specific receipts or fee rates. + ## Derivation Paths diff --git a/content/docs/sdk/wallet-modules/wallet-ton/guides/check-balances.mdx b/content/docs/sdk/wallet-modules/wallet-ton/guides/check-balances.mdx index 16d80a76..97be9c9b 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/guides/check-balances.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/guides/check-balances.mdx @@ -39,7 +39,7 @@ import { WalletAccountReadOnlyTon } from '@tetherto/wdk-wallet-ton' const readOnlyAccount = new WalletAccountReadOnlyTon(publicKey, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional } }) diff --git a/content/docs/sdk/wallet-modules/wallet-ton/guides/get-started.mdx b/content/docs/sdk/wallet-modules/wallet-ton/guides/get-started.mdx index 39408225..64508958 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/guides/get-started.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/guides/get-started.mdx @@ -25,18 +25,19 @@ You can create a new wallet instance using the [`WalletManagerTon`](/sdk/wallet- ```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 seedPhrase = process.env.WDK_SEED_PHRASE +if (!seedPhrase) throw new Error('WDK_SEED_PHRASE is required') const wallet = new WalletManagerTon(seedPhrase, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', 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. +**Secure the Seed Phrase:** Load seed phrases from secure storage; never hardcode or log them. This server-side example uses an environment variable. If the seed phrase is lost, the user will permanently lose access to their funds. ## 3. Get Your First Account diff --git a/content/docs/sdk/wallet-modules/wallet-ton/guides/handle-errors.mdx b/content/docs/sdk/wallet-modules/wallet-ton/guides/handle-errors.mdx index 157721a1..62b00a7f 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/guides/handle-errors.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/guides/handle-errors.mdx @@ -1,11 +1,11 @@ --- title: Handle Errors -description: Handle errors, manage fees, and dispose of sensitive data in TON wallets. +description: Handle errors, manage fees, and clean up derived account keys in TON wallets. docType: how-to schemaType: TechArticle --- -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. +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 derived key cleanup. ## Handle Transaction Errors @@ -18,12 +18,12 @@ try { value: 1000000000, bounceable: true }) - console.log('Transaction hash:', result.hash) + console.log('Signed transfer body 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('Exceeded maximum fee')) { + } else if (error.message === 'Exceeded maximum fee cost for transaction operation.') { console.error('Transaction fee exceeds transactionMaxFee') } else if (error.message.includes('invalid address')) { console.error('Invalid recipient address') @@ -46,12 +46,12 @@ try { recipient: 'EQ...', amount: 1000000 }) - console.log('Transfer submitted:', result.hash) + console.log('Signed transfer body hash:', 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')) { + } else if (error.message === 'Exceeded maximum fee cost for transfer operations.') { console.log('The transfer fee exceeds your configured maximum') } } @@ -61,7 +61,7 @@ try { ### Manage Fee Limits -Set `transactionMaxFee` when creating the wallet to cap native `sendTransaction()` and `signTransaction()` costs. Set `transferMaxFee` separately for Jetton `transfer()` costs. You can retrieve current network rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton/api-reference): +Set `transactionMaxFee` when creating the wallet to cap native `sendTransaction()` and `signTransaction()` costs. Set `transferMaxFee` separately for Jetton `transfer()` costs. You can retrieve mainnet TON API rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton/api-reference). In `1.0.0-beta.10`, this method does not follow a configured testnet client and returns the same calculated value for `normal` and `fast`: ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() @@ -69,9 +69,9 @@ console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` -### Dispose of Sensitive Data +### Dispose Derived Account Keys -Call [`dispose()`](/sdk/wallet-modules/wallet-ton/api-reference) on accounts and wallet managers to clear private keys and sensitive data from memory when they are no longer needed: +Call [`dispose()`](/sdk/wallet-modules/wallet-ton/api-reference) on accounts and wallet managers to clear cached accounts' derived private keys when they are no longer needed: ```javascript title="Memory Cleanup" account.dispose() @@ -80,5 +80,5 @@ wallet.dispose() ``` -Always call [`dispose()`](/sdk/wallet-modules/wallet-ton/api-reference) in a `finally` block or cleanup handler to ensure sensitive data is cleared even if an error occurs. +Call [`dispose()`](/sdk/wallet-modules/wallet-ton/api-reference) in a `finally` block or cleanup handler so derived account keys are cleared even if an error occurs. In the current beta, `wallet.dispose()` does not zero or unset `wallet.seed`; manage the seed lifecycle separately and release all manager references when finished. diff --git a/content/docs/sdk/wallet-modules/wallet-ton/guides/send-transactions.mdx b/content/docs/sdk/wallet-modules/wallet-ton/guides/send-transactions.mdx index 8dbc0652..deed1281 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/guides/send-transactions.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/guides/send-transactions.mdx @@ -5,7 +5,7 @@ docType: how-to schemaType: TechArticle --- -This guide explains how to [send native TON](#send-native-ton), [estimate transaction fees](#estimate-transaction-fees), [cap transaction fees](#cap-transaction-fees), [use dynamic fee rates](#use-dynamic-fee-rates), and [sign a transaction offline](#sign-a-transaction-offline). +This guide explains how to [send native TON](#send-native-ton), [estimate transaction fees](#estimate-transaction-fees), [cap transaction fees](#cap-transaction-fees), [read mainnet fee rates](#read-mainnet-fee-rates), and [prepare a signed transaction body](#prepare-a-signed-transaction-body). On TON, values are expressed in nanotons (1 TON = 10^9 nanotons). Transactions support an optional `bounceable` parameter specific to the TON network. @@ -21,7 +21,7 @@ const result = await account.sendTransaction({ value: 1000000000, // 1 TON in nanotons bounceable: true // Optional: specify if the address is bounceable }) -console.log('Transaction hash:', result.hash) +console.log('Signed transfer body hash:', result.hash) console.log('Transaction fee:', result.fee, 'nanotons') ``` @@ -44,14 +44,14 @@ Set [`transactionMaxFee`](/sdk/wallet-modules/wallet-ton/configuration#transacti ```javascript title="Cap Native Transaction Fees" const wallet = new WalletManagerTon(seedPhrase, { - tonClient: { url: 'https://toncenter.com/api/v3' }, + tonClient: { url: 'https://toncenter.com/api/v2/jsonRPC' }, transactionMaxFee: 1000000000n }) ``` -## Use Dynamic Fee Rates +## Read Mainnet Fee Rates -You can retrieve current fee rates from the wallet manager using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton/api-reference): +You can retrieve mainnet TON API fee rates from the wallet manager using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-ton/api-reference#getfeerates). In `1.0.0-beta.10`, this method does not follow a configured testnet client and returns the same calculated value for `normal` and `fast`: ```javascript title="Get Fee Rates" const feeRates = await wallet.getFeeRates() @@ -59,19 +59,17 @@ console.log('Normal fee rate:', feeRates.normal, 'nanotons') console.log('Fast fee rate:', feeRates.fast, 'nanotons') ``` -## Sign a Transaction Offline +## Prepare a Signed Transaction Body -You can sign a transaction without broadcasting it using [`account.signTransaction()`](/sdk/wallet-modules/wallet-ton/api-reference#signtransactiontx). This returns the signed external-message body as a TON `Cell`, which you can serialize and broadcast from another environment. +You can build a signed transaction body without broadcasting it using [`account.signTransaction()`](/sdk/wallet-modules/wallet-ton/api-reference#signtransactiontx). The method still requires the configured TON client to read the current sequence number and, when a fee cap is configured, estimate the fee. It returns the body `Cell` accepted by the matching opened `WalletContractV5R1.send()` call, not a complete external-message BOC. -```javascript title="Sign Transaction Offline" +```javascript title="Prepare Signed Transaction Body" const cell = await account.signTransaction({ to: 'EQ...', // TON address value: 1000000000 // 1 TON in nanotons }) -// Serialize to a wire-format payload for broadcast elsewhere -const boc = cell.toBoc().toString('base64') -console.log('Signed payload:', boc) +// `cell` is not broadcast by signTransaction(). ``` ## Next Steps diff --git a/content/docs/sdk/wallet-modules/wallet-ton/guides/transfer-tokens.mdx b/content/docs/sdk/wallet-modules/wallet-ton/guides/transfer-tokens.mdx index 9c891c59..ada6de07 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/guides/transfer-tokens.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/guides/transfer-tokens.mdx @@ -17,7 +17,7 @@ const transferResult = await account.transfer({ recipient: 'EQ...', // Recipient's TON address amount: 1000000 // Amount in Jetton's base units }) -console.log('Transfer hash:', transferResult.hash) +console.log('Signed transfer body hash:', transferResult.hash) console.log('Transfer fee:', transferResult.fee, 'nanotons') ``` @@ -69,7 +69,7 @@ async function transferJettonWithValidation(account, jettonAddress, recipient, a recipient, amount }) - console.log('Transfer hash:', result.hash) + console.log('Signed transfer body hash:', result.hash) console.log('Actual fee:', result.fee, 'nanotons') return result diff --git a/content/docs/sdk/wallet-modules/wallet-ton/index.mdx b/content/docs/sdk/wallet-modules/wallet-ton/index.mdx index b0a1b747..762e114d 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/index.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/index.mdx @@ -30,7 +30,7 @@ Use [`getAccountByPath`](/sdk/wallet-modules/wallet-ton/api-reference) to supply - **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 +- **Derived Key Cleanup**: Account disposal zeroes derived private key bytes with sodium-universal - **Provider Flexibility**: Support for custom TON RPC endpoints and TON Center API ## Supported Networks diff --git a/content/docs/sdk/wallet-modules/wallet-ton/usage.mdx b/content/docs/sdk/wallet-modules/wallet-ton/usage.mdx index 449d6024..d058c2c0 100644 --- a/content/docs/sdk/wallet-modules/wallet-ton/usage.mdx +++ b/content/docs/sdk/wallet-modules/wallet-ton/usage.mdx @@ -28,7 +28,7 @@ Transfer Jetton tokens and estimate fees. Sign messages and verify signatures. -Handle errors, manage fees, and dispose of sensitive data. +Handle errors, manage fees, and clean up derived account keys. diff --git a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/api-reference.mdx b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/api-reference.mdx index d172d99e..2650bd3f 100644 --- a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/api-reference.mdx +++ b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/api-reference.mdx @@ -34,7 +34,8 @@ new WalletManagerTronGasfree(seed, config) - `verifyingContract` (string): Gas-free verifying contract address - `gasFreeApiKey` (string, optional): API key for signed GasFree provider requests - `gasFreeApiSecret` (string, optional): API secret for signed GasFree provider requests. Provide together with `gasFreeApiKey`. - - `transferMaxFee` (number, optional): Maximum fee for transfer operations + - `transferMaxFee` (number | bigint, optional): Shared config field; the current runtime does not use it as a default transfer cap + - `transactionMaxFee` (number | bigint, optional): Shared config field; native transaction methods remain unsupported, so it has no runtime effect **Example:** ```javascript @@ -45,8 +46,7 @@ const wallet = new WalletManagerTronGasfree(seedPhrase, { serviceProvider: 'T...', verifyingContract: 'T...', gasFreeApiKey: 'your-api-key', // Optional: provide with gasFreeApiSecret - gasFreeApiSecret: 'your-api-secret', - transferMaxFee: 10000000 // Optional + gasFreeApiSecret: 'your-api-secret' }) ``` @@ -56,7 +56,7 @@ const wallet = new WalletManagerTronGasfree(seedPhrase, { |--------|-------------|---------| | `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}\>` | +| `getFeeRates()` | Returns current fee rates for normal and fast transactions | `Promise\<{normal: bigint, fast: bigint}\>` | | `dispose()` | Disposes all wallet accounts, clearing private keys from memory | `void` | ##### `getAccount(index)` @@ -88,7 +88,7 @@ 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 +**Returns:** `Promise\<{normal: bigint, fast: bigint}\>` - Object containing fee rates in sun - `normal`: Fee rate for normal priority transactions - `fast`: Fee rate for high priority transactions @@ -129,7 +129,7 @@ new WalletAccountTronGasfree(seed, path, config) | `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: bigint, activationFee: bigint}\>` | +| `transfer(options, config?)` | Transfers TRC20 tokens with an optional per-call fee cap | `Promise\<{hash: string, fee: bigint, activationFee: bigint}\>` | | `quoteTransfer(options)` | Estimates the fee for a TRC20 transfer | `Promise\<{fee: bigint, activationFee: bigint}\>` | | `sign(message)` | Signs a message using the account's private key | `Promise\` | | `signTransaction(tx)` | Unsupported on Tron GasFree; always throws | `Promise\` | @@ -181,7 +181,9 @@ Transfers TRC20 tokens to another address using the gas-free service. - `options` (TransferOptions): Transfer options - `token` (string): TRC20 contract address - `recipient` (string): Recipient's Tron address - - `amount` (number): Amount in token base units + - `amount` (number | bigint): Amount in token base units +- `config` (object, optional): Per-call transfer configuration + - `transferMaxFee` (number | bigint, optional): Reject when the quoted total fee is greater than this token-base-unit cap. A fee equal to the cap is allowed. **Returns:** `Promise\<{hash: string, fee: bigint, activationFee: bigint}\>` - Object containing transaction hash, total fee paid in token base units, and the activation-fee portion. `activationFee` is `0n` when no account activation fee applies. @@ -190,7 +192,9 @@ Transfers TRC20 tokens to another address using the gas-free service. const result = await account.transfer({ token: 'T...', // TRC20 contract address recipient: 'T...', // Recipient's address - amount: 1000000 // Amount in token base units + amount: 1000000n // Amount in token base units +}, { + transferMaxFee: 5000n }) console.log('Transaction hash:', result.hash) console.log('Fee paid:', result.fee, 'token base units') @@ -413,26 +417,29 @@ interface TransferOptions { * Amount to transfer in token base units * @example 1000000 // 1 USDT (6 decimals) */ - amount: number; + amount: number | bigint; } ``` -### TransferResult -Result object returned by transfer operations. +### Transfer Results + +The GasFree package re-exports `TransferResult` and `TronActivationFee` from `@tetherto/wdk-wallet-tron`. GasFree transfer and quote methods return intersections of those types: ```typescript -interface TransferResult { - /** - * The transaction hash - * @example '0x123...' - */ - hash: string; +import type { + TransferResult, + TronActivationFee +} from '@tetherto/wdk-wallet-tron-gasfree' - /** - * Fee paid in token base units - * @example 1000 // Fee in token base units - */ - fee: bigint; +type TronGasfreeTransferResult = TransferResult & TronActivationFee +type TronGasfreeTransferQuote = Omit & TronActivationFee +``` + +`TransferResult` supplies `hash: string` and `fee: bigint`. `TronActivationFee` supplies the activation-fee portion separately: + +```typescript +interface TronActivationFee { + activationFee: bigint; } ``` @@ -445,13 +452,13 @@ interface FeeRates { * Fee rate for normal priority transactions (in sun) * @example 1000 */ - normal: number; + normal: bigint; /** * Fee rate for high priority transactions (in sun) * @example 2000 */ - fast: number; + fast: bigint; } ``` @@ -585,9 +592,20 @@ interface TronGasfreeWalletConfig { * @example 10000000 */ transferMaxFee?: number | bigint; + + /** + * Shared wallet config field for native transaction methods. + * The GasFree module does not support quoteSendTransaction(), + * signTransaction(), or sendTransaction(), so this field has no + * runtime effect in the current release. + * @optional + */ + transactionMaxFee?: number | bigint; } ``` +The current runtime also does not use constructor-level `transferMaxFee` as a default. Enforce a GasFree transfer cap with the second argument to `account.transfer()`. + ### KeyPair Account key pair information. diff --git a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/configuration.mdx b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/configuration.mdx index 575cd323..5b89ad1d 100644 --- a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/configuration.mdx +++ b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/configuration.mdx @@ -32,8 +32,7 @@ const config = { // Optional parameters gasFreeApiKey: 'your-api-key', // Required only for signed GasFree API requests - gasFreeApiSecret: 'your-api-secret', // Provide together with gasFreeApiKey - transferMaxFee: 10000000 // Maximum fee in token base units + gasFreeApiSecret: 'your-api-secret' // Provide together with gasFreeApiKey } const wallet = new WalletManagerTronGasfree(seedPhrase, config) @@ -53,6 +52,10 @@ const config2 = { `gasFreeApiKey` and `gasFreeApiSecret` are optional. Omit both when your GasFree provider accepts unsigned requests. If you configure signed GasFree API requests, provide both values together; the constructor rejects partial credentials. + +`TronGasfreeWalletConfig` includes `transferMaxFee` and `transactionMaxFee` for shared wallet type compatibility. The current GasFree runtime does not use either constructor field as a fee cap. Pass `transferMaxFee` in the second argument to `account.transfer()`; native transaction methods are unsupported, so `transactionMaxFee` has no effect. + + ## Account Configuration Both `WalletAccountTronGasfree` and `WalletAccountReadOnlyTronGasfree` share similar configuration requirements: @@ -71,12 +74,11 @@ const account = new WalletAccountTronGasfree( serviceProvider: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', verifyingContract: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', gasFreeApiKey: 'your-api-key', // Optional: provide with gasFreeApiSecret - gasFreeApiSecret: 'your-api-secret', - transferMaxFee: 10000000 // Optional + gasFreeApiSecret: 'your-api-secret' } ) -// Read-only account (transferMaxFee not needed) +// Read-only account (fee-cap fields are omitted) const readOnlyAccount = new WalletAccountReadOnlyTronGasfree( 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', // Tron address { @@ -228,7 +230,7 @@ const config = { ### Transfer Max Fee -The `transferMaxFee` option sets a maximum limit for transaction fees to prevent unexpectedly high costs. +Pass `transferMaxFee` in the optional second argument to `account.transfer()` to cap one GasFree TRC20 transfer. The constructor-level field exists in `TronGasfreeWalletConfig` but is not used as a default by the current runtime. **Type:** `number | bigint` @@ -240,26 +242,29 @@ The `transferMaxFee` option sets a maximum limit for transaction fees to prevent ```javascript const config = { - transferMaxFee: 10000000 // Maximum fee in token base units + transferMaxFee: 5000n } -// 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') - } -} +const result = await account.transfer({ + token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', + recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', + amount: 1000000n +}, config) ``` +The transfer is rejected only when the quoted total fee is greater than the cap. A fee equal to `transferMaxFee` is allowed. Use an integer or `bigint` value because the runtime converts the cap with `BigInt()`. + +### Transaction Max Fee + +`transactionMaxFee` is present in the public config type for base-wallet compatibility. + +**Type:** `number | bigint` + +**Required:** No (optional) + +The GasFree module does not support `quoteSendTransaction()`, `signTransaction()`, or `sendTransaction()`. Those methods always throw, so this field does not control a runtime operation in the current release. Use the base `@tetherto/wdk-wallet-tron` package for native TRX transactions. + ## Network-Specific Configurations ### Tron Mainnet diff --git a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/handle-errors.mdx b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/handle-errors.mdx index d942e817..2561b760 100644 --- a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/handle-errors.mdx +++ b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/handle-errors.mdx @@ -17,6 +17,8 @@ try { token: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT recipient: 'TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH', amount: 1000000 + }, { + transferMaxFee: 1000n }) console.log('Transfer successful:', result.hash) console.log('Fee paid:', result.fee, 'token units') @@ -51,7 +53,7 @@ try { ### 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()`](/sdk/wallet-modules/wallet-tron-gasfree/api-reference): +Pass `transferMaxFee` in the second argument to each `account.transfer()` call that needs a cap. The constructor-level field is not used as a default by the current runtime. You can retrieve current network rates using [`wallet.getFeeRates()`](/sdk/wallet-modules/wallet-tron-gasfree/api-reference): ```javascript title="Fee Management" const feeRates = await wallet.getFeeRates() diff --git a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/send-transactions.mdx b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/send-transactions.mdx index 68538b53..d6e2f57d 100644 --- a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/send-transactions.mdx +++ b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/send-transactions.mdx @@ -7,6 +7,8 @@ schemaType: TechArticle The Tron GasFree wallet module is for gas-free TRC20 token transfers. It does not support native TRX transaction execution or native transaction fee quotes. +Although `transactionMaxFee` is present in the shared config type, it has no effect here because the native quote, sign, and send methods remain unsupported. + For gas-free TRC20 transfers, use [`transfer(options)`](/sdk/wallet-modules/wallet-tron-gasfree/api-reference#transferoptions) and [`quoteTransfer(options)`](/sdk/wallet-modules/wallet-tron-gasfree/api-reference#quotetransferoptions). If you need native TRX transactions, use the base `@tetherto/wdk-wallet-tron` module instead. ## Unsupported Methods diff --git a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/transfer-tokens.mdx b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/transfer-tokens.mdx index 21f312cf..3bbecac2 100644 --- a/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/transfer-tokens.mdx +++ b/content/docs/sdk/wallet-modules/wallet-tron-gasfree/guides/transfer-tokens.mdx @@ -22,7 +22,7 @@ console.log('Transfer fee:', transferResult.fee, 'token units') console.log('Activation fee:', transferResult.activationFee, 'token units') ``` -The returned `fee` includes the GasFree transfer fee and, when the GasFree account is not active yet, the token activation fee returned by the provider. Use `activationFee` to show that activation portion separately; it is `0n` when no activation fee applies. +The returned `fee` includes the GasFree transfer fee and, when the GasFree account is not active yet, the token activation fee returned by the provider. Both `fee` and `activationFee` are returned as `bigint`; `activationFee` is `0n` when no activation fee applies. ## Override Fee Limit @@ -41,6 +41,8 @@ console.log('Transfer fee:', result.fee, 'token units') console.log('Activation fee:', result.activationFee, 'token units') ``` +The call rejects only when the quoted total fee is greater than `transferMaxFee`; a fee equal to the cap is allowed. The constructor-level `transferMaxFee` field is not used as a default by the current runtime, so pass the cap on every transfer that needs one. + ## Estimate Transfer Fees You can get a fee estimate before executing the transfer using [`account.quoteTransfer()`](/sdk/wallet-modules/wallet-tron-gasfree/api-reference#quotetransferoptions): diff --git a/content/docs/start-building/react-native-quickstart.mdx b/content/docs/start-building/react-native-quickstart.mdx index 83b0561c..9ebb47a8 100644 --- a/content/docs/start-building/react-native-quickstart.mdx +++ b/content/docs/start-building/react-native-quickstart.mdx @@ -128,6 +128,10 @@ Integrate WDK into your existing React Native or Expo project using `@tetherto/w npm install @tetherto/wdk-react-native-core ``` + +`@tetherto/wdk-react-native-core` `v1.0.0-beta.13` includes the React Native source entry used by Metro, but its npm artifact omits the declared `dist/index.js` and `dist/index.d.ts` files. Default Node resolution and package declaration lookup fail for this tag. Use it only in a Metro flow you have verified; if your build requires the missing outputs, wait for a corrected artifact. + + ### Step 2: Configure Android minSdkVersion The library requires **Android API 29** or higher to support `react-native-bare-kit`. @@ -175,11 +179,7 @@ buildscript { ### 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: +The WDK engine runs inside a Bare worklet. Use the `@tetherto/wdk-worklet-bundler` CLI to generate an HRPC bundle with only the modules you need: ```bash # 1. Install the bundler CLI @@ -206,23 +206,8 @@ 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. - - - +`@tetherto/pear-wrk-wdk` provides worklet transport and runtime handlers; it does not export a pre-built WDK bundle. ### Step 4: Configure WDK Settings diff --git a/content/docs/tools/pear-wrk-wdk/api-reference.mdx b/content/docs/tools/pear-wrk-wdk/api-reference.mdx index 95783a77..516b193e 100644 --- a/content/docs/tools/pear-wrk-wdk/api-reference.mdx +++ b/content/docs/tools/pear-wrk-wdk/api-reference.mdx @@ -20,10 +20,12 @@ schemaType: APIReference | `generateEntropyAndEncrypt()` | `generateEntropyAndEncrypt(args: WdkGenerateEntropyParams): Promise\` | Generates encrypted seed and entropy buffers inside the worklet. | | `getMnemonicFromEntropy()` | `getMnemonicFromEntropy(args: WdkGetMnemonicParams): Promise\<{ mnemonic: string }\>` | Decrypts an encrypted entropy payload and returns the mnemonic. | | `getSeedAndEntropyFromMnemonic()` | `getSeedAndEntropyFromMnemonic(args: { mnemonic: string }): Promise\` | Converts a mnemonic into encrypted seed and entropy buffers. | -| `dispose()` | `dispose(args: DisposeRequest): void` | Disposes the worklet WDK instance. | +| `dispose()` | `dispose(args: DisposeRequest): void` | Disposes the full worklet WDK instance or only selected blockchains. | | `callMethod()` | `callMethod(args: CallMethodRequest): Promise\` | Looks up the target account and invokes one wallet or protocol method by name. | | `registerWallet()` | `registerWallet(args: { config: string }): Promise\<{ status: string, blockchains: string }\>` | Dynamically registers additional wallets from a JSON config string. | | `registerProtocol()` | `registerProtocol(args: { config: string }): Promise\<{ status: string }\>` | Dynamically registers additional protocols from a JSON config string. | +| `callModule()` | `callModule(args: CallModuleRequest): Promise\` | Calls a method on a configured generic module over HRPC. | +| `moduleEvent()` | `moduleEvent(args: ModuleEventRequest): void` | Sends a generic-module event from the worklet to the HRPC host. | #### Handler Registration Methods @@ -40,6 +42,8 @@ schemaType: APIReference | `onCallMethod()` | `onCallMethod(responseFn): void` | Registers the server-side handler for `callMethod()`. | | `onRegisterWallet()` | `onRegisterWallet(responseFn): void` | Registers the server-side handler for `registerWallet()`. | | `onRegisterProtocol()` | `onRegisterProtocol(responseFn): void` | Registers the server-side handler for `registerProtocol()`. | +| `onCallModule()` | `onCallModule(responseFn): void` | Registers the worklet-side handler for generic-module calls. | +| `onModuleEvent()` | `onModuleEvent(responseFn): void` | Registers the host-side handler for generic-module events. | #### `log` @@ -65,13 +69,15 @@ Returns: - `encryptedSeed?` (`string`): Base64-encoded encrypted seed buffer. - `config` (`string`): JSON stringified `WdkWorkletConfig`. -The handler requires `encryptionKey` and `encryptedSeed` to be passed together or omitted together. When a seeded WDK instance already exists, the runtime disposes it before re-registering the wallets and optional protocols in `config`. +The handler requires `encryptionKey` and `encryptedSeed` to be passed together or omitted together. When a seeded WDK instance already exists, the runtime disposes it and closes its generic modules before re-registering the wallets and optional protocols in `config`. + +In beta.9, HRPC generic modules are constructed from `context.moduleManagers` and `config.modules` only when that request includes the encrypted seed pair. A seedless reinitialization closes existing module instances without reconstructing them. Supply both seed fields on every initialization that must construct or reconstruct modules. #### `resetWdkWallets` - `config` (`string`): JSON stringified object containing a `networks` map. -The runtime validates `config.networks`, extracts each target `blockchain`, calls `wdk.dispose(targetChains)`, and re-registers only those wallet managers. This method does not re-register protocols. +The runtime validates `config.networks`, extracts each target `blockchain`, calls `wdk.dispose(targetChains)`, and re-registers only those wallet managers. This method does not re-register protocols or close generic modules; existing module instances keep running. #### `generateEntropyAndEncrypt` @@ -104,7 +110,9 @@ Returns: #### `dispose` -- `args` (`DisposeRequest`): Empty request object. +- `args` (`DisposeRequest`): Optional `blockchains` array. Omit it or pass an empty array for a full disposal. + +A full disposal closes all generic modules and clears the WDK instance. A non-empty `blockchains` array disposes only those wallets and leaves generic modules running. #### `callMethod` @@ -133,6 +141,24 @@ Returns: - `status` (`string`) +#### `callModule` + +Call one method on a configured generic module. This command is available on HRPC only. + +- `module` (`string`): Module name shared by `RpcContext.moduleManagers` and `WdkWorkletConfig.modules`. +- `method` (`string`): Non-empty method name on the constructed module instance. +- `args?` (`string`): Optional JSON string of arguments. Arrays are spread as positional arguments; a non-array value is passed as one argument. + +Returns `CallModuleResponse` with optional `result`, a JSON string. The runtime awaits promises, materializes values with `.toArray()`, and recursively converts `Uint8Array` values to hex before serialization. + +#### `moduleEvent` + +Send an HRPC module event to the host. + +- `module` (`string`): Module name. +- `event` (`string`): Event name. +- `payload?` (`string | null`): Optional JSON string payload. + #### `onLog` Registers the server-side handler used to service `log()` requests. @@ -177,12 +203,20 @@ Registers the server-side handler used to service `registerWallet()` requests. Registers the server-side handler used to service `registerProtocol()` requests. +#### `onCallModule` + +Registers the worklet-side handler used to service `callModule()` requests. + +#### `onModuleEvent` + +Registers the host-side handler used to receive `moduleEvent()` messages. + ### Export: `registerRpcHandlers(rpc, context)` Registers the package's server-side handlers on the provided RPC instance. - `rpc` (`any`): RPC server instance that supports the generated handler registration methods. -- `context` (`RpcContext`): Runtime context containing `wdk`, `WDK`, `walletManagers`, `protocolManagers`, and `wdkLoadError`. +- `context` (`RpcContext`): Runtime context containing `wdk`, `WDK`, `walletManagers`, `protocolManagers`, and `wdkLoadError`. HRPC generic modules can additionally supply `moduleManagers` and `capabilities`; the runtime manages `moduleRuntime` and `moduleInstances`. ### Types @@ -203,6 +237,47 @@ interface WdkWorkletConfig { config: unknown } } + modules?: { + [moduleName: string]: Record + } +} +``` + +The `modules` map contains runtime module configuration. Its names must match the module managers generated by Worklet Bundler or supplied manually in `RpcContext`. + +#### `WdkModuleManager` + +```ts +interface WdkModuleManager { + events?: string[] + createModule: (context: { + seed: any + config: any + capabilities: Record + emit: (event: string, payload?: any) => void + }) => any | Promise +} +``` + +The factory must consume `seed` synchronously rather than retain it. Module instances can optionally implement `close()`, `suspend()`, and `resume()`. The runtime calls `close()` during full disposal or reinitialization; targeted blockchain disposal and `resetWdkWallets()` leave generic modules running. Worklet Bundler-generated HRPC entrypoints forward Bare lifecycle events to `suspend()` and `resume()`; manual Pear integrations must wire those events themselves. Declared `events` are forwarded from the instance, and the injected `emit()` function can emit events directly. + +#### Module request types + +```ts +interface CallModuleRequest { + module: string + method: string + args?: string +} + +interface CallModuleResponse { + result?: string | null +} + +interface ModuleEventRequest { + module: string + event: string + payload?: string | null } ``` @@ -225,6 +300,38 @@ interface CallMethodOptions { } ``` +## JSON-RPC Transport + +Import `registerJsonRpcHandlers()` from the separate JSON-RPC entrypoint: + +```javascript +const { registerJsonRpcHandlers } = require('@tetherto/pear-wrk-wdk/jsonrpc') + +registerJsonRpcHandlers(ipc, context) +``` + +The server reads UTF-8 JSON-RPC 2.0 messages framed with a four-byte unsigned big-endian payload length. Every request requires an ID, and an ID cannot be reused while its earlier request is still in flight. Malformed frames are dropped without a response. The package does not export a JSON-RPC client or native-host helper. + +Beta.9 supports these JSON-RPC method names: + +- `workletStart` +- `generateEntropyAndEncrypt` +- `getMnemonicFromEntropy` +- `getSeedAndEntropyFromMnemonic` +- `initializeWDK` +- `callMethod` +- `registerWallet` +- `registerProtocol` +- `dispose` + +JSON-RPC does not support `resetWdkWallets`, generic-module calls, or module events in this release. Use HRPC for those operations. + + +INFO-level logging can include wallet-call arguments and JSON-RPC parameters or results. Production defaults to ERROR logging; do not enable more verbose logging for requests that may contain seeds, mnemonics, keys, or other sensitive values. + + +Mnemonic strings, encryption-key strings, and encrypted payload strings cannot be zeroed in JavaScript. Discard references promptly and never log them. The runtime validates imported mnemonics for 12 or 24 English BIP-39 words and clears temporary byte buffers where possible. + *** ## Need Help? diff --git a/content/docs/tools/pear-wrk-wdk/configuration.mdx b/content/docs/tools/pear-wrk-wdk/configuration.mdx index e453986f..29bd6dc5 100644 --- a/content/docs/tools/pear-wrk-wdk/configuration.mdx +++ b/content/docs/tools/pear-wrk-wdk/configuration.mdx @@ -1,33 +1,69 @@ --- title: Pear Worklet WDK Configuration -description: Configure the Bare worklet context and the JSON payloads passed to initializeWDK and resetWdkWallets +description: Configure Pear Worklet HRPC and JSON-RPC contexts, WDK payloads, and generic modules --- -This page explains how to [build the worklet context](#worklet-context), [shape the worklet config payload](#worklet-config-payload), [initialize-wdk](#initialize-wdk), and [reset-selected-wallets](#reset-selected-wallets). +This page explains how to [build the worklet context](#worklet-context), [shape the worklet config payload](#worklet-config-payload), [initialize WDK](#initialize-wdk), [call generic modules](#call-generic-module-methods), and [choose a transport](#json-rpc-transport). ## Worklet Context You can bind the shipped RPC handlers to your Bare worklet using `registerRpcHandlers()`: ```javascript title="Register RPC Handlers" +require('bare-node-runtime/global') + const { registerRpcHandlers } = require('@tetherto/pear-wrk-wdk/worklet') -const { WDK } = require('@tetherto/wdk') -const EvmWalletManager = require('@tetherto/wdk-wallet-evm') -const SparkWalletManager = require('@tetherto/wdk-wallet-spark') +const wdkModule = require('@tetherto/wdk', { with: { imports: 'bare-node-runtime/imports' } }) +const { createModule: createPreferencesModule } = require('@your-org/wdk-module-preferences') + +const WDK = wdkModule.default || wdkModule.WDK || wdkModule +const walletCache = {} + +function loadWalletManager(network) { + if (walletCache[network]) return walletCache[network] + + let walletModule + if (network === 'ethereum') { + walletModule = require('@tetherto/wdk-wallet-evm', { with: { imports: 'bare-node-runtime/imports' } }) + } + if (network === 'spark') { + walletModule = require('@tetherto/wdk-wallet-spark', { with: { imports: 'bare-node-runtime/imports' } }) + } + + if (walletModule) walletCache[network] = walletModule.default || walletModule + return walletCache[network] || null +} + +const walletManagers = new Proxy({}, { + get: (_, network) => loadWalletManager(network), + has: (_, network) => ['ethereum', 'spark'].includes(network) +}) const context = { wdk: null, WDK, - walletManagers: { - ethereum: EvmWalletManager, - spark: SparkWalletManager - }, + walletManagers, protocolManagers: {}, + moduleManagers: { + preferences: { + createModule: createPreferencesModule, + events: ['changed'] + } + }, + capabilities: {}, wdkLoadError: null } module.exports = (rpc) => { registerRpcHandlers(rpc, context) + + Bare.on('suspend', async () => { + await context.moduleRuntime?.suspendAll() + }) + + Bare.on('resume', async () => { + await context.moduleRuntime?.resumeAll() + }) } ``` @@ -39,11 +75,13 @@ module.exports = (rpc) => { - `protocolManagers`: A map from protocol name to protocol manager implementation. - `wdkLoadError`: Any startup error captured while loading WDK. Use `null` when there is no load failure. +For HRPC generic modules, `moduleManagers` optionally maps module names to `{ createModule, events? }`. The factory receives `{ seed, config, capabilities, emit }` and can return an instance or a promise. `capabilities` is an optional host-supplied object and is empty by default. The runtime manages `moduleRuntime` and `moduleInstances`; do not initialize those fields yourself. Manual integrations must forward Bare `suspend` and `resume` events as shown if module instances should receive those lifecycle calls. Worklet Bundler-generated HRPC entrypoints wire them automatically. + ## Worklet Config Payload Both [`initializeWDK()`](/tools/pear-wrk-wdk/api-reference) and [`resetWdkWallets()`](/tools/pear-wrk-wdk/api-reference) expect `config` to be a JSON string. The decoded object must contain at least one entry under `networks`. -```javascript title="Minimal Worklet Config JSON" +```javascript title="Worklet Config JSON" const workletConfig = { networks: { ethereum: { @@ -61,6 +99,11 @@ const workletConfig = { environment: 'sandbox' } } + }, + modules: { + preferences: { + storagePath: '/app-data/preferences' + } } } ``` @@ -70,8 +113,13 @@ const workletConfig = { - `networks` is required and must contain at least one network entry. - Each network entry must include `blockchain` and an object `config`. - `protocols` is optional during initialization. +- `modules` is optional and contains runtime config for named generic modules. Each key must match a `moduleManagers` key in the HRPC context and the corresponding build-time Worklet Bundler module name. - `resetWdkWallets()` reads only the `networks` portion of the decoded config. + +Generic modules are HRPC-only in beta.9. The JSON-RPC handler does not construct modules or expose module calls and events. + + ## Initialize WDK You can create and register the WDK instance inside the worklet using [`initializeWDK()`](/tools/pear-wrk-wdk/api-reference): @@ -92,7 +140,9 @@ await hrpc.initializeWDK({ - Pass both `encryptionKey` and `encryptedSeed`, or omit both together. - On first initialization, the worklet must receive an encrypted seed pair so it can create `context.wdk`. -- If `context.wdk` already exists, a later `initializeWDK()` call disposes the existing instance before re-registering wallets and protocols from the new config. +- If `context.wdk` already exists, a later `initializeWDK()` call disposes the existing instance and closes its generic modules before re-registering wallets and protocols from the new config. +- In beta.9, generic modules are constructed only when that `initializeWDK()` request includes both `encryptionKey` and `encryptedSeed`. A seedless reinitialization closes existing module instances but does not rebuild them, even when `config.modules` is present. Supply the seed pair on every initialization that must construct or reconstruct modules. +- Module `close()` is called during full disposal or reinitialization. Targeted blockchain disposal leaves generic modules running. Optional `suspend()` and `resume()` methods run only when the host forwards Bare lifecycle events; the manual context above and Worklet Bundler-generated HRPC entrypoints do so. ## Reset Selected Wallets @@ -119,6 +169,7 @@ await hrpc.resetWdkWallets({ - The handler calls `wdk.dispose(targetChains)` with the blockchains extracted from `config.networks`. - Only wallets listed in the request `networks` object are re-registered. - The reset flow does not re-register protocols. +- The reset flow does not close or reconstruct generic modules; existing module instances keep running. ## Call Wallet Methods @@ -139,6 +190,53 @@ const result = await hrpc.callMethod({ - When `args` decodes to an array, the handler spreads the values as positional method arguments. - When `args` decodes to an object or primitive, the handler passes it as a single argument. +## Call Generic Module Methods + +On an HRPC worklet configured with matching `moduleManagers` and runtime `modules`, call a module method by name: + +```javascript title="Call A Generic Module" +const response = await hrpc.callModule({ + module: 'preferences', + method: 'getTheme', + args: JSON.stringify([]) +}) + +const theme = response.result ? JSON.parse(response.result) : undefined +``` + +`args` is an optional JSON string. Arrays are spread into positional arguments; a non-array value is passed as one argument. Promise results are awaited, `.toArray()` results are materialized, and `Uint8Array` values are normalized to hex before the response is serialized. + +Subscribe to events declared by the module manager: + +```javascript title="Receive A Module Event" +hrpc.onModuleEvent(({ module, event, payload }) => { + if (module === 'preferences' && event === 'changed') { + const value = payload ? JSON.parse(payload) : undefined + console.log('Preferences changed:', value) + } +}) +``` + +## JSON-RPC Transport + +Native hosts can register the separate framed JSON-RPC server entrypoint: + +```javascript title="Register JSON-RPC Handlers" +const { registerJsonRpcHandlers } = require('@tetherto/pear-wrk-wdk/jsonrpc') + +module.exports = (ipc) => { + registerJsonRpcHandlers(ipc, context) +} +``` + +Messages are UTF-8 JSON-RPC 2.0 objects prefixed by a four-byte unsigned big-endian payload length. Requests require an ID, and IDs must be unique while a request is in flight. The package exports no JSON-RPC host/client helper; the native host must implement framing and correlation. + +JSON-RPC beta.9 supports WDK initialization and disposal, secret/mnemonic operations, wallet-account calls, and dynamic wallet/protocol registration. It does not support `resetWdkWallets`, `callModule`, or module events. See the [API reference](/tools/pear-wrk-wdk/api-reference#json-rpc-transport) for the exact method list. + + +INFO-level logs can contain wallet-call arguments and JSON-RPC parameters or results. Keep production logging at its default ERROR level when requests may contain sensitive values. + + *** ## Need Help? diff --git a/content/docs/tools/pear-wrk-wdk/index.mdx b/content/docs/tools/pear-wrk-wdk/index.mdx index b88842e1..0aa628c0 100644 --- a/content/docs/tools/pear-wrk-wdk/index.mdx +++ b/content/docs/tools/pear-wrk-wdk/index.mdx @@ -1,9 +1,9 @@ --- title: Pear Worklet WDK -description: Low-level HRPC infrastructure for running WDK inside a Bare worklet +description: HRPC and framed JSON-RPC infrastructure for running WDK inside a Bare worklet --- -Pear Worklet WDK is the low-level transport and handler layer for running WDK inside a Bare worklet. It provides the `HRPC` client, the `registerRpcHandlers()` server helper, and the typed request payloads needed to initialize WDK, call wallet methods, and reset selected wallet modules from the host app. +Pear Worklet WDK is the low-level transport and handler layer for running WDK inside a Bare worklet. It provides an `HRPC` client and server helper, a separate framed JSON-RPC server entrypoint for native hosts, and typed request payloads for WDK, wallet, protocol, and HRPC-only generic-module operations. Powered by `@tetherto/pear-wrk-wdk`. @@ -13,6 +13,8 @@ Powered by `@tetherto/pear-wrk-wdk`. - **Typed lifecycle requests**: Initialize WDK with `initializeWDK({ config, encryptionKey, encryptedSeed })` and tear it down with `dispose()` - **Selective wallet resets**: Re-register only the wallet modules listed in a new worklet `networks` config using `resetWdkWallets({ config })` - **Generic wallet method calls**: Call account methods through `callMethod({ methodName, network, accountIndex, args, options })` +- **HRPC generic modules**: Construct named modules during WDK initialization, call their methods with `callModule()`, and forward declared events to the host +- **Framed JSON-RPC server**: Register a length-prefixed JSON-RPC 2.0 server through `@tetherto/pear-wrk-wdk/jsonrpc` - **Dynamic registration hooks**: Register additional wallets or protocols with `registerWallet()` and `registerProtocol()` ## Why this matters @@ -20,14 +22,19 @@ Powered by `@tetherto/pear-wrk-wdk`. - You can keep WDK state and signing operations off the main thread in Bare-based apps - You can reconfigure selected wallet modules without fully disposing the worklet - You can use one transport layer across custom mobile, desktop, or embedded Bare integrations +- You can host the same wallet and protocol handlers behind HRPC or a native JSON-RPC bridge, within each transport's supported method set Use this package when you need direct control over the worklet host and RPC layer. If you want generated worklet entry files instead, start with [`@tetherto/wdk-worklet-bundler`](https://github.com/tetherto/wdk-worklet-bundler). + +Generic-module calls and events are HRPC-only in `v1.0.0-beta.9`; the JSON-RPC handler does not expose them. This package also does not export a pre-built WDK bundle. + + -Build the worklet context and pass the JSON config payloads used by initialize and reset requests +Build HRPC or JSON-RPC contexts and configure WDK, wallet, protocol, and generic-module initialization Review the exported class, server helper, and request shapes diff --git a/content/docs/tools/react-native-core/api-reference.mdx b/content/docs/tools/react-native-core/api-reference.mdx index c1d42709..ce3d8a87 100644 --- a/content/docs/tools/react-native-core/api-reference.mdx +++ b/content/docs/tools/react-native-core/api-reference.mdx @@ -12,6 +12,8 @@ schemaType: APIReference | [`useWalletManager`](#usewalletmanager) | Hook | Wallet lifecycle (create, restore, lock, unlock) | | [`useAccount`](#useaccount) | Hook | Account operations (send, sign, verify, estimateFee) | | [`useProtocol`](#useprotocol) | Hook | Protocol method calls through the active worklet account | +| [`useModule`](#usemodule) | Hook | Named generic-module calls and event subscriptions | +| [`ModuleService`](#moduleservice) | Class | Low-level static gateway for generic-module calls and events | | [`useAddresses`](#useaddresses) | Hook | Load and query wallet addresses | | [`useBalance`](#usebalance) | Hook | Single asset balance with TanStack Query | | [`useBalancesForWallet`](#usebalancesforwallet) | Hook | Bulk balance fetch for multiple assets | @@ -25,6 +27,8 @@ schemaType: APIReference | `UseAccountParams` | Type | Parameters for `useAccount` | | `UseAccountReturn` | Type | Return type of `useAccount` | | `UseProtocolParams` | Type | Parameters for `useProtocol` | +| `UseModuleProxy` | Type | Typed asynchronous module proxy returned by `useModule` | +| `ModuleEventListener` | Type | Listener for parsed module-event payloads | | `UseAddressesReturn` | Type | Return type of `useAddresses` | | `UseWalletManagerResult` | Type | Return type of `useWalletManager` | @@ -381,6 +385,76 @@ function SwapQuoteScreen() { --- +## useModule + +Hook that creates a typed proxy for one named generic module in the active HRPC worklet. Every method access is forwarded through `ModuleService.callModule()`. The proxy also exposes `on(event, listener)` for module events. + + +React Native Core `v1.0.0-beta.13` exposes this API but pins Pear Worklet `v1.0.0-beta.8`, which does not contain the required module HRPC methods. The default dependency graph therefore cannot run these calls. Installing Pear Worklet beta.9 separately does not replace the nested beta.8 dependency; wait for a dependency-aligned React Native Core release before adopting this API. + + +### Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `moduleName` | `string` | Name shared by the bundler's build-time `modules` map and runtime `wdkConfigs.modules` map | + +### Returns + +Returns `UseModuleProxy`. Define module methods as asynchronous in `T` because every proxy call crosses the worklet boundary and returns a promise. + +```typescript title="UseModuleProxy" +type UseModuleProxy = T & { + on: (event: string, listener: ModuleEventListener) => () => void +} + +type ModuleEventListener = (payload: unknown) => void +``` + +### Example + +```tsx title="Call A Named Module" +import { useEffect } from 'react' +import { useModule } from '@tetherto/wdk-react-native-core' + +type PreferencesModule = { + getTheme: () => Promise<'light' | 'dark'> + setTheme: (theme: 'light' | 'dark') => Promise +} + +function PreferencesScreen() { + const preferences = useModule('preferences') + + useEffect(() => { + return preferences.on('changed', payload => { + console.log('Preferences changed:', payload) + }) + }, [preferences]) + + // Module calls are asynchronous. + // const theme = await preferences.getTheme() +} +``` + +Subscriptions are removed automatically on unmount or when `moduleName` changes. Calling the returned unsubscribe function removes a subscription earlier. + +--- + +## ModuleService + +Low-level static service used by `useModule()`. Use it when a hook is not appropriate but the React Native worklet has already initialized. + +| Method | Signature | Description | +|--------|-----------|-------------| +| `callModule()` | `callModule(moduleName: string, method: string, ...args: unknown[]): Promise` | Serialize positional arguments, call the named module method, and parse the JSON response | +| `onModuleEvent()` | `onModuleEvent(moduleName: string, event: string, listener: ModuleEventListener): () => void` | Subscribe to one named event and return an unsubscribe function | + +`callModule()` requires non-empty module and method names plus an initialized worklet. It returns `undefined` when the worklet response is absent or empty. Arguments and results must be safely JSON-serializable; `bigint` arguments are serialized as strings, while circular and non-standard-prototype objects are rejected. + +`onModuleEvent()` parses JSON event payloads when possible and otherwise delivers the raw string. Listener failures do not stop delivery to other listeners. + +--- + ## useAddresses Hook to load and query wallet addresses across all networks. @@ -732,9 +806,14 @@ interface WdkConfigs, TProtocol = Record } + modules?: { + [moduleName: string]: Record + } } ``` +`modules` contains runtime configuration for generic modules. It is distinct from the Worklet Bundler's build-time `modules` map, which selects package names, factories, and forwarded events. Use the same module name in both maps. + #### WdkNetworkConfig Wrapper around `NetworkConfig` with typed `config` field. diff --git a/content/docs/tools/react-native-core/index.mdx b/content/docs/tools/react-native-core/index.mdx index bd31c587..54d7b7d6 100644 --- a/content/docs/tools/react-native-core/index.mdx +++ b/content/docs/tools/react-native-core/index.mdx @@ -8,12 +8,21 @@ description: Hooks-based React Native library for building multi-chain wallet ap ## Features - **Hooks-based architecture** - `useWdkApp`, `useWalletManager`, `useAccount`, `useProtocol`, `useBalance`, `useBalancesForWallets`, and more +- **Generic module API** - `useModule` and `ModuleService` expose named worklet-module calls and events - **TanStack Query caching** - automatic balance fetching across one or many account indices, per-token fallback for modules without batch balance support, cache invalidation, and optimistic updates - **Zustand state management** - persisted wallet state with MMKV storage - **Worklet runtime** - runs WDK in an isolated Bare worklet - **Biometric authentication** - secure storage with device biometrics - **Multi-wallet support** - create, restore, switch, lock, unlock, and delete wallets -- **TypeScript-first** - full type safety with exported types and interfaces +- **Typed React Native source API** - exported hook and service types are available through the package's React Native source condition + + +In `v1.0.0-beta.13`, the generic module API is not runnable through the default dependency graph: React Native Core pins Pear Worklet `v1.0.0-beta.8`, while module calls and events require the HRPC methods added in Pear Worklet `v1.0.0-beta.9`. Installing beta.9 separately does not replace the nested beta.8 dependency. Wait for a dependency-aligned React Native Core release before using `useModule()` or `ModuleService` in an end-to-end integration. + + + +The beta.13 npm artifact ships its `react-native` source entry but omits the declared default JavaScript and declaration outputs under `dist/`. Consume this release through React Native/Metro; the tag does not provide a working default Node entrypoint. + ## Quick Start @@ -67,9 +76,7 @@ For a full integration guide, see the [React Native Quickstart](/start-building/ ## Bundle Configuration -The WDK engine runs inside a Bare worklet. You need to provide a bundle - there are two approaches: - -### Custom Bundle (Recommended) +The WDK engine runs inside a Bare worklet. Generate an HRPC bundle with `@tetherto/wdk-worklet-bundler` and import it from the generated `./.wdk` entrypoint. Use the `@tetherto/wdk-worklet-bundler` CLI to generate a bundle with only the blockchain modules you need: @@ -93,27 +100,20 @@ Example `wdk.config.js`: ```javascript module.exports = { - modules: { - core: '@tetherto/wdk', - erc4337: '@tetherto/wdk-wallet-evm-erc-4337', - }, networks: { ethereum: { - module: 'erc4337', - chainId: 1, - blockchain: 'ethereum', - provider: 'https://eth.drpc.org', + package: '@tetherto/wdk-wallet-evm-erc-4337' }, polygon: { - module: 'erc4337', - chainId: 137, - blockchain: 'polygon', - provider: 'https://polygon.drpc.org', - }, + package: '@tetherto/wdk-wallet-evm-erc-4337' + } }, + transport: 'hrpc' } ``` +This file selects packages at build time. Pass chain IDs, providers, protocol settings, and any per-module runtime config through `wdkConfigs` on `WdkAppProvider`. The optional build-time `modules` map in the bundler is distinct from runtime `wdkConfigs.modules`; their names must match when generic-module support is available. + After running `wdk-worklet-bundler generate`, import and use the bundle: ```typescript @@ -124,23 +124,7 @@ import { bundle } from './.wdk' ``` -For full bundler documentation, see [wdk-worklet-bundler](https://github.com/tetherto/wdk-worklet-bundler). - -### Pre-built Bundle - -For quick prototyping, use the pre-built bundle from `@tetherto/pear-wrk-wdk` which includes all blockchain modules: - -```typescript -import { bundle } from '@tetherto/pear-wrk-wdk' - - - - -``` - - -The pre-built bundle includes all blockchain modules, resulting in a larger bundle size. For production apps, generate a custom bundle with only the modules you need. - +For the complete config and transport rules, see the [Worklet Bundler configuration guide](/tools/worklet-bundler/configuration). `@tetherto/pear-wrk-wdk` provides the worklet transport/runtime layer; it does not export a pre-built WDK bundle. ## Architecture @@ -157,6 +141,7 @@ WdkAppProvider +-- useWalletManager() - create, restore, lock, unlock, delete wallets +-- useAccount() - address, send, sign, verify, estimateFee +-- useProtocol() - call bridge, swap, lending, and fiat protocol methods + +-- useModule() - call named generic modules and subscribe to events (dependency-aligned HRPC builds only) +-- useAddresses() - load and query addresses +-- useBalance() - single balance with TanStack Query +-- useBalancesForWallet() - bulk balance fetch for one account index diff --git a/content/docs/tools/wdk-utils/api-reference.mdx b/content/docs/tools/wdk-utils/api-reference.mdx index 20825c1f..4510ae06 100644 --- a/content/docs/tools/wdk-utils/api-reference.mdx +++ b/content/docs/tools/wdk-utils/api-reference.mdx @@ -361,6 +361,61 @@ import { decryptWithKey } from '@tetherto/wdk-utils' const plaintext = decryptWithKey(encrypted, key) ``` +### Seed Key Derivation Helpers + +Derive deterministic, domain-separated key material from high-entropy seed bytes. + +| Function | Description | Returns | +| --- | --- | --- | +| `deriveSeedKey(seed, options)` | Derive a byte key with HKDF-SHA256. | `Uint8Array` | +| `deriveSeedKeyPair(seed, options)` | Derive a deterministic Ed25519 keypair. | `KeyPair` | + +```typescript title="Seed Key Derivation Types" +type SeedKeyOptions = { + salt: string | Uint8Array + info: string | Uint8Array + length?: number +} + +type KeyPair = { + publicKey: Uint8Array + secretKey: Uint8Array +} +``` + +#### `deriveSeedKey(seed, options)` + +Derive a key using HKDF-SHA256. `salt` and `info` are required caller-controlled domain-separation values, and `length` defaults to 32 bytes. + +```javascript title="Derive A Seed Key" +import { deriveSeedKey } from '@tetherto/wdk-utils' + +const key = deriveSeedKey(seedBytes, { + salt: 'com.example.wallet/v1', + info: 'local-encryption', + length: 32 +}) +``` + +The function throws `salt is required` or `info is required` when either field is absent. String inputs are consumed as raw UTF-8 bytes; a mnemonic string is not converted into BIP-39 seed bytes. + +#### `deriveSeedKeyPair(seed, options)` + +Derive a deterministic Ed25519 keypair from the same seed, salt, and info inputs. The function always uses a 32-byte derived seed, even if `options.length` is supplied, and returns a 32-byte public key plus a 64-byte secret key laid out as the derived seed followed by the public key. + +```javascript title="Derive An Ed25519 Keypair" +import { deriveSeedKeyPair } from '@tetherto/wdk-utils' + +const keyPair = deriveSeedKeyPair(seedBytes, { + salt: 'com.example.wallet/v1', + info: 'device-signing' +}) +``` + + +Treat the returned `secretKey` as sensitive and clear it after its final use. The implementation clears its intermediate derived seed, but the returned secret key remains in caller-managed memory. + + ### BIP-21 Bitcoin Payment URI Helpers | Function | Description | Returns | diff --git a/content/docs/tools/wdk-utils/configuration.mdx b/content/docs/tools/wdk-utils/configuration.mdx index 3a115c60..2a6227a0 100644 --- a/content/docs/tools/wdk-utils/configuration.mdx +++ b/content/docs/tools/wdk-utils/configuration.mdx @@ -1,6 +1,6 @@ --- title: WDK Utils Configuration -description: Install and import validation, encryption, BIP-21, BOLT11, and EIP-681 helpers from @tetherto/wdk-utils +description: Install and import validation, encryption, key-derivation, and payment-request helpers from @tetherto/wdk-utils --- This package does not have constructor options or runtime configuration. This page shows how to install `@tetherto/wdk-utils`, import the helpers you need, and understand the published runtime surface. @@ -68,6 +68,17 @@ import { } from '@tetherto/wdk-utils' ``` +## Import seed key derivation helpers + +Derive domain-separated byte keys or deterministic Ed25519 keypairs from high-entropy seed bytes: + +```javascript title="Import Seed Key Derivation Helpers" +import { + deriveSeedKey, + deriveSeedKeyPair +} from '@tetherto/wdk-utils' +``` + ## Import BOLT11 helpers You can validate, decode, sign, and encode BOLT11 Lightning invoices from the package entrypoint: @@ -91,6 +102,9 @@ import { - `encrypt()` returns a versioned payload with hex-encoded `salt`, `iv`, `tag`, and `ciphertext` fields plus the scrypt cost parameters used for key derivation. - `decrypt()` reads the scrypt cost parameters from the encrypted payload when they are present. - `deriveKey()` returns a 32-byte `Uint8Array` key, and `decryptWithKey()` can reuse that key for decrypting a payload. +- `deriveSeedKey()` uses HKDF-SHA256 and defaults to a 32-byte output. Both `salt` and `info` are required and are chosen by the caller; the package provides no built-in domain labels. +- Pass high-entropy BIP-39 seed bytes to the seed key derivation helpers, not a mnemonic phrase. Accepted string inputs are consumed literally as UTF-8 and are not converted from mnemonic words into seed bytes. +- `deriveSeedKeyPair()` always derives a 32-byte Ed25519 seed and returns a 32-byte `publicKey` plus a sensitive 64-byte `secretKey`, regardless of an `options.length` value. - BIP-21 amounts are decimal BTC strings with up to eight decimal places and a maximum value of `21000000`. - BOLT11 helpers support invoices for `bitcoin`, `testnet`, `regtest`, and `signet` networks. - `decode()` returns user-provided invoice descriptions when they are present. Sanitize descriptions before rendering them in HTML or storing them. @@ -161,6 +175,26 @@ const encrypted = encrypt(seedPhrase, passphrase) const restoredSeedPhrase = decrypt(encrypted, passphrase) ``` +You can derive independent keys for application-specific purposes by using distinct domain labels: + +```javascript title="Derive Domain-Separated Keys" +import { deriveSeedKey, deriveSeedKeyPair } from '@tetherto/wdk-utils' + +const syncKey = deriveSeedKey(seedBytes, { + salt: 'com.example.wallet/v1', + info: 'sync-encryption' +}) + +const signingKeyPair = deriveSeedKeyPair(seedBytes, { + salt: 'com.example.wallet/v1', + info: 'device-signing' +}) + +// Clear sensitive outputs after their final use. +syncKey.fill(0) +signingKeyPair.secretKey.fill(0) +``` + *** ## Need Help? diff --git a/content/docs/tools/wdk-utils/index.mdx b/content/docs/tools/wdk-utils/index.mdx index 3bc2f552..44c57982 100644 --- a/content/docs/tools/wdk-utils/index.mdx +++ b/content/docs/tools/wdk-utils/index.mdx @@ -1,15 +1,16 @@ --- title: WDK Utils -description: Address validation, seed encryption, BIP-21, BOLT11 invoice, and EIP-681 request helpers for @tetherto/wdk-utils +description: Address validation, seed encryption, deterministic key derivation, and payment-request helpers for @tetherto/wdk-utils --- -WDK Utils provides validation helpers for Bitcoin, EVM, Lightning, Spark, Tron, and UMA identifiers, passphrase-based seed encryption helpers, BIP-21 Bitcoin payment URI helpers, BOLT11 invoice helpers, and EIP-681 request parsing helpers for token transfer deep links. Powered by [`@tetherto/wdk-utils`](https://github.com/tetherto/wdk-utils). +WDK Utils provides validation helpers for Bitcoin, EVM, Lightning, Spark, Tron, and UMA identifiers, passphrase-based seed encryption, deterministic HKDF-SHA256 and Ed25519 key derivation, BIP-21 Bitcoin payment URI helpers, BOLT11 invoice helpers, and EIP-681 request parsing for token transfer deep links. Powered by [`@tetherto/wdk-utils`](https://github.com/tetherto/wdk-utils). ## Features - **Address validation helpers**: Validate Bitcoin, EVM, Lightning invoice, LNURL, Lightning address, Spark, Tron, and UMA inputs before you hand them to a wallet flow. - **BIP-21 payment URI helpers**: Detect, parse, and encode `bitcoin:` payment URIs with optional amount, label, and message fields. - **Seed encryption helpers**: Encrypt and decrypt seed phrases or other strings with AES-256-GCM and scrypt-derived keys. +- **Seed key derivation**: Derive domain-separated byte keys or deterministic Ed25519 keypairs from high-entropy seed bytes. - **Lightning payment parsing**: Decode LNURL strings and BOLT11 invoices before you display or route payment details. - **BOLT11 invoice helpers**: Validate, decode, hash, sign, and encode BOLT11 invoices for Bitcoin, testnet, regtest, and signet flows. - **EIP-681 request parsing**: Detect request-shaped EIP-681 strings and parse transfer payloads into `recipient`, `tokenAddress`, `chainId`, and `amountSmallest`. @@ -21,6 +22,7 @@ WDK Utils provides validation helpers for Bitcoin, EVM, Lightning, Spark, Tron, - Validate user input early and return machine-readable failure reasons before you attempt a transaction or resolution flow. - Protect seed phrases or other local strings with passphrase-based encryption before storing them in app-managed persistence. +- Derive separate application keys from one high-entropy seed without reusing the same key material across purposes. - Parse and encode BIP-21 Bitcoin payment links before pre-filling send forms. - Inspect BOLT11 invoice metadata, fallback addresses, routing information, and feature bits before presenting payment details. - Normalize EIP-681 payment links into structured transfer data that wallet UIs can inspect before execution. diff --git a/content/docs/tools/worklet-bundler/api-reference.mdx b/content/docs/tools/worklet-bundler/api-reference.mdx index 68524dc4..70b45312 100644 --- a/content/docs/tools/worklet-bundler/api-reference.mdx +++ b/content/docs/tools/worklet-bundler/api-reference.mdx @@ -18,20 +18,42 @@ schemaType: APIReference ```typescript title="WdkBundleConfig Shape" interface WdkBundleConfig { networks: Record - protocols?: Record + protocols?: Record + modules?: Record preloadModules?: string[] + transport?: 'hrpc' | 'jsonrpc' output?: { bundle?: string types?: string + addons?: { + ios?: string + macos?: string + android?: string + } + addonsYml?: string } options?: { minify?: boolean sourceMaps?: boolean targets?: string[] + linkAddons?: boolean + platforms?: Array<'ios' | 'macos' | 'android'> + swiftTarget?: string + convertEsmToCjs?: boolean } } ``` +`modules` is generated only for HRPC in beta.5. JSON-RPC entry generation ignores that map. JSON-RPC otherwise defaults addon linking and ESM-to-CJS conversion to `true`; HRPC defaults both to `false`. + + +Beta.5 declares `output.types`, `options.minify`, and `options.sourceMaps`, but its bundle generator does not honor those fields. Declarations are always written to `./.wdk/index.d.ts`; `minify` and `sourceMaps` do not control `bare-pack` output. JSON-RPC ESM-to-CJS conversion minifies independently. + + #### `ResolvedConfig` `ResolvedConfig` extends `WdkBundleConfig` with absolute filesystem paths produced by `loadConfig()`. @@ -43,6 +65,12 @@ interface ResolvedConfig extends WdkBundleConfig { resolvedOutput: { bundle: string types: string + addons: { + ios: string + macos: string + android: string + } + addonsYml: string } } ``` @@ -119,7 +147,10 @@ Run the uninstall flow from code and receive a structured `UninstallResult`. | `loadConfig(configPath?)` | Load, validate, and resolve a `wdk.config.js` file into absolute paths. | `Promise\` | | `generateBundle(config, options?)` | Generate the entrypoint, imports, bundle, and optional type output. | `Promise\` | | `generateSourceFiles(config, options?)` | Generate the source entrypoint and related artifacts without bundling. | `Promise\<{ entryPath: string }\>` | -| `generateEntryPoint(config, outputDir)` | Generate only the Bare worklet entrypoint file. | `Promise\` | +| `generateEntryPoint(config, outputDir)` | Generate an HRPC Bare worklet entrypoint file. | `Promise\` | +| `generateJsonRpcEntryPoint(config, outputDir)` | Generate a JSON-RPC Bare worklet entrypoint file. | `Promise\` | +| `linkAddons(config, options?)` | Link native addons for selected platforms with `bare-link`. | `Promise\` | +| `generateAddonsYml(iosAddonsDir, swiftTarget, outputPath)` | Generate the BareKit Swift addon dependency file. | `void` | | `generateWalletModulesCode(config)` | Generate the wallet-module section inserted into the entrypoint. | `string` | #### `loadConfig(configPath?)` @@ -154,6 +185,8 @@ Use `generateBundle()` when you want the same bundle workflow that powers the CL - `error?` - `missingModule?` +In beta.5, `typesPath` can reflect a configured `output.types` path even though the declaration file is still written to `./.wdk/index.d.ts`. + ```typescript title="Generate A Bundle Programmatically" import { generateBundle, loadConfig } from '@tetherto/wdk-worklet-bundler' @@ -167,10 +200,24 @@ Use `generateSourceFiles()` when you want the generated entrypoint without the f #### `generateEntryPoint(config, outputDir)` -Use `generateEntryPoint()` when you need the exact generated Bare entrypoint string written to a chosen output directory. +Use `generateEntryPoint()` when you need the generated HRPC Bare entrypoint written to a chosen output directory. This path includes configured generic modules and their lifecycle/event wiring. In `beta.3`, the generated entrypoint suspends and resumes both the `bare-http1` and `bare-https` global agents when the Bare runtime emits `suspend` and `resume`. +#### `generateJsonRpcEntryPoint(config, outputDir)` + +Generate the framed JSON-RPC entrypoint used by native hosts. In beta.5 this path includes wallet and protocol managers but not generic `modules`. + +#### `linkAddons(config, options?)` + +Link required Bare addons for iOS, macOS, Android, or a selected subset. `LinkAddonsOptions` supports `platforms`, `verbose`, and `silent`. The result contains `success`, `duration`, `platforms`, and optional `error`. + +When iOS is selected, addon linking also calls `generateAddonsYml()` with `config.options.swiftTarget` or the default target name `app`. + +#### `generateAddonsYml(iosAddonsDir, swiftTarget, outputPath)` + +Generate the `addons.yml` dependency list expected by BareKit Swift from linked iOS XCFrameworks. + #### `generateWalletModulesCode(config)` Use `generateWalletModulesCode()` when you only need the generated wallet-module section for inspection or custom generator flows. @@ -181,13 +228,17 @@ The published CLI exposes these commands through `wdk-worklet-bundler`: | Command | Description | Key Options | | --- | --- | --- | -| `generate` | Generate a WDK bundle from configuration. | `--config`, `--install`, `--keep-artifacts`, `--dry-run`, `--no-types`, `--source-only`, `--skip-generation`, `--verbose` | +| `generate` | Generate a WDK bundle from configuration. | `--config`, `--install`, `--keep-artifacts`, `--dry-run`, `--no-types`, `--source-only`, `--skip-generation`, `--transport`, `--link-addons`, `--skip-link-addons`, `--platforms`, `--no-esm-to-cjs`, `--verbose` | | `init` | Create a new `wdk.config.js` file. | `--yes` | | `validate` | Validate configuration without building. | `--config` | | `list-modules` | List available WDK modules. | `--json` | | `clean` | Remove the generated `.wdk` folder. | `--yes` | -For the end-to-end config workflow, see the Worklet Bundler configuration guide when it is available. +For the end-to-end config workflow and transport defaults, see the [Worklet Bundler configuration guide](/tools/worklet-bundler/configuration). + + +Beta.5 applies `--transport` after `loadConfig()` resolves output paths. The flag changes entrypoint generation but does not recompute the default bundle filename. Set `transport` in `wdk.config.js`, or configure `output.bundle` explicitly when using the flag. + *** diff --git a/content/docs/tools/worklet-bundler/configuration.mdx b/content/docs/tools/worklet-bundler/configuration.mdx index afa044c4..0631a79f 100644 --- a/content/docs/tools/worklet-bundler/configuration.mdx +++ b/content/docs/tools/worklet-bundler/configuration.mdx @@ -3,16 +3,19 @@ title: Worklet Bundler Configuration description: Configure wdk.config.js and generate Bare worklet bundles with @tetherto/wdk-worklet-bundler --- -This page shows how to install `@tetherto/wdk-worklet-bundler`, shape `wdk.config.js`, and generate a Bare worklet bundle for your WDK modules. +This page shows how to install `@tetherto/wdk-worklet-bundler` and its Pear runtime, shape `wdk.config.js`, and generate a Bare worklet bundle for your WDK modules. -## Install the package +## Install the packages -Install the bundler as a development dependency in the host project: +Install the bundler as a development dependency and Pear Worklet as a runtime dependency in the host project: -```bash title="Install @tetherto/wdk-worklet-bundler" -npm install --save-dev @tetherto/wdk-worklet-bundler +```bash title="Install The Bundler And Runtime" +npm install @tetherto/pear-wrk-wdk@1.0.0-beta.9 +npm install --save-dev @tetherto/wdk-worklet-bundler@1.0.0-beta.5 ``` +Worklet Bundler beta.5 generates entrypoints that import Pear Worklet, but `generate --install` does not add that package. Beta.9 is also required for the generated JSON-RPC entrypoint and HRPC generic-module methods documented here. + ## Create `wdk.config.js` Use `init` to create a starter config, or write the file yourself: @@ -21,7 +24,7 @@ Use `init` to create a starter config, or write the file yourself: npx wdk-worklet-bundler init ``` -The published config surface accepts `networks`, optional `protocols`, optional `preloadModules`, optional `output`, and optional `options`: +The published config surface accepts `networks`, optional `protocols`, HRPC-only generic `modules`, `transport`, `preloadModules`, `output`, and `options`: ```javascript title="Example wdk.config.js" module.exports = { @@ -40,18 +43,25 @@ module.exports = { } }, + modules: { + preferences: { + package: '@your-org/wdk-module-preferences', + factory: 'createModule', + events: ['changed'] + } + }, + + transport: 'hrpc', + preloadModules: [ 'spark-frost-bare-addon' ], output: { - bundle: './.wdk-bundle/wdk-worklet.bundle.js', - types: './.wdk/index.d.ts' + bundle: './.wdk-bundle/wdk-worklet.bundle.js' }, options: { - minify: false, - sourceMaps: false, targets: ['ios-arm64', 'android-arm64'] } } @@ -81,21 +91,77 @@ module.exports = { Use `protocols` when the worklet should preload WDK protocol packages alongside wallet modules. +### `modules` (optional, HRPC only) + +Use `modules` for named generic packages that expose a module factory. Each entry supports: + +- `package` (`string`, required): Package name or local path. +- `factory` (`string`, optional): Named factory export. When omitted, the package's callable default export is used. +- `events` (`string[]`, optional): Event names forwarded from the worklet to the host. + +The factory receives `{ seed, config, capabilities, emit }` and can return the module instance or a promise for it. A module that needs the seed must consume it synchronously rather than retain it. The build-time name, such as `preferences`, must match the key in the host's runtime module config. + + +Beta.5 generic modules are included only in generated HRPC entrypoints. Do not configure `modules` with `transport: 'jsonrpc'`; the current schema accepts the field, but JSON-RPC generation ignores it. + + +### `transport` (optional) + +Choose `hrpc` or `jsonrpc`. HRPC is the default and is the transport used by React Native Core. JSON-RPC produces a length-prefixed bundle for a native host and enables addon linking and ESM-to-CJS conversion by default. + ### `preloadModules` (optional) Use `preloadModules` for native addons or other modules that must be required before the generated worklet starts. ### `output` (optional) -If you omit `output.bundle`, the loader resolves the bundle path to `./.wdk-bundle/wdk-worklet.bundle.js`. If you omit `output.types`, the loader resolves the type path to `./.wdk/index.d.ts`. +Supported output fields are: + +- `bundle`: Bundle path. Defaults to `./.wdk-bundle/wdk-worklet.bundle.js` for HRPC and `./.wdk-bundle/wdk-worklet.bundle` for JSON-RPC. +- `types`: Declared in the beta.5 config type, but the generator does not honor a custom value and always writes declarations to `./.wdk/index.d.ts`. +- `addons.ios`, `addons.macos`, `addons.android`: Platform addon directories. Defaults are `./ios-addons`, `./mac-addons`, and `./android-addons`. +- `addonsYml`: BareKit Swift dependency file. Defaults to `./ios-addons/addons.yml` and is generated when iOS addons are linked. ### `options` (optional) The published config type supports these build options: -- `minify` (`boolean`): Minify the generated bundle. -- `sourceMaps` (`boolean`): Request source map output. +- `minify` (`boolean`): Declared in the beta.5 config type but not read by the bundle path. JSON-RPC ESM-to-CJS conversion minifies independently of this field. +- `sourceMaps` (`boolean`): Declared in the beta.5 config type but not read by the bundle path, so it does not produce source maps. - `targets` (`string[]`): Override the default Bare build hosts. The shipped defaults cover iOS arm64 and simulator targets plus Android arm, arm64, ia32, and x64 hosts. +- `linkAddons` (`boolean`): Link native addons with `bare-link`. Defaults to `true` for JSON-RPC and `false` for HRPC. +- `platforms` (`('ios' | 'macos' | 'android')[]`): Addon platforms. Defaults to all three when addon linking is active. +- `swiftTarget` (`string`): Xcode target written to `addons.yml`. Defaults to `app`. +- `convertEsmToCjs` (`boolean`): Convert the bundle for JSC runtimes. Defaults to `true` for JSON-RPC and `false` for HRPC. Android uses V8, so Android-only JSON-RPC builds can set this to `false`. + +## Configure JSON-RPC and native addons + +Use JSON-RPC when a native host will implement Pear Worklet's length-prefixed JSON-RPC protocol: + +```javascript title="JSON-RPC wdk.config.js" +module.exports = { + networks: { + ethereum: { + package: '@tetherto/wdk-wallet-evm' + } + }, + transport: 'jsonrpc', + output: { + addons: { + ios: './ios-addons', + macos: './mac-addons', + android: './android-addons' + }, + addonsYml: './ios-addons/addons.yml' + }, + options: { + platforms: ['ios', 'android'], + swiftTarget: 'app' + } +} +``` + +JSON-RPC generation defaults to a bundle without a `.js` suffix, ESM-to-CJS conversion, and addon linking. It links `bare-posix` with the other required Bare modules automatically. See the [Pear Worklet API reference](/tools/pear-wrk-wdk/api-reference#json-rpc-transport) for framing and supported methods. ## Validate and generate the bundle @@ -111,13 +177,15 @@ Use `generate` to build the worklet artifact: npx wdk-worklet-bundler generate --install ``` -`generate --install` can auto-install missing configured modules after the package manager is detected from the project root. Use `--source-only` when you want the generated `.wdk/wdk-worklet.generated.js` entrypoint and related artifacts without running `bare-pack`. +`generate --install` can auto-install missing configured wallet, protocol, generic, and preload modules after the package manager is detected from the project root. In beta.5 it does not install the Pear Worklet runtime imported by generated entrypoints; install Pear explicitly as shown above. Use `--source-only` when you want the generated `.wdk/wdk-worklet.generated.js` entrypoint and related artifacts without running `bare-pack`. + +The `generate` command also accepts `--transport hrpc|jsonrpc`, `--link-addons`, `--skip-link-addons`, `--platforms ios,macos,android`, and `--no-esm-to-cjs`. Set `transport` in `wdk.config.js` when you rely on its transport-specific default bundle path. In beta.5, `--transport` changes the generated transport after output paths have already been resolved, so it does not switch `.js` HRPC output to the extensionless JSON-RPC default, or vice versa. If you use the flag, set `output.bundle` explicitly to the intended path. ## Suspend and resume behavior -Generated `beta.3` worklet entrypoints register Bare lifecycle handlers for `suspend` and `resume`, then apply those handlers to both the `bare-http1` and `bare-https` global agents. No config flag is required for this behavior. +Generated HRPC worklet entrypoints register Bare lifecycle handlers for `suspend` and `resume`, then apply those handlers to both the `bare-http1` and `bare-https` global agents. No config flag is required for this behavior. -This matters when a generated worklet performs HTTPS-backed fetches. In `beta.2`, only the `bare-http1` agent was suspended and resumed. In `beta.3`, generated worklets suspend and resume both agents together. +This matters when a generated HRPC worklet performs HTTPS-backed fetches. Starting in beta.3, those generated entrypoints suspend and resume both agents together. ## Troubleshooting diff --git a/content/docs/tools/worklet-bundler/index.mdx b/content/docs/tools/worklet-bundler/index.mdx index 084863a1..af15abf2 100644 --- a/content/docs/tools/worklet-bundler/index.mdx +++ b/content/docs/tools/worklet-bundler/index.mdx @@ -3,21 +3,31 @@ title: Worklet Bundler description: CLI tool for generating WDK Bare worklet bundles --- -Worklet Bundler packages selected WDK wallet and protocol modules into a Bare runtime bundle that runs outside your main React Native application thread. Powered by [`@tetherto/wdk-worklet-bundler`](https://github.com/tetherto/wdk-worklet-bundler). +Worklet Bundler packages selected WDK wallet, protocol, and optional generic modules into a Bare runtime bundle that runs outside the host application thread. It can generate the default HRPC worklet used by React Native Core or a framed JSON-RPC bundle for a native host. Powered by [`@tetherto/wdk-worklet-bundler`](https://github.com/tetherto/wdk-worklet-bundler). ## Features -- **Config-driven bundle generation**: Map logical network names to wallet packages and optional protocol names to protocol packages in `wdk.config.js`. -- **Generated worklet artifact**: Produce a bundle for the Bare runtime plus generated TypeScript types for the host app. +- **Config-driven bundle generation**: Map logical network names to wallet packages, protocol names to protocol packages, and HRPC-only generic-module names to package factories. +- **HRPC and JSON-RPC transports**: Generate an HRPC JavaScript bundle by default or a length-prefixed JSON-RPC bundle for native hosts. +- **Generated worklet artifacts**: Produce a Bare bundle, a stable `./.wdk` host import, and generated TypeScript types. +- **Native addon outputs**: Link iOS, macOS, and Android addons and generate `addons.yml` for JSON-RPC/native integrations. - **Dependency validation helpers**: Validate configured modules, detect the active package manager, and generate install or uninstall commands when dependencies are missing. - **CLI workflow**: Use `init`, `validate`, `generate`, `list-modules`, and `clean` without building your own wrapper. -- **Bare suspend and resume handling**: `beta.3` generated entrypoints suspend and resume both the `bare-http1` and `bare-https` global agents when the Bare thread lifecycle changes. +- **Bare suspend and resume handling**: Generated HRPC entrypoints suspend and resume both the `bare-http1` and `bare-https` global agents when the Bare thread lifecycle changes. + + +`v1.0.0-beta.5` is the first published artifact that contains the built CLI and API files for the JSON-RPC, generic-module, and addon-linking surface introduced in beta.4. It also links `bare-posix` automatically for supported native platforms. + ## Why this matters - Bundle generation keeps wallet and protocol code in a separate Bare worklet instead of the UI thread. - The generated type output gives the host app a stable import for the bundle surface. -- The `beta.3` runtime fix reduces the chance that HTTPS-backed worklet fetches keep running after a Bare thread suspension. +- Transport-specific defaults produce a JavaScript HRPC bundle for React Native Core or native addon artifacts for JSON-RPC hosts. + + +Generic `modules` are generated only for HRPC in beta.5. A JSON-RPC config can currently accept a `modules` field but silently omits those modules from the generated entrypoint. + diff --git a/skills/wdk/references/wallet-ton.md b/skills/wdk/references/wallet-ton.md index ec180e7a..a620389a 100644 --- a/skills/wdk/references/wallet-ton.md +++ b/skills/wdk/references/wallet-ton.md @@ -6,10 +6,10 @@ |----------|-----| | **npm** | https://www.npmjs.com/package/@tetherto/wdk-wallet-ton | | **GitHub** | https://github.com/tetherto/wdk-wallet-ton | -| **Docs — Overview** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton | -| **Docs — Usage** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton/usage | -| **Docs — Configuration** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton/configuration | -| **Docs — API Reference** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton/api-reference | +| **Docs — Overview** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton | +| **Docs — Usage** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/usage | +| **Docs — Configuration** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/configuration | +| **Docs — API Reference** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton/api-reference | ## Links — wallet-ton-gasless @@ -17,10 +17,10 @@ |----------|-----| | **npm** | https://www.npmjs.com/package/@tetherto/wdk-wallet-ton-gasless | | **GitHub** | https://github.com/tetherto/wdk-wallet-ton-gasless | -| **Docs — Overview** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton-gasless | -| **Docs — Usage** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton-gasless/usage | -| **Docs — Configuration** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton-gasless/configuration | -| **Docs — API Reference** | https://docs.wallet.tether.io/sdk/wallet-modules/wallet-ton-gasless/api-reference | +| **Docs — Overview** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless | +| **Docs — Usage** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless/usage | +| **Docs — Configuration** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless/configuration | +| **Docs — API Reference** | https://docs.wdk.tether.io/sdk/wallet-modules/wallet-ton-gasless/api-reference | ## Packages @@ -36,13 +36,13 @@ import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless' ## Key Details — wallet-ton -- **Derivation**: BIP-44 (`m/44'/607'/0'/0/{index}`) +- **Derivation**: BIP-44 (`m/44'/607'/{index}'` in v1.0.0-beta.6+) - **Key type**: Ed25519 - **Wallet contract**: V5R1 - **Fee unit**: nanotons (1 TON = 1,000,000,000 nanotons) - **Token standard**: Jettons via `transfer()` - **USDT Jetton master**: `EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs` -- `sendTransaction` accepts a `payload` field for arbitrary contract calls — treat with caution. +- `sendTransaction` accepts a `body` field for arbitrary contract calls — treat with caution. > **Derivation path change in v1.0.0-beta.6+**: Previous default was `m/44'/607'/0'/0/{index}`, updated to match ecosystem conventions. Existing wallets created with old path will generate different addresses. Use `getAccountByPath` for legacy wallet recovery. @@ -51,7 +51,7 @@ import WalletManagerTonGasless from '@tetherto/wdk-wallet-ton-gasless' ```javascript const wallet = new WalletManagerTon(seedPhrase, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' // Optional but recommended for production }, transferMaxFee: 1000000000n // Optional: max fee in nanotons @@ -60,22 +60,22 @@ const wallet = new WalletManagerTon(seedPhrase, { ## Key Details — wallet-ton-gasless -- Same derivation and key type as wallet-ton -- **Gasless**: Paymaster covers transaction fees; user pays in Jettons -- Requires `tonApiClient` and `paymasterToken` config -- **Jetton-to-Jetton only**: `sendTransaction()` **throws** — use `transfer()` only -- Fee is typically 0 or covered by paymaster +- Same default derivation and key type as wallet-ton in gasless v1.0.0-beta.5+ +- **Gasless Jetton transfers**: fees are paid in a supported paymaster Jetton instead of native TON +- Requires a `tonApiClient` base URL and `paymasterToken.address` configuration +- **Jetton transfers only**: `sendTransaction()`, `quoteSendTransaction()`, and `signTransaction()` are unsupported — use `transfer()` and `quoteTransfer()` +- Transfer fees are returned in paymaster Jetton base units. The account pays them from its configured paymaster Jetton balance; if that Jetton is also being transferred, the same balance must cover both the transfer amount and the final fee. ## Configuration — wallet-ton-gasless ```javascript const wallet = new WalletManagerTonGasless(seedPhrase, { tonClient: { - url: 'https://toncenter.com/api/v3', + url: 'https://toncenter.com/api/v2/jsonRPC', secretKey: 'your-api-key' }, tonApiClient: { - url: 'https://tonapi.io/v3', + url: 'https://tonapi.io', secretKey: 'your-ton-api-key' }, paymasterToken: {