Environment variables
This commit is contained in:
+10
-6
@@ -19,10 +19,11 @@ export const custodyActionSchema = z.discriminatedUnion('type', [
|
||||
z.object({ type: z.literal('activity'), offset: z.number().int().min(0).max(10000).default(0) }).strict(),
|
||||
z.object({ type: z.literal('mock-credit') }).strict(),
|
||||
z.object({ type: z.literal('list'), cardHash: hex, sequence: z.number().int().nonnegative().safe(),
|
||||
priceAtomicXmr: amount, feeBps: z.number().int().min(0).max(5000) }).strict(),
|
||||
priceAtomicXmr: amount, feeBps: z.number().int().min(0).max(5000),
|
||||
hostFeeAddress: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{95}$/).optional() }).strict(),
|
||||
z.object({ type: z.literal('cancel-listing'), listingId: id }).strict(),
|
||||
z.object({ type: z.literal('reserve'), listingId: id, priceAtomicXmr: amount,
|
||||
feeBps: z.number().int().min(0).max(5000) }).strict(),
|
||||
feeBps: z.number().int().min(0).max(5000), hostFeeAddress: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{95}$/).optional() }).strict(),
|
||||
z.object({ type: z.literal('cancel-reservation'), orderId: id }).strict(),
|
||||
// No real Monero address accepted or generated in this phase.
|
||||
z.object({ type: z.literal('withdraw'), destination: z.literal('mock-external'), amountAtomicXmr: amount,
|
||||
@@ -44,18 +45,21 @@ export function custodyMessage(c: Omit<CustodyCommand, 'signature'>): string {
|
||||
: a.type === 'withdraw' ? [a.destination, 'XMR', a.amountAtomicXmr, a.maxFeeAtomicXmr]
|
||||
: a.type === 'cancel-withdrawal' ? [a.withdrawalId]
|
||||
: a.type === 'activity' ? [a.offset] : [MOCK_CREDIT_ATOMIC];
|
||||
const fees: (string | number)[] = [ADDITIONAL_MARKET_FEE.bps, ADDITIONAL_MARKET_FEE.address];
|
||||
if ((a.type === 'list' || a.type === 'reserve') && a.hostFeeAddress !== undefined) fees.push('host-fee-recipient-v1', a.hostFeeAddress);
|
||||
return JSON.stringify(['wikideck-custody-command-v1', c.version, c.mode, c.policy, c.network,
|
||||
c.chainId, c.custodianId, c.actor, c.publicKey, c.nonce, c.expiresAt, a.type, terms,
|
||||
[ADDITIONAL_MARKET_FEE.bps, ADDITIONAL_MARKET_FEE.address]]);
|
||||
fees]);
|
||||
}
|
||||
export type CustodyInfo = { enabled: true; mode: 'sandbox'; policy: typeof CUSTODY_POLICY;
|
||||
network: typeof NETWORK; chainId: string; custodianId: string; feeBps: number;
|
||||
liveDeposits: false; liveWithdrawals: false; nftSettlement: false };
|
||||
liveDeposits: false; liveWithdrawals: false; nftSettlement: false;
|
||||
marketEnabled?: boolean; tradingEnabled?: boolean; hostFeeAddress?: string };
|
||||
export type CustodyListing = { id: string; seller: string; cardHash: string; sequence: number;
|
||||
title: string; priceAtomicXmr: string; feeBps: number; status: 'open' | 'reserved' | 'cancelled' | 'sold'; createdAt: number };
|
||||
title: string; priceAtomicXmr: string; feeBps: number; status: 'open' | 'reserved' | 'cancelled' | 'sold'; createdAt: number; hostFeeAddress?: string };
|
||||
export type CustodyOrder = { id: string; listingId: string; seller: string; buyer: string; cardHash: string;
|
||||
sequence: number; grossAtomicXmr: string; sellerAtomicXmr: string; authorAtomicXmr: string;
|
||||
hostAtomicXmr: string; authorAddress: string; status: 'awaiting-lock' | 'cancelled' | 'settled'; createdAt: number };
|
||||
hostAtomicXmr: string; authorAddress: string; status: 'awaiting-lock' | 'cancelled' | 'settled'; createdAt: number; hostFeeAddress?: string };
|
||||
export type CustodyWithdrawal = { id: string; actor: string; destination: 'mock-external';
|
||||
amountAtomicXmr: string; maxFeeAtomicXmr: string; status: 'reserved' | 'prepared' | 'complete' | 'cancelled';
|
||||
attemptId?: string; transactionId?: string; feeAtomicXmr?: string; createdAt: number };
|
||||
|
||||
+7
-3
@@ -15,9 +15,11 @@ const feeBps = z.number().int().min(0).max(5000);
|
||||
|
||||
export const marketActionV3Schema = z.discriminatedUnion('type', [
|
||||
z.object({ type: z.literal('list'), cardHash: hex, sequence: z.number().int().nonnegative().safe(),
|
||||
kind: z.enum(['fixed', 'auction']), priceAtomicXmr: atomicPrice, endsAt: z.number().int().nonnegative().nullable(), feeBps }).strict(),
|
||||
kind: z.enum(['fixed', 'auction']), priceAtomicXmr: atomicPrice, endsAt: z.number().int().nonnegative().nullable(), feeBps,
|
||||
hostFeeAddress: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{95}$/).optional() }).strict(),
|
||||
z.object({ type: z.literal('bid'), listingId: id, priceAtomicXmr: atomicPrice }).strict(),
|
||||
z.object({ type: z.literal('buy'), listingId: id, priceAtomicXmr: atomicPrice, feeBps }).strict(),
|
||||
z.object({ type: z.literal('buy'), listingId: id, priceAtomicXmr: atomicPrice, feeBps,
|
||||
hostFeeAddress: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{95}$/).optional() }).strict(),
|
||||
z.object({ type: z.literal('cancel'), listingId: id }).strict(),
|
||||
z.object({ type: z.literal('retire-legacy-listing'), listingId: id }).strict(),
|
||||
z.object({ type: z.literal('mock-pay'), orderId: id }).strict(),
|
||||
@@ -44,7 +46,9 @@ export function marketMessageV3(command: Omit<MarketCommandV3, 'signature'>): st
|
||||
: a.type === 'deliver' ? [a.orderId, a.transfer.network, a.transfer.chainId, a.transfer.cardHash,
|
||||
a.transfer.from, a.transfer.to, a.transfer.sequence, a.transfer.publicKey, a.transfer.signature]
|
||||
: [a.orderId];
|
||||
const feeTerms = a.type === 'list' || a.type === 'buy' ? [ADDITIONAL_MARKET_FEE.bps, ADDITIONAL_MARKET_FEE.address] : [];
|
||||
const feeTerms: (string | number)[] = a.type === 'list' || a.type === 'buy' ? [ADDITIONAL_MARKET_FEE.bps, ADDITIONAL_MARKET_FEE.address] : [];
|
||||
// Preserve original v3 message bytes if omitted; omission authorizes ONLY the default author recipient.
|
||||
if ((a.type === 'list' || a.type === 'buy') && a.hostFeeAddress !== undefined) feeTerms.push('host-fee-recipient-v1', a.hostFeeAddress);
|
||||
return JSON.stringify([NETWORK, 'market-command-v3', command.version, command.chainId, command.marketId,
|
||||
command.actor, command.publicKey, command.nonce, command.expiresAt, a.type, terms, feeTerms]);
|
||||
}
|
||||
|
||||
+3
-1
@@ -49,6 +49,7 @@ export type MarketListing = {
|
||||
status: 'open' | 'reserved' | 'sold' | 'cancelled' | 'expired' | 'invalid';
|
||||
highestBid: { bidder: string; priceCents: number } | null;
|
||||
additionalFee?: AdditionalFeePolicy; // Absent on legacy listings; relisting requires fresh fee authorization.
|
||||
hostFeeAddress?: string; // Snapshotted signed recipient on new records; never rewrite historical terms.
|
||||
};
|
||||
export type MarketOrder = {
|
||||
id: string; listingId: string; seller: string; buyer: string; cardHash: string; sequence: number;
|
||||
@@ -58,10 +59,11 @@ export type MarketOrder = {
|
||||
feeXmr: string; sellerNetXmr: string; payout: 'not-started' | 'mock-paid' | 'review';
|
||||
transfer?: NftTransfer; transferId?: string; deliveryConfirmations: number; requiredConfirmations: number;
|
||||
additionalFee?: AdditionalFeePolicy & { amountXmr: string; payout: 'not-started' | 'mock-paid' | 'review' };
|
||||
hostFeeAddress?: string;
|
||||
};
|
||||
export type MarketInfo = { network: string; chainId: string; marketId: string; paymentMode: 'mock';
|
||||
marketVersion: 3; feeBps: number; additionalFee: AdditionalFeePolicy; deliveryConfirmations: number;
|
||||
serverTime: number };
|
||||
serverTime: number; marketEnabled?: boolean; tradingEnabled?: boolean; hostFeeAddress?: string };
|
||||
export type MarketActivity = { orders: MarketOrder[]; listings: MarketListing[] };
|
||||
export function formatUsd(cents: number): string {
|
||||
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(cents / 100);
|
||||
|
||||
Reference in New Issue
Block a user