Get Started

Overview

The Universal Gateway Transaction Protocol (UGTP) gives every user a single blockchain address that works across every supported network. Built on EIP-7702 set-code delegation, UGTP transforms an ordinary EOA into a full smart account — same address, same key, six mainnets.

The protocol is organized as a monorepo with six packages:

PackagePurpose
@ugtp/coreShared constants, types, contract addresses, chain registry
@ugtp/sdkClient-side helpers — delegation builder, intent builder, execution optimizer
@ugtp/waasServer-side Wallet as a Service SDK — institutional key management
ugtp-apiREST API server — delegation, sponsorship, balances, capabilities
ugtp-portalWeb wallet UI — connect, delegate, transfer, privacy
ugtp-landingMarketing site and documentation (this site)
Current version: Universal Gateway Transaction Protocol v0.1.0 — beta

Quickstart

Clone the monorepo and install dependencies with pnpm:

# Install dependencies
pnpm install

# Build core packages (required before other packages)
pnpm --filter @ugtp/core build
pnpm --filter @ugtp/sdk build

# Start the API server
pnpm --filter ugtp-api dev

# Start the portal
pnpm --filter ugtp-portal dev
The @ugtp/core and @ugtp/sdk packages must be built first — other packages import from them as workspace dependencies.

Server-side (WaaS)

For institutional integrations, install the WaaS SDK directly:

pnpm add @ugtp/waas @ugtp/core @ugtp/sdk

Authentication

UGTP supports two authentication paths:

Wallet Connect (Portal)

End users connect via MetaMask, WalletConnect, or any injected wallet. The connected address becomes their Universal Crypto Account. No additional signup or key generation is required.

Service Account (WaaS)

Server-side integrations authenticate through the external signer (e.g., Dfns). Credentials are loaded from environment variables and never exposed to the client:

# .env.local (server-side only — never commit)
DFNS_AUTH_TOKEN=              # service-account token
DFNS_ORG_ID=
DFNS_CRED_ID=
DFNS_PRIVATE_KEY_PATH=./.secrets/dfns-private.pem
DFNS_BASE_URL=https://api.dfns.io
Security: Never prefix server secrets with NEXT_PUBLIC_, PUBLIC_, or VITE_. The @ugtp/waas package is server-side only and must never be imported from a client component.
Concepts

Account Model

A Universal Crypto Account (UCA) is one persistent user identity across public, smart, and private execution. Your EOA address becomes your UCA — the same address on Ethereum, Base, Arbitrum, Optimism, Polygon, and Avalanche.

EOA = Smart = Private

On EIP-7702 chains, delegation upgrades the EOA to a full smart account — batch execution, session keys, sponsored gas — while preserving the original address. There is no separate smart-account contract to deploy; the delegation itself confers smart-account capabilities.

On Avalanche (the coordination chain), the account operates in standard EOA mode until ACP-209 enables 7702 support. Privacy features on Avalanche use a separate escrow pattern that does not require delegation.

Delegation Lifecycle

// 1. Build the authorization
import { DelegationHelper } from '@ugtp/sdk';
const auth = DelegationHelper.buildAuthorization(chainId, nonce);

// 2. Sign with the user's wallet
const signed = await wallet.signAuthorization(auth);

// 3. Submit to the API for on-chain execution
await fetch('/api/delegate', {
  method: 'POST',
  body: JSON.stringify({ authorization: signed }),
});

Operation Rails

UGTP selects the optimal execution path for each transaction based on chain capabilities and delegation status:

RailWhen UsedFeatures
EIP-7702Delegated account on 7702-capable chainBatch execution, session keys, sponsored gas, full smart-account UX
ERC-4337Chains with 4337 bundler support (fallback)UserOp-based execution, paymaster support
EOAStandard transfer, no delegation neededDirect transaction, lowest gas cost
import { ExecutionOptimizer } from '@ugtp/sdk';

const optimizer = new ExecutionOptimizer();
const mode = optimizer.selectMode(chainId, isDelegated);
// Returns: '7702' | '4337' | 'eoa'

Avalanche C-Chain

Avalanche C-Chain (43114) is the coordination chain — the source of truth for account state, privacy registration, and cross-chain routing.

Privacy Layer

Avalanche hosts the privacy escrow contracts that enable confidential transfers using Encrypted ERC (eERC) tokens. Users register for privacy on the coordination chain, then shield and unshield assets through the escrow contract.

The canonical Tether symbol on Avalanche (43114) is USDt, not USDT.

EIP-7702 Status

Avalanche C-Chain does not yet support EIP-7702 set-code transactions. The community proposal ACP-209 is in progress. Until then, accounts on Avalanche operate as standard EOAs. Once ACP-209 is activated, delegation will unlock smart-account features on the coordination chain as well.

