SDK
The Execution Escrow SDK is a TypeScript framework for secure blockchain transaction processing with multi-signature escrow. The SDK provides independent arbiter verification for AI agents and applications.
Installation
npm install @navalabs/execution-escrow-core
# or
pnpm add @navalabs/execution-escrow-core
The core package provides everything needed for transaction verification and execution.
Key Generation
Generate the required cryptographic keys using the CLI tool included with the adapter package.
- PGP Key Pair - Required for Type 1 and Type 2 (encrypts transaction manifests for arbiter review)
- P-256 Key Pair - Only required for Type 2 (AGENT_EXECUTED) where the agent signs transactions automatically
Install the Adapter
npm install @navalabs/execution-escrow-adapter
# or
pnpm add @navalabs/execution-escrow-adapter
Generate Keys
Run the key generation tool directly after installation:
# pnpm
pnpm generate-escrow-keys <walletType> <pgpPassphrase>
# npm
npx generate-escrow-keys <walletType> <pgpPassphrase>
Arguments
| Argument | Required | Description |
|---|---|---|
walletType | Yes | Wallet integration: privy |
pgpPassphrase | Yes | Passphrase to encrypt your PGP private key |
Examples
# Generate keys for Privy wallet
pnpm generate-escrow-keys privy "my-secure-passphrase"
Fireblocks Integration: We support Fireblocks wallet integration. Please contact us to set up Fireblocks for your deployment.
What Gets Generated
The tool generates and displays:
- PGP Key Pair - For encrypting transaction manifests (required for Type 1 and Type 2)
- Public key is needed for agent registration
- P-256 Key Pair - For agent transaction signing (required for Type 2 only)
- Base64-encoded for Privy (
PRIVY_EXECUTION_PRIVATE_KEY) - Not needed for Type 1 where you sign transactions yourself
- Base64-encoded for Privy (
Security Notes
- Keys are displayed in terminal only (copy them securely)
- Never commit private keys or
mcp-config.jsonto version control - Store private keys in a secure password manager or secrets vault
- Use environment variables for sensitive configuration in production
- Rotate keys regularly for production deployments
Quick Start
This example demonstrates the recommended Type 1 (USER_EXECUTED) flow where the arbiter verifies your transaction. Once verified, you or your agent can proceed with execution however you choose.
import {
ExecutionEscrowCore,
Configuration,
getNavaInboxAddress,
} from '@navalabs/execution-escrow-core';
// Configuration - use environment variables in production
const NAVA_API_KEY = process.env.NAVA_API_KEY!;
const ESCROW_ADDRESS = process.env.ESCROW_ADDRESS as `0x${string}`;
const RPC_URL = process.env.RPC_URL!;
const PGP_EXECUTOR_PRIVATE_KEY = process.env.PGP_EXECUTOR_PRIVATE_KEY!;
const PGP_EXECUTOR_PASSPHRASE = process.env.PGP_EXECUTOR_PASSPHRASE!;
const CHAIN_ID = '11155111'; // Sepolia
async function main() {
// Initialize with Type 1 (USER_EXECUTED) - arbiter reviews, you sign
const config = Configuration.fromObject({
navaApiKey: NAVA_API_KEY,
chainId: CHAIN_ID,
execution: {
pgpExecutorPrivateKey: PGP_EXECUTOR_PRIVATE_KEY,
pgpExecutorPassphrase: PGP_EXECUTOR_PASSPHRASE,
escrowAddress: ESCROW_ADDRESS,
rpcUrl: RPC_URL,
executionType: 1, // USER_EXECUTED (recommended)
},
});
const escrow = new ExecutionEscrowCore(config);
// Submit transaction for arbiter verification
const transaction = {
to: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' as `0x${string}`,
value: '0.001',
data: '0x' as `0x${string}`,
chainId: parseInt(CHAIN_ID, 10),
};
const agentContext = {
request: 'Transfer 0.001 ETH to test arbiter verification',
timestamp: Date.now(),
metadata: { source: 'quickstart' },
};
const result = await escrow.requestVerification(
transaction,
agentContext,
ESCROW_ADDRESS
);
console.log('Request submitted:', result.success);
// After arbiter approval, proceed with execution as needed
}
main();
Full Example: See the minimal-verification cookbook for a complete, runnable example with polling and status display.
Checking Verification Status
When you submit a transaction for verification using requestVerification(), a requestHash is returned in the response. You can use this hash to check whether the arbiter has approved the request.
// Submit for verification
const result = await escrow.requestVerification(
transaction,
agentContext,
ESCROW_ADDRESS
);
// Get the request hash from the response
const requestHash = result.data.requestHash;
// Check approval status
const status = await escrow.checkVerificationStatus(requestHash);
if (status.approved) {
// Proceed with execution
}
Integration Examples
For framework-specific integration examples, see:
Configuration
Environment Variables
# Required for all execution types
NAVA_API_KEY=nava_live_...
ESCROW_ADDRESS=0x...
CHAIN_ID=11155111
# Required for Type 1 and Type 2 (arbiter-reviewed flows)
PGP_EXECUTOR_PRIVATE_KEY=-----BEGIN PGP PRIVATE KEY BLOCK-----\n...\n-----END PGP PRIVATE KEY BLOCK-----
PGP_EXECUTOR_PASSPHRASE=your-passphrase
RPC_URL=https://eth-sepolia.g.alchemy.com/v2/your-key
# Optional (SDK provides defaults)
# NAVA_BASE_URL=https://api.nava.dev
# NAVA_INBOX_ADDRESS=0x... (derived from CHAIN_ID)
Execution Types
The Execution Escrow SDK supports three distinct execution types. The executionType field determines which workflow is used and which configuration fields are required.
Choosing an Execution Type
| Type | Who Signs? | Who Executes? | Best For |
|---|---|---|---|
| Type 1: USER_EXECUTED | User | User | Interactive apps where users want control over final execution |
| Type 2: AGENT_EXECUTED | Agent | Arbiter | Autonomous agents that need to operate without user intervention |
| Type 0: DIRECT_USER | User | User | Trusted environments with no oversight needed |
Type 1 (Recommended) is best for most use cases:
- Arbiter verifies the transaction before you proceed
- User or agent maintains control over final execution
- Flexibility to execute however you choose after verification
Type 2 is for fully autonomous agents:
- Agent signs transactions automatically
- Arbiter reviews AND executes approved transactions
- Requires Privy wallet credentials
- Use when building agents that must operate 24/7 without user interaction
Type 1: USER_EXECUTED (Recommended)
Arbiter reviews and verifies transactions, but the user executes them through their own wallet after approval.
Use Case: Balance between user control and oversight. Arbiter can block malicious transactions while user maintains execution control.
Required Configuration:
executionType: 1escrowAddresschainIdnavaApiKeypgpExecutorPrivateKey- For encrypting transaction manifestspgpExecutorPassphrase- For PGP key decryption
Example:
const config = Configuration.fromObject({
navaApiKey: NAVA_API_KEY,
chainId: '11155111',
execution: {
executionType: 1,
escrowAddress: '0x...',
pgpExecutorPrivateKey: '-----BEGIN PGP PRIVATE KEY BLOCK-----\n...',
pgpExecutorPassphrase: 'your_passphrase',
rpcUrl: 'https://eth-sepolia.g.alchemy.com/v2/...',
},
});
Type 2: AGENT_EXECUTED
Arbiter reviews and verifies transactions, and the agent automatically executes approved transactions.
Use Case: Fully automated agents that can operate autonomously after arbiter approval.
Required Configuration:
executionType: 2escrowAddresschainIdnavaApiKeypgpExecutorPrivateKey- For encrypting transaction manifestspgpExecutorPassphrase- For PGP key decryptionrpcUrl- For blockchain interaction- Privy wallet credentials:
privyWalletId+privyExecutionPrivateKey
Example:
const config = Configuration.fromObject({
navaApiKey: NAVA_API_KEY,
chainId: '11155111',
execution: {
executionType: 2,
escrowAddress: '0x...',
pgpExecutorPrivateKey: '-----BEGIN PGP PRIVATE KEY BLOCK-----\n...',
pgpExecutorPassphrase: 'your_passphrase',
rpcUrl: 'https://eth-sepolia.g.alchemy.com/v2/...',
walletProvider: 'privy',
privy: {
walletId: 'did:privy:...',
executionPrivateKey: 'MIGHAgEAMBMG...',
},
},
});
Fireblocks Integration: We support Fireblocks wallet integration for Type 2 execution. Please contact us to set up Fireblocks for your deployment.
Type 0: DIRECT_USER
User signs and executes transactions directly through their own wallet. No arbiter review or verification process.
Use Case: Minimal overhead for trusted environments where users want direct control without oversight.
Required Configuration:
executionType: 0escrowAddresschainIdnavaApiKey
Example:
const config = Configuration.fromObject({
navaApiKey: NAVA_API_KEY,
chainId: '11155111',
execution: {
executionType: 0,
escrowAddress: '0x...',
rpcUrl: 'https://eth-sepolia.g.alchemy.com/v2/...',
},
});
Configuration Requirements Table
| Field | Type 1 | Type 2 | Type 0 |
|---|---|---|---|
executionType | ✓ | ✓ | ✓ |
escrowAddress | ✓ | ✓ | ✓ |
chainId | ✓ | ✓ | ✓ |
navaApiKey | ✓ | ✓ | ✓ |
pgpExecutorPrivateKey | ✓ | ✓ | |
pgpExecutorPassphrase | ✓ | ✓ | |
rpcUrl | ✓ | ✓ | |
| Wallet credentials | ✓ |
SDK Defaults (Optional Fields)
The following fields have SDK-provided defaults and can be omitted unless you need to override them:
navaBaseUrl- Defaults tohttps://api.nava.devnavaInboxAddress- Defaults to official Nava Inbox contract address (derived from chainId)pgpArbiterPublicKey- Defaults to official arbiter public keywalletProvider- Defaults to'privy'privyAppId- Defaults to Nava Privy application ID
API Reference
Core Classes
ExecutionEscrowCore
The main class that handles the escrow logic.
class ExecutionEscrowCore {
constructor(config: Configuration);
async requestVerification(
transaction: TransactionRequest,
context: AgentContext,
escrowAddress: `0x${string}`
): Promise<ExecutionResult>;
async checkRequestStatus(
requestHash: `0x${string}`,
navaInbox: `0x${string}`
): Promise<RequestStatus>;
async getApprovalStatus(
requestHash: `0x${string}`
): Promise<ApprovalStatus>;
}
Types
interface TransactionRequest {
to: `0x${string}`;
data: `0x${string}`;
value: string;
chainId: number;
}
interface AgentContext {
request: string;
timestamp: number;
metadata?: Record<string, unknown>;
}
interface ExecutionResult {
success: boolean;
data: {
userMessage?: string;
nextSteps?: string;
transactionHash?: string;
error?: string;
};
}
Development
Building
git clone https://github.com/navalabs-dev/execution-escrow.git
cd execution-escrow
pnpm install
pnpm build
Development Commands
# Build all packages
pnpm build
# Development with watch mode
pnpm dev
# Run tests
pnpm test
# Lint all packages
pnpm lint