Files
the_order/packages/schemas/src/btc-basket.ts
defiQUG 3f7cc0f854 feat(finance): BTC basket flows, client scoping, and jewelry-box store
- Finance API: baskets, holdings, rebalances, deposits, bridge withdrawals, vault checks.
- Schemas: btc-basket; api-client finance types; workspace lockfile update.
- Vitest config for finance service; expanded tests.

Made-with: Cursor
2026-04-07 22:59:32 -07:00

137 lines
4.4 KiB
TypeScript

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<typeof BasketAllocationSchema>;
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<typeof BasketMandateSchema>;
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<typeof CreateBasketMandateSchema>;
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<typeof BtcDepositSchema>;
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<typeof CreateBtcDepositSchema>;
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<typeof HoldingSchema>;
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<typeof RebalanceSchema>;
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<typeof BridgeWithdrawalSchema>;
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<typeof CreateBridgeWithdrawalSchema>;