Build

WaaS SDK

The @ugtp/waas package is a server-side SDK for creating and operating UGTP wallets with institutional key management.

Initialize

import { createUgtpWaas, JsonFileWalletStore } from '@ugtp/waas';
import { dfnsFromEnv } from '@ugtp/waas/signer/dfns';

const waas = createUgtpWaas({
  signer: dfnsFromEnv(),
  store: new JsonFileWalletStore('./data/waas.json'),
  allowMainnet: true,
});

Create a Wallet

// Dfns MPC key → same address on all 6 chains
const wallet = await waas.wallets.create({ name: 'treasury-1' });

Plan & Execute

// Plan a batch transaction
const plan = await waas.batch.plan({
  walletId: wallet.id,
  recipient: '0x...',
  target: { chainId: 1, symbol: 'ETH', amount: '500000000000000' },
  sources: [{ chainId: 1, symbol: 'ETH' }],
});

// Execute (signs with Dfns, broadcasts, tracks stages)
const flow = await waas.batch.execute(plan.planId);

// Poll status
const status = await waas.batch.status(flow.flowId);

Full API

MethodReturnsDescription
waas.signers.list()SignerProvider[]All registered signer providers
waas.signers.health()HealthResult[]Connectivity check for each provider
waas.signers.get(id)SignerProviderLook up a provider by ID
waas.wallets.create(opts?)WalletRecordCreate signer + resolve UCA + optional activation
waas.wallets.get(id)WalletRecordFetch a wallet by ID
waas.wallets.list()WalletRecord[]All wallets in the store
waas.wallets.refresh(id)WalletRecordRe-read delegation state from chain
waas.wallets.activate(id, chainId)stringEIP-7702 delegation (self-signed tx)
waas.wallets.activateSponsored(id, chainId)objectGas-free delegation via /api/delegate
waas.wallets.balances(id)BalancesMulti-chain native + ERC-20 balances
waas.wallets.privacyStatus(id)stringAvalanche privacy registration state
waas.batch.plan(intent)BatchPlanBuild steps from an intent (quotes, fees)
waas.batch.execute(planId)ExecutionFlowSign and broadcast each step
waas.batch.status(flowId)ExecutionFlowPoll execution progress
waas.batch.list(walletId?)ExecutionFlow[]Past flows, optionally filtered

Error Codes

CodeMeaning
WALLET_NOT_FOUNDNo wallet with the given ID in the store
UNSUPPORTED_PROVIDERNo registered signer provider with the given ID
UNSUPPORTED_NETWORKChain does not support the requested operation
ACTIVATION_FAILEDEIP-7702 delegation transaction failed
PLANNING_FAILEDBatch plan could not be constructed
EXECUTION_FAILEDA step in the batch execution reverted or timed out
MAINNET_DISABLEDallowMainnet is false and step targets a mainnet chain
VALUE_CAP_EXCEEDEDNative value exceeds maxNativeValueWei safety cap

Safety Rails

  • ALLOW_MAINNET_TRANSACTIONS — must be explicitly true; the executor rejects every mainnet step otherwise.
  • MAX_NATIVE_VALUE_WEI — per-step native value cap (default 0.002 ETH). Any step exceeding it is rejected before signing.
  • Simulation — eth_call / estimateGas before every broadcast. Reverts are caught before the transaction reaches the mempool.
  • Pending policy status — when Dfns policies require multi-party approval, the executor surfaces Pending as a stage status rather than failing.

External Signers

UGTP's Wallet as a Service architecture decouples key management from protocol logic through the SignerProvider interface. Any institutional key management system that can sign EVM transactions can be plugged in as an external signer.

SignerProvider Interface

Every external signer implements this interface. Four EVM signing kinds are supported: Transaction, Eip7702, Eip712, and Eip191.

interface SignerProvider {
  id: string;
  createSigner(params: CreateSignerParams): Promise<SignerRecord>;
  signTransaction(signerId: string, tx: Record<string, unknown>): Promise<string>;
  signAuthorization(signerId: string, auth: Record<string, unknown>): Promise<SignedAuthorization>;
  signTypedData(signerId: string, data: Record<string, unknown>): Promise<string>;
  signMessage(signerId: string, message: string): Promise<string>;
  healthCheck(): Promise<{ ok: boolean; latencyMs: number }>;
}

The toProviderAccount() bridge wraps any SignerProvider as a viem Account so the full @ugtp/sdk works unchanged.

Dfns — Production Signer

Dfns is the production external signer for UGTP. It provides MPC-based key management with hardware-backed key shares, programmable policy engine, and multi-party approval workflows.

