Saltar al contenido principal

Arquitectura

Esta página describe la arquitectura objetivo de la pila no custodial de OrcaRail y, para cada componente, la ruta de código heredada a la que sustituye.

Diagrama del sistema​

Componentes​

PaymentLinkFactory (EVM)​

Uno por cadena. Direcciones CREATE2 deterministas derivadas de un hash de 32 bytes del UUID del enlace de pago. Expone:

  • computeAddress(bytes32 linkId) view returns (address): dirección previa al despliegue para la UI y la API.
  • deployAndPay(bytes32 linkId, Split split, address token, uint256 amount): despliegue diferido y reenvío en una sola transacción.
  • isDeployed(bytes32 linkId) view returns (bool).

Actualizable tras un proxy UUPS propiedad del multisig Safe 3 de 5, con un timelock de 48 horas. Los receptores por enlace no son actualizables.

Sustituye: la rama EVM de generateAddressForNetwork en api/src/payments/wallet.service.ts (derivación HD y cálculo de la dirección contrafactual de la smart account de Alchemy).

PaymentLinkReceiver (EVM)​

Clon mínimo EIP-1167, uno por enlace de pago. Acepta moneda nativa y ERC-20 (SafeERC20 para tokens no estándar como USDT). Emite Paid(linkId, payer, token, amount). Llama a FeeSplitter.split() de forma atómica.

Sustituye: el paso de barrido de SmartAccountWalletService.drainSmartAccountWallet en api/src/withdrawals/services/smart-account-wallet.service.ts.

FeeSplitter (EVM)​

Lógica de reparto sin estado. Recibe una estructura Split en puntos básicos y un importe, y lo distribuye entre las direcciones del comercio, la plataforma, el referido y la comisión de puente. El resto va al comercio (sin polvo).

Sustituye: los cálculos de reparto en TypeScript de drainSmartAccountWallet y buildNativeDrainCalls / la rama ERC-20 equivalente del mismo servicio.

SubscriptionHub (EVM)​

Uno por cadena. Guarda una estructura Subscription por cada bytes32 id. charge(id) es pública y no requiere permisos, y aplica:

  • block.timestamp >= nextChargeAt
  • lastChargedAt monótono
  • amountCharged + amount <= cap
  • comprobaciones de allowance y saldo ERC-20

Emite Charged, ChargeSkipped(reason), Canceled y SubscriptionCreated.

Sustituye: la extracción custodial en api/src/scheduler/processors/subscription-auto-charge.processor.ts, que hoy usa una smart account controlada por OrcaRail.

Programa Anchor con una PDA por enlace derivada de [b"pl", link_id]. Instrucciones: initialize, pay, refund. Reparte mediante CPI.

Sustituye: la rama Solana de generateAddressForNetwork en api/src/payments/wallet.service.ts (derivación ed25519-hd-key) y la ruta de barrido de SOL en api/src/withdrawals/services/solana-withdrawal-transfer.service.ts.

Programa subscription (Solana)​

Programa Anchor que usa Approve / Revoke de SPL como primitiva de autoridad delegada. charge(id) replica la semántica de SubscriptionHub.charge(id) en EVM.

Sustituye: la rama SOL de subscription-auto-charge.processor.ts y la extracción custodial mediante cuentas de token controladas por OrcaRail.

Multisig BTC 2 de 2 + reembolso prefirmado​

Dirección taproot por enlace con una clave pública del comercio y otra de la plataforma. La PSBT de reembolso prefirmada se guarda off-chain en el momento del depósito. La plataforma no puede mover los fondos de forma unilateral.

Sustituye: la hot wallet unilateral de api/src/withdrawals/services/bitcoin-hot-wallet.service.ts. La ruta de barrido de api/src/withdrawals/services/bitcoin-withdrawal-transfer.service.ts se mantiene, pero firma mediante multisig en lugar de con una clave unilateral.

Indexador de eventos​

Un servicio nuevo, payments/indexer/*, se suscribe a:

  • Los eventos EVM Paid, SubscriptionCreated, Charged, ChargeSkipped y Canceled (watchContractEvent de viem, con Alchemy como principal y un RPC público como respaldo).
  • Los logs de los programas de Solana (webhooks de Helius o streams de Triton).

Inserta o actualiza filas de PaymentTransaction y SubscriptionAutoCharge y despacha los eventos de webhook existentes en api/src/webhooks/webhooks.service.ts.

Sustituye: el sondeo de saldos de depósito y los callbacks de barrido completado que hoy disparan los webhooks.

Flujos de datos​

Pago único (EVM)​

Cobro de suscripción (EVM)​

Reembolso​

EVM: la EOA keeper del comercio o el multisig llama a PaymentLinkReceiver.refund(txId). Solana: el firmante invoca la instrucción refund. BTC: el comercio difunde la PSBT de reembolso prefirmada.

Liquidación entre cadenas​

Se sigue usando Relay (consulta api/src/withdrawals/services/bridge), pero el disparador es on-chain en lugar de custodial: el receptor llama al ejecutor de Relay en la misma transacción, o el keeper lo hace inmediatamente al recibir el evento Paid.

Qué sustituye en el código​

Lista condensada para ingenieros. Se sustituye o se evita en las fases 1–4 y se elimina en la Fase 7.

Archivo / ruta heredadaSustituto
api/src/payments/wallet.service.ts: derivación HD, smart account de AlchemycomputeAddress de la factory + findProgramAddressSync de Solana
api/src/withdrawals/services/smart-account-wallet.service.ts: vaciado / transferenciaReparto atómico en PaymentLinkReceiver.pay
api/src/withdrawals/services/solana-withdrawal-transfer.service.ts: barrido de SOLInstrucción pay del programa payment_link
api/src/scheduler/processors/subscription-auto-charge.processor.ts: extracción custodialSubscriptionHub.charge + charge de Anchor
api/src/withdrawals/services/bitcoin-hot-wallet.service.ts: clave BTC unilateralMultisig 2 de 2 por enlace con firmante del comercio
Tabla hd_wallet_seed + WALLET_ENCRYPTION_KEYEliminados para EVM/SOL; archivados en la Fase 7

Consulta también​