Skip to content

Deposits and Funding

View as Markdown
NeedPathWhat you receive
Native transaction feesNative faucet commandsNative THRU, not THRUSD
Add funds through the hosted walletThe wallet’s deposit provider flowTHRUSD in the prepared token account
Test THRUSDRestricted staging faucet, when access is providedTest tokens for an allowed mint and network, in an existing token account

A public, self-service Alphanet THRUSD faucet has not been verified for this guide. Ask your environment operator for the supported test-funding route. Do not assume Add funds is a free test faucet: the provider flow can involve an actual payment. THRUSD does not replace native THRU for fees.

The published 0.3.16 source still defaults some display symbols to CREDITS; the repository source normalizes those legacy symbols to THRUSD. The deposit methods used below exist in both. Read mint metadata from the prepared destination instead of hardcoding it.

This example was checked against published @thru/wallet@0.3.16 on September 18, 2026. Install that package; @thru/wallet/react is its React import path.

Terminal window
npm install @thru/wallet@0.3.16

Use a client component in Next.js. Configure both the RPC and the deposit network:

import type { ReactNode } from "react";
import { ThruNetwork } from "@thru/wallet";
import { ThruProvider } from "@thru/wallet/react";
export function WalletProvider({ children }: { children: ReactNode }) {
return (
<ThruProvider config={{
iframeUrl: "https://app.tid.sh/embedded",
rpcUrl: "https://rpc.alphanet.thru.org",
network: ThruNetwork.Alphanet,
}}>
{children}
</ThruProvider>
);
}

The RPC and network must identify the same chain. rpcUrl alone does not select a deposit network. The hosted wallet must also have a deposit target and provider configured for that network; the dApp cannot supply that configuration by changing its RPC.

Use https://app.tid.sh/embedded for embedding. wallet.tid.sh is a standalone link and blocks framing, even though the SDK trusts its origin.

Connect first using Embedded Wallet Integration. Obtain deposits from useWallet() or BrowserSDK.deposits, then call this helper from your Add funds handler:

import { DepositTarget, type DepositsApi } from "@thru/wallet";
// Call with useWallet().deposits after connecting. Disable repeat clicks
// while this promise is pending. Prepare again after changing wallet/network.
export async function addFunds(deposits: DepositsApi) {
const destination = await deposits.prepare(DepositTarget.THRUSD);
const before = await deposits.ensureAccount({ destination });
const result = await deposits.open({ destination });
if (result.status === "cancelled") {
return { status: "cancelled" as const };
}
try {
const balance = await deposits.waitForDeposit({
destination,
minimumBalanceRaw: before.balanceRaw + 1n,
signature: result.signature,
});
return { status: "credited" as const, balance };
} catch (error) {
// A timeout or RPC error does not prove the payment failed.
// Retain destination for a later getAccountState({ destination }) call.
return { status: "unverified" as const, destination, signature: result.signature, error };
}
}
  • prepare(DepositTarget.THRUSD) resolves the destination and mint metadata inside the wallet. Do not construct or alter the destination yourself. The enum retains the legacy wire value credits.
  • ensureAccount({ destination }) creates a missing token account or validates an existing one, then returns its balance. A new account may require wallet approval and setup fees; an existing account is reused.
  • open({ destination }) opens the provider flow. In this SDK release its result is completed, cancelled, or pending. A pending payment may still be credited asynchronously; do not ask the user to pay again.
  • waitForDeposit() observes the prepared account’s on-chain balance. The example’s one-base-unit increase detects a balance change, not a specific payment’s exact amount or identity. Use a known expected amount when your application needs amount reconciliation.
  • getAccountState({ destination }) refreshes the same account after a wait error or page refresh. Persist the baseline and destination for recovery, and revalidate them with prepare() for the same wallet and network before reuse. Display balanceLabel or use formatAmount(balanceRaw, destination).

Handle errors thrown by prepare, ensureAccount, and open in your UI, including rejected account-setup approval. Always clear the busy state in finally. A rejected request has no success result; an error after payment may require reconciliation. Do not automatically reopen the payment flow.

Closing the wallet UI is not proof that funds arrived. The credited result above follows an observed balance increase. For unverified, show that the balance could not be verified, retain any payment signature, and offer a balance refresh. After changing wallet or network, prepare a new destination instead of reusing the old one.

Deposit network is not configured originates in the hosted wallet when no supported deposit network reaches it. Check config.network first. A selected network with an unavailable target or provider is a separate hosted-wallet configuration problem; ask the wallet operator to verify support. Keep provider secrets and mint credentials out of the frontend.

See Wallet Troubleshooting for iframe and configuration checks.