Documentation

Getting started

Everything you need to add a self-custodial Trilema wallet to your product — from install to first sponsored transaction.

What is Trilema?

The Trilema SDK is a TypeScript library for identity-first smart accounts on EVM chains: passkey-authenticated, programmable, and extensible through delegated permissions.

Smart accounts are controlled by a contract rather than a raw private key, which is what makes the following possible:

  • Sponsored gas — people transact without holding a native token.
  • Batched actions — approve and swap settle in a single user operation.
  • Programmable permissions — grant scoped, revocable access to a third party.

Passkeys replace seed phrases with device biometrics — Face ID, a fingerprint, or a device PIN. Nothing to write down, phishing-resistant by construction, and synced across a person's devices by the platform keychain.

Installation

bash
npm install @trilema/wagmi wagmi @tanstack/react-query

Quick start

1. Configure the connector

ts
// config.ts
import { createConfig, http } from "wagmi";
import { base, baseSepolia } from "wagmi/chains";
import { trilema } from "@trilema/wagmi";

export const config = createConfig({
  chains: [base, baseSepolia],
  connectors: [
    trilema({
      apiKey: process.env.TRILEMA_API_KEY!,
      appName: "My app",
      appLogoUrl: "https://my-app.com/logo.png",
      sponsorGas: true,
    }),
  ],
  transports: {
    [base.id]: http(),
    [baseSepolia.id]: http(),
  },
});

2. Wrap your app in providers

tsx
// providers.tsx
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { config } from "./config";

const queryClient = new QueryClient();

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    </WagmiProvider>
  );
}

3. Connect and transact

tsx
import { useAccount, useSendTransaction } from "wagmi";
import { useConnect, useDisconnect } from "@trilema/wagmi";
import { parseUnits } from "viem";
import { config } from "./config";

export function WalletButton() {
  const { address, isConnected } = useAccount();
  const { mutate: connect, isPending } = useConnect();
  const { mutate: disconnect } = useDisconnect();
  const { sendTransaction } = useSendTransaction();

  if (!isConnected) {
    return (
      <button onClick={() => connect({ connector: config.connectors[0] })}>
        {isPending ? "Waiting for passkey…" : "Create wallet"}
      </button>
    );
  }

  return (
    <>
      <p>Signed in as {address}</p>
      <button
        onClick={() =>
          sendTransaction({ to: "0x…", value: parseUnits("5", 6) })
        }
      >
        Send 5 USDC
      </button>
      <button onClick={() => disconnect({})}>Sign out</button>
    </>
  );
}

The first click opens a passkey prompt. Trilema creates the smart account, reserves a readable name for it, and returns a signed-in session — no extension, no seed phrase.

Using the provider directly

For non-React apps, servers, or advanced flows, work against the EIP-1193 provider instead of the hooks.

ts
import { Trilema } from "@trilema/core";

const trilema = Trilema.create({
  apiKey: process.env.TRILEMA_API_KEY!,
  appName: "My app",
});

// EIP-1193 compatible provider
const accounts = await trilema.provider.request({
  method: "wallet_connect",
});

The same object exposes the permissions API used by the delegation flow in the interactive demo:

ts
// Grant an agent a scoped, revocable spending permission
const permission = await trilema.permissions.grant({
  spender: agentAddress,
  token: "USDC",
  limit: { amount: "50", period: "day" },
  expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
});

await trilema.permissions.revoke(permission.id);

Supported networks

NetworkChain IDStatus
Base8453Production
Base Sepolia84532Testnet
Optimism10Production
Arbitrum One42161Production
Ethereum1Beta

Next steps