forked from CredenceOrg/Credence-Frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmutationGuard.ts
More file actions
86 lines (77 loc) · 3.09 KB
/
Copy pathmutationGuard.ts
File metadata and controls
86 lines (77 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/**
* @file mutationGuard.ts
* @description Bounded-input guards and constants for bond and trust-score
* mutations.
*
* These are the **resource/rate limits** applied at the mutation boundary,
* *before* any expensive or irreversible work (signed transaction submissions,
* ledger writes, lookups) is attempted:
*
* - Bond amounts are bounded to a deterministic, finite range. Unbounded or
* adversarial input (Infinity, NaN, enormous values) is rejected up front
* instead of being forwarded to the wallet/network path.
* - Trust-score addresses are bounded in length and required to be non-empty,
* so the encoded lookup path cannot be abused with unbounded input.
*
* The invariant enforced is: a mutation is only executed when its inputs are
* within the documented bounds; otherwise an **actionable** validation error
* is produced and no partial work or wallet interaction occurs.
*/
/** Allowed bond amount range (USDC), finite and inclusive. */
export const BOND_AMOUNT_MIN_USDC = 10
export const BOND_AMOUNT_MAX_USDC = 1_000_000
/** Defensive cap on the trust-score address input length. */
export const TRUST_SCORE_ADDRESS_MAX_LENGTH = 128
export type MutationInputResult<T> = { ok: true; value: T } | { ok: false; message: string }
/**
* Validates a raw bond amount before the expensive mutation.
*
* Rejects non-finite numbers, values outside the documented bounds, and
* anything that is not a number. Returning a typed result lets the caller
* surface an actionable, user-facing message and always avoids calling the
* downstream submit path for invalid input.
*/
export function validateBondAmount(value: unknown): MutationInputResult<number> {
const numeric = typeof value === 'number' ? value : Number(value)
if (typeof value === 'number' && !Number.isFinite(value)) {
return { ok: false, message: 'Bond amount must be a finite number.' }
}
if (!Number.isFinite(numeric)) {
return { ok: false, message: 'Bond amount must be a valid number.' }
}
if (numeric < BOND_AMOUNT_MIN_USDC) {
return {
ok: false,
message: `Bond amount must be at least ${BOND_AMOUNT_MIN_USDC} USDC.`,
}
}
if (numeric > BOND_AMOUNT_MAX_USDC) {
return {
ok: false,
message: `Bond amount must not exceed ${BOND_AMOUNT_MAX_USDC} USDC.`,
}
}
return { ok: true, value: numeric }
}
/**
* Validates a Stellar trust-score address before a lookup mutation.
*
* Rejects empty input, non-strings, and inputs exceeding the length bound so
* the encoded lookup path is not fed unbounded input.
*/
export function validateTrustScoreAddress(value: unknown): MutationInputResult<string> {
if (typeof value !== 'string') {
return { ok: false, message: 'Trust score address must be a string.' }
}
const trimmed = value.trim()
if (trimmed.length === 0) {
return { ok: false, message: 'Trust score address must not be empty.' }
}
if (trimmed.length > TRUST_SCORE_ADDRESS_MAX_LENGTH) {
return {
ok: false,
message: `Trust score address must not exceed ${TRUST_SCORE_ADDRESS_MAX_LENGTH} characters.`,
}
}
return { ok: true, value: trimmed }
}