- 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
137 lines
4.4 KiB
TypeScript
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>;
|