Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/covenant-gov/pacto-app/llms.txt

Use this file to discover all available pages before exploring further.

Pacto ships with a fully embedded EVM wallet that requires no separate setup or configuration. Every EVM account is derived from the same BIP-39 mnemonic that backs your Nostr identity, so a single recovery phrase gives you both your Nostr keypair and your on-chain accounts. Private keys never leave the Rust backend and are decrypted only for approved signing operations.

Key types

Pacto distinguishes two EVM account purposes. The rules are enforced at the backend — squad paths reject advanced signers, and advanced paths reject squad signers.
Key typePurpose tagUsed for
Squad keysquadDM WalletBar sends, treasury deploy, governance commands, roster shares. Only squad-purpose keys may be the active signer or a profile receiving address.
Advanced keyadvancedSettings → Advanced panel only (WalletAdvancedPanel.svelte). Backend command evm_send_advanced_contract_call refuses squad signers; squad paths refuse advanced addresses.
Squad and advanced key paths are mutually exclusive by design. Squad keys cannot call advanced contract paths, and advanced keys cannot sign squad transactions or governance commands. This separation is enforced in the Rust backend (Phase G).

Read vs. write architecture

Pacto keeps a clean separation between on-chain reads (frontend) and signed writes (backend):

Read-plane (frontend — viem)

All read-only chain access — balances, ERC-20 contract reads, Safe state reads, and receipt polling — runs through the TypeScript viem layer in src/lib/evm/read-plane.ts. No private key is present in the frontend. The read-plane builds viem public clients from the resolved RPC URLs for the active chain, using createPublicClient with a fallback transport.

Rust send (backend — Alloy)

WalletBar sends, treasury deploys, and all governance writes are handled entirely in the Rust backend using Alloy. The EVM private key is decrypted inside Rust only for the duration of the signing operation. This approach avoids shipping or spawning a JavaScript runtime for signing and keeps the private key lifecycle entirely in the Tauri process.
ConcernLayerMechanism
RPC URL selection (UI reads)FrontendALCHEMY_RPC_KEY + user prefs + getEffectiveRpcUrlsForChain
RPC URL selection (backend sends)BackendSame ALCHEMY_RPC_KEY via wallet_rpc_providers.rs + curated fallbacks
Read-only JSON-RPCFrontendviem createPublicClient + fallback via src/lib/evm/read-plane.ts
WalletBar send / raw txBackendRust (Alloy): encode, sign, eth_sendRawTransaction
Advanced opaque contract callBackendevm_send_advanced_contract_call — advanced-purpose signer only
Squad curated deploy / gov writesBackendTyped Alloy commands + squad-purpose gate

WalletBar

The WalletBar is the in-thread wallet UI that appears inside DM conversations. From the WalletBar you can:
  • Send tokens — ETH, USDC, or USDT to the peer’s EVM address.
  • Request payment — post a wallet_tx_request card into the thread; the recipient can accept and pre-fill the send form.
  • Announce transactions — after broadcast, an optimistic wallet_tx_announcement card appears immediately, then updates to confirmed once the receipt arrives.
For DM sends, the peer’s EVM address is resolved as dm_peer_evm first, then profiles.evm_address. A raw 0x address from Settings bypasses npub resolution entirely.

Balance cache

The last successful get_wallet_summary response is stored per account under the localStorage key:
pacto_wallet_summary_cache_v1_<npub>
The cached value includes a fingerprint of the watched-token list. On login, loadAccountState in src/stores/persistence.ts reads the cache (via src/lib/wallet/wallet-summary-cache.ts) so the WalletBar shows data immediately while a background refresh runs. The key is cleared with all other npub-scoped storage on logout via clearAccountState.

USD spot pricing

Wallet balances are displayed with live USD values sourced from Chainlink on-chain price feeds on Ethereum mainnet. The backend calls latestRoundData() on the standard aggregator proxies for ETH/USD, USDC/USD, and USDT/USD, then caches results for 90 seconds to limit RPC load. There are no static price fallbacks — if the oracle read fails, the UI shows that live pricing is unavailable. The Tauri command is wallet_get_usd_spot_prices; the TypeScript helper is getWalletUsdSpotPrices() in src/lib/wallet/pricing.ts.

Squad allowlisted contract calls

Beyond the standard native and ERC-20 transfer paths, squad keys can call explicitly allowlisted contract targets via evm_send_squad_allowlisted_contract_call. The allowlist is managed in Dashboard → Settings → Smart contract security. Implicit deploy-infra targets are always permitted.

Learn more

Key Derivation

BIP-44 path, address hash rule, legacy history, and the reference test vector.

Transactions

Broadcast-then-release UX, background receipt polling, and optimistic DM wallet cards.

Governance

pacto-gov, Gnosis Safe treasury, Hats Protocol roles, and squad infra deployment.

Chain Config

Supported networks, RPC URL resolution, viem read/write split, and USD pricing.

Build docs developers (and LLMs) love