Architecture

  • MPC key generation — private key shares are distributed across Dfns infrastructure. No single party (including Dfns) ever holds the complete key.
  • Deterministic addressing — one MPC key derives the same Ethereum address on all six UGTP chains. The wallet is portable without bridging.
  • Policy engine — configurable rules (spend limits, allowlists, time locks) enforced at the signing layer. Policies requiring multi-party approval surface as Pending status in the WaaS executor.
  • Service-account auth — the customer's institutional signer holds the key. Authentication uses asymmetric credentials (RSA key pair). The private key never leaves the server.

Configuration

# .env.local (server-side only)
DFNS_AUTH_TOKEN=sa_...           # service-account token
DFNS_ORG_ID=or_...              # organization ID
DFNS_CRED_ID=cr_...             # credential ID
DFNS_PRIVATE_KEY_PATH=./.secrets/dfns-private.pem
DFNS_BASE_URL=https://api.dfns.io
DFNS_DEFAULT_NETWORK=Ethereum

Usage

import { dfnsFromEnv } from '@ugtp/waas/signer/dfns';

// Initialize from environment variables
const signer = dfnsFromEnv();

// Or configure explicitly
import { DfnsSignerProvider } from '@ugtp/waas/signer/dfns';

const signer = new DfnsSignerProvider({
  authToken: process.env.DFNS_AUTH_TOKEN,
  orgId: process.env.DFNS_ORG_ID,
  credId: process.env.DFNS_CRED_ID,
  privateKeyPath: process.env.DFNS_PRIVATE_KEY_PATH,
  baseUrl: process.env.DFNS_BASE_URL,
});

Supported Operations

OperationDfns MethodUGTP Usage
Create walletPOST /walletswaas.wallets.create() — generates MPC key, returns address
Sign transactionPOST /wallets/:id/signatureswaas.batch.execute() — signs each step in a batch
Sign EIP-7702 authPOST /wallets/:id/signatureswaas.wallets.activate() — delegation authorization
Sign typed dataPOST /wallets/:id/signaturesPrivacy registration (EIP-712 domain)
Sign messagePOST /wallets/:id/signaturesArbitrary message signing (EIP-191)
Health checkGET /healthwaas.signers.health() — latency and connectivity

Utila

PlannedNext integration

Utila provides institutional-grade MPC wallet infrastructure with policy-based access controls, multi-chain support, and SOC 2 compliance. The Utila adapter will implement the SignerProvider interface, allowing UGTP wallets to use Utila as an alternative to Dfns for key management.

Cobo

PlannedNext integration

Cobo offers a full-stack digital asset custody solution with MPC-TSS technology, risk management engine, and comprehensive API coverage. The Cobo adapter will follow the same SignerProvider pattern, enabling enterprises already using Cobo to integrate with UGTP without changing their custody infrastructure.

Adding a Custom Provider

To integrate a new key-management system, implement the SignerProvider interface in a single adapter file and register it:

import { createUgtpWaas } from '@ugtp/waas';
import { MyCustomProvider } from './my-provider';

const waas = createUgtpWaas({
  signer: new MyCustomProvider({ /* config */ }),
  store: new JsonFileWalletStore('./data/waas.json'),
});

Transactions

UGTP transactions are expressed as intents — declarative descriptions of what the user wants to accomplish. The SDK resolves intents into executable steps.

Intent Builder

import { IntentBuilder } from '@ugtp/sdk';

// Native transfer
const intent = IntentBuilder.transfer({
  from: address,
  to: recipient,
  chainId: 1,
  asset: 'ETH',
  amount: '1000000000000000000', // 1 ETH in wei
});

// ERC-20 transfer
const tokenIntent = IntentBuilder.transfer({
  from: address,
  to: recipient,
  chainId: 43114,
  asset: 'USDt',
  amount: '2000000', // 2 USDt (6 decimals)
});

Batch Execution

On delegated accounts, multiple operations can be batched into a single transaction. The batch planner quotes fees, selects source chains, and produces an ordered list of steps:

const plan = await waas.batch.plan({
  walletId: wallet.id,
  recipient: '0x...',
  target: { chainId: 1, symbol: 'ETH', amount: '500000000000000' },
  sources: [
    { chainId: 1, symbol: 'ETH' },
    { chainId: 8453, symbol: 'ETH' },  // fallback to Base
  ],
});

// Each step: { chainId, type, to, value, data, gasEstimate }
console.log(plan.steps);

Private Tokens

UGTP integrates with Encrypted ERC (eERC) tokens on Avalanche C-Chain for confidential transfers. Amounts and balances are encrypted on-chain; only the account holder (and authorized auditors) can decrypt them.

