Mental model
Three things sit at the core of every Tally wallet:- The wallet — an Ethereum-compatible address that holds USDC.
- Signers — keys that can move funds out of the wallet. There are two kinds, covered below.
- Policies — rules that bound what each signer can do. Enforced inside Privy’s secure enclave, not by Tally’s server.
Server wallets, not browser-embedded wallets
Tally uses Privy server wallets as the underlying primitive. A server wallet lives in Privy’s infrastructure (a secure enclave with hardware-backed key isolation), not in a browser. This is a different model from “embedded wallets” — browser-side wallets where keys are held client-side. Both keep custody with the wallet owner (not Tally), but server wallets give you two properties that matter for agentic finance:- Agents can act asynchronously. You don’t need an active browser session for an agent to sign a transaction. The signer Tally holds is a separate, scoped key — not your primary key.
- No browser-side secrets to leak. Your authentication (passkey, email-OTP) only authorizes Privy to act on your behalf; no signing material ever leaves the enclave.
Anatomy of a wallet
Every wallet has:| Field | Description |
|---|---|
address | Ethereum-compatible address. Public; safe to share. |
displayName | Human-readable label. Defaults to Main Wallet for the first wallet. |
mode | test (Base Sepolia) or live (Base mainnet). Fixed at creation. |
accountId | The Tally account that owns the wallet. |
roleLabel | Optional free-text label like “operations” or “ad spend”. |
Provisioning
Your first wallet is created automatically. When you sign in for the first time, Tally provisions an account, makes you the owner, and creates a single test-mode wallet called Main Wallet on Base Sepolia. No extra steps; the wallet is ready to receive USDC the moment you land on the dashboard. Additional wallets can be created from the dashboard or programmatically via the SDK:owner-role member of the account, so any future signer changes go through the same passkey as dashboard-created wallets.
Test vs live wallets are separate. A wallet’s mode is fixed at creation, and live-mode wallets live on Base mainnet with a separate Privy app config. Moving an account to live mode provisions fresh live wallets — it does not “promote” the test wallet.
Two kinds of signers
A signer is anything that can authorize a transaction leaving the wallet. Tally wallets have two:Owner signer (you)
You’re the wallet’s owner. Your authentication with Privy — passkey, email, or whatever method’s configured — is what gives you owner-level rights. You can:- Add or remove agent signers
- Approve or revoke policies
- Sign transactions directly (rare; mostly relevant when withdrawing funds)
Agent signer (Tally, bounded by policy)
When you grant an agent permission to spend from a wallet, the following happens, in order:- Tally generates a fresh P-256 keypair specifically for that (agent, wallet) pair.
- The private key is envelope-encrypted via AWS KMS and stored. It never leaves Tally’s infrastructure unencrypted, and Tally only decrypts it transiently — just long enough to sign a single payment request, then drops it from memory.
- The public key is registered with Privy as an additional signer on the wallet.
- A policy (see below) is created and attached to that signer.
- You sign the addition with your passkey from the dashboard. Until you do, the signer is registered but inactive.
What a policy enforces
Every agent signer has exactly one policy attached. The policy is signed during the permission flow and bounds what the signer can do. Today’s policy supports:| Field | What it bounds |
|---|---|
maxPerTxUsdc | Required. The largest single transfer this signer can make. |
dailyCapUsdc | Optional. Tally-enforced rolling 24-hour cap, on top of the enclave rules. |
recipientAllowlist | Optional. If set, transfers can only go to addresses on this list. |
contractAllowlist | Defaults to USDC. The set of contracts the signer is allowed to interact with. |
expiresAt | Optional. After this time, the signer stops working until rotated or extended. |
Gas, sponsorship, and what you’ll see on basescan
Agent payments are gas-sponsored by default — your wallet doesn’t need an ETH balance to send USDC. On-chain, this is implemented through Privy’s account-abstraction infrastructure (EIP-7702 delegation + ERC-4337 UserOperations). Two practical consequences for you:- Fund USDC only. No ETH required for sponsored sends. The Fund button targets USDC and Privy’s paymaster covers the gas.
- Basescan’s “From” looks unfamiliar. When you open a sponsored payment on basescan, the top-line
Fromfield shows a bundler EOA (operated by Privy), not your wallet. The actual sender of USDC is your wallet — visible in the “Tokens Transferred” / “ERC-20 Token Txns” section of the same tx page. The Tally dashboard reads the token-transfer logs directly, so it always attributes the payment to the correct wallet.
basescan.org/address/<your-wallet>) → Token Transfers tab. That always shows USDC flow in/out of your wallet, regardless of how the tx was submitted.
What this gets you
The wallet + signer + policy model lines up cleanly with the trust story:- Tally never custodies funds. We only hold per-agent signing keys, each bounded by a policy you approved.
- You can revoke any agent at any time from the dashboard. Revocation removes the signer from the wallet on-chain.
- If Tally goes away, your wallet persists. You keep control through Privy directly. Permissions stay in force or revocable — no Tally action required.
- Even a compromised Tally can’t drain your wallet. An attacker with full access to Tally’s infrastructure could sign payments — but only ones your policy already authorizes (capped per-tx, capped daily, contract-restricted, optionally recipient-restricted).
Working with wallets from your code
Wallets are accessible from the SDK two ways. To list every wallet in the account + mode:agent.wallets[] is set on every tally.agents.upsert/list/get() result and contains only the wallets the agent has active permissions on.
What’s on the roadmap
- First-class smart wallets (Kernel / Safe). Privy already uses EIP-7702 + ERC-4337 under the hood to enable gas sponsorship (see “Gas, sponsorship, and what you’ll see on basescan” above), but exposing first-class smart-wallet primitives — batched transactions, session keys, advanced paymaster policies — would unlock UX patterns that aren’t currently possible. The owner / signer / policy model carries forward unchanged; only the wallet identity shifts. No timeline yet.
- Multi-signer policies (N-of-M co-signing for high-value wallets). The Privy primitives are there; the policy schema and grant UI aren’t.