Skip to main content
Programmable addresses enable routing and settlement rules to be attached to a persistent address, which can be scoped to a product-specific domain or affiliated with a user’s wallet. When funds arrive, they swap and settle automatically. No manual bridging. No extra transactions. Each programmable address is a smart contract deterministically derived from a wallet address using CREATE2. The same input always produces the same address on every supported chain. Compute it once, and it exists forever: a permanent endpoint that can be shared publicly, embedded in invoices, or surfaced in a product UI.

How it works

When tokens arrive at a programmable address, the attached logic executes automatically:
  1. Tokens land at the programmable address
  2. The contract deploys on first deposit only (no gas until funds actually arrive)
  3. The pre-programmed action executes
The sender makes a normal transfer. They don’t bridge, they don’t use a special app. The programmable address handles swapping, bridging, or settling: whatever it’s programmed to do.

Step-by-step flow

  1. Address generation: Request a programmable address for your destination wallet
  2. Deterministic computation: The factory computes a unique EVM address from the destination using CREATE2
  3. Token transfer: Send USDC to the programmable address on Base
  4. Contract deployment: The system detects the deposit and deploys the contract if needed
  5. Action execution: The pre-programmed logic executes. For cross-chain deposits, this creates an intent via createIntent()
  6. Fulfillment: Solvers compete to fulfill the intent, delivering tokens to the destination wallet

Supported chains and tokens

Use caseSourceTokenDestination
Solana depositsBaseUSDCSolana
Gateway depositsAll supported USDC chainsUSDCGateway (through Arc)
Additional chains, tokens, and use cases will be added over time.

Deposit addresses: the first use case

A deposit address is a programmable address configured to receive tokens and route them to a destination automatically. The sender makes a vanilla ERC-20 transfer. No bridge UI, no approval step, no contract interaction required. Deposit addresses are live today:

Solana Deposits

USDC arrives on Base and settles to a Solana wallet automatically.

Gateway Deposits

USDC arrives from any supported chain and deposits into Gateway through Arc.
The architecture supports arbitrarily encoded actions and more complex settlement rules. Deposit addresses are the first use case, not the last.

Architecture

Components

Address Factory

The factory contract manages programmable address generation:
  • Computes deterministic addresses via getDepositAddress()
  • Deploys programmable address contracts via deploy()
  • Stores immutable configuration for destination chain, tokens, and Portal

Programmable Address Contract

Individual programmable address contracts handle token reception and action execution:
  • Receives tokens from users
  • Executes the programmed action (e.g., creates intents via createIntent())
Refunds for expired intents are handled by the refund logic on the Routes service.

Built on Routes

Programmable addresses use Routes as the execution layer. When the programmed action involves cross-chain movement, the programmable address creates a Routes intent. Solvers compete to fulfill it. Provers verify execution. This means programmable addresses inherit Routes’ properties:
  • Fast execution through solver competition
  • Cryptographic proof of delivery
  • Automatic refunds if an intent expires unfulfilled

What you can build

Deposit addresses

Give any wallet a persistent address that auto-routes deposits to a destination: a Solana wallet, a Gateway balance, a protocol vault. The user makes a single transfer. Everything else is handled.

Programmable payment flows

Accept payments from any chain and route them automatically to a treasury, into a yield protocol, or split between multiple destinations. The logic executes on every deposit without manual intervention.

Automated bridging for exchanges

Users withdraw to a destination address. The exchange sends to the programmable address on any EVM chain. Funds bridge and arrive at the destination. No bridge integration, no user-facing complexity, no support tickets about stuck transactions.

One-step cross-chain deposits

Users deposit into your protocol from any chain. The programmable address bridges and deposits in a single flow. Users don’t think about which chain your contracts are on. They just deposit.

Configuration

Each factory is configured with immutable parameters:
ParameterTypeDescription
destinationChainuint64Target chain ID (Solana)
sourceTokenaddressToken address on source chain
targetTokenbytes32Token address on destination
portalAddressaddressRoutes Portal contract address
proverAddressaddressCross-chain prover address
destinationPortalbytes32Portal on destination chain
intentDeadlineDurationuint64Time window for intent fulfillment

Data types

Programmable Address

interface ProgrammableAddress {
  chainId: number;
  factoryAddress: Address;
  solanaAddress: Hex;
  depositor: Address;
  evmDepositAddress: Address;
  isDeployed: boolean;
  deploymentTxHash?: Hex;
  deploymentBlockNumber?: bigint;
  lastCheckedBalance: bigint;
  lastBalanceCheckAt: Date;
  createdAt: Date;
  updatedAt: Date;
}

Intent

interface Intent {
  chainId: number;
  intentHash: Hex;
  depositAddress: Address;
  factoryAddress: Address;
  solanaAddress: Hex;
  amount: bigint;
  status: 'pending' | 'funded' | 'fulfilled' | 'expired' | 'failed';
  txHash: Hex | null;
  blockNumber: bigint | null;
  createdAt: Date;
  updatedAt: Date;
  fulfilledAt: Date | null;
  fulfilledTxHash: Hex | null;
  error: string | null;
  lastCheckedAt: Date;
}