Privacy Lifecycle

  1. Register — derive a privacy key pair from the account, register the public key on the coordination chain.
  2. Shield — deposit tokens into the privacy escrow. The escrow mints an equivalent encrypted balance.
  3. Transfer — send encrypted tokens to another registered account. The transfer is visible on-chain but the amount is encrypted.
  4. Unshield — withdraw from the escrow back to a standard ERC-20 balance.
Privacy key derivation uses the constant KEY_DERIVATION_PURPOSE = 'Derive UGTP private-account keys' — this value must not change.

Swaps & Routing

Cross-chain routing selects the cheapest path to fulfill a transfer intent. When the source and destination chains differ, the router computes bridge fees, DEX swap quotes, and gas costs to find the optimal route.

The batch planner integrates routing automatically — specify multiple source chains in the sources array, and the planner picks the best combination:

const plan = await waas.batch.plan({
  walletId: wallet.id,
  recipient: '0x...',
  target: { chainId: 1, symbol: 'ETH', amount: '1000000000000000' },
  sources: [
    { chainId: 1, symbol: 'ETH' },
    { chainId: 8453, symbol: 'ETH' },
    { chainId: 42161, symbol: 'ETH' },
  ],
});
// plan.route describes the chosen path and estimated costs
Operate

Network Support

UGTP supports six production mainnets. Each chain has a specific capability profile based on EIP support and contract deployment status:

NetworkChain ID77024337PrivacyRole
Ethereum1✓✓—Primary L1
Base8453✓✓—Preferred for first type-4 tx
Arbitrum One42161✓✓—L2 Rollup
Optimism10✓✓—L2 Rollup
Polygon PoS137✓✓—Sidechain
Avalanche C-Chain43114——✓Coordination chain
Base (8453) is the preferred chain for first type-4 (EIP-7702) transactions due to low gas costs and fast finality.

Fees & Lifecycle

UGTP applies a transparent fee model on every batch execution:

ComponentValueDescription
Proportional25 bpsApplied to the transfer amount (fee-from-amount)
Flat0.001 ETHPer-batch flat fee in native currency
Recipient0xdC7C3AB388375FF0E83fcc66F61A2214C94B64dbSystem fee collector address

Fees are calculated fee-from-amount — deducted from the transfer value, not added on top. The recipient receives the amount minus fees.

Execution Lifecycle

A batch flow moves through these stages:

  1. Plan — intent is resolved into steps with fee quotes
  2. Simulate — each step is dry-run via eth_call
  3. Sign — external signer signs each transaction
  4. Broadcast — signed transactions are submitted to the network
  5. Confirm — receipts are collected and the flow is marked complete

API Reference

The ugtp-api server exposes the following REST endpoints:

MethodEndpointDescription
GET/api/healthHealth check and protocol status
GET/api/uca/:addressUCA delegation status across all chains
GET/api/balances/:addressMulti-chain asset balances
GET/api/capabilitiesPer-chain capability matrix and contract status
POST/api/delegateSubmit a signed EIP-7702 delegation
POST/api/sponsorSubmit a sponsored execution request
GET/api/legacy/aw/:eoaCheck for legacy Advanced Wallet deployment

WaaS Endpoints

MethodEndpointDescription
GET/api/waas/signersList all registered signer providers
GET/api/waas/signers/healthHealth check all signers
POST/api/waas/walletsCreate a new WaaS wallet
GET/api/waas/walletsList all wallets
GET/api/waas/wallets/:idGet wallet details
POST/api/waas/wallets/:id/activateActivate (delegate) on a chain
GET/api/waas/wallets/:id/balancesMulti-chain balances for a wallet
POST/api/waas/batch/planPlan a batch transaction
POST/api/waas/batch/executeExecute a planned batch
GET/api/waas/batch/:flowIdCheck batch execution status
Reference

Deployed Contracts

Canonical contract addresses — deployed once, reused across the protocol:

ContractAddressChain
UGTPAccount0xa4B2befEE38792B931777df37FEaE679Ed8cfA17All EIP-7702 chains
PrivacyEscrowSee @ugtp/coreAvalanche (43114)
These addresses are canonical — reuse them, never redeploy. The UGTPAccount address is the delegation target for EIP-7702 set-code transactions on all supported chains.

Protocol Constants

ConstantValue
UGTPAccount Address0xa4B2befEE38792B931777df37FEaE679Ed8cfA17
Coordination ChainAvalanche (43114)
Fee (Proportional)25 bps
Fee (Flat)0.001 ETH
Fee Recipient0xdC7C3AB388375FF0E83fcc66F61A2214C94B64db
Protocol Version0.1.0
Statusbeta

Links