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 uses a single canonical source for all chain and asset configuration: src/lib/wallet/wallet-assets.json. Both the TypeScript frontend and the Rust backend embed this file so token addresses, explorer URLs, and network metadata are never duplicated or allowed to drift between layers. RPC URL resolution follows a deterministic priority order — operator key first, user preferences second, public defaults last.

Supported networks

Network keyChainAlchemy host
mainnetEthereum Mainneteth-mainnet
sepoliaEthereum Sepolia (testnet)eth-sepolia
arbitrumArbitrum Onearb-mainnet
optimismOP Mainnetopt-mainnet
gnosisGnosis Chaingnosis-mainnet
Arbitrum is the product-default preferred network in Settings → EVM. For production-like use, configure an ALCHEMY_RPC_KEY in your .env file — one key covers all five supported chains.

wallet-assets.json

src/lib/wallet/wallet-assets.json defines the following fields for each network key:
  • Display name and viem chain key (frontend)
  • Explorer transaction URL prefix
  • Native ETH symbol and decimals
  • USDC and USDT contract addresses and decimals
Frontend import:
// src/lib/wallet/assets.ts
import WALLET_ASSETS from "./wallet-assets.json";
The exported constant WALLET_ASSETS is the canonical token and network registry for all TypeScript code. Do not hardcode addresses or decimals elsewhere. Rust embed:
// src-tauri/src/evm/wallet_chain_config.rs
const WALLET_ASSETS: &str = include_str!("../../../src/lib/wallet/wallet-assets.json");
The Rust layer maps network keys to numeric chain IDs (not stored in the JSON) and resolves RPC URLs using the same asset file. All wallet send and balance code should use the wallet_chain_config helpers (wallet_networks, network_by_key, rpc_urls_for, etc.).

RPC URL resolution

A single ALCHEMY_RPC_KEY environment variable builds per-chain URLs automatically:
https://{host}.g.alchemy.com/v2/{ALCHEMY_RPC_KEY}
When no operator key is set, the app falls back to curated public defaults or personal RPC URLs from Settings → EVM. Resolution order in getEffectiveRpcUrlsForChain:
  1. Operator provider key URL + curated fallbacks (when ALCHEMY_RPC_KEY is set)
  2. User default / personal RPC preferences (Settings → EVM)
  3. Curated public defaults
Frontend: src/lib/wallet/rpc-providers.ts — Vite exposes ALCHEMY_* via envPrefix in vite.config.ts; getEffectiveRpcUrlsForChain in chains.ts is the single merge point for viem read clients. Backend: src-tauri/src/evm/wallet_rpc_providers.rs — reads the same ALCHEMY_RPC_KEY at runtime and appends curated public fallbacks when a key is present.

Read vs. write separation

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
Generic contract reads (observation)FrontendreadContract / multicall in read-plane.ts — not duplicated in Rust for ad-hoc ABIs
WalletBar send / raw txBackendRust (Alloy): encode, sign, eth_sendRawTransaction
Advanced opaque contract callBackendevm_send_advanced_contract_call — advanced-purpose signer only (advanced_contract_call.rs)
Squad curated deploy / gov writesBackendTyped Alloy commands + squad-purpose gate
USD spot displayBackend + TSwallet_get_usd_spot_prices + src/lib/wallet/pricing.ts

Adding a new network

  1. Edit wallet-assets.json: add the network key with display name, viem chain key, explorer URL, native symbol, decimals, and token addresses.
  2. If the chain ID or viem mapping changes, also update chains.ts.
  3. Add the Alchemy host mapping in src/lib/wallet/rpc-providers.ts (TypeScript) and src-tauri/src/evm/wallet_rpc_providers.rs (Rust).
  4. Run cargo check inside src-tauri to exercise the compile-time JSON embed and catch parse errors early.

USD spot pricing

Wallet balances are annotated with live USD values sourced from Chainlink on-chain price feeds on Ethereum mainnet, regardless of which chain the user has selected for sending. The backend issues eth_call to the standard aggregator proxy addresses:
PairProxy address
ETH / USD0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
USDC / USD0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6
USDT / USD0x3E7d1eAB13ad0104d2750B8863b489D65364e32D
Successful reads are cached in the Rust process for 90 seconds. Failed reads are not cached — if the oracle call fails, the UI shows that live pricing is unavailable rather than displaying a stale or fabricated rate. There are no static price fallbacks. The Tauri command is wallet_get_usd_spot_prices; the TypeScript helper is getWalletUsdSpotPrices() in src/lib/wallet/pricing.ts.
USD figures from Chainlink are UX estimates for display purposes only — not settlement prices or tax-relevant valuations.

Security

Never commit ALCHEMY_RPC_KEY to source control or any version-controlled file. API keys and provider path segments must not appear in returned errors or server logs.Use src-tauri/src/wallet_security.rs when formatting RPC-related errors in the backend to ensure URLs are redacted before being surfaced to the UI or logs.Never log decrypted EVM private key hex or signer secrets. See the comment at the decrypt site in wallet_ops.rs.
Public RPC defaults are convenient for development but unsuitable for production. Production builds should use dedicated providers with monitored quotas.

Build docs developers (and LLMs) love