import { z } from 'zod'; const EthAddressSchema = z.string().regex(/^0x[a-fA-F0-9]{40}$/); export const BasketAllocationSchema = z.object({ symbol: z.string().min(2).max(16), targetWeightBps: z.number().int().positive().max(10_000), routeHint: z.string().optional(), }); export type BasketAllocation = z.infer; export const BasketStatusSchema = z.enum(['draft', 'active', 'rebalancing', 'closed']); export const BasketMandateSchema = z.object({ id: z.string().uuid(), clientId: z.string().min(1), mandateName: z.string().min(1), chain138VaultAddress: EthAddressSchema, baseAssetSymbol: z.string().min(2).max(16).default('cBTC'), status: BasketStatusSchema, allocations: z.array(BasketAllocationSchema).min(1), createdAt: z.date().or(z.string().datetime()), updatedAt: z.date().or(z.string().datetime()), }); export type BasketMandate = z.infer; export const CreateBasketMandateSchema = BasketMandateSchema.omit({ id: true, status: true, createdAt: true, updatedAt: true, }).extend({ baseAssetSymbol: z.string().min(2).max(16).default('cBTC'), }); export type CreateBasketMandate = z.infer; export const BtcDepositStatusSchema = z.enum([ 'instruction_created', 'pending_confirmations', 'confirmed', 'minted', 'frozen', ]); export const BtcDepositSchema = z.object({ id: z.string().uuid(), clientId: z.string().min(1), basketId: z.string().uuid(), chain138VaultAddress: EthAddressSchema, depositAddress: z.string().min(16), expectedAmountSats: z.number().int().positive().optional(), confirmationsRequired: z.number().int().positive(), currentConfirmations: z.number().int().nonnegative(), status: BtcDepositStatusSchema, observedTxId: z.string().optional(), freezeReason: z.string().optional(), createdAt: z.date().or(z.string().datetime()), updatedAt: z.date().or(z.string().datetime()), }); export type BtcDeposit = z.infer; export const CreateBtcDepositSchema = z.object({ clientId: z.string().min(1), basketId: z.string().uuid().optional(), mandateName: z.string().min(1).optional(), chain138VaultAddress: EthAddressSchema, allocations: z.array(BasketAllocationSchema).min(1).optional(), expectedAmountSats: z.number().int().positive().optional(), clientReference: z.string().min(1).optional(), }); export type CreateBtcDeposit = z.infer; export const HoldingStatusSchema = z.enum(['pending_funding', 'funded']); export const HoldingSchema = z.object({ clientId: z.string().min(1), basketId: z.string().uuid(), symbol: z.string().min(2).max(16), allocationWeightBps: z.number().int().min(0).max(10_000), bookValueSats: z.number().int().nonnegative(), status: HoldingStatusSchema, updatedAt: z.date().or(z.string().datetime()), }); export type Holding = z.infer; export const RebalanceStatusSchema = z.enum(['planned', 'queued', 'executed', 'failed']); export const RebalanceSchema = z.object({ id: z.string().uuid(), clientId: z.string().min(1), basketId: z.string().uuid(), sourceSymbol: z.string().min(2).max(16), targetSymbols: z.array(z.string().min(2).max(16)).min(1), reason: z.string().min(1), status: RebalanceStatusSchema, createdAt: z.date().or(z.string().datetime()), updatedAt: z.date().or(z.string().datetime()), }); export type Rebalance = z.infer; export const BridgeWithdrawalStatusSchema = z.enum(['pending', 'approved', 'submitted', 'failed']); export const BridgeWithdrawalSchema = z.object({ id: z.string().uuid(), clientId: z.string().min(1), basketId: z.string().uuid(), sourceSymbol: z.string().min(2).max(16), destinationSymbol: z.string().min(2).max(16), destinationChainId: z.number().int().positive(), destinationAddress: EthAddressSchema, amount: z.string().min(1), status: BridgeWithdrawalStatusSchema, createdAt: z.date().or(z.string().datetime()), updatedAt: z.date().or(z.string().datetime()), }); export type BridgeWithdrawal = z.infer; export const CreateBridgeWithdrawalSchema = BridgeWithdrawalSchema.omit({ id: true, status: true, createdAt: true, updatedAt: true, }).extend({ sourceSymbol: z.string().min(2).max(16).optional(), destinationSymbol: z.string().min(2).max(16).optional(), }); export type CreateBridgeWithdrawal = z.infer;