- Phoenix API Railing: proxy to PHOENIX_RAILING_URL, tenant me routes - Tenant-auth: X-API-Key support for /api/v1/* (api_keys table) - Migration 026: api_keys table; 025 sovereign stack marketplace - GET /graphql/schema, GET /graphql-playground, api/docs OpenAPI - Integration tests: phoenix-railing.test.ts - docs/api/API_VERSIONING: /api/v1/ railing alignment - docs/phoenix/PORTAL_RAILING_WIRING Made-with: Cursor
113 lines
2.7 KiB
TypeScript
113 lines
2.7 KiB
TypeScript
/**
|
|
* Phoenix Wallet Registry Service
|
|
* Wallet mapping, chain support, policy engine, and recovery
|
|
*/
|
|
|
|
import { getDb } from '../../db/index.js'
|
|
import { logger } from '../../lib/logger.js'
|
|
|
|
export interface Wallet {
|
|
walletId: string
|
|
userId: string
|
|
orgId: string | null
|
|
address: string
|
|
chainId: number
|
|
custodyType: 'USER' | 'SHARED' | 'PLATFORM'
|
|
status: 'ACTIVE' | 'SUSPENDED' | 'RECOVERED'
|
|
}
|
|
|
|
export interface TransactionRequest {
|
|
from: string
|
|
to: string
|
|
value: string
|
|
data?: string
|
|
chainId: number
|
|
}
|
|
|
|
export interface TransactionSimulation {
|
|
success: boolean
|
|
gasEstimate: string
|
|
error?: string
|
|
warnings?: string[]
|
|
}
|
|
|
|
class WalletRegistryService {
|
|
/**
|
|
* Register a wallet
|
|
*/
|
|
async registerWallet(
|
|
userId: string,
|
|
address: string,
|
|
chainId: number,
|
|
custodyType: 'USER' | 'SHARED' | 'PLATFORM',
|
|
orgId?: string
|
|
): Promise<Wallet> {
|
|
const db = getDb()
|
|
|
|
const result = await db.query(
|
|
`INSERT INTO wallets (user_id, org_id, address, chain_id, custody_type, status)
|
|
VALUES ($1, $2, $3, $4, $5, 'ACTIVE')
|
|
RETURNING *`,
|
|
[userId, orgId || null, address, chainId, custodyType]
|
|
)
|
|
|
|
logger.info('Wallet registered', { walletId: result.rows[0].id, address })
|
|
return this.mapWallet(result.rows[0])
|
|
}
|
|
|
|
/**
|
|
* Build a transaction
|
|
*/
|
|
async buildTransaction(request: TransactionRequest): Promise<string> {
|
|
// This would use a transaction builder service with deterministic encoding
|
|
logger.info('Building transaction', { request })
|
|
|
|
// Placeholder - would integrate with actual transaction builder
|
|
return '0x' // Serialized transaction
|
|
}
|
|
|
|
/**
|
|
* Simulate a transaction
|
|
*/
|
|
async simulateTransaction(request: TransactionRequest): Promise<TransactionSimulation> {
|
|
logger.info('Simulating transaction', { request })
|
|
|
|
// Placeholder - would call chain RPC for simulation
|
|
return {
|
|
success: true,
|
|
gasEstimate: '21000',
|
|
warnings: []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get wallets for user
|
|
*/
|
|
async getWalletsForUser(userId: string, chainId?: number): Promise<Wallet[]> {
|
|
const db = getDb()
|
|
|
|
const query = chainId
|
|
? `SELECT * FROM wallets WHERE user_id = $1 AND chain_id = $2`
|
|
: `SELECT * FROM wallets WHERE user_id = $1`
|
|
|
|
const params = chainId ? [userId, chainId] : [userId]
|
|
const result = await db.query(query, params)
|
|
|
|
return result.rows.map(this.mapWallet)
|
|
}
|
|
|
|
private mapWallet(row: any): Wallet {
|
|
return {
|
|
walletId: row.id,
|
|
userId: row.user_id,
|
|
orgId: row.org_id,
|
|
address: row.address,
|
|
chainId: row.chain_id,
|
|
custodyType: row.custody_type,
|
|
status: row.status
|
|
}
|
|
}
|
|
}
|
|
|
|
export const walletRegistryService = new WalletRegistryService()
|