Create a wallet
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.
Prerequisites
- Node.js 20 or later.
Option 1: ethers.js
Install the library and generate a key pair.
npm install ethers// wallet.ts
import { 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.tsAddress: 0xAlice...1234
Seed phrase: liberty shoot ... (12 words)Option 2: Tether WDK
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.
npm install @tetherto/wdk @tetherto/wdk-wallet-evm// wallet-wdk.ts
import 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.tsAddress: 0xAlice...1234
Seed phrase: liberty shoot ... (12 words)Fund the wallet
Before the wallet can transact, it needs USDT0 for gas. On testnet, request from the faucet:
open https://faucet.stable.xyzPaste 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.
Check the balance
Native USDT0 uses 18 decimals. The native balance is the one gas is paid from.
// balance.ts
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://rpc.testnet.stable.xyz");
const balance = await provider.getBalance("0xYourAddress");
console.log("Balance:", ethers.formatEther(balance), "USDT0");npx tsx balance.tsBalance: 1.0 USDT0Next recommended
- Delegate with EIP-7702 — Add batch payments, spending limits, and session keys to this wallet.
- Send your first USDT0 — Native and ERC-20 transfers on the same balance.
- Fund a testnet wallet — Faucet and Sepolia bridge options for larger test balances.

