Skip to main content
Get your API key at hackathon-apikey.vercel.app.
Disposable EOAs for temporary DeFi interactions without exposing your main account. Lifecycle: create, fund from contract, interact with DeFi, deposit back, dispose. If you are deciding between BurnerWallet and execute(), start with DeFi.

Create a burner

import { BurnerWallet } from "@unlink-xyz/sdk";

const burner = await BurnerWallet.create();
// burner.address - the ephemeral EOA address
Pass a custom BurnerStorage implementation for persistence (default is in-memory):
const burner = await BurnerWallet.create(myStorage);

Restore a burner

const burner = await BurnerWallet.restore("0xBurnerAddress", myStorage);
// Returns null if not found in storage

Use with viem

const viemAccount = burner.toViemAccount();
// Use viemAccount with a WalletClient for DeFi interactions
Withdraw tokens from the unlink contract to fund the burner. Burner operations require a low-level Client from createUnlinkClient (separate from the high-level createUnlink client) and account keys derived from the same mnemonic.
import { createUnlinkClient, unlinkAccount } from "@unlink-xyz/sdk";

const client = createUnlinkClient(engineUrl, apiKey);

// Derive account keys from the same mnemonic used with createUnlink()
const account = unlinkAccount.fromMnemonic({ mnemonic });
const accountKeys = await account.getAccountKeys();

const result = await burner.fundFromPool(client, {
  senderKeys: accountKeys,
  token: "0xTokenAddress",
  amount: "1000000000000000000",
  environment: "base-sepolia",
});
This call prepares the withdrawal, signs it with the sender’s EdDSA key, and submits it. After the withdrawal confirms, the relayer funds the burner with ETH for gas.

Fetch burner config

Before depositing back, fetch the chain config the SDK needs:
const info = await BurnerWallet.getInfo(client);

console.log(info.pool_address);
console.log(info.permit2_address);
console.log(info.chain_id);
console.log(info.gas_funding_wei);
gas_funding_wei is the ETH amount the relayer sends to the burner after the funding withdrawal confirms, so the burner can pay gas for follow-up transactions.

Approve Permit2 from the burner

Before calling depositToPool(), the burner must approve Permit2 for the token it will deposit back. Using viem, that looks like:
import { createWalletClient, erc20Abi, http } from "viem";
import { baseSepolia } from "viem/chains";

const info = await BurnerWallet.getInfo(client);

const burnerWalletClient = createWalletClient({
  account: burner.toViemAccount(),
  chain: baseSepolia,
  transport: http(process.env.RPC_URL),
});

await burnerWalletClient.writeContract({
  address: "0xTokenAddress",
  abi: erc20Abi,
  functionName: "approve",
  args: [info.permit2_address, 1000000000000000000n],
});

Deposit back to contract

After your DeFi interactions, deposit tokens back into the unlink contract:
const info = await BurnerWallet.getInfo(client);

const result = await burner.depositToPool(client, {
  unlinkAddress: "unlink1...",
  token: "0xTokenAddress",
  amount: "1000000000000000000",
  environment: "base-sepolia",
  chainId: info.chain_id,
  permit2Address: info.permit2_address,
  poolAddress: info.pool_address,
  deadline: Math.floor(Date.now() / 1000) + 3600,
});
If you already manage Permit2 nonces elsewhere in your app, you can also pass nonce or a shared nonceManager.

Check status and dispose

const status = await burner.getStatus(client);

await burner.dispose(client, result.txId);
await burner.deleteKey(); // Remove private key from storage
Burner statuses are:
  • pending - burner created, not yet funded
  • gas_pending - withdrawal confirmed, waiting for relayer to send ETH for gas
  • funded - ready to use
  • disposed - lifecycle complete
  • gas_funding_failed - relayer failed to send gas; retry by calling fundFromPool again