@xochi/client 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/LICENSE +21 -0
  3. package/README.md +119 -2
  4. package/dist/cjs/claim.d.ts +33 -0
  5. package/dist/cjs/claim.js +44 -0
  6. package/dist/cjs/fee.d.ts +247 -0
  7. package/dist/cjs/fee.js +295 -0
  8. package/dist/cjs/index.d.ts +18 -0
  9. package/dist/cjs/index.js +33 -0
  10. package/dist/cjs/machine/claimInfo.d.ts +29 -0
  11. package/dist/cjs/machine/claimInfo.js +26 -0
  12. package/dist/cjs/machine/decisions.d.ts +452 -0
  13. package/dist/cjs/machine/decisions.js +665 -0
  14. package/dist/cjs/machine/deposit.d.ts +113 -0
  15. package/dist/cjs/machine/deposit.js +265 -0
  16. package/dist/cjs/machine/index.d.ts +23 -0
  17. package/dist/cjs/machine/index.js +53 -0
  18. package/dist/cjs/machine/machine.d.ts +409 -0
  19. package/dist/cjs/machine/machine.js +1615 -0
  20. package/dist/cjs/machine/phase.d.ts +24 -0
  21. package/dist/cjs/machine/phase.js +45 -0
  22. package/dist/cjs/machine/quoteChecks.d.ts +41 -0
  23. package/dist/cjs/machine/quoteChecks.js +82 -0
  24. package/dist/cjs/machine/receipt.d.ts +151 -0
  25. package/dist/cjs/machine/receipt.js +69 -0
  26. package/dist/cjs/machine/recipientEcho.d.ts +16 -0
  27. package/dist/cjs/machine/recipientEcho.js +27 -0
  28. package/dist/cjs/machine/solverPin.d.ts +110 -0
  29. package/dist/cjs/machine/solverPin.js +214 -0
  30. package/dist/cjs/machine/state.d.ts +167 -0
  31. package/dist/cjs/machine/state.js +31 -0
  32. package/dist/cjs/machine/transition.d.ts +15 -0
  33. package/dist/cjs/machine/transition.js +20 -0
  34. package/dist/cjs/machine/validateRequest.d.ts +15 -0
  35. package/dist/cjs/machine/validateRequest.js +127 -0
  36. package/dist/cjs/machine/view.d.ts +3 -0
  37. package/dist/cjs/machine/view.js +74 -0
  38. package/dist/cjs/machine/wire.d.ts +527 -0
  39. package/dist/cjs/machine/wire.js +280 -0
  40. package/dist/cjs/package.json +1 -0
  41. package/dist/cjs/shared/api.d.ts +9 -0
  42. package/dist/cjs/shared/api.js +5 -0
  43. package/dist/cjs/shared/chains.d.ts +243 -0
  44. package/dist/cjs/shared/chains.js +250 -0
  45. package/dist/cjs/shared/eip712.d.ts +44 -0
  46. package/dist/cjs/shared/eip712.js +64 -0
  47. package/dist/cjs/shared/index.d.ts +15 -0
  48. package/dist/cjs/shared/index.js +31 -0
  49. package/dist/cjs/shared/intentStream.d.ts +74 -0
  50. package/dist/cjs/shared/intentStream.js +59 -0
  51. package/dist/cjs/shared/intents.d.ts +88 -0
  52. package/dist/cjs/shared/intents.js +227 -0
  53. package/dist/cjs/shared/schemas.d.ts +928 -0
  54. package/dist/cjs/shared/schemas.js +524 -0
  55. package/dist/cjs/shared/stealth.d.ts +53 -0
  56. package/dist/cjs/shared/stealth.js +68 -0
  57. package/dist/cjs/shared/trading.d.ts +153 -0
  58. package/dist/cjs/shared/trading.js +185 -0
  59. package/dist/cjs/shared/types.d.ts +37 -0
  60. package/dist/cjs/shared/types.js +7 -0
  61. package/dist/cjs/shared/validators.d.ts +30 -0
  62. package/dist/cjs/shared/validators.js +79 -0
  63. package/dist/cjs/transport/client.d.ts +234 -0
  64. package/dist/cjs/transport/client.js +1456 -0
  65. package/dist/esm/claim.d.ts +33 -0
  66. package/dist/esm/claim.js +41 -0
  67. package/dist/esm/fee.d.ts +247 -0
  68. package/dist/esm/fee.js +285 -0
  69. package/dist/esm/index.d.ts +18 -0
  70. package/dist/esm/index.js +17 -0
  71. package/dist/esm/machine/claimInfo.d.ts +29 -0
  72. package/dist/esm/machine/claimInfo.js +23 -0
  73. package/dist/esm/machine/decisions.d.ts +452 -0
  74. package/dist/esm/machine/decisions.js +640 -0
  75. package/dist/esm/machine/deposit.d.ts +113 -0
  76. package/dist/esm/machine/deposit.js +260 -0
  77. package/dist/esm/machine/index.d.ts +23 -0
  78. package/dist/esm/machine/index.js +23 -0
  79. package/dist/esm/machine/machine.d.ts +409 -0
  80. package/dist/esm/machine/machine.js +1609 -0
  81. package/dist/esm/machine/phase.d.ts +24 -0
  82. package/dist/esm/machine/phase.js +42 -0
  83. package/dist/esm/machine/quoteChecks.d.ts +41 -0
  84. package/dist/esm/machine/quoteChecks.js +78 -0
  85. package/dist/esm/machine/receipt.d.ts +151 -0
  86. package/dist/esm/machine/receipt.js +64 -0
  87. package/dist/esm/machine/recipientEcho.d.ts +16 -0
  88. package/dist/esm/machine/recipientEcho.js +24 -0
  89. package/dist/esm/machine/solverPin.d.ts +110 -0
  90. package/dist/esm/machine/solverPin.js +210 -0
  91. package/dist/esm/machine/state.d.ts +167 -0
  92. package/dist/esm/machine/state.js +28 -0
  93. package/dist/esm/machine/transition.d.ts +15 -0
  94. package/dist/esm/machine/transition.js +17 -0
  95. package/dist/esm/machine/validateRequest.d.ts +15 -0
  96. package/dist/esm/machine/validateRequest.js +123 -0
  97. package/dist/esm/machine/view.d.ts +3 -0
  98. package/dist/esm/machine/view.js +71 -0
  99. package/dist/esm/machine/wire.d.ts +527 -0
  100. package/dist/esm/machine/wire.js +266 -0
  101. package/dist/esm/shared/api.d.ts +9 -0
  102. package/dist/esm/shared/api.js +4 -0
  103. package/dist/esm/shared/chains.d.ts +243 -0
  104. package/dist/esm/shared/chains.js +236 -0
  105. package/dist/esm/shared/eip712.d.ts +44 -0
  106. package/dist/esm/shared/eip712.js +61 -0
  107. package/dist/esm/shared/index.d.ts +15 -0
  108. package/dist/esm/shared/index.js +15 -0
  109. package/dist/esm/shared/intentStream.d.ts +74 -0
  110. package/dist/esm/shared/intentStream.js +55 -0
  111. package/dist/esm/shared/intents.d.ts +88 -0
  112. package/dist/esm/shared/intents.js +213 -0
  113. package/dist/esm/shared/schemas.d.ts +928 -0
  114. package/dist/esm/shared/schemas.js +521 -0
  115. package/dist/esm/shared/stealth.d.ts +53 -0
  116. package/dist/esm/shared/stealth.js +64 -0
  117. package/dist/esm/shared/trading.d.ts +153 -0
  118. package/dist/esm/shared/trading.js +182 -0
  119. package/dist/esm/shared/types.d.ts +37 -0
  120. package/dist/esm/shared/types.js +6 -0
  121. package/dist/esm/shared/validators.d.ts +30 -0
  122. package/dist/esm/shared/validators.js +74 -0
  123. package/dist/esm/transport/client.d.ts +234 -0
  124. package/dist/esm/transport/client.js +1447 -0
  125. package/package.json +61 -4
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Trading Constants
3
+ *
4
+ * Shared trading configuration for slippage, quotes, and limits.
5
+ */
6
+ /** Default slippage in basis points (0.5%) */
7
+ export declare const DEFAULT_SLIPPAGE_BPS = 50;
8
+ /** Available slippage options in basis points */
9
+ export declare const SLIPPAGE_OPTIONS: readonly [10, 50, 100, 200];
10
+ export type SlippageOption = (typeof SLIPPAGE_OPTIONS)[number];
11
+ /** Slippage presets with labels */
12
+ export declare const SLIPPAGE_PRESETS: {
13
+ readonly low: 10;
14
+ readonly medium: 50;
15
+ readonly high: 100;
16
+ };
17
+ /** Quote expiry in seconds */
18
+ export declare const QUOTE_EXPIRY_SEC = 30;
19
+ /** Maximum retries for failed quotes */
20
+ export declare const MAX_QUOTE_RETRIES = 3;
21
+ /** Maximum decimal places for token amounts */
22
+ export declare const MAX_TOKEN_DECIMALS = 18;
23
+ /** Minimum trade amount in USD */
24
+ export declare const MIN_TRADE_USD = 1;
25
+ /** Maximum slippage percentage */
26
+ export declare const MAX_SLIPPAGE_PERCENT = 50;
27
+ /** Minimum slippage percentage */
28
+ export declare const MIN_SLIPPAGE_PERCENT = 0.01;
29
+ /**
30
+ * Hard ceiling on how far below market a fill may be before execution is
31
+ * refused. This is all-in value loss (fees + fixed network minimum + market
32
+ * slippage) versus the live market rate, not the user's configurable slippage
33
+ * tolerance. Protects users from executing trades -- typically dust orders --
34
+ * where costs eat more than half the notional.
35
+ */
36
+ export declare const MAX_PRICE_IMPACT_PERCENT = 50;
37
+ /**
38
+ * Minimum trust score for Aztec L2 shielded settlement (the Private privacy
39
+ * level). L1 stealth (ERC-5564) is NOT trust-gated: privacy is free by default,
40
+ * so any wallet can settle to a one-time stealth address and simply pays its own
41
+ * trust-tier fee. Only the deeper Aztec-shielded tiers -- Private (50+) and
42
+ * Sovereign (75+), both reached via pxe-bridge -- require trust.
43
+ */
44
+ export declare const SHIELDED_MIN_SCORE = 50;
45
+ /** Trust score thresholds by tier */
46
+ export declare const TRUST_THRESHOLDS: {
47
+ readonly trusted: 25;
48
+ readonly verified: 50;
49
+ readonly premium: 75;
50
+ readonly institutional: 100;
51
+ };
52
+ /** Basis points denominator (1 bps = 0.01%) */
53
+ export declare const BPS_DENOMINATOR = 10000;
54
+ /** Maximum deadline offset in seconds (1 hour) */
55
+ export declare const MAX_DEADLINE_OFFSET_SEC = 3600;
56
+ /**
57
+ * Server-side ceiling on a quote request's `deadline`, in seconds from now.
58
+ *
59
+ * Deliberately looser than MAX_DEADLINE_OFFSET_SEC, which is the CLIENT's rule
60
+ * (src/utils/validators.ts) and the value the frontend actually sends. This is
61
+ * the outer bound the API will accept from anyone, sized so an agent or a device
62
+ * with a skewed clock is not rejected for asking a reasonable question.
63
+ *
64
+ * The reason there is a ceiling at all: `deadline` is what the user signs into
65
+ * the intent EIP-712, so an unbounded value is an authorization with no
66
+ * expiry -- and `decideReconcile` treats "past the signed deadline" as the point
67
+ * where an in-doubt intent can no longer move funds.
68
+ */
69
+ export declare const MAX_QUOTE_DEADLINE_FUTURE_SEC: number;
70
+ /**
71
+ * How far in the PAST a quote `deadline` may be and still be accepted, in
72
+ * seconds. Pure clock-skew tolerance: no correct client asks for a deadline that
73
+ * has already passed, but one whose clock is behind might.
74
+ *
75
+ * A past-dated deadline is not inert data: the abandoned-deposit sweep reads
76
+ * `deadline` to decide when a deposit route has died, so `deadline: 1` would
77
+ * mean "terminalise this live route on the next cron tick". The sweep gates on
78
+ * the server-set `created_at` too; this is the other half: the value never
79
+ * gets stored in the first place.
80
+ */
81
+ export declare const MAX_QUOTE_DEADLINE_PAST_SEC = 3600;
82
+ /**
83
+ * Sanity bound on the SOLVER-supplied `deposit_deadline`, in seconds from the
84
+ * quote, applied only when Xochi persists it.
85
+ *
86
+ * The client treats this field as untrusted: `POLL_CEILING_MAX_MS` exists
87
+ * because a malformed or hostile `deposit_deadline` far in the future must not
88
+ * turn the poll into a permanent background request loop. Persisting it makes
89
+ * the server trust it more than the browser does, and it is the PRIMARY gate
90
+ * on the abandoned-deposit sweep (`COALESCE(deposit_deadline, deadline)`), so
91
+ * one bad value -- a misparsed `XOCHI_DEPOSIT_DEADLINE_SECONDS`, a solver bug
92
+ * -- would make every deposit row permanently and silently unsweepable.
93
+ *
94
+ * Riddler's default is 1800s, so this is two orders of magnitude of headroom: it
95
+ * rejects nothing a correctly configured solver can mint. A value outside it is
96
+ * stored as NULL, which degrades the sweep to the quote `deadline` rather than
97
+ * to no gate at all. The value SERVED to the client is never altered -- it is
98
+ * covered by the deposit attestation signature, so changing it would break
99
+ * client-side verification.
100
+ */
101
+ export declare const MAX_DEPOSIT_WINDOW_SEC: number;
102
+ /** Maximum proof age in seconds (1 hour) -- proofs older than this are rejected server-side */
103
+ export declare const MAX_PROOF_AGE_SEC = 3600;
104
+ /** Grace period for rotated provider sets in seconds (24 hours) */
105
+ export declare const PROVIDER_SET_GRACE_PERIOD_SEC = 86400;
106
+ /** Ethereum address length including 0x prefix */
107
+ export declare const ETH_ADDRESS_LENGTH = 42;
108
+ /** Max slippage in basis points */
109
+ export declare const MAX_SLIPPAGE_BPS: number;
110
+ /** Multipliers for attestation scoring within a category */
111
+ export declare const ATTESTATION_MULTIPLIERS: {
112
+ readonly first: 1;
113
+ readonly second: 0.25;
114
+ readonly subsequent: 0.1;
115
+ };
116
+ /** Default query limit for paginated API responses */
117
+ export declare const DEFAULT_QUERY_LIMIT = 50;
118
+ /** Maximum query limit for announcement scanning */
119
+ export declare const MAX_ANNOUNCEMENT_LIMIT = 1000;
120
+ /** Default announcement query limit */
121
+ export declare const DEFAULT_ANNOUNCEMENT_LIMIT = 100;
122
+ /** Rate limit window in milliseconds (15 minutes) */
123
+ export declare const RATE_LIMIT_WINDOW_MS: number;
124
+ /** Maximum rate-limited attempts per window */
125
+ export declare const RATE_LIMIT_MAX_ATTEMPTS = 5;
126
+ /** JWT token expiry in hours */
127
+ export declare const JWT_EXPIRY_HOURS = 4;
128
+ /** Tier proof expiry in milliseconds (7 days) */
129
+ export declare const TIER_PROOF_EXPIRY_MS: number;
130
+ /** Max rate limit store size before cleanup */
131
+ export declare const RATE_LIMIT_STORE_MAX = 10000;
132
+ /** Base delay for failed auth in milliseconds */
133
+ export declare const AUTH_FAILURE_BASE_DELAY_MS = 500;
134
+ /** Max delay for failed auth in milliseconds */
135
+ export declare const AUTH_FAILURE_MAX_DELAY_MS = 5000;
136
+ /** Max demo code length */
137
+ export declare const MAX_DEMO_CODE_LENGTH = 100;
138
+ /** Mock spread factor (1% spread = 99/100) */
139
+ export declare const MOCK_SPREAD_NUMERATOR = 99n;
140
+ export declare const MOCK_SPREAD_DENOMINATOR = 100n;
141
+ /** All trading constants in one object */
142
+ export declare const TRADING: {
143
+ readonly defaultSlippageBps: 50;
144
+ readonly slippageOptions: readonly [10, 50, 100, 200];
145
+ readonly quoteExpirySec: 30;
146
+ readonly maxQuoteRetries: 3;
147
+ readonly maxTokenDecimals: 18;
148
+ readonly minTradeUsd: 1;
149
+ readonly maxSlippagePercent: 50;
150
+ readonly minSlippagePercent: 0.01;
151
+ readonly maxPriceImpactPercent: 50;
152
+ readonly shieldedMinScore: 50;
153
+ };
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Trading Constants
3
+ *
4
+ * Shared trading configuration for slippage, quotes, and limits.
5
+ */
6
+ // ============================================================
7
+ // Slippage Configuration
8
+ // ============================================================
9
+ /** Default slippage in basis points (0.5%) */
10
+ export const DEFAULT_SLIPPAGE_BPS = 50;
11
+ /** Available slippage options in basis points */
12
+ export const SLIPPAGE_OPTIONS = [10, 50, 100, 200];
13
+ /** Slippage presets with labels */
14
+ export const SLIPPAGE_PRESETS = {
15
+ low: 10, // 0.1%
16
+ medium: 50, // 0.5%
17
+ high: 100, // 1%
18
+ };
19
+ // ============================================================
20
+ // Quote Configuration
21
+ // ============================================================
22
+ /** Quote expiry in seconds */
23
+ export const QUOTE_EXPIRY_SEC = 30;
24
+ /** Maximum retries for failed quotes */
25
+ export const MAX_QUOTE_RETRIES = 3;
26
+ // ============================================================
27
+ // Trading Limits
28
+ // ============================================================
29
+ /** Maximum decimal places for token amounts */
30
+ export const MAX_TOKEN_DECIMALS = 18;
31
+ /** Minimum trade amount in USD */
32
+ export const MIN_TRADE_USD = 1;
33
+ /** Maximum slippage percentage */
34
+ export const MAX_SLIPPAGE_PERCENT = 50;
35
+ /** Minimum slippage percentage */
36
+ export const MIN_SLIPPAGE_PERCENT = 0.01;
37
+ /**
38
+ * Hard ceiling on how far below market a fill may be before execution is
39
+ * refused. This is all-in value loss (fees + fixed network minimum + market
40
+ * slippage) versus the live market rate, not the user's configurable slippage
41
+ * tolerance. Protects users from executing trades -- typically dust orders --
42
+ * where costs eat more than half the notional.
43
+ */
44
+ export const MAX_PRICE_IMPACT_PERCENT = 50;
45
+ // ============================================================
46
+ // Trust Thresholds
47
+ // ============================================================
48
+ /**
49
+ * Minimum trust score for Aztec L2 shielded settlement (the Private privacy
50
+ * level). L1 stealth (ERC-5564) is NOT trust-gated: privacy is free by default,
51
+ * so any wallet can settle to a one-time stealth address and simply pays its own
52
+ * trust-tier fee. Only the deeper Aztec-shielded tiers -- Private (50+) and
53
+ * Sovereign (75+), both reached via pxe-bridge -- require trust.
54
+ */
55
+ export const SHIELDED_MIN_SCORE = 50;
56
+ /** Trust score thresholds by tier */
57
+ export const TRUST_THRESHOLDS = {
58
+ trusted: 25,
59
+ verified: 50,
60
+ premium: 75,
61
+ institutional: 100,
62
+ };
63
+ // ============================================================
64
+ // Numeric Constants
65
+ // ============================================================
66
+ /** Basis points denominator (1 bps = 0.01%) */
67
+ export const BPS_DENOMINATOR = 10_000;
68
+ /** Maximum deadline offset in seconds (1 hour) */
69
+ export const MAX_DEADLINE_OFFSET_SEC = 3600;
70
+ /**
71
+ * Server-side ceiling on a quote request's `deadline`, in seconds from now.
72
+ *
73
+ * Deliberately looser than MAX_DEADLINE_OFFSET_SEC, which is the CLIENT's rule
74
+ * (src/utils/validators.ts) and the value the frontend actually sends. This is
75
+ * the outer bound the API will accept from anyone, sized so an agent or a device
76
+ * with a skewed clock is not rejected for asking a reasonable question.
77
+ *
78
+ * The reason there is a ceiling at all: `deadline` is what the user signs into
79
+ * the intent EIP-712, so an unbounded value is an authorization with no
80
+ * expiry -- and `decideReconcile` treats "past the signed deadline" as the point
81
+ * where an in-doubt intent can no longer move funds.
82
+ */
83
+ export const MAX_QUOTE_DEADLINE_FUTURE_SEC = 24 * 3600;
84
+ /**
85
+ * How far in the PAST a quote `deadline` may be and still be accepted, in
86
+ * seconds. Pure clock-skew tolerance: no correct client asks for a deadline that
87
+ * has already passed, but one whose clock is behind might.
88
+ *
89
+ * A past-dated deadline is not inert data: the abandoned-deposit sweep reads
90
+ * `deadline` to decide when a deposit route has died, so `deadline: 1` would
91
+ * mean "terminalise this live route on the next cron tick". The sweep gates on
92
+ * the server-set `created_at` too; this is the other half: the value never
93
+ * gets stored in the first place.
94
+ */
95
+ export const MAX_QUOTE_DEADLINE_PAST_SEC = 3600;
96
+ /**
97
+ * Sanity bound on the SOLVER-supplied `deposit_deadline`, in seconds from the
98
+ * quote, applied only when Xochi persists it.
99
+ *
100
+ * The client treats this field as untrusted: `POLL_CEILING_MAX_MS` exists
101
+ * because a malformed or hostile `deposit_deadline` far in the future must not
102
+ * turn the poll into a permanent background request loop. Persisting it makes
103
+ * the server trust it more than the browser does, and it is the PRIMARY gate
104
+ * on the abandoned-deposit sweep (`COALESCE(deposit_deadline, deadline)`), so
105
+ * one bad value -- a misparsed `XOCHI_DEPOSIT_DEADLINE_SECONDS`, a solver bug
106
+ * -- would make every deposit row permanently and silently unsweepable.
107
+ *
108
+ * Riddler's default is 1800s, so this is two orders of magnitude of headroom: it
109
+ * rejects nothing a correctly configured solver can mint. A value outside it is
110
+ * stored as NULL, which degrades the sweep to the quote `deadline` rather than
111
+ * to no gate at all. The value SERVED to the client is never altered -- it is
112
+ * covered by the deposit attestation signature, so changing it would break
113
+ * client-side verification.
114
+ */
115
+ export const MAX_DEPOSIT_WINDOW_SEC = 24 * 3600;
116
+ /** Maximum proof age in seconds (1 hour) -- proofs older than this are rejected server-side */
117
+ export const MAX_PROOF_AGE_SEC = 3600;
118
+ /** Grace period for rotated provider sets in seconds (24 hours) */
119
+ export const PROVIDER_SET_GRACE_PERIOD_SEC = 86400;
120
+ /** Ethereum address length including 0x prefix */
121
+ export const ETH_ADDRESS_LENGTH = 42;
122
+ /** Max slippage in basis points */
123
+ export const MAX_SLIPPAGE_BPS = MAX_SLIPPAGE_PERCENT * 100;
124
+ // ============================================================
125
+ // Attestation Diminishing Returns
126
+ // ============================================================
127
+ /** Multipliers for attestation scoring within a category */
128
+ export const ATTESTATION_MULTIPLIERS = {
129
+ first: 1.0,
130
+ second: 0.25,
131
+ subsequent: 0.1,
132
+ };
133
+ // ============================================================
134
+ // Query Limits
135
+ // ============================================================
136
+ /** Default query limit for paginated API responses */
137
+ export const DEFAULT_QUERY_LIMIT = 50;
138
+ /** Maximum query limit for announcement scanning */
139
+ export const MAX_ANNOUNCEMENT_LIMIT = 1000;
140
+ /** Default announcement query limit */
141
+ export const DEFAULT_ANNOUNCEMENT_LIMIT = 100;
142
+ // ============================================================
143
+ // Auth & Rate Limiting
144
+ // ============================================================
145
+ /** Rate limit window in milliseconds (15 minutes) */
146
+ export const RATE_LIMIT_WINDOW_MS = 15 * 60 * 1000;
147
+ /** Maximum rate-limited attempts per window */
148
+ export const RATE_LIMIT_MAX_ATTEMPTS = 5;
149
+ /** JWT token expiry in hours */
150
+ export const JWT_EXPIRY_HOURS = 4;
151
+ /** Tier proof expiry in milliseconds (7 days) */
152
+ export const TIER_PROOF_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;
153
+ /** Max rate limit store size before cleanup */
154
+ export const RATE_LIMIT_STORE_MAX = 10_000;
155
+ /** Base delay for failed auth in milliseconds */
156
+ export const AUTH_FAILURE_BASE_DELAY_MS = 500;
157
+ /** Max delay for failed auth in milliseconds */
158
+ export const AUTH_FAILURE_MAX_DELAY_MS = 5000;
159
+ /** Max demo code length */
160
+ export const MAX_DEMO_CODE_LENGTH = 100;
161
+ // ============================================================
162
+ // Mock Spread
163
+ // ============================================================
164
+ /** Mock spread factor (1% spread = 99/100) */
165
+ export const MOCK_SPREAD_NUMERATOR = 99n;
166
+ export const MOCK_SPREAD_DENOMINATOR = 100n;
167
+ // ============================================================
168
+ // Bundled Trading Config
169
+ // ============================================================
170
+ /** All trading constants in one object */
171
+ export const TRADING = {
172
+ defaultSlippageBps: DEFAULT_SLIPPAGE_BPS,
173
+ slippageOptions: SLIPPAGE_OPTIONS,
174
+ quoteExpirySec: QUOTE_EXPIRY_SEC,
175
+ maxQuoteRetries: MAX_QUOTE_RETRIES,
176
+ maxTokenDecimals: MAX_TOKEN_DECIMALS,
177
+ minTradeUsd: MIN_TRADE_USD,
178
+ maxSlippagePercent: MAX_SLIPPAGE_PERCENT,
179
+ minSlippagePercent: MIN_SLIPPAGE_PERCENT,
180
+ maxPriceImpactPercent: MAX_PRICE_IMPACT_PERCENT,
181
+ shieldedMinScore: SHIELDED_MIN_SCORE,
182
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared Types
3
+ *
4
+ * Type definitions used across frontend and backend.
5
+ */
6
+ /** Lowercase tier id used on the wire + in the fee breakdown. */
7
+ export type Tier = "standard" | "trusted" | "verified" | "premium" | "institutional";
8
+ /**
9
+ * Itemized fee breakdown for a quote (economics.md Part 1, "Frontend display spec").
10
+ * Three additive layers on a never-discounted cost floor: solver spread + gas
11
+ * floor (Riddler), venue fee (Xochi), routing fee (Raxol -> buyback). Amounts are
12
+ * destination-token smallest units (strings); rates are bps. Discounts carve
13
+ * venue + routing only, never the solver floor.
14
+ */
15
+ export interface FeeBreakdown {
16
+ tier: Tier;
17
+ assetClass: "stable" | "volatile";
18
+ /** Guaranteed minimum, never discounted (Riddler). */
19
+ gasFloor: {
20
+ amount: string;
21
+ usd: string;
22
+ };
23
+ solverFeeBps: number;
24
+ solverFee: string;
25
+ /** > 0 only on large-vs-depth fills; render as a warning, not a fee. */
26
+ priceImpactBps: number;
27
+ priceImpact: string;
28
+ venueFeeBps: number;
29
+ venueFee: string;
30
+ routingFeeBps: number;
31
+ routingFee: string;
32
+ totalBps: number;
33
+ totalFee: string;
34
+ totalUsd: string;
35
+ /** 15 -- solver upside on positive slippage; the user keeps the other 85%. */
36
+ surplusSharePct: number;
37
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared Types
3
+ *
4
+ * Type definitions used across frontend and backend.
5
+ */
6
+ export {};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Validators
3
+ *
4
+ * Address validators: EVM hex20 and checksummed Tron base58.
5
+ */
6
+ /** Ethereum address regex pattern */
7
+ export declare const ETH_ADDRESS_REGEX: RegExp;
8
+ /** Zero address constant */
9
+ export declare const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
10
+ /** Check if string is a valid Ethereum address */
11
+ export declare function isValidAddress(address: string): boolean;
12
+ /**
13
+ * Tron mainnet address shape: 34 chars, leading "T", base58 alphabet (no
14
+ * 0/O/I/l). Shape alone is NOT sufficient to accept an address -- see
15
+ * `isValidTronAddress`, which also verifies the base58check checksum.
16
+ */
17
+ export declare const TRON_ADDRESS_REGEX: RegExp;
18
+ /**
19
+ * Validate a Tron address, checksum included.
20
+ *
21
+ * The shape regex alone accepts any typo that keeps the length and alphabet,
22
+ * which is nearly all of them. Base58check carries a 4-byte checksum, so a
23
+ * mistyped address survives it with probability about 1 in 4 billion. That
24
+ * matters here specifically because a Tron payout recipient is typed by hand on
25
+ * an EVM-origin swap: there is no Tron wallet in the flow to catch it later, and
26
+ * a TRC-20 transfer to a well-formed but unowned address is irrecoverable.
27
+ *
28
+ * Checksum = first 4 bytes of sha256(sha256(0x41 || address_bytes)).
29
+ */
30
+ export declare function isValidTronAddress(address: string): boolean;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Validators
3
+ *
4
+ * Address validators: EVM hex20 and checksummed Tron base58.
5
+ */
6
+ import { sha256 } from "viem";
7
+ // ============================================================
8
+ // Address Validation
9
+ // ============================================================
10
+ /** Ethereum address regex pattern */
11
+ export const ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
12
+ /** Zero address constant */
13
+ export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
14
+ /** Check if string is a valid Ethereum address */
15
+ export function isValidAddress(address) {
16
+ return ETH_ADDRESS_REGEX.test(address);
17
+ }
18
+ /**
19
+ * Tron mainnet address shape: 34 chars, leading "T", base58 alphabet (no
20
+ * 0/O/I/l). Shape alone is NOT sufficient to accept an address -- see
21
+ * `isValidTronAddress`, which also verifies the base58check checksum.
22
+ */
23
+ export const TRON_ADDRESS_REGEX = /^T[1-9A-HJ-NP-Za-km-z]{33}$/;
24
+ const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
25
+ /** Decoded Tron address: 0x41 prefix + 20 address bytes + 4 checksum bytes. */
26
+ const TRON_DECODED_BYTES = 25;
27
+ const TRON_ADDRESS_PREFIX = 0x41;
28
+ /** Decode base58 into bytes. Returns null on any character outside the alphabet. */
29
+ function base58Decode(input) {
30
+ let acc = 0n;
31
+ for (const char of input) {
32
+ const digit = BASE58_ALPHABET.indexOf(char);
33
+ if (digit < 0)
34
+ return null;
35
+ acc = acc * 58n + BigInt(digit);
36
+ }
37
+ const bytes = [];
38
+ while (acc > 0n) {
39
+ bytes.unshift(Number(acc % 256n));
40
+ acc /= 256n;
41
+ }
42
+ // Every leading '1' in base58 encodes one leading zero byte.
43
+ for (const char of input) {
44
+ if (char !== BASE58_ALPHABET[0])
45
+ break;
46
+ bytes.unshift(0);
47
+ }
48
+ return Uint8Array.from(bytes);
49
+ }
50
+ /**
51
+ * Validate a Tron address, checksum included.
52
+ *
53
+ * The shape regex alone accepts any typo that keeps the length and alphabet,
54
+ * which is nearly all of them. Base58check carries a 4-byte checksum, so a
55
+ * mistyped address survives it with probability about 1 in 4 billion. That
56
+ * matters here specifically because a Tron payout recipient is typed by hand on
57
+ * an EVM-origin swap: there is no Tron wallet in the flow to catch it later, and
58
+ * a TRC-20 transfer to a well-formed but unowned address is irrecoverable.
59
+ *
60
+ * Checksum = first 4 bytes of sha256(sha256(0x41 || address_bytes)).
61
+ */
62
+ export function isValidTronAddress(address) {
63
+ if (!TRON_ADDRESS_REGEX.test(address))
64
+ return false;
65
+ const decoded = base58Decode(address);
66
+ if (!decoded || decoded.length !== TRON_DECODED_BYTES)
67
+ return false;
68
+ if (decoded[0] !== TRON_ADDRESS_PREFIX)
69
+ return false;
70
+ const payload = decoded.subarray(0, 21);
71
+ const checksum = decoded.subarray(21);
72
+ const digest = sha256(sha256(payload, "bytes"), "bytes");
73
+ return checksum.every((byte, i) => byte === digest[i]);
74
+ }