Generate a new Stable wallet or restore one from a seed phrase using ethers.js or the Tether WDK.
A Stable wallet is an Ethereum-standard key pair. Any wallet library that produces an EVM account works on Stable without modification. This guide shows two paths: ethers.js for most applications, and Tether’s WDK (Wallet Development Kit) for integrations that want a turnkey self-custody layer for agents and payments.
No registration, no Stable-specific account setup. A wallet can immediately receive USDT0 from the testnet faucet or a mainnet transfer.
// wallet.tsimport { ethers } from "ethers";const provider = new ethers.JsonRpcProvider("https://rpc.testnet.stable.xyz");/** Create a new wallet for a new user. */export function createWallet() { const wallet = ethers.Wallet.createRandom(provider); return { wallet, address: wallet.address, seedPhrase: wallet.mnemonic!.phrase, // show to the user once for backup };}/** Restore a wallet from a seed phrase (returning user). */export function restoreWallet(seedPhrase: string) { const wallet = ethers.Wallet.fromPhrase(seedPhrase, provider); return { wallet, address: wallet.address };}if (import.meta.url === `file://${process.argv[1]}`) { const { address, seedPhrase } = createWallet(); console.log("Address: ", address); console.log("Seed phrase:", seedPhrase);}
npx tsx wallet.ts
Address: 0xAlice...1234Seed phrase: liberty shoot ... (12 words)
Never log or store the seed phrase in plain text in production. Encrypt it at rest, or use a secrets manager. ethers.Wallet.createRandom returns the phrase once per call — if you lose it, funds are unrecoverable.
The WDK wraps key derivation, signing, and transaction submission into a single interface. It’s the right choice when you want self-custody without re-implementing common account flows, and it integrates directly with x402 for agent payments.
// wallet-wdk.tsimport WDK from "@tetherto/wdk";import WalletManagerEvm from "@tetherto/wdk-wallet-evm";function initWdk(seedPhrase: string) { return new WDK(seedPhrase) .registerWallet("stable", WalletManagerEvm, { provider: "https://rpc.testnet.stable.xyz", });}/** Create a new wallet for a new user. */export async function createWallet() { const seedPhrase = WDK.getRandomSeedPhrase(); const wdk = initWdk(seedPhrase); const account = await wdk.getAccount("stable", 0); return { account, address: await account.getAddress(), seedPhrase, // show to the user once for backup };}/** Restore a wallet from a seed phrase (returning user). */export async function restoreWallet(seedPhrase: string) { const wdk = initWdk(seedPhrase); const account = await wdk.getAccount("stable", 0); return { account, address: await account.getAddress() };}
npx tsx wallet-wdk.ts
Address: 0xAlice...1234Seed phrase: liberty shoot ... (12 words)
Before the wallet can transact, it needs USDT0 for gas. On testnet, request from the faucet:
open https://faucet.stable.xyz
Paste the address and select the button to receive 1 testnet USDT0 (enough for thousands of native transfers). For mainnet, send USDT0 from any supported exchange or bridge; see Bridging to Stable.