@coinlist-co/react 0.10.1 → 0.11.1-rc.10770e8
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.
- package/README.md +32 -0
- package/dist/chunk-7CTH4KPU.js +2399 -0
- package/dist/chunk-7CTH4KPU.js.map +1 -0
- package/dist/{chunk-AQVCOWOV.js → chunk-LSPZETDH.js} +249 -317
- package/dist/chunk-LSPZETDH.js.map +1 -0
- package/dist/chunk-UZUQALFY.js +279 -0
- package/dist/chunk-UZUQALFY.js.map +1 -0
- package/dist/client/index.cjs +13430 -3308
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +5486 -899
- package/dist/client/index.d.ts +5486 -899
- package/dist/client/index.js +11025 -2388
- package/dist/client/index.js.map +1 -1
- package/dist/collections-BBI_XydI.d.cts +116 -0
- package/dist/collections-BrX9rRWc.d.ts +116 -0
- package/dist/config-CMl1bR3F.d.cts +2959 -0
- package/dist/config-CMl1bR3F.d.ts +2959 -0
- package/dist/server/index.cjs +1768 -511
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +266 -162
- package/dist/server/index.d.ts +266 -162
- package/dist/server/index.js +235 -169
- package/dist/server/index.js.map +1 -1
- package/dist/shared/index.cjs +2423 -926
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.d.cts +325 -132
- package/dist/shared/index.d.ts +325 -132
- package/dist/shared/index.js +112 -28
- package/package.json +12 -8
- package/dist/chunk-AQVCOWOV.js.map +0 -1
- package/dist/chunk-TBU3EBNM.js +0 -442
- package/dist/chunk-TBU3EBNM.js.map +0 -1
- package/dist/chunk-UOHD7US2.js +0 -855
- package/dist/chunk-UOHD7US2.js.map +0 -1
- package/dist/collections-Bv1Oxzu_.d.ts +0 -28
- package/dist/collections-DDyxbOPZ.d.cts +0 -28
- package/dist/requirement-oVZA1INj.d.cts +0 -1040
- package/dist/requirement-oVZA1INj.d.ts +0 -1040
|
@@ -0,0 +1,2959 @@
|
|
|
1
|
+
import { Hash, Hex } from 'viem';
|
|
2
|
+
|
|
3
|
+
declare const __brand: unique symbol;
|
|
4
|
+
type Newtype<Base, Branding> = Base & {
|
|
5
|
+
readonly [__brand]: Branding;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type AuthorizationCode = Newtype<string, 'AuthorizationCode'>;
|
|
9
|
+
declare const AuthorizationCode: (value: string) => AuthorizationCode;
|
|
10
|
+
type CodeVerifier = Newtype<string, 'CodeVerifier'>;
|
|
11
|
+
declare const CodeVerifier: (value: string) => CodeVerifier;
|
|
12
|
+
type CodeChallenge = Newtype<string, 'CodeChallenge'>;
|
|
13
|
+
declare const CodeChallenge: (value: string) => CodeChallenge;
|
|
14
|
+
type PKCEState = Newtype<string, 'PKCEState'>;
|
|
15
|
+
declare const PKCEState: (value: string) => PKCEState;
|
|
16
|
+
type RedirectUri = Newtype<string, 'RedirectUri'>;
|
|
17
|
+
declare const RedirectUri: (value: string) => RedirectUri;
|
|
18
|
+
type ClientId = Newtype<string, 'ClientId'>;
|
|
19
|
+
declare const ClientId: (value: string) => ClientId;
|
|
20
|
+
type ClientSecret = Newtype<string, 'ClientSecret'>;
|
|
21
|
+
declare const ClientSecret: (value: string) => ClientSecret;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A classified wallet or transaction failure. The SDK derives this from
|
|
25
|
+
* whatever the {@link EvmWallet} throws, so hosts get a stable, typed error
|
|
26
|
+
* shape regardless of the wallet library underneath.
|
|
27
|
+
*
|
|
28
|
+
* Lives here rather than beside its classifier because it is the failure half
|
|
29
|
+
* of the {@link EvmWallet} contract, and because both `@/shared` and
|
|
30
|
+
* `@/client` name it: {@link LogCause} carries one, and classifying a thrown
|
|
31
|
+
* error into one needs viem's error classes, which are browser-side.
|
|
32
|
+
*/
|
|
33
|
+
type WalletError = {
|
|
34
|
+
type: 'user_rejected';
|
|
35
|
+
} | {
|
|
36
|
+
type: 'insufficient_funds';
|
|
37
|
+
} | {
|
|
38
|
+
type: 'contract_reverted';
|
|
39
|
+
/**
|
|
40
|
+
* What the contract said, when it said anything: a `require` string, a
|
|
41
|
+
* panic description, a custom error's name, or the four-byte selector of
|
|
42
|
+
* an error the ABI could not decode.
|
|
43
|
+
*
|
|
44
|
+
* `null` when a revert carried no data, since the string the RPC node
|
|
45
|
+
* offers in its place is not the contract's - see `classifyWalletError`.
|
|
46
|
+
* Nullable rather than optional so that every arm has to answer the
|
|
47
|
+
* question: "it reverted and said nothing" is a fact about the revert,
|
|
48
|
+
* and a caller should have to read it rather than miss it.
|
|
49
|
+
*
|
|
50
|
+
* Never the custom error's arguments. A name is a compile-time
|
|
51
|
+
* identifier; its operands are runtime values - an address, a balance -
|
|
52
|
+
* and those are `'debug'` material.
|
|
53
|
+
*/
|
|
54
|
+
reason: string | null;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'timeout';
|
|
57
|
+
hash: Hash;
|
|
58
|
+
} | {
|
|
59
|
+
type: 'unknown';
|
|
60
|
+
cause: unknown;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* A {@link WalletError} as it may be reported above `'debug'`: the
|
|
64
|
+
* classification, never the throw.
|
|
65
|
+
*
|
|
66
|
+
* Only the `unknown` arm differs, and it differs because it is the one arm
|
|
67
|
+
* carrying a value the SDK did not author - the raw error the wallet library
|
|
68
|
+
* threw, whose message and metadata hold the transaction's `from`, `to`,
|
|
69
|
+
* `value` and calldata. The other four carry compile-time constants or a
|
|
70
|
+
* server-minted identifier already, so they pass through as they stand.
|
|
71
|
+
*
|
|
72
|
+
* This exists as a type rather than as a scrub some function remembers to
|
|
73
|
+
* apply: `LogCause` names it, so an arm that grew a raw field would fail the
|
|
74
|
+
* build instead of quietly reaching {@link Logger.error}.
|
|
75
|
+
*/
|
|
76
|
+
type RedactedWalletError = Exclude<WalletError, {
|
|
77
|
+
type: 'unknown';
|
|
78
|
+
}> | {
|
|
79
|
+
type: 'unknown';
|
|
80
|
+
};
|
|
81
|
+
declare const RedactedWalletError: {
|
|
82
|
+
fromWalletError: (error: WalletError) => RedactedWalletError;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The observability seam a host implements to see inside the SDK.
|
|
87
|
+
*
|
|
88
|
+
* Pass an implementation as {@link Config.logger} and the SDK reports every
|
|
89
|
+
* request it makes, every failure it classifies, and every state a hook
|
|
90
|
+
* settles into. Leave it out and the SDK logs nothing at all - there is no
|
|
91
|
+
* fallback to `console`, at any level, on any codepath.
|
|
92
|
+
*
|
|
93
|
+
* Four methods over a {@link LogEvent} lambda, plus {@link level}. An event is
|
|
94
|
+
* a constant `msg`, the {@link LogScope} it came from, the accumulated
|
|
95
|
+
* {@link LogBindings}, and a bag of `fields` - so a host forwards structured
|
|
96
|
+
* records rather than parsing strings.
|
|
97
|
+
*
|
|
98
|
+
* ```ts
|
|
99
|
+
* const logger: Logger = {
|
|
100
|
+
* level: () => 'info',
|
|
101
|
+
* debug: () => {},
|
|
102
|
+
* info: (event) => sink.info(toRecord(event())),
|
|
103
|
+
* warn: (event) => sink.warn(toRecord(event())),
|
|
104
|
+
* error: (event) => sink.error(toRecord(event())),
|
|
105
|
+
* };
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* {@link pinoClientLogger} and {@link pinoServerLogger} are ready-made
|
|
109
|
+
* implementations over pino, and are what most hosts should reach for.
|
|
110
|
+
*
|
|
111
|
+
* ## Where to run it
|
|
112
|
+
*
|
|
113
|
+
* **Not in production, as the default answer.** Development, tests, staging,
|
|
114
|
+
* and reproducing a reported bug are where this seam earns its keep. Left
|
|
115
|
+
* undefined elsewhere it discloses nothing, and that holds no matter what a
|
|
116
|
+
* later revision of the SDK puts on a line.
|
|
117
|
+
*
|
|
118
|
+
* Where you do run one in production, `'info'` and above is the only sane
|
|
119
|
+
* choice, and the shipped implementations make the alternative unrepresentable
|
|
120
|
+
* rather than merely discouraged: `isDev: false` narrows the level to
|
|
121
|
+
* {@link ProductionLogLevel}, so `'debug'` does not compile. That narrowing is
|
|
122
|
+
* a guard for the partner who ignored this paragraph, not an endorsement of
|
|
123
|
+
* the practice.
|
|
124
|
+
*
|
|
125
|
+
* The distinction worth holding onto: `'info'` and above are **redacted by
|
|
126
|
+
* construction** - see the next section for exactly what that covers, and the
|
|
127
|
+
* type that enforces it. Redacted is a mechanism the SDK can hold itself to. A
|
|
128
|
+
* blanket "safe in production" is a promise about your environment that the
|
|
129
|
+
* SDK is in no position to make, and one that a single future field could
|
|
130
|
+
* quietly break.
|
|
131
|
+
*
|
|
132
|
+
* `'debug'` is for reproducing a bug: a developer's machine, tests, and beta
|
|
133
|
+
* or staging environments where the data flowing through the SDK is not real
|
|
134
|
+
* customer data.
|
|
135
|
+
*
|
|
136
|
+
* ## What each level may disclose
|
|
137
|
+
*
|
|
138
|
+
* **`'debug'` is unredacted. Every other level is not.**
|
|
139
|
+
*
|
|
140
|
+
* At `'debug'` the SDK reports request and response bodies, request headers,
|
|
141
|
+
* the full URL including its query string, and operation parameters
|
|
142
|
+
* **verbatim** - bearer tokens, KYC answers, tax-document fields, wallet
|
|
143
|
+
* signatures, the lot. There is no denylist and no redaction: see ADR-8 for
|
|
144
|
+
* why a partial guarantee was rejected in favour of an honest absence of one.
|
|
145
|
+
*
|
|
146
|
+
* At `'info'`, `'warn'` and `'error'` the SDK emits only its own
|
|
147
|
+
* classification of what happened and identifiers the server minted: a method
|
|
148
|
+
* and a bare path, a status, a duration, a {@link RequestId}, a frontline
|
|
149
|
+
* error code and event id, a {@link LogCause} arm. No request body, no
|
|
150
|
+
* response body, no query string, no host-supplied parameters, and no message
|
|
151
|
+
* text read off a thrown error the SDK did not author.
|
|
152
|
+
*
|
|
153
|
+
* The type carries that boundary rather than merely documenting it:
|
|
154
|
+
* {@link SafeEvent} constrains every field value to a {@link LogValue} scalar,
|
|
155
|
+
* so spreading a body, a DTO or an operation's params into an `info`, `warn`
|
|
156
|
+
* or `error` line does not compile. Only {@link DebugEvent} accepts arbitrary
|
|
157
|
+
* values.
|
|
158
|
+
*
|
|
159
|
+
* The one deliberate exception is an SDK-authored validation message, which
|
|
160
|
+
* quotes the single scalar that failed to map - `Unsupported chain:
|
|
161
|
+
* "solana_mainnet"`. It is a hand-written template naming one offending value,
|
|
162
|
+
* not a payload, and it is the whole reason this seam exists.
|
|
163
|
+
*
|
|
164
|
+
* ## Your responsibility
|
|
165
|
+
*
|
|
166
|
+
* The SDK hands you events. What happens next is yours: **you own the final
|
|
167
|
+
* filtering, redaction and retention** before anything is written to a file, a
|
|
168
|
+
* console, or a third-party sink such as Sentry or Datadog. In particular, if
|
|
169
|
+
* you implement {@link debug} and forward it anywhere durable, you have taken
|
|
170
|
+
* on storing live credentials and personal data, deliberately. Implement
|
|
171
|
+
* `debug` as a no-op - or return a level below it from {@link level} - in any
|
|
172
|
+
* environment where that is not acceptable.
|
|
173
|
+
*
|
|
174
|
+
* **Every event is a lambda, and that is load bearing.** The SDK consults
|
|
175
|
+
* {@link level} first and never invokes the lambda when the level forbids it,
|
|
176
|
+
* so an expensive debug event - a serialized DTO, a loop over balances - costs
|
|
177
|
+
* nothing in production where the level is `'error'` or `'none'`. Build the
|
|
178
|
+
* event inside the lambda, never outside it.
|
|
179
|
+
*
|
|
180
|
+
* ## Every method must be total
|
|
181
|
+
*
|
|
182
|
+
* **None of the five methods may throw, and that includes {@link level}.** The
|
|
183
|
+
* SDK calls them inline, on the codepath of the work it is reporting, and it
|
|
184
|
+
* does not catch them: a `logger.error` that throws while reporting a failed
|
|
185
|
+
* request turns that request's rejection into your logger's exception, and a
|
|
186
|
+
* `level()` that throws breaks the call it was asked about even when nothing
|
|
187
|
+
* else went wrong.
|
|
188
|
+
*
|
|
189
|
+
* That is deliberate. Swallowing would hide a logger that is broken in every
|
|
190
|
+
* environment, and the SDK cannot tell a transport blip in your sink from a
|
|
191
|
+
* bug in your implementation. So the contract is on this side of the seam:
|
|
192
|
+
* catch inside your implementation, and never let an exception out. The
|
|
193
|
+
* shipped pino implementations do exactly that.
|
|
194
|
+
*
|
|
195
|
+
* ```ts
|
|
196
|
+
* error: (event) => {
|
|
197
|
+
* try {
|
|
198
|
+
* const e = event();
|
|
199
|
+
* Sentry.captureMessage(e.msg, { extra: e });
|
|
200
|
+
* } catch {
|
|
201
|
+
* // never rethrow: the SDK is on the other side of this call
|
|
202
|
+
* }
|
|
203
|
+
* },
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
interface Logger {
|
|
207
|
+
/**
|
|
208
|
+
* The most detailed level this logger wants. Consulted before **every** log
|
|
209
|
+
* call, so keep it cheap and pure: return a captured constant or read a
|
|
210
|
+
* plain field. Do not read an environment variable, hit storage, or call
|
|
211
|
+
* out to a feature-flag service here.
|
|
212
|
+
*
|
|
213
|
+
* Returning `'none'` silences the SDK as completely as omitting the logger.
|
|
214
|
+
*
|
|
215
|
+
* **Must not throw.** It is consulted inside every SDK operation, so an
|
|
216
|
+
* exception here fails the operation itself.
|
|
217
|
+
*/
|
|
218
|
+
level(): LogLevel;
|
|
219
|
+
/**
|
|
220
|
+
* Fine-grained detail: request and response bodies, full URLs, headers,
|
|
221
|
+
* operation parameters, hook transitions.
|
|
222
|
+
*
|
|
223
|
+
* **Unredacted.** This is the only level that may carry credentials or
|
|
224
|
+
* personal data, and it always may. Its event is a {@link DebugEvent}, whose
|
|
225
|
+
* fields accept arbitrary values for exactly that reason. Do not forward it
|
|
226
|
+
* to a durable or third-party sink outside development and beta.
|
|
227
|
+
*
|
|
228
|
+
* **Must not throw**, here and on every method below.
|
|
229
|
+
*/
|
|
230
|
+
debug(event: () => DebugEvent): void;
|
|
231
|
+
/** Notable, expected events: a request completing, a flow advancing. */
|
|
232
|
+
info(event: () => SafeEvent): void;
|
|
233
|
+
/**
|
|
234
|
+
* Recoverable trouble: a retried request, a renewed session, a poll tick
|
|
235
|
+
* that failed while the last value still stands.
|
|
236
|
+
*
|
|
237
|
+
* Carries a {@link LogCause} when one was classified, the same as
|
|
238
|
+
* {@link error} does. What separates the two levels is whether anything
|
|
239
|
+
* actually broke, not how much is known about it.
|
|
240
|
+
*/
|
|
241
|
+
warn(event: () => SafeEvent): void;
|
|
242
|
+
/**
|
|
243
|
+
* A failure. {@link SafeEvent.cause} carries what the SDK knows about it,
|
|
244
|
+
* classified into {@link LogCause}, and is absent when the failure is not an
|
|
245
|
+
* error the SDK caught - a flow reporting the step it stopped at, for
|
|
246
|
+
* instance.
|
|
247
|
+
*
|
|
248
|
+
* Every part of the event is SDK-authored classification or server-authored
|
|
249
|
+
* identifiers, so forwarding it as it stands is safe. `scope` says which
|
|
250
|
+
* part of the SDK the line came from, which is what to route or filter on.
|
|
251
|
+
*/
|
|
252
|
+
error(event: () => SafeEvent): void;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* A value the SDK is willing to put in a structured field above `'debug'`.
|
|
256
|
+
*
|
|
257
|
+
* Scalars only, and that is the redaction boundary made structural rather than
|
|
258
|
+
* documentary. Every leak ADR-8 found was an *object* spread onto a line that
|
|
259
|
+
* a host forwards to a tracker - an operation's params, a thrown wallet error,
|
|
260
|
+
* a response body. None of them is assignable to this, so each is now a
|
|
261
|
+
* compile error rather than a review catch.
|
|
262
|
+
*
|
|
263
|
+
* It does not stop a call site writing `{ token: accessToken }`, and it is not
|
|
264
|
+
* meant to: a string is a string. What it stops is the mistake that actually
|
|
265
|
+
* happened.
|
|
266
|
+
*/
|
|
267
|
+
type LogValue = string | number | boolean | null;
|
|
268
|
+
/**
|
|
269
|
+
* Fields safe at every level: SDK-authored classification and server-minted
|
|
270
|
+
* identifiers, constrained to {@link LogValue}.
|
|
271
|
+
*/
|
|
272
|
+
type SafeFields = Readonly<Record<string, LogValue>>;
|
|
273
|
+
/**
|
|
274
|
+
* Fields for `'debug'` only: bodies, headers, full URLs, operation params,
|
|
275
|
+
* raw thrown values. Arbitrary values, because that is the point of the level.
|
|
276
|
+
*
|
|
277
|
+
* The SDK's own implementations render these into a form that cannot fail to
|
|
278
|
+
* serialize - a `bigint`, a cycle or a getter that throws must never turn a
|
|
279
|
+
* log line into a second failure - but they are otherwise passed through.
|
|
280
|
+
*/
|
|
281
|
+
type UnredactedFields = Readonly<Record<string, unknown>>;
|
|
282
|
+
/**
|
|
283
|
+
* One narrowing applied to a logger by {@link InternalLogger.child}.
|
|
284
|
+
*
|
|
285
|
+
* A union of single-key objects rather than a positional `string`, because the
|
|
286
|
+
* three things the SDK narrows by are not the same kind of thing: a request id
|
|
287
|
+
* correlates retries of one wire call, a flow name names an on-chain
|
|
288
|
+
* procedure, a hook name names a React binding. Rendered into one `[SCOPE:x]`
|
|
289
|
+
* prefix they were indistinguishable; as fields they must not be.
|
|
290
|
+
*
|
|
291
|
+
* `requestId` keeps its {@link RequestId} newtype rather than widening to
|
|
292
|
+
* `string` at the seam.
|
|
293
|
+
*/
|
|
294
|
+
type LogBinding = {
|
|
295
|
+
readonly requestId: RequestId;
|
|
296
|
+
} | {
|
|
297
|
+
readonly flow: string;
|
|
298
|
+
} | {
|
|
299
|
+
readonly hook: string;
|
|
300
|
+
} | {
|
|
301
|
+
readonly op: string;
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Every {@link LogBinding} applied so far, merged. This is what reaches a
|
|
305
|
+
* host, so a line from `prepareOndoSell` carries `flow: 'prepareSell'` as its
|
|
306
|
+
* own key and is filterable without parsing anything.
|
|
307
|
+
*/
|
|
308
|
+
type LogBindings = {
|
|
309
|
+
readonly [K in LogBinding as keyof K]?: K[keyof K];
|
|
310
|
+
};
|
|
311
|
+
type BaseEvent = {
|
|
312
|
+
/**
|
|
313
|
+
* What happened, as a **constant string literal**.
|
|
314
|
+
*
|
|
315
|
+
* Never interpolated. A log aggregator groups by message, so a `msg` that
|
|
316
|
+
* embeds a status, a count or a reason produces one group per distinct
|
|
317
|
+
* value and is not groupable at all. Every varying value belongs in
|
|
318
|
+
* `fields`, which is what a host filters and facets on.
|
|
319
|
+
*
|
|
320
|
+
* This is a convention, not a checked rule: deslop reasons about import
|
|
321
|
+
* edges and cannot see a template literal, and the type-level approximations
|
|
322
|
+
* catch only some interpolations. ADR-8 records why a partial guarantee was
|
|
323
|
+
* refused here as elsewhere.
|
|
324
|
+
*/
|
|
325
|
+
readonly msg: string;
|
|
326
|
+
/**
|
|
327
|
+
* Which part of the SDK reported this. Stamped by
|
|
328
|
+
* {@link internalLogger}, never by a call site.
|
|
329
|
+
*/
|
|
330
|
+
readonly scope: LogScope;
|
|
331
|
+
/** Every {@link LogBinding} applied by {@link InternalLogger.child}. */
|
|
332
|
+
readonly bindings: LogBindings;
|
|
333
|
+
};
|
|
334
|
+
/**
|
|
335
|
+
* An event for `'info'`, `'warn'` and `'error'` - the levels a host may run in
|
|
336
|
+
* production.
|
|
337
|
+
*
|
|
338
|
+
* Its fields are {@link SafeFields}, so nothing but a scalar can reach it.
|
|
339
|
+
*/
|
|
340
|
+
type SafeEvent = BaseEvent & {
|
|
341
|
+
readonly fields: SafeFields;
|
|
342
|
+
/**
|
|
343
|
+
* What the SDK knows about an accompanying failure, classified. Absent when
|
|
344
|
+
* there is nothing to classify.
|
|
345
|
+
*/
|
|
346
|
+
readonly cause?: LogCause;
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* An event for `'debug'`, the unredacted level. Its fields accept anything.
|
|
350
|
+
*/
|
|
351
|
+
type DebugEvent = BaseEvent & {
|
|
352
|
+
readonly fields: UnredactedFields;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* How much the SDK may report, from silent to everything.
|
|
356
|
+
*
|
|
357
|
+
* Ordered: each level admits itself and everything before it, so `'info'`
|
|
358
|
+
* shows errors, warnings and info but not debug. `'none'` admits nothing.
|
|
359
|
+
*
|
|
360
|
+
* `'debug'` is the unredacted level, and it is deliberately the bottom of the
|
|
361
|
+
* ladder: the guarantee "`debug` is unredacted and every other level is not"
|
|
362
|
+
* only closes if there is nothing below it. That is why the SDK keeps its own
|
|
363
|
+
* five levels rather than adopting pino's seven, which put `trace` underneath.
|
|
364
|
+
*/
|
|
365
|
+
type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
366
|
+
/**
|
|
367
|
+
* The redacted levels: the only ones to consider running in production.
|
|
368
|
+
*
|
|
369
|
+
* Every level except `'debug'`, which is unredacted by design. Used by the
|
|
370
|
+
* shipped pino implementations to make a production `'debug'` logger
|
|
371
|
+
* unrepresentable rather than merely discouraged - see
|
|
372
|
+
* {@link PinoLoggerOptions}.
|
|
373
|
+
*
|
|
374
|
+
* The name marks which levels are *redacted*, not a verdict that running them
|
|
375
|
+
* in production is safe. The SDK's advice is to leave {@link Config.logger}
|
|
376
|
+
* undefined there; this type is what stops the partner who does not take it
|
|
377
|
+
* from reaching the unredacted level as well.
|
|
378
|
+
*/
|
|
379
|
+
type ProductionLogLevel = Exclude<LogLevel, 'debug'>;
|
|
380
|
+
/**
|
|
381
|
+
* How to build one of the SDK's pino-backed loggers.
|
|
382
|
+
*
|
|
383
|
+
* A union rather than `{ level, isDev }`, and that is the whole point:
|
|
384
|
+
* `{ isDev: false, level: 'debug' }` does not typecheck, so a production
|
|
385
|
+
* build cannot ship a logger that prints bearer tokens to a browser console.
|
|
386
|
+
*
|
|
387
|
+
* `isDev` does exactly one thing - decide whether `'debug'` is a legal level.
|
|
388
|
+
* It changes no formatting: dev output and production output are the same
|
|
389
|
+
* shape, so what you debug is what you ship. Pretty-printing is a pipe the
|
|
390
|
+
* host owns (`node server.js | npx pino-pretty`), not a dependency the SDK
|
|
391
|
+
* takes.
|
|
392
|
+
*/
|
|
393
|
+
type PinoLoggerOptions = {
|
|
394
|
+
readonly isDev: true;
|
|
395
|
+
readonly level: LogLevel;
|
|
396
|
+
} | {
|
|
397
|
+
readonly isDev: false;
|
|
398
|
+
readonly level: ProductionLogLevel;
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Which part of the SDK a line came from, carried as the `scope` field on
|
|
402
|
+
* every event.
|
|
403
|
+
*
|
|
404
|
+
* It names the seam that **reported** the line, not the layer that raised what
|
|
405
|
+
* it reports: an error from `OFFERS` surfaced by `useOffers` is reported on a
|
|
406
|
+
* `HOOKS` line, because that is the hook telling you what it did with it. The
|
|
407
|
+
* `OFFERS` line for the same error is emitted separately, by the namespace.
|
|
408
|
+
*
|
|
409
|
+
* A closed union rather than a free string so that `ONDO` and `Ondo` cannot
|
|
410
|
+
* both appear, so that adding a namespace without giving it a scope fails to
|
|
411
|
+
* compile, and so that a host can `switch` on it when routing. Anything finer
|
|
412
|
+
* - an operation, a flow, a hook - is a {@link LogBinding} and appears as its
|
|
413
|
+
* own field.
|
|
414
|
+
*/
|
|
415
|
+
type LogScope = 'HTTP' | 'AUTH' | 'OFFERS' | 'REQUIREMENTS' | 'WALLETS' | 'ERC20' | 'TOKEN_SALE' | 'SUPERSTATE' | 'ONDO' | 'TOKENS' | 'SUPPORT' | 'HOOKS';
|
|
416
|
+
/**
|
|
417
|
+
* Correlates every line one logical request produces. The first attempt, each
|
|
418
|
+
* retry, and the re-send after a session renewal all carry the same id, so a
|
|
419
|
+
* failure can be read back to the request that caused it.
|
|
420
|
+
*/
|
|
421
|
+
type RequestId = Newtype<string, 'RequestId'>;
|
|
422
|
+
/**
|
|
423
|
+
* The id frontline keys its own logs by, minted server-side and returned as
|
|
424
|
+
* `event_id` on an error envelope. Quote it when raising a ticket with
|
|
425
|
+
* CoinList support: it is what leads from a partner's log line to the request
|
|
426
|
+
* as the backend saw it.
|
|
427
|
+
*
|
|
428
|
+
* A {@link Newtype} rather than a bare `string` because it sits next to
|
|
429
|
+
* {@link RequestId} and frontline's `code` on the same cause, and the three
|
|
430
|
+
* are not interchangeable: an id swapped for a code reads plausibly and points
|
|
431
|
+
* a support engineer at nothing.
|
|
432
|
+
*/
|
|
433
|
+
type FrontlineEventId = Newtype<string, 'FrontlineEventId'>;
|
|
434
|
+
/**
|
|
435
|
+
* What the SDK knows about a failure, classified.
|
|
436
|
+
*
|
|
437
|
+
* **Safe to forward as it stands.** Every arm is SDK-authored classification
|
|
438
|
+
* or a server-authored identifier: no request or response body, no host-
|
|
439
|
+
* supplied parameter, and no value read off a thrown error the SDK did not
|
|
440
|
+
* author. There is nothing here to strip before handing it to an error
|
|
441
|
+
* tracker, which is deliberate - a `LogCause` reaches {@link Logger.error},
|
|
442
|
+
* the level a host actually runs in production, and a guarantee that depends
|
|
443
|
+
* on the host remembering to strip a field is not a guarantee.
|
|
444
|
+
*
|
|
445
|
+
* It is the SDK's **only** structured classification of a thrown error, and it
|
|
446
|
+
* reaches {@link Logger.warn} as well as {@link Logger.error}: a recoverable
|
|
447
|
+
* failure is no less worth naming than a fatal one, and rendering it into a
|
|
448
|
+
* string instead would have meant interpolating into `msg`.
|
|
449
|
+
*
|
|
450
|
+
* Bodies are a `'debug'`-only disclosure and stay on the `HTTP` lines, which
|
|
451
|
+
* {@link RequestId} points at.
|
|
452
|
+
*
|
|
453
|
+
* The arms are the remedies, not the exception classes: a `validation` cause
|
|
454
|
+
* means the backend sent something the SDK does not understand and is worth
|
|
455
|
+
* reporting to CoinList, while an `invariant` cause means the SDK itself
|
|
456
|
+
* computed something impossible and is worth reporting as an SDK bug. Reading
|
|
457
|
+
* `type` should tell you who has to fix it.
|
|
458
|
+
*
|
|
459
|
+
* It carries no scope of its own. The {@link SafeEvent} it arrives on has one,
|
|
460
|
+
* and a cause could only ever have repeated it: the scope is stamped by the
|
|
461
|
+
* logger that *emits* the line, not by the layer that raised the error, so a
|
|
462
|
+
* `validation` failure from `OFFERS` surfaced by `useOffers` would have been
|
|
463
|
+
* tagged `HOOKS` on the hook's line. Forward the event, not the cause alone.
|
|
464
|
+
*/
|
|
465
|
+
type LogCause =
|
|
466
|
+
/**
|
|
467
|
+
* A request reached the backend and came back non-2xx.
|
|
468
|
+
*
|
|
469
|
+
* Deliberately carries no response body. `requestId` is how you get the
|
|
470
|
+
* rest: the `HTTP` lines for the same request carry the method, the path,
|
|
471
|
+
* the duration, every retry, and at `'debug'` the body itself. `code` and
|
|
472
|
+
* `eventId` are frontline's own - quote `eventId` when raising a ticket with
|
|
473
|
+
* CoinList support.
|
|
474
|
+
*/
|
|
475
|
+
{
|
|
476
|
+
type: 'http';
|
|
477
|
+
requestId: RequestId | null;
|
|
478
|
+
status: number;
|
|
479
|
+
code: string | null;
|
|
480
|
+
eventId: FrontlineEventId | null;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* The wire succeeded; the payload was not a shape the SDK can map.
|
|
484
|
+
*
|
|
485
|
+
* `message` is an SDK-authored template and may quote the single scalar that
|
|
486
|
+
* failed - `Unsupported chain: "solana_mainnet"`, `expires_at: not a date
|
|
487
|
+
* ("13/40/2026")`. That one value is the point of the arm; it is never a
|
|
488
|
+
* body and never a whole field set.
|
|
489
|
+
*/
|
|
490
|
+
| {
|
|
491
|
+
type: 'validation';
|
|
492
|
+
message: string;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* The SDK computed something impossible. An SDK bug - please report it.
|
|
496
|
+
* `message` is an SDK-authored template, like `validation`'s.
|
|
497
|
+
*/
|
|
498
|
+
| {
|
|
499
|
+
type: 'invariant';
|
|
500
|
+
message: string;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Every operand was well-formed and the arithmetic on them still had no
|
|
504
|
+
* answer: a division by zero, a result outside the range its type can hold.
|
|
505
|
+
* `message` is an SDK-authored template, like `validation`'s.
|
|
506
|
+
*
|
|
507
|
+
* Separate from `invariant` because the remedy differs. An `invariant` says
|
|
508
|
+
* the SDK computed something impossible and is a bug to report against the
|
|
509
|
+
* SDK; a `math` says the operation was well-posed and the operands, which
|
|
510
|
+
* came off the wire, admit no result - so it points at the response the same
|
|
511
|
+
* way `validation` does, one step later.
|
|
512
|
+
*/
|
|
513
|
+
| {
|
|
514
|
+
type: 'math';
|
|
515
|
+
message: string;
|
|
516
|
+
}
|
|
517
|
+
/** An API-backed call was made without a logged-in user. */
|
|
518
|
+
| {
|
|
519
|
+
type: 'not-authenticated';
|
|
520
|
+
}
|
|
521
|
+
/** A code path the SDK has not shipped yet. */
|
|
522
|
+
| {
|
|
523
|
+
type: 'not-implemented';
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* The user's wallet, or the chain, refused.
|
|
527
|
+
*
|
|
528
|
+
* {@link RedactedWalletError} rather than the full `WalletError`: its
|
|
529
|
+
* `unknown` arm arrives with its `cause` dropped, that field holding the raw
|
|
530
|
+
* wallet-library error whose message and metadata carry the transaction's
|
|
531
|
+
* `from`, `to`, `value` and calldata. It is still on the flow's own returned
|
|
532
|
+
* result, and on the `'debug'` line the flow seam emits beside this one.
|
|
533
|
+
*
|
|
534
|
+
* A type rather than a scrub applied at the call site, so an arm that grew a
|
|
535
|
+
* raw field would fail the build.
|
|
536
|
+
*/
|
|
537
|
+
| {
|
|
538
|
+
type: 'wallet';
|
|
539
|
+
error: RedactedWalletError;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Something the SDK does not recognise - usually a host-supplied lambda
|
|
543
|
+
* (`getAccessToken`, an {@link EvmWallet} method) throwing, or a
|
|
544
|
+
* network-level `fetch` failure.
|
|
545
|
+
*
|
|
546
|
+
* `name` is the error's class name and nothing else. The message and the
|
|
547
|
+
* thrown value itself are host-authored, so they are a `'debug'` disclosure:
|
|
548
|
+
* the paired debug line renders them in full.
|
|
549
|
+
*/
|
|
550
|
+
| {
|
|
551
|
+
type: 'generic-error';
|
|
552
|
+
name: string;
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* The exhaustive chain set: a new {@link EthereumChain} is a compile error
|
|
557
|
+
* here until it is listed, which is what keeps the constructor total.
|
|
558
|
+
*/
|
|
559
|
+
declare const ETHEREUM_CHAINS: Record<EthereumChain, true>;
|
|
560
|
+
type EthereumChain = 'ethereum_mainnet' | 'ethereum_sepolia' | 'base_mainnet' | 'base_sepolia';
|
|
561
|
+
/**
|
|
562
|
+
* Validates that a raw backend string names a chain the SDK supports.
|
|
563
|
+
*
|
|
564
|
+
* @throws ValidationError on anything else. Passing an unknown chain through
|
|
565
|
+
* would let downstream EIP-155 lookups blow up far from the response that
|
|
566
|
+
* caused it.
|
|
567
|
+
*/
|
|
568
|
+
declare const EthereumChain: (value: string) => EthereumChain;
|
|
569
|
+
/**
|
|
570
|
+
* The exhaustive chain set: a new {@link SolanaChain} is a compile error
|
|
571
|
+
* here until it is listed, which is what keeps the constructor total.
|
|
572
|
+
*/
|
|
573
|
+
declare const SOLANA_CHAINS: Record<SolanaChain, true>;
|
|
574
|
+
type SolanaChain = 'solana_mainnet' | 'solana_devnet';
|
|
575
|
+
/**
|
|
576
|
+
* Validates that a raw backend string names a chain the SDK supports.
|
|
577
|
+
*
|
|
578
|
+
* @throws ValidationError on anything else. Passing an unknown chain through
|
|
579
|
+
* would let downstream EIP-155 lookups blow up far from the response that
|
|
580
|
+
* caused it.
|
|
581
|
+
*/
|
|
582
|
+
declare const SolanaChain: (value: string) => SolanaChain;
|
|
583
|
+
type Chain = EthereumChain | SolanaChain;
|
|
584
|
+
declare const Chain: (value: string) => Chain;
|
|
585
|
+
/**
|
|
586
|
+
* Protocol a wallet binding is scoped to. EVM-only for now: an EVM address
|
|
587
|
+
* binds once per option regardless of which EVM chain proved ownership.
|
|
588
|
+
* Frontline's enum also has `:solana`, but we don't handle Solana bindings yet,
|
|
589
|
+
* so this stays `'ethereum'` until Solana support lands.
|
|
590
|
+
*/
|
|
591
|
+
type WalletProtocol = 'ethereum';
|
|
592
|
+
/**
|
|
593
|
+
* EVM addresses keep a `0x${string}` base so they stay assignable to the
|
|
594
|
+
* `0x${string}` shapes that on-chain libraries (viem/wagmi) expect. We only
|
|
595
|
+
* drop the runtime `0x` narrowing: values are trusted at the boundary and
|
|
596
|
+
* branded via the constructor.
|
|
597
|
+
*/
|
|
598
|
+
type EvmWalletAddress = Newtype<`0x${string}`, 'EvmWalletAddress'>;
|
|
599
|
+
declare const EvmWalletAddress: (value: string) => EvmWalletAddress;
|
|
600
|
+
type EvmContractAddress = Newtype<`0x${string}`, 'EvmContractAddress'>;
|
|
601
|
+
declare const EvmContractAddress: (value: string) => EvmContractAddress;
|
|
602
|
+
/**
|
|
603
|
+
* What uniquely identifies a token: the chain it is deployed on plus its
|
|
604
|
+
* contract address. Never a symbol, which can collide across issuers.
|
|
605
|
+
*/
|
|
606
|
+
type TokenIdentifier = {
|
|
607
|
+
/** The chain the token contract is deployed on. */
|
|
608
|
+
chain: EthereumChain;
|
|
609
|
+
/**
|
|
610
|
+
* The token's contract address, in any casing — consumers that need the
|
|
611
|
+
* EIP-55 form (e.g. the token registry routes) checksum it themselves.
|
|
612
|
+
*/
|
|
613
|
+
address: EvmContractAddress;
|
|
614
|
+
};
|
|
615
|
+
type HexEncodedTransactionData = Newtype<`0x${string}`, 'HexEncodedTransactionData'>;
|
|
616
|
+
declare const HexEncodedTransactionData: (value: string) => HexEncodedTransactionData;
|
|
617
|
+
/**
|
|
618
|
+
* A transaction the backend has already encoded for us — the caller only
|
|
619
|
+
* broadcasts it. Used by the flows that hand a wallet a ready-made `to`/`data`
|
|
620
|
+
* pair (allow-listing a wallet, an Ondo swap) rather than encoding a contract
|
|
621
|
+
* call themselves.
|
|
622
|
+
*/
|
|
623
|
+
type Tx = {
|
|
624
|
+
to: EvmContractAddress;
|
|
625
|
+
data: HexEncodedTransactionData;
|
|
626
|
+
};
|
|
627
|
+
/**
|
|
628
|
+
* The largest exponent whose power of ten still fits a uint256: 10^77 fits,
|
|
629
|
+
* 10^78 does not.
|
|
630
|
+
*
|
|
631
|
+
* The bound is arithmetic rather than a token standard's. ERC-20 reports
|
|
632
|
+
* `decimals()` as a `uint8`, so 255 is what a contract *can* say, but every
|
|
633
|
+
* {@link AssetDecimals} in this codebase is paired with a {@link Uint256} raw
|
|
634
|
+
* by construction, and scaling by anything past this leaves that pairing
|
|
635
|
+
* unrepresentable. A value between 78 and 255 would therefore pass a
|
|
636
|
+
* standard-faithful check and then break the first multiplication it reached.
|
|
637
|
+
*/
|
|
638
|
+
declare const MAX_ASSET_DECIMALS = 77;
|
|
639
|
+
/**
|
|
640
|
+
* How many decimal places one whole token divides into.
|
|
641
|
+
*
|
|
642
|
+
* Validated, unlike its neighbours here — {@link Uint256} is a bare `bigint`
|
|
643
|
+
* with a separate {@link assertUint256} guard, and {@link DecimalString} casts
|
|
644
|
+
* unchecked. The asymmetry is deliberate and follows the value's provenance:
|
|
645
|
+
* an `AssetDecimals` used to come only from literals and the token registry,
|
|
646
|
+
* but backends now publish exponents of their own (`asset_decimals` on an Ondo
|
|
647
|
+
* quote, both scales on a built swap), and those feed `10n ** BigInt(d)`
|
|
648
|
+
* during render. Guarding at construction is what keeps a fractional or
|
|
649
|
+
* unbounded exponent from surfacing as a `RangeError` mid-render — or, at
|
|
650
|
+
* 10^200, as a hung tab — instead of as the failed state the screen has.
|
|
651
|
+
*
|
|
652
|
+
* See docs/ADR-7-VALIDATED-NEWTYPES.md.
|
|
653
|
+
*
|
|
654
|
+
* @throws ValidationError on a non-integer, a negative, or anything above
|
|
655
|
+
* {@link MAX_ASSET_DECIMALS}.
|
|
656
|
+
*/
|
|
657
|
+
type AssetDecimals = Newtype<number, 'AssetDecimals'>;
|
|
658
|
+
declare const AssetDecimals: (value: number) => AssetDecimals;
|
|
659
|
+
declare const STABLE_DECIMALS: AssetDecimals;
|
|
660
|
+
/**
|
|
661
|
+
* A non-negative decimal number the backend sent as a string, kept unscaled.
|
|
662
|
+
*
|
|
663
|
+
* Reach for it when a response gives you a number but not the decimals to
|
|
664
|
+
* scale it by, or gives you one it has already applied. Inventing an exponent
|
|
665
|
+
* for either is how a display ends up orders of magnitude out.
|
|
666
|
+
*
|
|
667
|
+
* Contrast {@link BlockchainAmount}, which pairs a raw uint256 with the
|
|
668
|
+
* decimals it is denominated in and so is only constructible when you know
|
|
669
|
+
* both. Arithmetic on a `DecimalString` needs a decimal library we
|
|
670
|
+
* deliberately do not ship.
|
|
671
|
+
*/
|
|
672
|
+
type DecimalString = Newtype<string, 'DecimalString'>;
|
|
673
|
+
declare const DecimalString: (value: string) => DecimalString;
|
|
674
|
+
declare const MAX_UINT_256: bigint;
|
|
675
|
+
/**
|
|
676
|
+
* A non-negative integer within uint256 bounds. Kept unbranded (a plain
|
|
677
|
+
* `bigint`) so raw on-chain amounts flow in without ceremony; bounds are
|
|
678
|
+
* enforced where it matters (see {@link combineAmounts}).
|
|
679
|
+
*/
|
|
680
|
+
type Uint256 = bigint;
|
|
681
|
+
/**
|
|
682
|
+
* Asserts a computed bigint falls within uint256 bounds. Use at on-chain
|
|
683
|
+
* arithmetic boundaries (bps math, price computation) where the SDK's own
|
|
684
|
+
* arithmetic could underflow below zero or overflow above 2^256-1.
|
|
685
|
+
*
|
|
686
|
+
* Throws {@link InvariantError}, because reaching it means the SDK computed
|
|
687
|
+
* something no chain could represent. **For a value that came off the wire,
|
|
688
|
+
* use {@link parseUint256} instead**: the backend sending an unrepresentable
|
|
689
|
+
* number is a {@link ValidationError}, and the two have different remedies.
|
|
690
|
+
*/
|
|
691
|
+
declare const assertUint256: (value: bigint) => Uint256;
|
|
692
|
+
/**
|
|
693
|
+
* {@link assertUint256} at a wire boundary: the same bounds check, reported as
|
|
694
|
+
* a {@link ValidationError} against the named field, because a value out of
|
|
695
|
+
* range here is the backend's, not the SDK's.
|
|
696
|
+
*
|
|
697
|
+
* `label` names the field the way a DTO mapper's other failures do, so a log
|
|
698
|
+
* line says which one - `SwapPreview.pay_input_amount`, not `a number`.
|
|
699
|
+
*/
|
|
700
|
+
declare const parseUint256: (value: bigint, label: string) => Uint256;
|
|
701
|
+
type BlockchainAmount = Newtype<{
|
|
702
|
+
raw: Uint256;
|
|
703
|
+
decimals: AssetDecimals;
|
|
704
|
+
}, 'BlockchainAmount'>;
|
|
705
|
+
/**
|
|
706
|
+
* Constructs a {@link BlockchainAmount} and exposes arithmetic helpers.
|
|
707
|
+
* TypeScript has no operator overloading, so use `BlockchainAmount.add(a, b)`
|
|
708
|
+
* instead of `+`/`-`/`*`/`/` on the objects directly.
|
|
709
|
+
*/
|
|
710
|
+
declare const BlockchainAmount: ((value: {
|
|
711
|
+
raw: Uint256;
|
|
712
|
+
decimals: AssetDecimals;
|
|
713
|
+
}) => BlockchainAmount) & {
|
|
714
|
+
add: (a: BlockchainAmount, b: BlockchainAmount) => BlockchainAmount;
|
|
715
|
+
sub: (a: BlockchainAmount, b: BlockchainAmount) => BlockchainAmount;
|
|
716
|
+
mul: typeof multiplyAmounts;
|
|
717
|
+
div: typeof divideAmounts;
|
|
718
|
+
};
|
|
719
|
+
/**
|
|
720
|
+
* `a * b`, denominated in `a`'s decimals - a price times a quantity, an amount
|
|
721
|
+
* times a rate.
|
|
722
|
+
*
|
|
723
|
+
* The exact inverse of {@link divideAmounts}, and it reads the same way round:
|
|
724
|
+
* the answer stays in `a`'s scale and `b`'s divides back out, so the two
|
|
725
|
+
* compose - `mul(div(a, b), b)` is `a` again, short only what truncation took.
|
|
726
|
+
* That is what makes `price x quantity` land in the currency the price was
|
|
727
|
+
* quoted in rather than at some product of two exponents no token uses.
|
|
728
|
+
*
|
|
729
|
+
* The multiplication happens *before* the division by `10^b.decimals`, so the
|
|
730
|
+
* full precision of both operands survives into the one rounding at the end.
|
|
731
|
+
* Like `div` it truncates towards zero on both signs, which is the safe
|
|
732
|
+
* direction for money: a total is never inflated past what the parts hold.
|
|
733
|
+
*
|
|
734
|
+
* Total - unlike `div`, there is nothing here to reject. The scale it divides
|
|
735
|
+
* by is a power of ten, never zero, and a product is not bounds-checked for
|
|
736
|
+
* the same reason a quotient is not: whether one past uint256 is a corrupt
|
|
737
|
+
* response or an expected magnitude belongs to the caller.
|
|
738
|
+
*/
|
|
739
|
+
declare function multiplyAmounts(a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount;
|
|
740
|
+
/**
|
|
741
|
+
* `a / b`, denominated in `a`'s decimals - a price, a ratio, a rate.
|
|
742
|
+
*
|
|
743
|
+
* Unlike {@link combineAmounts}, the two operands may be at different scales,
|
|
744
|
+
* and usually are: dividing dollars by shares is the point of the operation,
|
|
745
|
+
* and the two tokens rarely share an exponent. `b`'s scale divides back out -
|
|
746
|
+
* the numerator is scaled by `10^b.decimals` *before* the division, so nothing
|
|
747
|
+
* is lost to integer truncation early and the quotient lands in `a`'s scale,
|
|
748
|
+
* which is the one the amounts it is rendered beside are in.
|
|
749
|
+
*
|
|
750
|
+
* Truncates towards zero on both signs, which is what BigInt division already
|
|
751
|
+
* does and the safe direction for money: the total a price implies never
|
|
752
|
+
* exceeds, in magnitude, the amount that actually moved.
|
|
753
|
+
*
|
|
754
|
+
* A zero divisor is the only rejection. The quotient is deliberately *not*
|
|
755
|
+
* bounds-checked the way {@link combineAmounts} checks a sum: scaling the
|
|
756
|
+
* numerator carries even legal pairs past uint256 (a maximal amount over a
|
|
757
|
+
* single base unit), and whether that reads as a corrupt response or an
|
|
758
|
+
* expected magnitude is the caller's to judge - see `computeOndoBuyPrice` and
|
|
759
|
+
* `computeOndoSellPrice`, which bounds-check the price they build out of this.
|
|
760
|
+
*
|
|
761
|
+
* @throws MathError when `b` is zero. `add` and `sub` throw a bare `Error`
|
|
762
|
+
* because a scale mismatch is a programming error caught in review; a zero
|
|
763
|
+
* divisor arrives from a server response and is divided by during render, so
|
|
764
|
+
* it is a named failure a screen can catch and map to a failed state.
|
|
765
|
+
*/
|
|
766
|
+
declare function divideAmounts(a: BlockchainAmount, b: BlockchainAmount): BlockchainAmount;
|
|
767
|
+
type AssetSymbol = Newtype<string, 'AssetSymbol'>;
|
|
768
|
+
declare const AssetSymbol: (value: string) => AssetSymbol;
|
|
769
|
+
/**
|
|
770
|
+
* A stablecoin symbol is an {@link AssetSymbol} narrowed to the coins we
|
|
771
|
+
* support. It shares the `AssetSymbol` brand so it stays assignable to it.
|
|
772
|
+
*/
|
|
773
|
+
type StablecoinSymbol = Newtype<'USDC' | 'USDT', 'AssetSymbol'>;
|
|
774
|
+
declare const StablecoinSymbol: (value: "USDC" | "USDT") => StablecoinSymbol;
|
|
775
|
+
type KnownAssetSymbol = StablecoinSymbol;
|
|
776
|
+
declare const KnownAssetSymbol: (value: "USDC" | "USDT") => StablecoinSymbol;
|
|
777
|
+
type Erc20Asset = {
|
|
778
|
+
name: string;
|
|
779
|
+
symbol: AssetSymbol;
|
|
780
|
+
decimals: AssetDecimals;
|
|
781
|
+
};
|
|
782
|
+
type Bps = Newtype<bigint, 'Bps'>;
|
|
783
|
+
declare const Bps: (value: bigint) => Bps;
|
|
784
|
+
|
|
785
|
+
type GetTokenAllowanceParams = {
|
|
786
|
+
tokenAddress: EvmContractAddress;
|
|
787
|
+
owner: EvmWalletAddress;
|
|
788
|
+
spender: EvmContractAddress;
|
|
789
|
+
chain: EthereumChain;
|
|
790
|
+
};
|
|
791
|
+
type GetTokenBalanceParams = {
|
|
792
|
+
tokenAddress: EvmContractAddress;
|
|
793
|
+
owner: EvmWalletAddress;
|
|
794
|
+
chain: EthereumChain;
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* OAuth 2.0 token response (RFC 6749 §5.1).
|
|
799
|
+
* Maps to OpenAPI schema OauthToken.
|
|
800
|
+
*/
|
|
801
|
+
type OAuthSessionDto = {
|
|
802
|
+
access_token: string;
|
|
803
|
+
expires_in: number;
|
|
804
|
+
refresh_token?: string;
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
type ClientCredentialsOAuth = Newtype<OAuthAccessToken, 'ClientCredentialsOAuth'>;
|
|
808
|
+
declare const ClientCredentialsOAuth: (value: OAuthAccessToken) => ClientCredentialsOAuth;
|
|
809
|
+
type OAuthAccessToken = {
|
|
810
|
+
value: string;
|
|
811
|
+
expiresAt: Date;
|
|
812
|
+
};
|
|
813
|
+
type OAuthRefreshToken = Newtype<string, 'OAuthRefreshToken'>;
|
|
814
|
+
declare const OAuthRefreshToken: (value: string) => OAuthRefreshToken;
|
|
815
|
+
type OAuthSession = {
|
|
816
|
+
accessToken: OAuthAccessToken;
|
|
817
|
+
refreshToken?: OAuthRefreshToken;
|
|
818
|
+
};
|
|
819
|
+
declare const OAuthSession: {
|
|
820
|
+
fromDto: (dto: OAuthSessionDto) => OAuthSession;
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
type HttpRequestAttributes = {
|
|
824
|
+
/**
|
|
825
|
+
* Correlates the log lines of one logical request. Minted by
|
|
826
|
+
* {@link HttpClient} on the first attempt and carried onto every retry and
|
|
827
|
+
* post-renewal re-send by {@link concat}, which is what lets a reader tell
|
|
828
|
+
* three attempts of one request from three separate requests.
|
|
829
|
+
*/
|
|
830
|
+
requestId?: RequestId;
|
|
831
|
+
protected?: boolean;
|
|
832
|
+
userAgent?: boolean;
|
|
833
|
+
idempotencyKey?: boolean;
|
|
834
|
+
/** Zero-based attempt index: 0 = first request, 1 = first retry, etc. */
|
|
835
|
+
retryAttempt?: number;
|
|
836
|
+
renewAttempted?: boolean;
|
|
837
|
+
clientCredentials?: ClientCredentialsOAuth;
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* The value types a query-string parameter may take.
|
|
842
|
+
*
|
|
843
|
+
* Declared here rather than beside the HTTP client because domain models build
|
|
844
|
+
* query parameters too: `ParticipationsPaginationParams.toQueryParams` returns
|
|
845
|
+
* a `Record<string, QueryParamValue>`, and a domain model must not import
|
|
846
|
+
* `@/shared/api/**`.
|
|
847
|
+
*/
|
|
848
|
+
type QueryParamValue = string | number | boolean | null | undefined;
|
|
849
|
+
type QueryParamValues = QueryParamValue | QueryParamValue[];
|
|
850
|
+
|
|
851
|
+
type HttpRequest<TBody = unknown> = {
|
|
852
|
+
method: 'GET';
|
|
853
|
+
url: string;
|
|
854
|
+
queryParams?: Record<string, QueryParamValues>;
|
|
855
|
+
headers?: Record<string, string>;
|
|
856
|
+
attributes?: HttpRequestAttributes;
|
|
857
|
+
redirect?: RequestRedirect;
|
|
858
|
+
} | {
|
|
859
|
+
method: 'POST';
|
|
860
|
+
url: string;
|
|
861
|
+
queryParams?: Record<string, QueryParamValues>;
|
|
862
|
+
headers?: Record<string, string>;
|
|
863
|
+
body: TBody;
|
|
864
|
+
attributes?: HttpRequestAttributes;
|
|
865
|
+
redirect?: RequestRedirect;
|
|
866
|
+
} | {
|
|
867
|
+
method: 'DELETE';
|
|
868
|
+
url: string;
|
|
869
|
+
queryParams?: Record<string, QueryParamValues>;
|
|
870
|
+
headers?: Record<string, string>;
|
|
871
|
+
attributes?: HttpRequestAttributes;
|
|
872
|
+
redirect?: RequestRedirect;
|
|
873
|
+
};
|
|
874
|
+
type HttpResponse<TBody = unknown> = {
|
|
875
|
+
status: number;
|
|
876
|
+
headers?: Record<string, string>;
|
|
877
|
+
body: TBody | null;
|
|
878
|
+
/**
|
|
879
|
+
* The id of the request that produced this response, stamped by
|
|
880
|
+
* {@link HttpClient} so that whoever turns a non-2xx into an
|
|
881
|
+
* {@link HttpError} can carry it without threading the request alongside.
|
|
882
|
+
* Absent when the response did not come from an `HttpClient`.
|
|
883
|
+
*/
|
|
884
|
+
requestId?: RequestId;
|
|
885
|
+
};
|
|
886
|
+
declare class HttpError<TBody = unknown> extends Error {
|
|
887
|
+
readonly response: HttpResponse<TBody>;
|
|
888
|
+
constructor(response: HttpResponse<TBody>);
|
|
889
|
+
/**
|
|
890
|
+
* Correlates this failure with the `[HTTP]` log lines for the same request,
|
|
891
|
+
* which carry the method, the URL, the duration and every retry. `null` when
|
|
892
|
+
* the response did not come from an {@link HttpClient}.
|
|
893
|
+
*
|
|
894
|
+
* Worth quoting in a bug report: it is what makes a log excerpt readable.
|
|
895
|
+
*/
|
|
896
|
+
get requestId(): RequestId | null;
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* The machine-readable `code` frontline attaches to an error, or `null` for
|
|
900
|
+
* anything else - a non-HTTP failure, or an error body that carries only a
|
|
901
|
+
* message.
|
|
902
|
+
*
|
|
903
|
+
* Frontline answers a failure with `{ type, message, code?, errors?,
|
|
904
|
+
* event_id? }`, and `code` is the only part of it meant to be branched on:
|
|
905
|
+
* `message` is prose that may be reworded, and `type` distinguishes
|
|
906
|
+
* `invalid_request_error` from `api_error` without saying which one.
|
|
907
|
+
*
|
|
908
|
+
* Reach for this only where a code has a distinct remedy the user can act on.
|
|
909
|
+
* Mapping the whole vocabulary would couple the SDK to strings frontline does
|
|
910
|
+
* not version; falling back to a generic failure is the right default.
|
|
911
|
+
*/
|
|
912
|
+
declare function apiErrorCode(error: unknown): string | null;
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Structural interface satisfied by both {@link AuthenticatedApiClient} and
|
|
916
|
+
* {@link ApiClient}. Used by the shared frontline API functions so they can
|
|
917
|
+
* be called from either the client or server without any browser dependencies.
|
|
918
|
+
*/
|
|
919
|
+
interface Sender {
|
|
920
|
+
send<T>(request: HttpRequest): Promise<T>;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
interface SharedNamespaceContext {
|
|
924
|
+
readonly api: Sender;
|
|
925
|
+
/**
|
|
926
|
+
* The host's logger, or `null` when they supplied none.
|
|
927
|
+
*
|
|
928
|
+
* Deliberately the raw port rather than a pre-scoped {@link InternalLogger}:
|
|
929
|
+
* one context serves every namespace, and each namespace owns its own scope.
|
|
930
|
+
* A namespace turns it into something usable in its constructor, with
|
|
931
|
+
* `internalLogger(ctx.logger, 'OFFERS')`.
|
|
932
|
+
*/
|
|
933
|
+
readonly logger: Logger | null;
|
|
934
|
+
ensureUserAuthenticated(): Promise<void>;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* Raw JSON models for the on-chain swap endpoints. uint256 values are encoded
|
|
939
|
+
* as decimal strings because they can exceed the safe integer range of JSON
|
|
940
|
+
* consumers.
|
|
941
|
+
*/
|
|
942
|
+
type WalletAuthorizationDto = {
|
|
943
|
+
object: 'wallet_authorization';
|
|
944
|
+
authorized: boolean;
|
|
945
|
+
};
|
|
946
|
+
type SwapPreviewDto = {
|
|
947
|
+
object: 'swap_preview';
|
|
948
|
+
pay_input_amount: string;
|
|
949
|
+
fee: string;
|
|
950
|
+
receive_output_amount: string;
|
|
951
|
+
};
|
|
952
|
+
type SwapStatusDto = {
|
|
953
|
+
object: 'swap_status';
|
|
954
|
+
stopped: string;
|
|
955
|
+
swap_level: string;
|
|
956
|
+
};
|
|
957
|
+
type TokenAllowanceDto = {
|
|
958
|
+
object: 'token_allowance';
|
|
959
|
+
allowance: string;
|
|
960
|
+
};
|
|
961
|
+
type TokenBalanceDto = {
|
|
962
|
+
object: 'token_balance';
|
|
963
|
+
balance: string;
|
|
964
|
+
};
|
|
965
|
+
type AllowWalletResponseDto = {
|
|
966
|
+
action: 'broadcast_transaction';
|
|
967
|
+
to: string;
|
|
968
|
+
data: string;
|
|
969
|
+
} | {
|
|
970
|
+
action: 'none';
|
|
971
|
+
already_allowed: boolean;
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Whether a wallet is authorized to interact with a given swap contract.
|
|
976
|
+
*/
|
|
977
|
+
type SwapAuthorization = {
|
|
978
|
+
authorized: boolean;
|
|
979
|
+
};
|
|
980
|
+
declare const SwapAuthorization: {
|
|
981
|
+
fromDto: (dto: WalletAuthorizationDto) => SwapAuthorization;
|
|
982
|
+
};
|
|
983
|
+
/**
|
|
984
|
+
* A read-only quote for a swap: how much goes in, the protocol fee, and how
|
|
985
|
+
* much would come out. All amounts are raw on-chain integers (uint256).
|
|
986
|
+
*/
|
|
987
|
+
type SwapPreview = {
|
|
988
|
+
inputAmount: Uint256;
|
|
989
|
+
fee: Uint256;
|
|
990
|
+
outputAmount: Uint256;
|
|
991
|
+
};
|
|
992
|
+
declare const SwapPreview: {
|
|
993
|
+
fromDto: (dto: SwapPreviewDto) => SwapPreview;
|
|
994
|
+
};
|
|
995
|
+
/**
|
|
996
|
+
* The on-chain state of a swap contract.
|
|
997
|
+
*
|
|
998
|
+
* - `stopped`: non-zero when the contract is paused/halted.
|
|
999
|
+
* - `swapLevel`: the current swap level/tier.
|
|
1000
|
+
*/
|
|
1001
|
+
type SwapStatus = {
|
|
1002
|
+
stopped: Uint256;
|
|
1003
|
+
swapLevel: Uint256;
|
|
1004
|
+
};
|
|
1005
|
+
declare const SwapStatus: {
|
|
1006
|
+
fromDto: (dto: SwapStatusDto) => SwapStatus;
|
|
1007
|
+
};
|
|
1008
|
+
/**
|
|
1009
|
+
* The ERC-20 allowance an owner has granted a spender for a token.
|
|
1010
|
+
*/
|
|
1011
|
+
type TokenAllowance = {
|
|
1012
|
+
allowance: Uint256;
|
|
1013
|
+
};
|
|
1014
|
+
declare const TokenAllowance: {
|
|
1015
|
+
fromDto: (dto: TokenAllowanceDto) => TokenAllowance;
|
|
1016
|
+
};
|
|
1017
|
+
/**
|
|
1018
|
+
* The raw ERC-20 balance an owner holds of a token (uint256).
|
|
1019
|
+
*/
|
|
1020
|
+
type TokenBalance = {
|
|
1021
|
+
balance: Uint256;
|
|
1022
|
+
};
|
|
1023
|
+
declare const TokenBalance: {
|
|
1024
|
+
fromDto: (dto: TokenBalanceDto) => TokenBalance;
|
|
1025
|
+
};
|
|
1026
|
+
/**
|
|
1027
|
+
* The backend's response to an allow-wallet request. Either the caller must
|
|
1028
|
+
* broadcast an on-chain transaction to complete allow-listing, or nothing is
|
|
1029
|
+
* required because the wallet is already allowed.
|
|
1030
|
+
*/
|
|
1031
|
+
type AllowWalletResponse = {
|
|
1032
|
+
action: 'broadcast_transaction';
|
|
1033
|
+
to: EvmContractAddress;
|
|
1034
|
+
data: HexEncodedTransactionData;
|
|
1035
|
+
} | {
|
|
1036
|
+
action: 'none';
|
|
1037
|
+
alreadyAllowed: boolean;
|
|
1038
|
+
};
|
|
1039
|
+
declare const AllowWalletResponse: {
|
|
1040
|
+
fromDto: (dto: AllowWalletResponseDto) => AllowWalletResponse;
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* Generic ERC-20 reads shared across on-chain flows (swap, token sale): the
|
|
1045
|
+
* allowance an owner has granted a spender, and the raw token balance an owner
|
|
1046
|
+
* holds. These are plain token reads, not tied to any single product flow.
|
|
1047
|
+
*/
|
|
1048
|
+
interface Erc20Namespace {
|
|
1049
|
+
/**
|
|
1050
|
+
* Reads the ERC-20 allowance an `owner` has granted a `spender`.
|
|
1051
|
+
*/
|
|
1052
|
+
getAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance>;
|
|
1053
|
+
/**
|
|
1054
|
+
* Reads the raw ERC-20 balance an `owner` holds of a token.
|
|
1055
|
+
*/
|
|
1056
|
+
getBalance(params: GetTokenBalanceParams): Promise<TokenBalance>;
|
|
1057
|
+
}
|
|
1058
|
+
declare class Erc20NamespaceImpl implements Erc20Namespace {
|
|
1059
|
+
private readonly ctx;
|
|
1060
|
+
private readonly log;
|
|
1061
|
+
constructor(ctx: SharedNamespaceContext);
|
|
1062
|
+
getAllowance(params: GetTokenAllowanceParams): Promise<TokenAllowance>;
|
|
1063
|
+
getBalance(params: GetTokenBalanceParams): Promise<TokenBalance>;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* The logging surface SDK code uses. Never exported to hosts: they implement
|
|
1068
|
+
* {@link Logger}, which is deliberately smaller.
|
|
1069
|
+
*/
|
|
1070
|
+
type InternalLogger = {
|
|
1071
|
+
/**
|
|
1072
|
+
* A logger narrowed by one more {@link LogBinding}, which every line it
|
|
1073
|
+
* emits carries as its own field.
|
|
1074
|
+
*/
|
|
1075
|
+
child(binding: LogBinding): InternalLogger;
|
|
1076
|
+
/**
|
|
1077
|
+
* The unredacted level. Request and response bodies, full URLs, headers,
|
|
1078
|
+
* operation params and raw thrown errors belong here and **only** here.
|
|
1079
|
+
*/
|
|
1080
|
+
debug(event: () => InternalDebugEvent): void;
|
|
1081
|
+
info(event: () => InternalSafeEvent): void;
|
|
1082
|
+
warn(event: () => InternalSafeEvent): void;
|
|
1083
|
+
/**
|
|
1084
|
+
* Reports a failure whose cause is already known, or has none. Prefer
|
|
1085
|
+
* {@link failure}, which classifies a thrown error for you.
|
|
1086
|
+
*/
|
|
1087
|
+
error(event: () => InternalSafeEvent): void;
|
|
1088
|
+
/**
|
|
1089
|
+
* Reports a thrown error, classifying it into a {@link LogCause}. Prefer
|
|
1090
|
+
* this over `error` at a `catch`: classification only happens when the level
|
|
1091
|
+
* admits it.
|
|
1092
|
+
*
|
|
1093
|
+
* The `error` line names the error's class but never its message, since an
|
|
1094
|
+
* error the SDK did not author may say anything at all. The verbatim
|
|
1095
|
+
* rendering goes onto a paired `debug` line instead.
|
|
1096
|
+
*
|
|
1097
|
+
* For a failure the SDK recovers from, use {@link warning} instead. An
|
|
1098
|
+
* `error` line a host cannot act on is worse than no line at all: it trains
|
|
1099
|
+
* them to ignore the ones that matter.
|
|
1100
|
+
*/
|
|
1101
|
+
failure(event: () => InternalSafeEvent, error: unknown): void;
|
|
1102
|
+
/**
|
|
1103
|
+
* {@link failure} for trouble that did not break anything: a poll tick that
|
|
1104
|
+
* failed while the last value still stands, a retried request.
|
|
1105
|
+
*
|
|
1106
|
+
* Carries the classified {@link LogCause} exactly as `failure` does. The two
|
|
1107
|
+
* differ in level and in nothing else, because what separates them is
|
|
1108
|
+
* whether anything actually broke - not how much is known about it.
|
|
1109
|
+
*/
|
|
1110
|
+
warning(event: () => InternalSafeEvent, error: unknown): void;
|
|
1111
|
+
/**
|
|
1112
|
+
* Runs one namespace operation with logging around it: the call and its
|
|
1113
|
+
* params at `debug`, and any throw at `error` with the cause classified.
|
|
1114
|
+
* Every line carries `op` as a binding.
|
|
1115
|
+
*
|
|
1116
|
+
* **The params never reach the `error` line.** They routinely hold the
|
|
1117
|
+
* things this SDK must not put in front of a production error tracker - an
|
|
1118
|
+
* app bearer token, a document's signing fields, a wallet signature - and
|
|
1119
|
+
* the `debug` line plus the request id is how you get them back. The type
|
|
1120
|
+
* says so: `params` is `unknown`, which is not a {@link SafeFields} value.
|
|
1121
|
+
*
|
|
1122
|
+
* Always rethrows. Logging observes behaviour, it never changes it.
|
|
1123
|
+
*/
|
|
1124
|
+
wrap<T>(op: string, params: unknown, run: () => Promise<T>): Promise<T>;
|
|
1125
|
+
};
|
|
1126
|
+
/**
|
|
1127
|
+
* What a call site hands to `info`, `warn`, `error`, `failure` or `warning` -
|
|
1128
|
+
* a {@link SafeEvent} minus the scope and bindings the logger stamps itself.
|
|
1129
|
+
*/
|
|
1130
|
+
type InternalSafeEvent = {
|
|
1131
|
+
/** A **constant** string literal. Every varying value belongs in `fields`. */
|
|
1132
|
+
readonly msg: string;
|
|
1133
|
+
readonly fields?: SafeFields;
|
|
1134
|
+
readonly cause?: LogCause;
|
|
1135
|
+
};
|
|
1136
|
+
/** What a call site hands to `debug`. Its fields accept anything. */
|
|
1137
|
+
type InternalDebugEvent = {
|
|
1138
|
+
/** A **constant** string literal. Every varying value belongs in `fields`. */
|
|
1139
|
+
readonly msg: string;
|
|
1140
|
+
readonly fields?: UnredactedFields;
|
|
1141
|
+
};
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* The product an offer is checked out through. The backend sends one compound
|
|
1145
|
+
* `{supplier}::{saleType}` string, verbatim as spelled below: a double colon
|
|
1146
|
+
* between the two halves, `snake_case` within each. CoinList's token sale is
|
|
1147
|
+
* `coinlist::token_sale`; there is no `coinlist::sale` and no
|
|
1148
|
+
* `coinlist_token_sale`.
|
|
1149
|
+
*
|
|
1150
|
+
* Kept flat rather than split into a supplier and a sale type, because a flat
|
|
1151
|
+
* union makes a `switch` over it exhaustive: adding a provider without
|
|
1152
|
+
* handling it becomes a compile error.
|
|
1153
|
+
*/
|
|
1154
|
+
type OfferTypeDto = 'coinlist::token_sale' | 'superstate::swap' | 'ondo::swap';
|
|
1155
|
+
type OfferDto = {
|
|
1156
|
+
id: string;
|
|
1157
|
+
slug: string;
|
|
1158
|
+
type: OfferTypeDto;
|
|
1159
|
+
tagline: string;
|
|
1160
|
+
banner_url: string;
|
|
1161
|
+
logo_url: string;
|
|
1162
|
+
starts_at: string;
|
|
1163
|
+
ends_at: string | null;
|
|
1164
|
+
tokens: OfferTokenDto[];
|
|
1165
|
+
};
|
|
1166
|
+
type OfferTokenDto = {
|
|
1167
|
+
role: 'funding' | 'distribution' | 'swap';
|
|
1168
|
+
chain: string;
|
|
1169
|
+
address: string;
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
type OfferId = Newtype<string, 'OfferId'>;
|
|
1173
|
+
declare const OfferId: (value: string) => OfferId;
|
|
1174
|
+
type OfferSlug = Newtype<string, 'OfferSlug'>;
|
|
1175
|
+
declare const OfferSlug: (value: string) => OfferSlug;
|
|
1176
|
+
type OfferType = OfferTypeDto;
|
|
1177
|
+
type Offer = {
|
|
1178
|
+
id: OfferId;
|
|
1179
|
+
slug: OfferSlug;
|
|
1180
|
+
type: OfferType;
|
|
1181
|
+
tagline: string;
|
|
1182
|
+
bannerUrl: string;
|
|
1183
|
+
logoUrl: string;
|
|
1184
|
+
startsAt: Date;
|
|
1185
|
+
endsAt: Date | null;
|
|
1186
|
+
tokens: OfferToken[];
|
|
1187
|
+
};
|
|
1188
|
+
declare const Offer: {
|
|
1189
|
+
fromDto: (dto: OfferDto) => Offer;
|
|
1190
|
+
};
|
|
1191
|
+
type TokenRole = 'funding' | 'distribution' | 'swap';
|
|
1192
|
+
type OfferToken = {
|
|
1193
|
+
role: TokenRole;
|
|
1194
|
+
chain: Chain;
|
|
1195
|
+
address: EvmContractAddress;
|
|
1196
|
+
};
|
|
1197
|
+
declare const OfferToken: {
|
|
1198
|
+
fromDto: (dto: OfferTokenDto) => OfferToken;
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1201
|
+
/**
|
|
1202
|
+
* The cursor-paginated envelope every list endpoint returns.
|
|
1203
|
+
*
|
|
1204
|
+
* Generic in its item type, so each resource pairs it with its own item DTO
|
|
1205
|
+
* rather than declaring an envelope of its own.
|
|
1206
|
+
*/
|
|
1207
|
+
interface PaginatedResponseDto<T> {
|
|
1208
|
+
data: T[];
|
|
1209
|
+
starting_after?: string;
|
|
1210
|
+
starting_before?: string;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
type Cursor = Newtype<string, 'Cursor'>;
|
|
1214
|
+
declare const Cursor: (value: string) => Cursor;
|
|
1215
|
+
interface PaginatedResponse<T> {
|
|
1216
|
+
data: T[];
|
|
1217
|
+
startingAfter: Cursor | null;
|
|
1218
|
+
startingBefore: Cursor | null;
|
|
1219
|
+
}
|
|
1220
|
+
declare const PaginatedResponse: {
|
|
1221
|
+
fromDto: <A, B>(dto: PaginatedResponseDto<A>, itemMapper: (item: A) => B) => PaginatedResponse<B>;
|
|
1222
|
+
};
|
|
1223
|
+
/**
|
|
1224
|
+
* Cursor-based pagination input used when requesting paginated API resources.
|
|
1225
|
+
* Set `after` or `before` to navigate relative to a known cursor, and `limit`
|
|
1226
|
+
* to control the maximum number of returned items.
|
|
1227
|
+
*/
|
|
1228
|
+
interface PaginationParams {
|
|
1229
|
+
before?: Cursor;
|
|
1230
|
+
after?: Cursor;
|
|
1231
|
+
limit?: number;
|
|
1232
|
+
}
|
|
1233
|
+
declare const PaginationParams: {
|
|
1234
|
+
toQueryParams: (params: PaginationParams) => Record<string, QueryParamValue>;
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
type AssetDto = {
|
|
1238
|
+
code: string;
|
|
1239
|
+
fractional_digits: number;
|
|
1240
|
+
id: string;
|
|
1241
|
+
name: string;
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
type AssetId = Newtype<string, 'AssetId'>;
|
|
1245
|
+
declare const AssetId: (value: string) => AssetId;
|
|
1246
|
+
type AssetCode = Newtype<string, 'AssetCode'>;
|
|
1247
|
+
declare const AssetCode: (value: string) => AssetCode;
|
|
1248
|
+
type Asset = {
|
|
1249
|
+
id: AssetId;
|
|
1250
|
+
code: AssetCode;
|
|
1251
|
+
name: string;
|
|
1252
|
+
fractionalDigits: number;
|
|
1253
|
+
};
|
|
1254
|
+
declare const Asset: {
|
|
1255
|
+
fromDto: (dto: AssetDto) => Asset;
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
type ParticipationStatusDto = 'prepared' | 'pending' | 'submitted' | 'completed' | 'failed' | 'remit_submitted' | 'remitted' | 'remit_failed';
|
|
1259
|
+
type ParticipationDto = {
|
|
1260
|
+
object: 'participation';
|
|
1261
|
+
id: string;
|
|
1262
|
+
offer_id: string;
|
|
1263
|
+
offer_option_id: string;
|
|
1264
|
+
status: ParticipationStatusDto;
|
|
1265
|
+
amount: string;
|
|
1266
|
+
amount_string: string;
|
|
1267
|
+
asset: AssetDto;
|
|
1268
|
+
chain: string;
|
|
1269
|
+
inserted_at: string | null | undefined;
|
|
1270
|
+
updated_at: string | null | undefined;
|
|
1271
|
+
wallet_address: string | null | undefined;
|
|
1272
|
+
};
|
|
1273
|
+
type CreateParticipationDto = {
|
|
1274
|
+
offer_id: string;
|
|
1275
|
+
offer_option_id: string;
|
|
1276
|
+
chain: string;
|
|
1277
|
+
wallet_address: string;
|
|
1278
|
+
amount: string;
|
|
1279
|
+
asset_id: string;
|
|
1280
|
+
approval_transaction_hash: string | null | undefined;
|
|
1281
|
+
};
|
|
1282
|
+
|
|
1283
|
+
type OfferDetailDto = {
|
|
1284
|
+
asset: AssetDto;
|
|
1285
|
+
faqs: OfferDetailFaqDto[];
|
|
1286
|
+
funding_assets: AssetDto[];
|
|
1287
|
+
tokens: OfferTokenDto[];
|
|
1288
|
+
id: string;
|
|
1289
|
+
links: OfferDetailLinkDto[];
|
|
1290
|
+
milestones: OfferDetailMilestoneDto[];
|
|
1291
|
+
name: string;
|
|
1292
|
+
object: 'offer_details';
|
|
1293
|
+
options: OfferDetailOptionDto[];
|
|
1294
|
+
slug: string;
|
|
1295
|
+
type: OfferTypeDto;
|
|
1296
|
+
terms: OfferDetailTermDto[];
|
|
1297
|
+
about: string | null | undefined;
|
|
1298
|
+
banner_url: string;
|
|
1299
|
+
category: string;
|
|
1300
|
+
ends_at: string | null;
|
|
1301
|
+
logo_url: string;
|
|
1302
|
+
starts_at: string;
|
|
1303
|
+
tagline: string;
|
|
1304
|
+
};
|
|
1305
|
+
type OfferDetailFaqDto = {
|
|
1306
|
+
answer: string | null;
|
|
1307
|
+
question: string | null;
|
|
1308
|
+
};
|
|
1309
|
+
type OfferDetailLinkDto = {
|
|
1310
|
+
label: string | null;
|
|
1311
|
+
url: string | null;
|
|
1312
|
+
};
|
|
1313
|
+
type OfferDetailMilestoneDto = {
|
|
1314
|
+
name: string | null;
|
|
1315
|
+
schedule: string | null;
|
|
1316
|
+
status: 'completed' | 'active' | 'upcoming';
|
|
1317
|
+
};
|
|
1318
|
+
type OfferDetailOptionDto = {
|
|
1319
|
+
bid_increment: number | null;
|
|
1320
|
+
floor_price_usd: number | null;
|
|
1321
|
+
id: string;
|
|
1322
|
+
minimum_purchase_usd: number | null;
|
|
1323
|
+
price_usd: string | null;
|
|
1324
|
+
sale_agreement_url: string | null;
|
|
1325
|
+
slug: string;
|
|
1326
|
+
total_token_supply: number | null;
|
|
1327
|
+
};
|
|
1328
|
+
type OfferDetailTermDto = {
|
|
1329
|
+
key: string | null;
|
|
1330
|
+
value: string | null;
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
type OfferOptionId = Newtype<string, 'OfferOptionId'>;
|
|
1334
|
+
declare const OfferOptionId: (value: string) => OfferOptionId;
|
|
1335
|
+
type OfferOptionSlug = Newtype<string, 'OfferOptionSlug'>;
|
|
1336
|
+
declare const OfferOptionSlug: (value: string) => OfferOptionSlug;
|
|
1337
|
+
type OfferDetail = {
|
|
1338
|
+
id: OfferId;
|
|
1339
|
+
slug: OfferSlug;
|
|
1340
|
+
type: OfferType;
|
|
1341
|
+
name: string;
|
|
1342
|
+
asset: Asset;
|
|
1343
|
+
fundingAssets: Asset[];
|
|
1344
|
+
tokens: OfferToken[];
|
|
1345
|
+
about: string | null;
|
|
1346
|
+
tagline: string;
|
|
1347
|
+
bannerUrl: string;
|
|
1348
|
+
logoUrl: string;
|
|
1349
|
+
category: string;
|
|
1350
|
+
startsAt: Date;
|
|
1351
|
+
endsAt: Date | null;
|
|
1352
|
+
faqs: FaqItem[];
|
|
1353
|
+
links: Link[];
|
|
1354
|
+
milestones: Milestone[];
|
|
1355
|
+
options: OfferOption[];
|
|
1356
|
+
terms: TermItem[];
|
|
1357
|
+
};
|
|
1358
|
+
declare const OfferDetail: {
|
|
1359
|
+
fromDto: (dto: OfferDetailDto) => OfferDetail;
|
|
1360
|
+
};
|
|
1361
|
+
type OfferOption = {
|
|
1362
|
+
id: OfferOptionId;
|
|
1363
|
+
slug: OfferOptionSlug;
|
|
1364
|
+
bidIncrement: number | null;
|
|
1365
|
+
floorPriceUsd: number | null;
|
|
1366
|
+
minimumPurchaseUsd: number | null;
|
|
1367
|
+
priceUsd: string | null;
|
|
1368
|
+
saleAgreementUrl: string | null;
|
|
1369
|
+
totalTokenSupply: number | null;
|
|
1370
|
+
};
|
|
1371
|
+
declare const OfferOption: {
|
|
1372
|
+
fromDto: (dto: OfferDetailOptionDto) => OfferOption;
|
|
1373
|
+
};
|
|
1374
|
+
type FaqItem = {
|
|
1375
|
+
question: string | null;
|
|
1376
|
+
answer: string | null;
|
|
1377
|
+
};
|
|
1378
|
+
declare const FaqItem: {
|
|
1379
|
+
fromDto: (dto: OfferDetailFaqDto) => FaqItem;
|
|
1380
|
+
};
|
|
1381
|
+
type Link = {
|
|
1382
|
+
label: string | null;
|
|
1383
|
+
url: string | null;
|
|
1384
|
+
};
|
|
1385
|
+
declare const Link: {
|
|
1386
|
+
fromDto: (dto: OfferDetailLinkDto) => Link;
|
|
1387
|
+
};
|
|
1388
|
+
type TermItem = {
|
|
1389
|
+
key: string | null;
|
|
1390
|
+
value: string | null;
|
|
1391
|
+
};
|
|
1392
|
+
declare const TermItem: {
|
|
1393
|
+
fromDto: (dto: OfferDetailTermDto) => TermItem;
|
|
1394
|
+
};
|
|
1395
|
+
type Milestone = {
|
|
1396
|
+
name: string | null;
|
|
1397
|
+
schedule: string | null;
|
|
1398
|
+
status: 'completed' | 'active' | 'upcoming';
|
|
1399
|
+
};
|
|
1400
|
+
declare const Milestone: {
|
|
1401
|
+
fromDto: (dto: OfferDetailMilestoneDto) => Milestone;
|
|
1402
|
+
};
|
|
1403
|
+
|
|
1404
|
+
/** Unique identifier for a participation. */
|
|
1405
|
+
type ParticipationId = Newtype<string, 'ParticipationId'>;
|
|
1406
|
+
/** Casts a string into a typed {@link ParticipationId}. */
|
|
1407
|
+
declare const ParticipationId: (value: string) => ParticipationId;
|
|
1408
|
+
/** Blockchain identifier for where a participation is funded. */
|
|
1409
|
+
type Blockchain = Newtype<string, 'Blockchain'>;
|
|
1410
|
+
/** Casts a string into a typed {@link Blockchain}. */
|
|
1411
|
+
declare const Blockchain: (value: string) => Blockchain;
|
|
1412
|
+
/** Wallet address used for a participation. */
|
|
1413
|
+
type WalletAddress = Newtype<`0x${string}`, 'WalletAddress'>;
|
|
1414
|
+
/** Casts a `0x`-prefixed string into a typed {@link WalletAddress}. */
|
|
1415
|
+
declare const WalletAddress: (value: `0x${string}`) => WalletAddress;
|
|
1416
|
+
/** Possible participation lifecycle states returned by the API. */
|
|
1417
|
+
type ParticipationStatus = ParticipationStatusDto;
|
|
1418
|
+
/** Pagination params for listing participations, with an optional offer filter. */
|
|
1419
|
+
interface ParticipationsPaginationParams extends PaginationParams {
|
|
1420
|
+
offerId?: OfferId;
|
|
1421
|
+
}
|
|
1422
|
+
declare const ParticipationsPaginationParams: {
|
|
1423
|
+
toQueryParams: (params: ParticipationsPaginationParams) => Record<string, QueryParamValue>;
|
|
1424
|
+
};
|
|
1425
|
+
/** Domain model for a participation returned by CoinList APIs. */
|
|
1426
|
+
type Participation = {
|
|
1427
|
+
/** Unique participation id. */
|
|
1428
|
+
id: ParticipationId;
|
|
1429
|
+
/** Parent offer id. */
|
|
1430
|
+
offerId: OfferId;
|
|
1431
|
+
/** Selected offer option id. */
|
|
1432
|
+
offerOptionId: OfferOptionId;
|
|
1433
|
+
/** Current processing status. */
|
|
1434
|
+
status: ParticipationStatus;
|
|
1435
|
+
/** Raw participation amount from API. */
|
|
1436
|
+
amount: string;
|
|
1437
|
+
/** Human-readable formatted amount from API. */
|
|
1438
|
+
displayAmount: string;
|
|
1439
|
+
/** Asset metadata for the participation amount. */
|
|
1440
|
+
asset: Asset;
|
|
1441
|
+
/** Funding chain identifier. */
|
|
1442
|
+
chain: Blockchain;
|
|
1443
|
+
/** Creation timestamp, if returned by API. */
|
|
1444
|
+
insertedAt: Date | null;
|
|
1445
|
+
/** Last update timestamp, if returned by API. */
|
|
1446
|
+
updatedAt: Date | null;
|
|
1447
|
+
/** Wallet used for participation, blank values normalized to null. */
|
|
1448
|
+
walletAddress: WalletAddress | null;
|
|
1449
|
+
};
|
|
1450
|
+
declare const Participation: {
|
|
1451
|
+
/** Maps API DTO shape into the SDK participation domain model. */
|
|
1452
|
+
fromDto: (dto: ParticipationDto) => Participation;
|
|
1453
|
+
};
|
|
1454
|
+
/** Parameters required to create a new participation. */
|
|
1455
|
+
type CreateParticipationParams = {
|
|
1456
|
+
/** Offer to participate in. */
|
|
1457
|
+
offerId: OfferId;
|
|
1458
|
+
/** Offer option selected for participation. */
|
|
1459
|
+
offerOptionId: OfferOptionId;
|
|
1460
|
+
/** Blockchain for funding. */
|
|
1461
|
+
chain: Blockchain;
|
|
1462
|
+
/** Wallet address that funds the participation. */
|
|
1463
|
+
walletAddress: WalletAddress;
|
|
1464
|
+
/**
|
|
1465
|
+
* Decimal token amount to participate with (e.g. `"100"` for 100 USDC), NOT
|
|
1466
|
+
* raw base units. The backend rescales this by the asset's decimals to verify
|
|
1467
|
+
* it against the on-chain approval allowance.
|
|
1468
|
+
*/
|
|
1469
|
+
amount: string;
|
|
1470
|
+
/** Funding asset id. */
|
|
1471
|
+
assetId: AssetId;
|
|
1472
|
+
/**
|
|
1473
|
+
* Hash of the ERC-20 `approve()` transaction covering this participation.
|
|
1474
|
+
* Required: the backend verifies it on-chain (sender, token, spender, and
|
|
1475
|
+
* approved amount) before confirming the participation.
|
|
1476
|
+
*/
|
|
1477
|
+
approvalTransactionHash: string;
|
|
1478
|
+
};
|
|
1479
|
+
declare const CreateParticipationParams: {
|
|
1480
|
+
/** Maps participation creation params into API DTO payload. */
|
|
1481
|
+
toDto: (params: CreateParticipationParams) => CreateParticipationDto;
|
|
1482
|
+
};
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* Read/write operations for token sales: listing and reading the current user's
|
|
1486
|
+
* participations, and recording a new one. The on-chain execution flow
|
|
1487
|
+
* (`executeTokenSale`) is layered on top of this in the client-side namespace.
|
|
1488
|
+
*/
|
|
1489
|
+
interface CoinListTokenSaleNamespace {
|
|
1490
|
+
/**
|
|
1491
|
+
* Fetches all participations by iterating through every paginated response,
|
|
1492
|
+
* optionally filtered by offer.
|
|
1493
|
+
*
|
|
1494
|
+
* Requires an authenticated user; throws {@link NotAuthenticatedError}
|
|
1495
|
+
* otherwise.
|
|
1496
|
+
*/
|
|
1497
|
+
list(offerId?: OfferId): Promise<Participation[]>;
|
|
1498
|
+
/**
|
|
1499
|
+
* Fetches a single page of participations, optionally filtered by offer.
|
|
1500
|
+
*
|
|
1501
|
+
* Requires an authenticated user; throws {@link NotAuthenticatedError}
|
|
1502
|
+
* otherwise.
|
|
1503
|
+
*/
|
|
1504
|
+
listPage(params: ParticipationsPaginationParams): Promise<PaginatedResponse<Participation>>;
|
|
1505
|
+
/**
|
|
1506
|
+
* Fetches a participation by id.
|
|
1507
|
+
*
|
|
1508
|
+
* Requires an authenticated user; throws {@link NotAuthenticatedError}
|
|
1509
|
+
* otherwise.
|
|
1510
|
+
*/
|
|
1511
|
+
get(id: ParticipationId): Promise<Participation>;
|
|
1512
|
+
/**
|
|
1513
|
+
* Records a participation with CoinList.
|
|
1514
|
+
*
|
|
1515
|
+
* Requires an authenticated user; throws {@link NotAuthenticatedError}
|
|
1516
|
+
* otherwise.
|
|
1517
|
+
*/
|
|
1518
|
+
createParticipation(params: CreateParticipationParams): Promise<Participation>;
|
|
1519
|
+
}
|
|
1520
|
+
declare class CoinListTokenSaleNamespaceImpl implements CoinListTokenSaleNamespace {
|
|
1521
|
+
private readonly ctx;
|
|
1522
|
+
protected readonly log: InternalLogger;
|
|
1523
|
+
constructor(ctx: SharedNamespaceContext);
|
|
1524
|
+
list(offerId?: OfferId): Promise<Participation[]>;
|
|
1525
|
+
listPage(params: ParticipationsPaginationParams): Promise<PaginatedResponse<Participation>>;
|
|
1526
|
+
get(id: ParticipationId): Promise<Participation>;
|
|
1527
|
+
createParticipation(params: CreateParticipationParams): Promise<Participation>;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
type Ticker = Newtype<string, 'Ticker'>;
|
|
1531
|
+
declare const Ticker: (value: string) => Ticker;
|
|
1532
|
+
type OrderBookSide = 'buy' | 'sell';
|
|
1533
|
+
|
|
1534
|
+
/**
|
|
1535
|
+
* No `chain` on the read params: Ondo runs no sandbox, so every environment
|
|
1536
|
+
* prices against Ondo production on Ethereum mainnet. Accepting a chain would
|
|
1537
|
+
* let a caller ask for Sepolia and silently receive mainnet pricing.
|
|
1538
|
+
* {@link BuildOndoSwapTransactionParams} is the exception, and says why.
|
|
1539
|
+
*/
|
|
1540
|
+
type GetOndoTradingStatusParams = {
|
|
1541
|
+
symbol: AssetSymbol;
|
|
1542
|
+
/**
|
|
1543
|
+
* Required, and deliberately not defaulted: `tradable` and both order caps
|
|
1544
|
+
* describe this side only. Guessing `buy` would hand buy caps to someone
|
|
1545
|
+
* sizing a sell. The endpoint answers 422 without it.
|
|
1546
|
+
*/
|
|
1547
|
+
side: OrderBookSide;
|
|
1548
|
+
};
|
|
1549
|
+
/** How long Ondo should hold the price. Omit to take Ondo's own default. */
|
|
1550
|
+
type OndoQuoteDuration = 'short' | 'long';
|
|
1551
|
+
/**
|
|
1552
|
+
* A quote is sized by the quantity or by the dollar amount. The endpoint takes
|
|
1553
|
+
* exactly one; `getOndoQuote` sends whichever is present.
|
|
1554
|
+
*/
|
|
1555
|
+
type OndoQuoteSize = {
|
|
1556
|
+
tokenAmount: BlockchainAmount;
|
|
1557
|
+
} | {
|
|
1558
|
+
notionalValue: DecimalString;
|
|
1559
|
+
};
|
|
1560
|
+
type GetOndoQuoteParams = {
|
|
1561
|
+
symbol: AssetSymbol;
|
|
1562
|
+
side: OrderBookSide;
|
|
1563
|
+
duration?: OndoQuoteDuration;
|
|
1564
|
+
} & OndoQuoteSize;
|
|
1565
|
+
/**
|
|
1566
|
+
* What both builders take, before the one field whose meaning forks.
|
|
1567
|
+
*
|
|
1568
|
+
* There is no funding token and no asset here - frontline resolves both from
|
|
1569
|
+
* the offer, because Ninshubur signs a request bound to them and a caller that
|
|
1570
|
+
* could name them could have CoinList sign for a contract of its own. Which
|
|
1571
|
+
* endpoint was called is what says which of the two `amount` counts.
|
|
1572
|
+
*
|
|
1573
|
+
* `chain` is required although the read params refuse it, because these name a
|
|
1574
|
+
* real contract on a real chain rather than asking Ondo for a price.
|
|
1575
|
+
*/
|
|
1576
|
+
type BuildOndoSwapParamsCore = {
|
|
1577
|
+
symbol: AssetSymbol;
|
|
1578
|
+
chain: EthereumChain;
|
|
1579
|
+
/**
|
|
1580
|
+
* The wallet that will *send* the transaction, and that receives the other
|
|
1581
|
+
* token. The calldata is signed over it, so a transaction built for one
|
|
1582
|
+
* wallet and broadcast by another reverts.
|
|
1583
|
+
*/
|
|
1584
|
+
walletAddress: EvmWalletAddress;
|
|
1585
|
+
};
|
|
1586
|
+
/**
|
|
1587
|
+
* What it takes to turn an indicative price into signed, fillable calldata for
|
|
1588
|
+
* a purchase: `POST /v1/ondo/swap/buy`.
|
|
1589
|
+
*
|
|
1590
|
+
* Separate from {@link BuildOndoSellParams} although the fields match today,
|
|
1591
|
+
* because `amount` is denominated in a different token on each - which is
|
|
1592
|
+
* frontline's own reason for splitting the endpoint rather than taking a
|
|
1593
|
+
* `side`. Sharing one type would re-merge the distinction the split exists to
|
|
1594
|
+
* make, and the two will diverge the day either side gains a knob.
|
|
1595
|
+
*/
|
|
1596
|
+
type BuildOndoBuyParams = BuildOndoSwapParamsCore & {
|
|
1597
|
+
/**
|
|
1598
|
+
* The **gross** deposit, in the base units of the funding token - the coin
|
|
1599
|
+
* the user chose and approved.
|
|
1600
|
+
*
|
|
1601
|
+
* Sized by `amount` alone, with no `notionalValue` alternative: the calldata
|
|
1602
|
+
* authorises a specific ERC-20 pull, so the number that ends up on chain has
|
|
1603
|
+
* to be the number the caller meant rather than one derived from a dollar
|
|
1604
|
+
* figure. CoinList's fee comes off it, and Ondo prices the remainder.
|
|
1605
|
+
*
|
|
1606
|
+
* Its `decimals` are also what the response's `spend_input_decimals` is
|
|
1607
|
+
* checked against: frontline resolves the funding token from the offer
|
|
1608
|
+
* rather than from this request, so the two are independent answers to the
|
|
1609
|
+
* same question and a disagreement means the wrong token was sized.
|
|
1610
|
+
*/
|
|
1611
|
+
amount: BlockchainAmount;
|
|
1612
|
+
};
|
|
1613
|
+
/**
|
|
1614
|
+
* What it takes to turn an indicative price into signed, fillable calldata for
|
|
1615
|
+
* a sale: `POST /v1/ondo/swap/sell`.
|
|
1616
|
+
*
|
|
1617
|
+
* See {@link BuildOndoBuyParams} for why this is its own type.
|
|
1618
|
+
*/
|
|
1619
|
+
type BuildOndoSellParams = BuildOndoSwapParamsCore & {
|
|
1620
|
+
/**
|
|
1621
|
+
* The quantity of the **asset** to sell, in the asset's own base units - not
|
|
1622
|
+
* in the funding token's, which is the same integer meaning something 1e12
|
|
1623
|
+
* different.
|
|
1624
|
+
*
|
|
1625
|
+
* This is the figure the wallet must have approved: a sale delivers the
|
|
1626
|
+
* asset, so the swap contract pulls it with `transferFrom` exactly as it
|
|
1627
|
+
* pulls the deposit on a purchase.
|
|
1628
|
+
*
|
|
1629
|
+
* Its `decimals` are checked against the response's `spend_input_decimals`,
|
|
1630
|
+
* which frontline reads on-chain from the asset on `chain`. The SDK's own
|
|
1631
|
+
* answer comes from the quote, which resolves the asset on Ethereum mainnet,
|
|
1632
|
+
* so on a testnet these are two independent resolutions of two different
|
|
1633
|
+
* contracts - and the check is what says so.
|
|
1634
|
+
*/
|
|
1635
|
+
amount: BlockchainAmount;
|
|
1636
|
+
};
|
|
1637
|
+
|
|
1638
|
+
/**
|
|
1639
|
+
* Raw JSON models for the Ondo swap endpoints, mirroring
|
|
1640
|
+
* `OndoSwapTradingStatus`, `OndoSwapQuote`, `OndoSwapBuy` and `OndoSwapSell`
|
|
1641
|
+
* in frontline's OpenAPI schema. The two GETs are free to poll: neither spends
|
|
1642
|
+
* an attestation, so a client may call them while the user edits an order. The
|
|
1643
|
+
* two POSTs are not - each spends one and hands back signed calldata with a
|
|
1644
|
+
* deadline.
|
|
1645
|
+
*
|
|
1646
|
+
* **One endpoint per side, and therefore one model per side.** The reads take
|
|
1647
|
+
* a `side` and answer the same shape either way, so they stay single. The
|
|
1648
|
+
* writes do not: a buy commits to an exact quantity, a sell to a range with a
|
|
1649
|
+
* floor beneath it, and `amount` is the funding token on one and the asset on
|
|
1650
|
+
* the other. Only the transport fields mean the same thing on both.
|
|
1651
|
+
* `POST /v1/ondo/swap/transaction` survives as a deprecated alias of the buy
|
|
1652
|
+
* under the old `pay_input_*` names; the SDK does not call it.
|
|
1653
|
+
*
|
|
1654
|
+
* Neither GET takes a `chain`. Ondo runs no sandbox, so every environment
|
|
1655
|
+
* prices against Ondo production on Ethereum mainnet. The POSTs do carry one:
|
|
1656
|
+
* they target a real contract, which on every environment but production is
|
|
1657
|
+
* the Sepolia one with the mocked attestation.
|
|
1658
|
+
*/
|
|
1659
|
+
/**
|
|
1660
|
+
* Whether an asset can be traded right now, and the caps if so.
|
|
1661
|
+
*
|
|
1662
|
+
* Every cap is a *human decimal* string and is nullable — Ondo answers a
|
|
1663
|
+
* restricted `/v1/limits/*` with a 403, which frontline turns into
|
|
1664
|
+
* `tradable: false` and three nulls rather than an error. A null cap therefore
|
|
1665
|
+
* means **Ondo restricted the asset, not that the cap is unlimited**. The
|
|
1666
|
+
* response carries no `asset_decimals`, so there is nothing to scale
|
|
1667
|
+
* `gross_max_tokens` by.
|
|
1668
|
+
*
|
|
1669
|
+
* There is no `reason` field. A restriction surfaces only as `tradable: false`
|
|
1670
|
+
* plus the nulls; frontline keeps Ondo's reason codes to its own admin surface
|
|
1671
|
+
* and does not forward them.
|
|
1672
|
+
*/
|
|
1673
|
+
type OndoTradingStatusDto = {
|
|
1674
|
+
object: 'ondo_swap_trading_status';
|
|
1675
|
+
/** The `side` the request asked for, echoed back. */
|
|
1676
|
+
side: 'buy' | 'sell';
|
|
1677
|
+
/** For `side` only — an asset can be sellable while not buyable. */
|
|
1678
|
+
tradable: boolean;
|
|
1679
|
+
/** Whole tokens, for `side` only. E.g. `"100.000000000000000000"`. */
|
|
1680
|
+
gross_max_tokens: string | null;
|
|
1681
|
+
/** USD, for `side` only. E.g. `"1234.560000000000000000"`. */
|
|
1682
|
+
gross_max_notional_value: string | null;
|
|
1683
|
+
/**
|
|
1684
|
+
* USD cap for the session the market is currently in, e.g. `"200000"`.
|
|
1685
|
+
* Unlike the two above this comes from Ondo's sideless session endpoint, so
|
|
1686
|
+
* it applies across buys and sells together.
|
|
1687
|
+
*/
|
|
1688
|
+
gross_max_active_notional_value: string | null;
|
|
1689
|
+
};
|
|
1690
|
+
/** An indicative, size- and side-aware price for an Ondo asset. */
|
|
1691
|
+
type OndoQuoteDto = {
|
|
1692
|
+
object: 'ondo_swap_quote';
|
|
1693
|
+
/** EIP-155 chain id. Always `"1"`, per the no-sandbox note above. */
|
|
1694
|
+
chain_id: string;
|
|
1695
|
+
symbol: string;
|
|
1696
|
+
/** Ticker of the underlying security, e.g. `"AAPL"` for `"AAPLon"`. */
|
|
1697
|
+
ticker: string;
|
|
1698
|
+
asset_address: string;
|
|
1699
|
+
/** Decimals of the `asset_address` contract. Scales `token_base_units`. */
|
|
1700
|
+
asset_decimals: number;
|
|
1701
|
+
side: 'buy' | 'sell';
|
|
1702
|
+
/**
|
|
1703
|
+
* Quantity of the asset in its smallest unit, as a raw uint256 string:
|
|
1704
|
+
* `"5000000000000000000"` is 5 tokens at 18 decimals. Map it with
|
|
1705
|
+
* `blockchainAmountFromRawOrThrow`, not `parseBlockchainAmountOrThrow`.
|
|
1706
|
+
*
|
|
1707
|
+
* Not to be confused with the `token_amount` *request* parameter, which is
|
|
1708
|
+
* the same quantity in whole tokens. Ondo names both `tokenAmount`, 1e18
|
|
1709
|
+
* apart, so echoing one back as the other is a real hazard.
|
|
1710
|
+
*/
|
|
1711
|
+
token_base_units: string;
|
|
1712
|
+
/**
|
|
1713
|
+
* USD price of one whole token as a human decimal string, e.g.
|
|
1714
|
+
* `"225.273151158540753535"`. Already scaled, so it needs none of the
|
|
1715
|
+
* handling `token_base_units` does.
|
|
1716
|
+
*/
|
|
1717
|
+
price: string;
|
|
1718
|
+
};
|
|
1719
|
+
/**
|
|
1720
|
+
* The transport half of a built swap, identical on both sides.
|
|
1721
|
+
*
|
|
1722
|
+
* `spend_input_amount` is the only key here whose *token* depends on the side,
|
|
1723
|
+
* and `spend_input_decimals` is what says at what scale. Everything below this
|
|
1724
|
+
* point differs, which is why the two responses are two types rather than one
|
|
1725
|
+
* with nullable halves.
|
|
1726
|
+
*
|
|
1727
|
+
* There is no `object` envelope and no `side` echo. `action` says what to do
|
|
1728
|
+
* with the body, matching `AllowWalletResponseDto`; which trade it encodes is
|
|
1729
|
+
* settled by the endpoint that was called, so nothing on the wire has to say
|
|
1730
|
+
* it and nothing has to be checked against it.
|
|
1731
|
+
*/
|
|
1732
|
+
type OndoSwapDtoCore = {
|
|
1733
|
+
action: 'broadcast_transaction';
|
|
1734
|
+
/** The swap contract the transaction is sent to. */
|
|
1735
|
+
to: string;
|
|
1736
|
+
/** ABI-encoded `swap(...)` calldata. Broadcast verbatim - never re-encode it. */
|
|
1737
|
+
data: string;
|
|
1738
|
+
/**
|
|
1739
|
+
* When the signed calldata stops being accepted - RFC3339, e.g.
|
|
1740
|
+
* `"2026-08-13T23:04:12Z"`. This is Ninshubur's `expiration`, which signs
|
|
1741
|
+
* the same instant as the EIP-712 `deadline` in the calldata, so a
|
|
1742
|
+
* transaction broadcast after it reverts.
|
|
1743
|
+
*/
|
|
1744
|
+
expires_at: string;
|
|
1745
|
+
/**
|
|
1746
|
+
* Gross amount the wallet spends, echoing the requested `amount`, in the
|
|
1747
|
+
* smallest unit of the token this side spends - the funding token on a buy,
|
|
1748
|
+
* the asset on a sell. The approval is compared against this.
|
|
1749
|
+
*
|
|
1750
|
+
* Named `pay_input_amount` on the deprecated
|
|
1751
|
+
* `POST /v1/ondo/swap/transaction`. `pay` was accurate only while a buy was
|
|
1752
|
+
* the sole thing this could encode: a sell delivers the asset rather than
|
|
1753
|
+
* paying for one.
|
|
1754
|
+
*/
|
|
1755
|
+
spend_input_amount: string;
|
|
1756
|
+
/**
|
|
1757
|
+
* Decimals `spend_input_amount` is counted in.
|
|
1758
|
+
*
|
|
1759
|
+
* Frontline reads it on-chain from the token the side spends, which it
|
|
1760
|
+
* resolves from the offer rather than from anything the caller sent. That
|
|
1761
|
+
* makes it the only published scale for a token the request never names -
|
|
1762
|
+
* and an independent answer to the one the SDK derived when it sized the
|
|
1763
|
+
* order, which is why both builders compare the two.
|
|
1764
|
+
*
|
|
1765
|
+
* **The same key, two scales.** It counts whichever token the side spends:
|
|
1766
|
+
* the funding token's 6 on a buy, the asset's 18 on a sell. Worth knowing
|
|
1767
|
+
* before integrating against both.
|
|
1768
|
+
*/
|
|
1769
|
+
spend_input_decimals: number;
|
|
1770
|
+
};
|
|
1771
|
+
/**
|
|
1772
|
+
* Signed, ready-to-broadcast calldata for a purchase, and the amounts it
|
|
1773
|
+
* commits to: `POST /v1/ondo/swap/buy`.
|
|
1774
|
+
*
|
|
1775
|
+
* Unlike {@link OndoQuoteDto} this **spends an attestation**, so it is not
|
|
1776
|
+
* pollable: one call per order, plus one per user-requested refresh. Frontline
|
|
1777
|
+
* also reads the wallet's allowance on the funding token before asking
|
|
1778
|
+
* Ninshubur for anything, so an unapproved wallet is refused here rather than
|
|
1779
|
+
* reverting on chain.
|
|
1780
|
+
*
|
|
1781
|
+
* The quantity is attested and exact, with no floor beneath it, which is what
|
|
1782
|
+
* separates a buy from an {@link OndoSellDto}.
|
|
1783
|
+
*
|
|
1784
|
+
* **Carries no identity and no price.** No `chain_id`, `symbol`, `ticker` or
|
|
1785
|
+
* `price` - the request named the first few and frontline drops Ninshubur's
|
|
1786
|
+
* `price` deliberately, because `GET /v1/ondo/swap/quote` already publishes
|
|
1787
|
+
* one under that name at a different scale. Anything the UI needs beyond the
|
|
1788
|
+
* amounts comes from that GET or from the offer.
|
|
1789
|
+
*
|
|
1790
|
+
* Two scales are on the wire: `fee` and `notional_value` are in
|
|
1791
|
+
* `spend_input_decimals`, and `receive_output_amount` is in
|
|
1792
|
+
* `receive_output_decimals`. Neither is interchangeable with the quote's
|
|
1793
|
+
* `asset_decimals`, which answers for a different number.
|
|
1794
|
+
*/
|
|
1795
|
+
type OndoBuyDto = OndoSwapDtoCore & {
|
|
1796
|
+
/**
|
|
1797
|
+
* CoinList's cut of `spend_input_amount`, in the same units. `"0"` until
|
|
1798
|
+
* ENG-1718 turns a fee on - frontline rejects a non-zero one today.
|
|
1799
|
+
*
|
|
1800
|
+
* Taken at execution rather than added on top, so the wallet never approves
|
|
1801
|
+
* more than `spend_input_amount`.
|
|
1802
|
+
*/
|
|
1803
|
+
fee: string;
|
|
1804
|
+
/**
|
|
1805
|
+
* `spend_input_amount` less `fee`, in `spend_input_decimals`: the part that
|
|
1806
|
+
* reaches Ondo, what the quantity was priced against, and what the
|
|
1807
|
+
* signature commits to.
|
|
1808
|
+
*/
|
|
1809
|
+
notional_value: string;
|
|
1810
|
+
/**
|
|
1811
|
+
* Quantity of the asset the wallet receives, in the asset's smallest unit.
|
|
1812
|
+
* Scale it by `receive_output_decimals`, not by the funding token's and not
|
|
1813
|
+
* by {@link OndoQuoteDto}'s `asset_decimals`.
|
|
1814
|
+
*/
|
|
1815
|
+
receive_output_amount: string;
|
|
1816
|
+
/**
|
|
1817
|
+
* Decimals `receive_output_amount` is counted in.
|
|
1818
|
+
*
|
|
1819
|
+
* Reported by whatever priced the quantity, rather than looked up from the
|
|
1820
|
+
* asset. That is not the same number as {@link OndoQuoteDto}'s
|
|
1821
|
+
* `asset_decimals`, which frontline resolves from its own catalogue: the two
|
|
1822
|
+
* are allowed to disagree, and only this one answers for the quantity in
|
|
1823
|
+
* this response.
|
|
1824
|
+
*/
|
|
1825
|
+
receive_output_decimals: number;
|
|
1826
|
+
};
|
|
1827
|
+
/**
|
|
1828
|
+
* Signed, ready-to-broadcast calldata for a sale, and the range it commits to:
|
|
1829
|
+
* `POST /v1/ondo/swap/sell`.
|
|
1830
|
+
*
|
|
1831
|
+
* Like {@link OndoBuyDto} it **spends an attestation** and expires, so it is
|
|
1832
|
+
* called once on confirmation and never on a timer. Frontline reads the
|
|
1833
|
+
* wallet's allowance on the **asset** before signing - a sell delivers it -
|
|
1834
|
+
* and refuses a short one with a 422 naming that address.
|
|
1835
|
+
*
|
|
1836
|
+
* **A sell commits to a range rather than a quantity.** Ondo settles through
|
|
1837
|
+
* USDon before converting to the settlement token, so the response publishes
|
|
1838
|
+
* what to expect and the floor the calldata enforces, each with the fee
|
|
1839
|
+
* charged at it. There is no `notional_value`: a sell commits on the output
|
|
1840
|
+
* side, so there is no fee-exclusive input to report and frontline declines to
|
|
1841
|
+
* relate numbers Ninshubur did not relate.
|
|
1842
|
+
*
|
|
1843
|
+
* All four amounts below are in `receive_output_decimals`. The one amount that
|
|
1844
|
+
* is not is `spend_input_amount`, in `spend_input_decimals` - see
|
|
1845
|
+
* {@link OndoSwapDtoCore}.
|
|
1846
|
+
*
|
|
1847
|
+
* One thing the response does not say, and the calldata does: the floor signed
|
|
1848
|
+
* into `data` is **gross** of CoinList's fee, so a caller decoding it finds a
|
|
1849
|
+
* larger number than `minimum_quantity`. Both are correct; `minimum_quantity`
|
|
1850
|
+
* is what the wallet actually receives.
|
|
1851
|
+
*/
|
|
1852
|
+
type OndoSellDto = OndoSwapDtoCore & {
|
|
1853
|
+
/**
|
|
1854
|
+
* CoinList's cut at the expected outcome, in the settlement token. Already
|
|
1855
|
+
* deducted from `expected_quantity` rather than charged on top of it.
|
|
1856
|
+
*
|
|
1857
|
+
* `"0"` until ENG-1718 turns a fee on - frontline rejects a non-zero one on
|
|
1858
|
+
* either side today.
|
|
1859
|
+
*/
|
|
1860
|
+
expected_fee: string;
|
|
1861
|
+
/**
|
|
1862
|
+
* What the sale is expected to return, **net of `expected_fee`**, in the
|
|
1863
|
+
* settlement token's smallest unit.
|
|
1864
|
+
*
|
|
1865
|
+
* An expectation rather than a guarantee. What the contract enforces is
|
|
1866
|
+
* {@link OndoSellDto.minimum_quantity}.
|
|
1867
|
+
*/
|
|
1868
|
+
expected_quantity: string;
|
|
1869
|
+
/**
|
|
1870
|
+
* CoinList's cut at the floor, in the same units.
|
|
1871
|
+
*
|
|
1872
|
+
* A different number from `expected_fee` because the two are charged on
|
|
1873
|
+
* different amounts - which is why frontline publishes both rather than one.
|
|
1874
|
+
* This is the one to disclose worst-case cost with.
|
|
1875
|
+
*/
|
|
1876
|
+
minimum_fee: string;
|
|
1877
|
+
/**
|
|
1878
|
+
* The least the wallet can receive, **net of `minimum_fee`**, in the same
|
|
1879
|
+
* units. Below it the transaction reverts on chain.
|
|
1880
|
+
*
|
|
1881
|
+
* Frontline guarantees it is at most `expected_quantity` and greater than
|
|
1882
|
+
* zero. The settlement lands somewhere between the two.
|
|
1883
|
+
*/
|
|
1884
|
+
minimum_quantity: string;
|
|
1885
|
+
/**
|
|
1886
|
+
* Decimals both quantities and both fees are counted in, reported by
|
|
1887
|
+
* whatever priced them rather than looked up from the token.
|
|
1888
|
+
*
|
|
1889
|
+
* Not the same number as {@link OndoQuoteDto}'s `asset_decimals`, which
|
|
1890
|
+
* answers for the asset being sold rather than for the coin the proceeds
|
|
1891
|
+
* arrive in.
|
|
1892
|
+
*/
|
|
1893
|
+
receive_output_decimals: number;
|
|
1894
|
+
};
|
|
1895
|
+
|
|
1896
|
+
/**
|
|
1897
|
+
* Whether an Ondo asset can be traded right now.
|
|
1898
|
+
*
|
|
1899
|
+
* The caps only mean anything while trading is open, so they live on the
|
|
1900
|
+
* `tradable` branch. They stay {@link DecimalString} rather than
|
|
1901
|
+
* {@link BlockchainAmount} because the response carries no `asset_decimals`:
|
|
1902
|
+
* there is no honest exponent to attach, and the USD caps arrive with more
|
|
1903
|
+
* fractional digits than a stablecoin has decimals.
|
|
1904
|
+
*
|
|
1905
|
+
* Each cap is independently nullable even when tradable — Ondo may open an
|
|
1906
|
+
* asset for trading without publishing every limit.
|
|
1907
|
+
*
|
|
1908
|
+
* `side` is carried through from the response rather than dropped: the whole
|
|
1909
|
+
* status describes one side, so a buy and a sell status are otherwise
|
|
1910
|
+
* indistinguishable once a caller holds both.
|
|
1911
|
+
*/
|
|
1912
|
+
type OndoTradingStatus = {
|
|
1913
|
+
type: 'tradable';
|
|
1914
|
+
side: OrderBookSide;
|
|
1915
|
+
/** Largest order in whole tokens. */
|
|
1916
|
+
grossMaxTokens: DecimalString | null;
|
|
1917
|
+
/** Largest order in USD. */
|
|
1918
|
+
grossMaxNotionalValue: DecimalString | null;
|
|
1919
|
+
/** USD cap for the session the market is currently in. */
|
|
1920
|
+
grossMaxActiveNotionalValue: DecimalString | null;
|
|
1921
|
+
} | {
|
|
1922
|
+
type: 'not-tradable';
|
|
1923
|
+
side: OrderBookSide;
|
|
1924
|
+
};
|
|
1925
|
+
declare const OndoTradingStatus: {
|
|
1926
|
+
fromDto: (dto: OndoTradingStatusDto) => OndoTradingStatus;
|
|
1927
|
+
};
|
|
1928
|
+
/**
|
|
1929
|
+
* An indicative price for an Ondo asset, free to poll while the user edits an
|
|
1930
|
+
* order.
|
|
1931
|
+
*
|
|
1932
|
+
* **No CoinList fee is applied to the quantity or the price.** Ondo prices
|
|
1933
|
+
* exactly the amount asked for. A CoinList approval is fee-inclusive, so
|
|
1934
|
+
* sizing a quote against one without netting the fee first overstates what the
|
|
1935
|
+
* user receives. Showing a gross/net breakdown needs a CoinList swap
|
|
1936
|
+
* contract's `preview`, and no such contract exists for Ondo yet.
|
|
1937
|
+
*
|
|
1938
|
+
* The quote carries no transaction to broadcast and no expiry. Building one is
|
|
1939
|
+
* a separate endpoint per side that spends an attestation - see
|
|
1940
|
+
* {@link OndoBuyTransaction} and {@link OndoSellTransaction}.
|
|
1941
|
+
*/
|
|
1942
|
+
type OndoQuote = {
|
|
1943
|
+
/** Always `ethereum_mainnet`: Ondo runs no sandbox in any environment. */
|
|
1944
|
+
chain: EthereumChain;
|
|
1945
|
+
ticker: Ticker;
|
|
1946
|
+
/**
|
|
1947
|
+
* Needed to approve or transfer the asset; the quote is the only source.
|
|
1948
|
+
*
|
|
1949
|
+
* **Resolved on Ethereum mainnet**, like everything else on this quote, and
|
|
1950
|
+
* therefore not necessarily the contract the swap pulls from on the chain
|
|
1951
|
+
* the order executes on. Frontline resolves that one per chain and publishes
|
|
1952
|
+
* it nowhere, so on a testnet these are two different tokens. Tracked
|
|
1953
|
+
* against the frontline stack that follows ENG-1756.
|
|
1954
|
+
*/
|
|
1955
|
+
assetAddress: EvmContractAddress;
|
|
1956
|
+
/**
|
|
1957
|
+
* The asset as the quote resolves it, from frontline's own catalogue.
|
|
1958
|
+
*
|
|
1959
|
+
* Its `decimals` scale {@link tokenBaseUnits} and nothing else. They are
|
|
1960
|
+
* **not** the scale of a built transaction's spend or output: those are
|
|
1961
|
+
* reported by whatever priced them, the sources are allowed to disagree, and
|
|
1962
|
+
* only the one that produced a number answers for it.
|
|
1963
|
+
*/
|
|
1964
|
+
asset: Erc20Asset;
|
|
1965
|
+
side: OrderBookSide;
|
|
1966
|
+
tokenBaseUnits: BlockchainAmount;
|
|
1967
|
+
/**
|
|
1968
|
+
* USD price of one whole token. Unscaled because Ondo has already scaled it,
|
|
1969
|
+
* and by USDon's 18 decimals rather than the stablecoin's 6 — re-scaling it
|
|
1970
|
+
* by either would be wrong.
|
|
1971
|
+
*/
|
|
1972
|
+
price: DecimalString;
|
|
1973
|
+
};
|
|
1974
|
+
declare const OndoQuote: {
|
|
1975
|
+
fromDto: (dto: OndoQuoteDto) => OndoQuote;
|
|
1976
|
+
};
|
|
1977
|
+
/**
|
|
1978
|
+
* The half of a built swap that both sides share: the calldata, its deadline,
|
|
1979
|
+
* and what the wallet parts with.
|
|
1980
|
+
*
|
|
1981
|
+
* There is deliberately **no union over the two sides**. Each is built by its
|
|
1982
|
+
* own endpoint and its own namespace method, so a caller never holds one
|
|
1983
|
+
* without knowing which it is, and a union would only re-pose a question the
|
|
1984
|
+
* call site had already answered. What is genuinely common lives here, and
|
|
1985
|
+
* {@link executeOndoSwap} takes this rather than either arm - broadcasting
|
|
1986
|
+
* knows nothing about the direction of the trade.
|
|
1987
|
+
*
|
|
1988
|
+
* `side` is not on this type but on each arm, as a literal the SDK authors
|
|
1989
|
+
* from the method that was called. The wire stopped echoing one when the
|
|
1990
|
+
* endpoint split, and it is still worth carrying: `OndoOrderPlaced` is a union
|
|
1991
|
+
* the SDK builds from both, and that union needs a tag.
|
|
1992
|
+
*/
|
|
1993
|
+
type OndoSwapTransactionCore = {
|
|
1994
|
+
/**
|
|
1995
|
+
* Broadcast as-is. The `to` is the swap contract, which is also the ERC-20
|
|
1996
|
+
* spender the user must have approved.
|
|
1997
|
+
*/
|
|
1998
|
+
tx: Tx;
|
|
1999
|
+
/**
|
|
2000
|
+
* When the calldata stops being accepted. A transaction broadcast after this
|
|
2001
|
+
* reverts, so callers must compare against it before signing.
|
|
2002
|
+
*/
|
|
2003
|
+
expiresAt: Date;
|
|
2004
|
+
/**
|
|
2005
|
+
* Gross amount the wallet spends, in the decimals of the token this side
|
|
2006
|
+
* spends: the funding token on a buy, the asset on a sell.
|
|
2007
|
+
*
|
|
2008
|
+
* The same field at two scales, which is the whole reason the two sides are
|
|
2009
|
+
* two types. It is also what the approval has to cover.
|
|
2010
|
+
*/
|
|
2011
|
+
spendInputAmount: BlockchainAmount;
|
|
2012
|
+
};
|
|
2013
|
+
/**
|
|
2014
|
+
* A signed, expiring purchase: a funding token in, an exact quantity of the
|
|
2015
|
+
* asset out.
|
|
2016
|
+
*
|
|
2017
|
+
* Distinct from {@link OndoQuote} in three ways that matter: it costs an
|
|
2018
|
+
* attestation to obtain, it expires, and it carries a {@link Tx} the wallet
|
|
2019
|
+
* broadcasts verbatim. Treat it as single-use - once broadcast (or once
|
|
2020
|
+
* `expiresAt` passes) it is spent, and a new one must be built.
|
|
2021
|
+
*
|
|
2022
|
+
* **The quantity is attested and exact, with no floor beneath it.** That is
|
|
2023
|
+
* what separates it from an {@link OndoSellTransaction}, which commits to a
|
|
2024
|
+
* range: nothing here is an estimate.
|
|
2025
|
+
*
|
|
2026
|
+
* **It carries no other identity.** No chain, ticker or asset: the endpoint
|
|
2027
|
+
* publishes none of them, and inventing them from the request would assert
|
|
2028
|
+
* what the server resolved rather than report it. What it does publish is the
|
|
2029
|
+
* scale of every amount on it, so a caller needs nothing alongside it to read
|
|
2030
|
+
* the numbers - only to name the assets, which the offer already does.
|
|
2031
|
+
*
|
|
2032
|
+
* It carries no price either. See `computeOndoBuyPrice`, which derives it from
|
|
2033
|
+
* the amounts the response does carry - the price this transaction fills at,
|
|
2034
|
+
* rather than an indicative one that has since moved.
|
|
2035
|
+
*/
|
|
2036
|
+
type OndoBuyTransaction = OndoSwapTransactionCore & {
|
|
2037
|
+
side: 'buy';
|
|
2038
|
+
/**
|
|
2039
|
+
* CoinList's cut, in `spendInputAmount`'s decimals. Zero until ENG-1718
|
|
2040
|
+
* lands - frontline rejects a non-zero one on either side today.
|
|
2041
|
+
*
|
|
2042
|
+
* Taken at execution rather than added on top, so the approval never has to
|
|
2043
|
+
* cover more than `spendInputAmount`.
|
|
2044
|
+
*/
|
|
2045
|
+
fee: BlockchainAmount;
|
|
2046
|
+
/**
|
|
2047
|
+
* `spendInputAmount` less `fee`, in the same decimals: what Ondo priced, and
|
|
2048
|
+
* the numerator of the fill price.
|
|
2049
|
+
*
|
|
2050
|
+
* Read from the response rather than subtracted here. Whether the fee comes
|
|
2051
|
+
* off the deposit or goes on top of it is the server's definition to change,
|
|
2052
|
+
* and a client that derives this cannot notice when it does.
|
|
2053
|
+
*/
|
|
2054
|
+
notionalValue: BlockchainAmount;
|
|
2055
|
+
/**
|
|
2056
|
+
* Quantity of the asset the wallet receives, at the scale whatever priced it
|
|
2057
|
+
* reported - not at the {@link OndoQuote}'s `asset.decimals`.
|
|
2058
|
+
*/
|
|
2059
|
+
receiveOutputAmount: BlockchainAmount;
|
|
2060
|
+
};
|
|
2061
|
+
declare const OndoBuyTransaction: {
|
|
2062
|
+
fromDto: (dto: OndoBuyDto) => OndoBuyTransaction;
|
|
2063
|
+
};
|
|
2064
|
+
/**
|
|
2065
|
+
* One end of the range a sale commits to: what arrives, and what CoinList took
|
|
2066
|
+
* to get it there.
|
|
2067
|
+
*
|
|
2068
|
+
* The two travel together because they are charged against each other -
|
|
2069
|
+
* `quantity` is already **net** of `fee` - and because the pair a caller wants
|
|
2070
|
+
* is always both halves of the same outcome. Grouping them is what makes
|
|
2071
|
+
* "the expected quantity, less the fee at the floor" unrepresentable rather
|
|
2072
|
+
* than merely wrong.
|
|
2073
|
+
*/
|
|
2074
|
+
type OndoSellOutcome = {
|
|
2075
|
+
/** What the wallet receives at this outcome, net of {@link fee}. */
|
|
2076
|
+
quantity: BlockchainAmount;
|
|
2077
|
+
/**
|
|
2078
|
+
* CoinList's cut at this outcome, in the same decimals. Zero until ENG-1718
|
|
2079
|
+
* lands - frontline rejects a non-zero one on either side today.
|
|
2080
|
+
*
|
|
2081
|
+
* Already deducted from {@link quantity} rather than charged on top of it.
|
|
2082
|
+
*/
|
|
2083
|
+
fee: BlockchainAmount;
|
|
2084
|
+
};
|
|
2085
|
+
/**
|
|
2086
|
+
* A signed, expiring sale: the asset in, a settlement coin out, somewhere
|
|
2087
|
+
* between two published outcomes.
|
|
2088
|
+
*
|
|
2089
|
+
* Single-use and expiring for the same reasons as an {@link OndoBuyTransaction},
|
|
2090
|
+
* and obtained the same way - one endpoint, one attestation.
|
|
2091
|
+
*
|
|
2092
|
+
* **A sale commits to a range, not a quantity.** Ondo settles through USDon
|
|
2093
|
+
* before converting to the settlement token, so {@link expected} is what to
|
|
2094
|
+
* expect and {@link minimum} is what the calldata enforces. A screen that
|
|
2095
|
+
* shows only the first presents a firm-looking number the contract may
|
|
2096
|
+
* legitimately fill below.
|
|
2097
|
+
*
|
|
2098
|
+
* There is deliberately no counterpart to a buy's `notionalValue`. A sale
|
|
2099
|
+
* commits on the output side, so frontline reports no fee-exclusive input and
|
|
2100
|
+
* refuses to relate numbers Ninshubur did not relate. What it does relate is
|
|
2101
|
+
* each quantity to the fee beside it, which is why {@link OndoSellOutcome}
|
|
2102
|
+
* pairs them.
|
|
2103
|
+
*
|
|
2104
|
+
* One thing this type cannot see: the floor signed into `tx.data` is gross of
|
|
2105
|
+
* the fee, so a caller decoding the calldata finds a larger number than
|
|
2106
|
+
* `minimum.quantity`. Both are correct; `minimum.quantity` is what the wallet
|
|
2107
|
+
* actually receives.
|
|
2108
|
+
*/
|
|
2109
|
+
type OndoSellTransaction = OndoSwapTransactionCore & {
|
|
2110
|
+
side: 'sell';
|
|
2111
|
+
/** What the sale is expected to return. An expectation, not a guarantee. */
|
|
2112
|
+
expected: OndoSellOutcome;
|
|
2113
|
+
/**
|
|
2114
|
+
* The floor the calldata enforces. A fill below it reverts on chain, so this
|
|
2115
|
+
* - not {@link expected} - is what a seller is actually guaranteed.
|
|
2116
|
+
*/
|
|
2117
|
+
minimum: OndoSellOutcome;
|
|
2118
|
+
};
|
|
2119
|
+
declare const OndoSellTransaction: {
|
|
2120
|
+
fromDto: (dto: OndoSellDto) => OndoSellTransaction;
|
|
2121
|
+
};
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Ondo swap reads, plus the write that turns one into a fillable transaction.
|
|
2125
|
+
*
|
|
2126
|
+
* The two reads are free to poll - neither spends an attestation, so a client
|
|
2127
|
+
* may call them while the user edits an order. The two builders are not:
|
|
2128
|
+
* budget one call per order placed, plus one per refresh the user asks for.
|
|
2129
|
+
*
|
|
2130
|
+
* **One builder per side, mirroring the endpoints.** A purchase and a sale
|
|
2131
|
+
* agree on how to broadcast and on nothing else: a purchase commits to an
|
|
2132
|
+
* exact quantity, a sale to a range with a floor beneath it, and `amount` is
|
|
2133
|
+
* the funding token on one and the asset on the other. A single method taking
|
|
2134
|
+
* a `side` would have to return a union the caller then re-narrows, having
|
|
2135
|
+
* already decided which trade it was placing.
|
|
2136
|
+
*
|
|
2137
|
+
* **No CoinList fee is applied to a read quote, and no read discloses one.**
|
|
2138
|
+
* Ondo prices exactly the amount passed. A CoinList approval is fee-inclusive,
|
|
2139
|
+
* so sizing a quote against a user's approval without subtracting the fee
|
|
2140
|
+
* first overstates what they receive. A built transaction carries the fee
|
|
2141
|
+
* explicitly, and it is zero until one lands (ENG-1718).
|
|
2142
|
+
*
|
|
2143
|
+
* Every method requires `AuthState === 'logged-in'` and throws
|
|
2144
|
+
* {@link NotAuthenticatedError} otherwise.
|
|
2145
|
+
*/
|
|
2146
|
+
interface OndoNamespace {
|
|
2147
|
+
getTradingStatus(params: GetOndoTradingStatusParams): Promise<OndoTradingStatus>;
|
|
2148
|
+
getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;
|
|
2149
|
+
/**
|
|
2150
|
+
* Builds a purchase for a specific wallet and deposit: spends an attestation
|
|
2151
|
+
* and returns calldata to broadcast, valid until
|
|
2152
|
+
* {@link OndoBuyTransaction.expiresAt}.
|
|
2153
|
+
*
|
|
2154
|
+
* The wallet must have approved the swap contract to spend `amount` of the
|
|
2155
|
+
* offer's **funding token** first. Frontline reads that allowance before
|
|
2156
|
+
* asking Ninshubur for anything, and rejects a short one with a 422 carrying
|
|
2157
|
+
* `code: "insufficient_allowance"`. See `prepareBuy` on the client
|
|
2158
|
+
* namespace, which approves and then builds, in that order.
|
|
2159
|
+
*
|
|
2160
|
+
* The tokens themselves are the offer's rather than the caller's to name.
|
|
2161
|
+
*/
|
|
2162
|
+
buildBuyTransaction(params: BuildOndoBuyParams): Promise<OndoBuyTransaction>;
|
|
2163
|
+
/**
|
|
2164
|
+
* Builds a sale for a specific wallet and quantity: spends an attestation
|
|
2165
|
+
* and returns calldata to broadcast, valid until
|
|
2166
|
+
* {@link OndoSellTransaction.expiresAt}.
|
|
2167
|
+
*
|
|
2168
|
+
* The approval this one needs is on the **asset**, not on a stablecoin - a
|
|
2169
|
+
* sale delivers the asset, so the swap contract pulls it with `transferFrom`
|
|
2170
|
+
* exactly as it pulls the deposit on a purchase. Same 422 when it is short,
|
|
2171
|
+
* with a message naming that address. See `prepareSell` on the client
|
|
2172
|
+
* namespace.
|
|
2173
|
+
*
|
|
2174
|
+
* Returns a range rather than a quantity: Ondo settles through USDon before
|
|
2175
|
+
* converting to the settlement token, so disclose
|
|
2176
|
+
* {@link OndoSellTransaction.minimum} and not only `expected`.
|
|
2177
|
+
*/
|
|
2178
|
+
buildSellTransaction(params: BuildOndoSellParams): Promise<OndoSellTransaction>;
|
|
2179
|
+
}
|
|
2180
|
+
declare class OndoNamespaceImpl implements OndoNamespace {
|
|
2181
|
+
private readonly ctx;
|
|
2182
|
+
protected readonly log: InternalLogger;
|
|
2183
|
+
constructor(ctx: SharedNamespaceContext);
|
|
2184
|
+
getTradingStatus(params: GetOndoTradingStatusParams): Promise<OndoTradingStatus>;
|
|
2185
|
+
getQuote(params: GetOndoQuoteParams): Promise<OndoQuote>;
|
|
2186
|
+
buildBuyTransaction(params: BuildOndoBuyParams): Promise<OndoBuyTransaction>;
|
|
2187
|
+
buildSellTransaction(params: BuildOndoSellParams): Promise<OndoSellTransaction>;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
/** Parameters shared by contract reads scoped to a chain. */
|
|
2191
|
+
type SwapContractRef = {
|
|
2192
|
+
contractAddress: EvmContractAddress;
|
|
2193
|
+
chain: EthereumChain;
|
|
2194
|
+
};
|
|
2195
|
+
type GetSwapAuthorizationParams = SwapContractRef & {
|
|
2196
|
+
walletAddress: EvmWalletAddress;
|
|
2197
|
+
};
|
|
2198
|
+
type GetSwapPreviewParams = SwapContractRef & {
|
|
2199
|
+
inputToken: EvmContractAddress;
|
|
2200
|
+
amount: bigint;
|
|
2201
|
+
};
|
|
2202
|
+
type AllowWalletParams = {
|
|
2203
|
+
offerId: OfferId;
|
|
2204
|
+
walletAddress: EvmWalletAddress;
|
|
2205
|
+
chain: EthereumChain;
|
|
2206
|
+
signature: string;
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* Read/write operations for the on-chain swap flow: quoting a swap, inspecting
|
|
2211
|
+
* contract state, checking token allowances, and proving/allow-listing wallet
|
|
2212
|
+
* ownership.
|
|
2213
|
+
*/
|
|
2214
|
+
interface SuperstateSwapNamespace {
|
|
2215
|
+
/**
|
|
2216
|
+
* Checks whether a wallet is authorized to swap against the given contract.
|
|
2217
|
+
*/
|
|
2218
|
+
getAuthorization(params: GetSwapAuthorizationParams): Promise<SwapAuthorization>;
|
|
2219
|
+
/**
|
|
2220
|
+
* Fetches a read-only quote for swapping `amount` of `inputToken`.
|
|
2221
|
+
*/
|
|
2222
|
+
getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;
|
|
2223
|
+
/**
|
|
2224
|
+
* Reads the current on-chain state of a swap contract.
|
|
2225
|
+
*/
|
|
2226
|
+
getStatus(params: SwapContractRef): Promise<SwapStatus>;
|
|
2227
|
+
/**
|
|
2228
|
+
* Reads the ERC-20 output token a swap contract pays out.
|
|
2229
|
+
*/
|
|
2230
|
+
getOutputToken(params: SwapContractRef): Promise<Erc20Asset>;
|
|
2231
|
+
/**
|
|
2232
|
+
* Submits a signed wallet-ownership challenge to allow-list the wallet for
|
|
2233
|
+
* an offer, identified by its offer id. Obtain the challenge from
|
|
2234
|
+
* `WalletsNamespace.createOwnershipChallenge`.
|
|
2235
|
+
*/
|
|
2236
|
+
allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;
|
|
2237
|
+
}
|
|
2238
|
+
declare class SuperstateSwapNamespaceImpl implements SuperstateSwapNamespace {
|
|
2239
|
+
private readonly ctx;
|
|
2240
|
+
protected readonly log: InternalLogger;
|
|
2241
|
+
constructor(ctx: SharedNamespaceContext);
|
|
2242
|
+
getAuthorization(params: GetSwapAuthorizationParams): Promise<SwapAuthorization>;
|
|
2243
|
+
getPreview(params: GetSwapPreviewParams): Promise<SwapPreview>;
|
|
2244
|
+
getStatus(params: SwapContractRef): Promise<SwapStatus>;
|
|
2245
|
+
getOutputToken(params: SwapContractRef): Promise<Erc20Asset>;
|
|
2246
|
+
allowWallet(params: AllowWalletParams): Promise<AllowWalletResponse>;
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
/** Request body for `POST /v1/offers/:offer_id/addresses`. */
|
|
2250
|
+
type CreateOfferOptionAddressDto = {
|
|
2251
|
+
offer_option_id: string;
|
|
2252
|
+
wallet_address: string;
|
|
2253
|
+
chain: string;
|
|
2254
|
+
signature: string;
|
|
2255
|
+
};
|
|
2256
|
+
/** Binding object returned by the `/v1/offers/:offer_id/addresses` resource. */
|
|
2257
|
+
type OfferOptionAddressDto = {
|
|
2258
|
+
id: string;
|
|
2259
|
+
offer_option_id: string;
|
|
2260
|
+
address: string;
|
|
2261
|
+
protocol: WalletProtocol;
|
|
2262
|
+
created_at: string;
|
|
2263
|
+
};
|
|
2264
|
+
|
|
2265
|
+
/** Unique identifier for a proven wallet binding on an offer option. */
|
|
2266
|
+
type OfferOptionAddressId = Newtype<string, 'OfferOptionAddressId'>;
|
|
2267
|
+
/** Casts a string into a typed {@link OfferOptionAddressId}. */
|
|
2268
|
+
declare const OfferOptionAddressId: (value: string) => OfferOptionAddressId;
|
|
2269
|
+
/**
|
|
2270
|
+
* A user's external wallet, proven via a wallet-ownership challenge and bound
|
|
2271
|
+
* to an offer option. Returned by the `/v1/offers/:offer_id/addresses` resource.
|
|
2272
|
+
*/
|
|
2273
|
+
type OfferOptionAddress = {
|
|
2274
|
+
/** Unique binding id. */
|
|
2275
|
+
id: OfferOptionAddressId;
|
|
2276
|
+
/** Offer option the wallet is bound to. */
|
|
2277
|
+
offerOptionId: OfferOptionId;
|
|
2278
|
+
/** The connected external wallet address. */
|
|
2279
|
+
address: EvmWalletAddress;
|
|
2280
|
+
/**
|
|
2281
|
+
* Protocol the binding is scoped to. An EVM address binds once per option
|
|
2282
|
+
* regardless of which EVM chain proved ownership.
|
|
2283
|
+
*/
|
|
2284
|
+
protocol: WalletProtocol;
|
|
2285
|
+
/** When the binding was created. */
|
|
2286
|
+
createdAt: Date;
|
|
2287
|
+
};
|
|
2288
|
+
declare const OfferOptionAddress: {
|
|
2289
|
+
/** Maps the API DTO into the SDK offer-option-address domain model. */
|
|
2290
|
+
fromDto: (dto: OfferOptionAddressDto) => OfferOptionAddress;
|
|
2291
|
+
};
|
|
2292
|
+
/** Parameters required to connect a proven external wallet to an offer option. */
|
|
2293
|
+
type ConnectExternalWalletParams = {
|
|
2294
|
+
/** Offer the option belongs to. */
|
|
2295
|
+
offerId: OfferId;
|
|
2296
|
+
/** Offer option to bind the wallet to. */
|
|
2297
|
+
offerOptionId: OfferOptionId;
|
|
2298
|
+
/** External wallet address that was proven. */
|
|
2299
|
+
walletAddress: EvmWalletAddress;
|
|
2300
|
+
/** Chain the ownership was proven on. */
|
|
2301
|
+
chain: EthereumChain;
|
|
2302
|
+
/** Signature of the wallet-ownership challenge message. */
|
|
2303
|
+
signature: Hex;
|
|
2304
|
+
};
|
|
2305
|
+
declare const ConnectExternalWalletParams: {
|
|
2306
|
+
/** Maps connect-wallet params into the API DTO payload. */
|
|
2307
|
+
toDto: (params: ConnectExternalWalletParams) => CreateOfferOptionAddressDto;
|
|
2308
|
+
};
|
|
2309
|
+
|
|
2310
|
+
/** Challenge kinds accepted by `POST /v1/wallet-ownership`. */
|
|
2311
|
+
type WalletOwnershipChallengeTypeDto = 'plain' | 'siwe';
|
|
2312
|
+
/**
|
|
2313
|
+
* Request body for `POST /v1/wallet-ownership`. `challenge_type` defaults to
|
|
2314
|
+
* `plain` on the backend; the SIWE fields (`domain`, `uri`, `statement`) are
|
|
2315
|
+
* required only when `challenge_type` is `siwe` and must be absent otherwise.
|
|
2316
|
+
*/
|
|
2317
|
+
type CreateWalletOwnershipChallengeDto = {
|
|
2318
|
+
wallet_address: string;
|
|
2319
|
+
chain: string;
|
|
2320
|
+
challenge_type?: WalletOwnershipChallengeTypeDto;
|
|
2321
|
+
domain?: string;
|
|
2322
|
+
uri?: string;
|
|
2323
|
+
statement?: string;
|
|
2324
|
+
};
|
|
2325
|
+
/** Response body for `POST /v1/wallet-ownership`. */
|
|
2326
|
+
type WalletOwnershipChallengeDto = {
|
|
2327
|
+
message: string;
|
|
2328
|
+
expires_at: string;
|
|
2329
|
+
};
|
|
2330
|
+
|
|
2331
|
+
/** Fields common to every wallet-ownership challenge request. */
|
|
2332
|
+
type WalletOwnershipChallengeParamsBase = {
|
|
2333
|
+
/** Wallet address to prove ownership of. */
|
|
2334
|
+
walletAddress: EvmWalletAddress;
|
|
2335
|
+
/** Chain the wallet belongs to. */
|
|
2336
|
+
chain: EthereumChain;
|
|
2337
|
+
};
|
|
2338
|
+
/**
|
|
2339
|
+
* How the ownership challenge is framed: a plain message or a Sign-In With
|
|
2340
|
+
* Ethereum challenge. Extracted as its own type so SDK consumers can pass it as
|
|
2341
|
+
* a standalone param without reaching into the {@link CreateWalletOwnershipChallengeParams}
|
|
2342
|
+
* union.
|
|
2343
|
+
*/
|
|
2344
|
+
type WalletChallengeType = CreateWalletOwnershipChallengeParams['challengeType'];
|
|
2345
|
+
/**
|
|
2346
|
+
* A single-use ownership challenge returned by `POST /v1/wallet-ownership`.
|
|
2347
|
+
* The consumer signs {@link message} with their wallet, then submits the
|
|
2348
|
+
* signature to connect the wallet to an offer option.
|
|
2349
|
+
*/
|
|
2350
|
+
type WalletOwnershipChallenge = {
|
|
2351
|
+
/** The message the wallet must sign. */
|
|
2352
|
+
message: string;
|
|
2353
|
+
/** When the challenge expires and can no longer be consumed. */
|
|
2354
|
+
expiresAt: Date;
|
|
2355
|
+
};
|
|
2356
|
+
declare const WalletOwnershipChallenge: {
|
|
2357
|
+
/** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
|
|
2358
|
+
fromDto: (dto: WalletOwnershipChallengeDto) => WalletOwnershipChallenge;
|
|
2359
|
+
};
|
|
2360
|
+
/**
|
|
2361
|
+
* Parameters for requesting a wallet-ownership challenge. Modeled as a
|
|
2362
|
+
* discriminated union on `challengeType` so a `siwe` challenge must carry
|
|
2363
|
+
* `domain`/`uri`/`statement`, matching the backend contract at compile time.
|
|
2364
|
+
*/
|
|
2365
|
+
type CreateWalletOwnershipChallengeParams = (WalletOwnershipChallengeParamsBase & {
|
|
2366
|
+
/** A bare message the wallet signs. */
|
|
2367
|
+
challengeType: 'plain';
|
|
2368
|
+
}) | (WalletOwnershipChallengeParamsBase & {
|
|
2369
|
+
/** Marks this as a Sign-In With Ethereum challenge. */
|
|
2370
|
+
challengeType: 'siwe';
|
|
2371
|
+
/** The requesting site's hostname (e.g. `example.com`). */
|
|
2372
|
+
domain: string;
|
|
2373
|
+
/** The requesting site's URI. */
|
|
2374
|
+
uri: string;
|
|
2375
|
+
/** Human-readable statement shown in the signing prompt. */
|
|
2376
|
+
statement: string;
|
|
2377
|
+
});
|
|
2378
|
+
declare const CreateWalletOwnershipChallengeParams: {
|
|
2379
|
+
/**
|
|
2380
|
+
* Maps challenge-request params into the API DTO payload. The discriminated
|
|
2381
|
+
* union guarantees SIWE fields are present exactly when `challengeType` is
|
|
2382
|
+
* `siwe`, so the mapping narrows on the discriminant.
|
|
2383
|
+
*/
|
|
2384
|
+
toDto: (params: CreateWalletOwnershipChallengeParams) => CreateWalletOwnershipChallengeDto;
|
|
2385
|
+
};
|
|
2386
|
+
|
|
2387
|
+
type ListOptionAddressesParams = {
|
|
2388
|
+
offerId: OfferId;
|
|
2389
|
+
/** Offer option whose bindings to list. */
|
|
2390
|
+
offerOptionId: OfferOptionId;
|
|
2391
|
+
};
|
|
2392
|
+
type RemoveOptionAddressParams = {
|
|
2393
|
+
offerId: OfferId;
|
|
2394
|
+
/** Binding to remove, as returned by {@link WalletsNamespace.list}. */
|
|
2395
|
+
addressId: OfferOptionAddressId;
|
|
2396
|
+
};
|
|
2397
|
+
/**
|
|
2398
|
+
* The user's external wallets: proving ownership of one, binding it to an
|
|
2399
|
+
* offer option, and managing those bindings.
|
|
2400
|
+
*
|
|
2401
|
+
* Ownership proof is a provider-agnostic primitive — the swap flow uses the
|
|
2402
|
+
* same challenge to allow-list a wallet — so it lives here rather than being
|
|
2403
|
+
* duplicated per product namespace.
|
|
2404
|
+
*
|
|
2405
|
+
* Every method requires an authenticated user and throws
|
|
2406
|
+
* {@link NotAuthenticatedError} otherwise.
|
|
2407
|
+
*/
|
|
2408
|
+
interface WalletsNamespace {
|
|
2409
|
+
/**
|
|
2410
|
+
* Creates a single-use challenge the user signs to prove they control a
|
|
2411
|
+
* wallet. Supports both `plain` and `siwe` challenges. Pass the signature of
|
|
2412
|
+
* the returned {@link WalletOwnershipChallenge.message} to
|
|
2413
|
+
* {@link connectExternal}.
|
|
2414
|
+
*/
|
|
2415
|
+
createOwnershipChallenge(params: CreateWalletOwnershipChallengeParams): Promise<WalletOwnershipChallenge>;
|
|
2416
|
+
/**
|
|
2417
|
+
* Binds a proven external wallet to an offer option, using a signature of a
|
|
2418
|
+
* challenge from {@link createOwnershipChallenge}.
|
|
2419
|
+
*/
|
|
2420
|
+
connectExternal(params: ConnectExternalWalletParams): Promise<OfferOptionAddress>;
|
|
2421
|
+
/**
|
|
2422
|
+
* Lists the user's proven wallet bindings for one offer option — the single
|
|
2423
|
+
* bound address for an `external_wallet` option, or every allow-listed
|
|
2424
|
+
* wallet for a `whitelisted_wallet` option.
|
|
2425
|
+
*/
|
|
2426
|
+
list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]>;
|
|
2427
|
+
/**
|
|
2428
|
+
* Removes one of the user's wallet bindings and returns the removed binding.
|
|
2429
|
+
*/
|
|
2430
|
+
remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress>;
|
|
2431
|
+
}
|
|
2432
|
+
declare class WalletsNamespaceImpl implements WalletsNamespace {
|
|
2433
|
+
private readonly ctx;
|
|
2434
|
+
private readonly log;
|
|
2435
|
+
constructor(ctx: SharedNamespaceContext);
|
|
2436
|
+
createOwnershipChallenge(params: CreateWalletOwnershipChallengeParams): Promise<WalletOwnershipChallenge>;
|
|
2437
|
+
connectExternal(params: ConnectExternalWalletParams): Promise<OfferOptionAddress>;
|
|
2438
|
+
list(params: ListOptionAddressesParams): Promise<OfferOptionAddress[]>;
|
|
2439
|
+
remove(params: RemoveOptionAddressParams): Promise<OfferOptionAddress>;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
type DocumentSubmissionStatusDto = 'INITIALIZED' | 'SENT' | 'VIEWED' | 'COMPLETED' | 'DECLINED' | 'EXPIRED';
|
|
2443
|
+
type DocumentFormTypeDto = 'w8_ben' | 'w8_ben_e';
|
|
2444
|
+
type DocumentSubmissionDto = {
|
|
2445
|
+
object: 'document_submission';
|
|
2446
|
+
status: DocumentSubmissionStatusDto;
|
|
2447
|
+
form_type: DocumentFormTypeDto;
|
|
2448
|
+
};
|
|
2449
|
+
|
|
2450
|
+
/** Document types that can be signed via {@link CoinListClient.submitDocument}. */
|
|
2451
|
+
type DocumentType = 'tax_certification';
|
|
2452
|
+
/** Signing-state machine status for a document submission. */
|
|
2453
|
+
type DocumentSubmissionStatus = DocumentSubmissionStatusDto;
|
|
2454
|
+
/** The tax form derived from the entity's kind (individual vs company/trust). */
|
|
2455
|
+
type DocumentFormType = DocumentFormTypeDto;
|
|
2456
|
+
/** Result of starting (or resuming) a document signing submission. */
|
|
2457
|
+
type DocumentSubmission = {
|
|
2458
|
+
status: DocumentSubmissionStatus;
|
|
2459
|
+
formType: DocumentFormType;
|
|
2460
|
+
};
|
|
2461
|
+
declare const DocumentSubmission: {
|
|
2462
|
+
fromDto: (dto: DocumentSubmissionDto) => DocumentSubmission;
|
|
2463
|
+
};
|
|
2464
|
+
|
|
2465
|
+
type KycTokenDto = {
|
|
2466
|
+
object: 'kyc_token';
|
|
2467
|
+
token: string;
|
|
2468
|
+
};
|
|
2469
|
+
|
|
2470
|
+
/**
|
|
2471
|
+
* Sumsub verification level name. Determines which screens the Sumsub WebSDK
|
|
2472
|
+
* shows (levels are configured in the Sumsub dashboard). The backend
|
|
2473
|
+
* prescribes the level (and whether the applicant must be reset first) in the
|
|
2474
|
+
* requirement statuses response — clients never compute levels themselves.
|
|
2475
|
+
*/
|
|
2476
|
+
type KycLevelName = string;
|
|
2477
|
+
/** Short-lived Sumsub WebSDK access token scoped to the current user. */
|
|
2478
|
+
type KycToken = {
|
|
2479
|
+
token: string;
|
|
2480
|
+
};
|
|
2481
|
+
declare const KycToken: {
|
|
2482
|
+
fromDto: (dto: KycTokenDto) => KycToken;
|
|
2483
|
+
};
|
|
2484
|
+
|
|
2485
|
+
type PiiKindDto = 'person' | 'company';
|
|
2486
|
+
type PiiJurisdictionDto = {
|
|
2487
|
+
iso_2: string;
|
|
2488
|
+
name: string | null;
|
|
2489
|
+
};
|
|
2490
|
+
type PiiAddressDto = {
|
|
2491
|
+
street: string | null;
|
|
2492
|
+
city: string | null;
|
|
2493
|
+
state: string | null;
|
|
2494
|
+
postal_code: string | null;
|
|
2495
|
+
country: string | null;
|
|
2496
|
+
};
|
|
2497
|
+
type PiiDto = {
|
|
2498
|
+
object: 'user_pii';
|
|
2499
|
+
kind: PiiKindDto;
|
|
2500
|
+
full_legal_name: string | null;
|
|
2501
|
+
date_of_birth: string | null;
|
|
2502
|
+
jurisdiction: PiiJurisdictionDto | null;
|
|
2503
|
+
tax_id: string | null;
|
|
2504
|
+
permanent_address: PiiAddressDto;
|
|
2505
|
+
};
|
|
2506
|
+
|
|
2507
|
+
/** Whether the PII belongs to an individual or a company/trust entity. */
|
|
2508
|
+
type PiiKind = PiiKindDto;
|
|
2509
|
+
/** ISO 3166-1 alpha-2 country code (e.g. `'US'`). */
|
|
2510
|
+
type Iso2CountryCode = Newtype<string, 'Iso2CountryCode'>;
|
|
2511
|
+
declare const Iso2CountryCode: (value: string) => Iso2CountryCode;
|
|
2512
|
+
/** Jurisdiction derived from the entity's address country. */
|
|
2513
|
+
type PiiJurisdiction = {
|
|
2514
|
+
iso2: Iso2CountryCode;
|
|
2515
|
+
name: string | null;
|
|
2516
|
+
};
|
|
2517
|
+
declare const PiiJurisdiction: {
|
|
2518
|
+
fromDto: (dto: PiiJurisdictionDto) => PiiJurisdiction;
|
|
2519
|
+
};
|
|
2520
|
+
/** Permanent address on file for the entity. */
|
|
2521
|
+
type PiiAddress = {
|
|
2522
|
+
street: string | null;
|
|
2523
|
+
city: string | null;
|
|
2524
|
+
state: string | null;
|
|
2525
|
+
postalCode: string | null;
|
|
2526
|
+
country: string | null;
|
|
2527
|
+
};
|
|
2528
|
+
declare const PiiAddress: {
|
|
2529
|
+
fromDto: (dto: PiiAddressDto) => PiiAddress;
|
|
2530
|
+
};
|
|
2531
|
+
/**
|
|
2532
|
+
* The current user's PII, used to pre-fill tax forms such as the W-8BEN.
|
|
2533
|
+
* Fields the entity hasn't provided are `null`.
|
|
2534
|
+
*/
|
|
2535
|
+
type Pii = {
|
|
2536
|
+
kind: PiiKind;
|
|
2537
|
+
fullLegalName: string | null;
|
|
2538
|
+
dateOfBirth: string | null;
|
|
2539
|
+
jurisdiction: PiiJurisdiction | null;
|
|
2540
|
+
taxId: string | null;
|
|
2541
|
+
permanentAddress: PiiAddress;
|
|
2542
|
+
};
|
|
2543
|
+
declare const Pii: {
|
|
2544
|
+
fromDto: (dto: PiiDto) => Pii;
|
|
2545
|
+
};
|
|
2546
|
+
|
|
2547
|
+
type RequirementTypeDto = 'kyc_approved' | 'external_wallet' | 'whitelisted_wallet' | 'jurisdiction' | 'accreditation' | 'document';
|
|
2548
|
+
type RequirementDto = {
|
|
2549
|
+
object: 'requirement';
|
|
2550
|
+
id: string;
|
|
2551
|
+
type: RequirementTypeDto;
|
|
2552
|
+
details: Record<string, unknown> | null;
|
|
2553
|
+
};
|
|
2554
|
+
type RequirementStatusValueDto = 'not_started' | 'in_progress' | 'action_needed' | 'completed' | 'rejected';
|
|
2555
|
+
type RequirementActionNeededReasonDto = 'kyc_not_verified' | 'update_pii_data';
|
|
2556
|
+
/**
|
|
2557
|
+
* Object form of a requirement status, used when the status carries extra
|
|
2558
|
+
* data: the action-needed reason and/or the Sumsub flow that resolves the
|
|
2559
|
+
* requirement (kyc_level + kyc_reset, forwarded to the kyc-token endpoint).
|
|
2560
|
+
*/
|
|
2561
|
+
type RequirementStatusObjectDto = {
|
|
2562
|
+
status: RequirementStatusValueDto;
|
|
2563
|
+
action?: RequirementActionNeededReasonDto;
|
|
2564
|
+
kyc_level?: string;
|
|
2565
|
+
kyc_reset?: boolean;
|
|
2566
|
+
};
|
|
2567
|
+
type RequirementStatusesDto = {
|
|
2568
|
+
object: 'requirement_statuses';
|
|
2569
|
+
offer_id: string;
|
|
2570
|
+
statuses: Record<string, RequirementStatusValueDto | RequirementStatusObjectDto>;
|
|
2571
|
+
};
|
|
2572
|
+
|
|
2573
|
+
type RequirementId = Newtype<string, 'RequirementId'>;
|
|
2574
|
+
declare const RequirementId: (value: string) => RequirementId;
|
|
2575
|
+
type RequirementType = RequirementTypeDto;
|
|
2576
|
+
type RequirementStatusValue = RequirementStatusValueDto;
|
|
2577
|
+
type RequirementActionNeededReason = RequirementActionNeededReasonDto;
|
|
2578
|
+
type Requirement = {
|
|
2579
|
+
id: RequirementId;
|
|
2580
|
+
type: RequirementType;
|
|
2581
|
+
details: Record<string, unknown> | null;
|
|
2582
|
+
};
|
|
2583
|
+
declare const Requirement: {
|
|
2584
|
+
fromDto: (dto: RequirementDto) => Requirement;
|
|
2585
|
+
};
|
|
2586
|
+
type RequirementStatusInfo = {
|
|
2587
|
+
id: RequirementId;
|
|
2588
|
+
status: RequirementStatusValue;
|
|
2589
|
+
/** Why the requirement needs action (KYC-backed requirements only). */
|
|
2590
|
+
action: RequirementActionNeededReason | null;
|
|
2591
|
+
/**
|
|
2592
|
+
* The Sumsub verification level that resolves this requirement, prescribed
|
|
2593
|
+
* by the backend. Present exactly when an inline Sumsub flow can be started.
|
|
2594
|
+
*/
|
|
2595
|
+
kycLevel?: KycLevelName;
|
|
2596
|
+
/**
|
|
2597
|
+
* Whether the Sumsub applicant must be reset before starting the flow
|
|
2598
|
+
* (redoing an already-approved level, e.g. to update stale PII). Forward to
|
|
2599
|
+
* the kyc-token request as-is.
|
|
2600
|
+
*/
|
|
2601
|
+
kycReset?: boolean;
|
|
2602
|
+
};
|
|
2603
|
+
declare const RequirementStatusInfo: {
|
|
2604
|
+
fromStatusesDto: (dto: RequirementStatusesDto) => RequirementStatusInfo[];
|
|
2605
|
+
};
|
|
2606
|
+
|
|
2607
|
+
type CreateKycTokenParams = {
|
|
2608
|
+
/**
|
|
2609
|
+
* Sumsub verification level to run. Defaults to the backend's standard
|
|
2610
|
+
* level.
|
|
2611
|
+
*/
|
|
2612
|
+
levelName?: KycLevelName;
|
|
2613
|
+
/**
|
|
2614
|
+
* Resets the Sumsub applicant first, so an already-approved level can be
|
|
2615
|
+
* executed again (e.g. to update stale PII). Pass the `kycReset` value from
|
|
2616
|
+
* the requirement status, and never on mid-flow token refreshes.
|
|
2617
|
+
*/
|
|
2618
|
+
reset?: boolean;
|
|
2619
|
+
};
|
|
2620
|
+
type SubmitDocumentParams = {
|
|
2621
|
+
/** Currently only `tax_certification` (W-8BEN / W-8BEN-E). */
|
|
2622
|
+
documentType: DocumentType;
|
|
2623
|
+
/**
|
|
2624
|
+
* Signing-form values keyed by the document's DocuSeal field names,
|
|
2625
|
+
* forwarded verbatim to pre-fill the document.
|
|
2626
|
+
*/
|
|
2627
|
+
fields: Record<string, string>;
|
|
2628
|
+
};
|
|
2629
|
+
/**
|
|
2630
|
+
* Everything a user must satisfy before they can participate in an offer:
|
|
2631
|
+
* reading the checklist and its live statuses, and the operations that satisfy
|
|
2632
|
+
* individual requirements — identity verification (KYC) and tax-document
|
|
2633
|
+
* signing.
|
|
2634
|
+
*
|
|
2635
|
+
* Wallet requirements (`external_wallet`, `whitelisted_wallet`) are satisfied
|
|
2636
|
+
* through `WalletsNamespace` instead, since wallet proofs are also used
|
|
2637
|
+
* outside the requirements flow.
|
|
2638
|
+
*
|
|
2639
|
+
* Every method requires an authenticated user and throws
|
|
2640
|
+
* {@link NotAuthenticatedError} otherwise.
|
|
2641
|
+
*/
|
|
2642
|
+
interface RequirementsNamespace {
|
|
2643
|
+
/**
|
|
2644
|
+
* Fetches the requirements for every option of an offer, grouped by option
|
|
2645
|
+
* id. This is the definition of the checklist; {@link statuses} tells you
|
|
2646
|
+
* where the user stands against it.
|
|
2647
|
+
*/
|
|
2648
|
+
forOffer(offerId: OfferId): Promise<Record<OfferOptionId, Requirement[]>>;
|
|
2649
|
+
/**
|
|
2650
|
+
* Fetches the current user's status for each requirement of an offer.
|
|
2651
|
+
*/
|
|
2652
|
+
statuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;
|
|
2653
|
+
/**
|
|
2654
|
+
* Creates a short-lived Sumsub WebSDK access token so an identity
|
|
2655
|
+
* verification (KYC) flow can be started, e.g. by the `IdentityVerification`
|
|
2656
|
+
* component.
|
|
2657
|
+
*/
|
|
2658
|
+
createKycToken(params?: CreateKycTokenParams): Promise<KycToken>;
|
|
2659
|
+
/**
|
|
2660
|
+
* Fetches the current user's PII, used to pre-fill tax forms such as the
|
|
2661
|
+
* W-8BEN. Fields the entity hasn't provided are `null`.
|
|
2662
|
+
*/
|
|
2663
|
+
getPii(): Promise<Pii>;
|
|
2664
|
+
/**
|
|
2665
|
+
* Starts (or resumes) a document signing submission.
|
|
2666
|
+
*/
|
|
2667
|
+
submitDocument(params: SubmitDocumentParams): Promise<DocumentSubmission>;
|
|
2668
|
+
}
|
|
2669
|
+
declare class RequirementsNamespaceImpl implements RequirementsNamespace {
|
|
2670
|
+
protected readonly ctx: SharedNamespaceContext;
|
|
2671
|
+
protected readonly log: InternalLogger;
|
|
2672
|
+
constructor(ctx: SharedNamespaceContext);
|
|
2673
|
+
forOffer(offerId: OfferId): Promise<Record<OfferOptionId, Requirement[]>>;
|
|
2674
|
+
statuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;
|
|
2675
|
+
createKycToken(params?: CreateKycTokenParams): Promise<KycToken>;
|
|
2676
|
+
getPii(): Promise<Pii>;
|
|
2677
|
+
submitDocument(params: SubmitDocumentParams): Promise<DocumentSubmission>;
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
/**
|
|
2681
|
+
* Reads over CoinList's offers: the catalogue a user can browse, and the full
|
|
2682
|
+
* detail of a single offer.
|
|
2683
|
+
*
|
|
2684
|
+
* Every method requires an authenticated user and throws
|
|
2685
|
+
* {@link NotAuthenticatedError} otherwise. On the server, the same reads are
|
|
2686
|
+
* additionally available with an app-level token — see
|
|
2687
|
+
* `ServerOffersNamespace`.
|
|
2688
|
+
*/
|
|
2689
|
+
interface OffersNamespace {
|
|
2690
|
+
/**
|
|
2691
|
+
* Fetches every offer, iterating through all pages. Prefer {@link listPage}
|
|
2692
|
+
* when you render a paginated list yourself.
|
|
2693
|
+
*/
|
|
2694
|
+
list(): Promise<Offer[]>;
|
|
2695
|
+
/**
|
|
2696
|
+
* Fetches a single page of offers. Pass the previous response's
|
|
2697
|
+
* `startingAfter` as `after` to advance.
|
|
2698
|
+
*/
|
|
2699
|
+
listPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;
|
|
2700
|
+
/**
|
|
2701
|
+
* Fetches the full detail of one offer, including its options. Note this
|
|
2702
|
+
* returns {@link OfferDetail} — a richer model than the {@link Offer}
|
|
2703
|
+
* summaries {@link list} returns.
|
|
2704
|
+
*/
|
|
2705
|
+
get(id: OfferId): Promise<OfferDetail>;
|
|
2706
|
+
}
|
|
2707
|
+
declare class OffersNamespaceImpl implements OffersNamespace {
|
|
2708
|
+
private readonly ctx;
|
|
2709
|
+
private readonly log;
|
|
2710
|
+
constructor(ctx: SharedNamespaceContext);
|
|
2711
|
+
list(): Promise<Offer[]>;
|
|
2712
|
+
listPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;
|
|
2713
|
+
get(id: OfferId): Promise<OfferDetail>;
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
/**
|
|
2717
|
+
* Raw JSON from the token registry (Nabu), a static CDN serving token display
|
|
2718
|
+
* metadata. It is a separate backend from frontline: responses omit optional
|
|
2719
|
+
* fields rather than sending `null`, and may grow unknown fields at any time;
|
|
2720
|
+
* we only read the fields named here.
|
|
2721
|
+
*/
|
|
2722
|
+
type NabuLogoImageDto = {
|
|
2723
|
+
url: string;
|
|
2724
|
+
width: number;
|
|
2725
|
+
height: number;
|
|
2726
|
+
};
|
|
2727
|
+
/**
|
|
2728
|
+
* A logo is either a single vector (valid at any size) or a dimensioned
|
|
2729
|
+
* raster original plus pre-scaled variants at ascending widths.
|
|
2730
|
+
*/
|
|
2731
|
+
type NabuLogoDto = {
|
|
2732
|
+
kind: 'VECTOR';
|
|
2733
|
+
url: string;
|
|
2734
|
+
} | {
|
|
2735
|
+
kind: 'RASTER';
|
|
2736
|
+
original: NabuLogoImageDto;
|
|
2737
|
+
variants: NabuLogoImageDto[];
|
|
2738
|
+
};
|
|
2739
|
+
/** One token from the registry's `/{chain}/token/{address}` route. */
|
|
2740
|
+
type NabuTokenDto = {
|
|
2741
|
+
data_version: string;
|
|
2742
|
+
schema_version: number;
|
|
2743
|
+
chain: string;
|
|
2744
|
+
protocol: string;
|
|
2745
|
+
chain_id: number;
|
|
2746
|
+
kind: string;
|
|
2747
|
+
name: string;
|
|
2748
|
+
symbol: string;
|
|
2749
|
+
decimals: number;
|
|
2750
|
+
logo: NabuLogoDto;
|
|
2751
|
+
logo_dark?: NabuLogoDto;
|
|
2752
|
+
coingecko_id?: string;
|
|
2753
|
+
teller_code?: string;
|
|
2754
|
+
address: string;
|
|
2755
|
+
};
|
|
2756
|
+
/**
|
|
2757
|
+
* One asset inside a chain snapshot. The snapshot mixes the chain's native
|
|
2758
|
+
* coin (`kind: 'COIN'`, no address) with its tokens (`kind: 'TOKEN'`), so
|
|
2759
|
+
* `address` is optional here where {@link NabuTokenDto} requires it.
|
|
2760
|
+
*/
|
|
2761
|
+
type NabuChainAssetDto = {
|
|
2762
|
+
kind: string;
|
|
2763
|
+
name: string;
|
|
2764
|
+
symbol: string;
|
|
2765
|
+
decimals: number;
|
|
2766
|
+
logo: NabuLogoDto;
|
|
2767
|
+
logo_dark?: NabuLogoDto;
|
|
2768
|
+
address?: string;
|
|
2769
|
+
};
|
|
2770
|
+
/** The registry's `/{chain}/assets.json` route: one chain, all its assets. */
|
|
2771
|
+
type NabuChainAssetsDto = {
|
|
2772
|
+
data_version: string;
|
|
2773
|
+
schema_version: number;
|
|
2774
|
+
chain: string;
|
|
2775
|
+
protocol: string;
|
|
2776
|
+
assets: NabuChainAssetDto[];
|
|
2777
|
+
};
|
|
2778
|
+
/** The registry's `/assets.json` route: the complete snapshot, every chain. */
|
|
2779
|
+
type NabuRegistryDto = {
|
|
2780
|
+
data_version: string;
|
|
2781
|
+
schema_version: number;
|
|
2782
|
+
chains: Array<{
|
|
2783
|
+
chain: string;
|
|
2784
|
+
protocol: string;
|
|
2785
|
+
assets: NabuChainAssetDto[];
|
|
2786
|
+
}>;
|
|
2787
|
+
};
|
|
2788
|
+
|
|
2789
|
+
/**
|
|
2790
|
+
* An absolute URL to a logo image in the token registry. Registry image URLs
|
|
2791
|
+
* are content-fingerprinted and served immutable, so a value is safe to cache
|
|
2792
|
+
* for as long as you hold it.
|
|
2793
|
+
*/
|
|
2794
|
+
type TokenLogoUrl = Newtype<string, 'TokenLogoUrl'>;
|
|
2795
|
+
declare const TokenLogoUrl: (value: string) => TokenLogoUrl;
|
|
2796
|
+
type TokenLogoImage = {
|
|
2797
|
+
url: TokenLogoUrl;
|
|
2798
|
+
width: number;
|
|
2799
|
+
height: number;
|
|
2800
|
+
};
|
|
2801
|
+
/**
|
|
2802
|
+
* `VECTOR` is a single SVG. `RASTER` has webp variants at 32/64/128/256/512px
|
|
2803
|
+
* widths (never wider than the original): use the smallest one that covers
|
|
2804
|
+
* your render size, or `original` if none does.
|
|
2805
|
+
*/
|
|
2806
|
+
type TokenLogo = {
|
|
2807
|
+
kind: 'VECTOR';
|
|
2808
|
+
url: TokenLogoUrl;
|
|
2809
|
+
} | {
|
|
2810
|
+
kind: 'RASTER';
|
|
2811
|
+
original: TokenLogoImage;
|
|
2812
|
+
variants: TokenLogoImage[];
|
|
2813
|
+
};
|
|
2814
|
+
declare const TokenLogo: {
|
|
2815
|
+
/** `baseUrl` is the registry origin; registry URLs are root-relative. */
|
|
2816
|
+
fromDto: (dto: NabuLogoDto, baseUrl: string) => TokenLogo;
|
|
2817
|
+
};
|
|
2818
|
+
/**
|
|
2819
|
+
* Display metadata for one token, from CoinList's public token registry.
|
|
2820
|
+
*
|
|
2821
|
+
* Keyed by `(chain, address)` — never by symbol, which can collide. The
|
|
2822
|
+
* registry is curated: a token missing from it is an expected answer, not an
|
|
2823
|
+
* error, so lookups return `null` rather than throwing.
|
|
2824
|
+
*/
|
|
2825
|
+
type TokenMetadata = {
|
|
2826
|
+
identifier: TokenIdentifier;
|
|
2827
|
+
name: string;
|
|
2828
|
+
symbol: AssetSymbol;
|
|
2829
|
+
decimals: AssetDecimals;
|
|
2830
|
+
logo: TokenLogo;
|
|
2831
|
+
/** Dark-theme logo; `null` when the registry configures none. */
|
|
2832
|
+
logoDark: TokenLogo | null;
|
|
2833
|
+
};
|
|
2834
|
+
declare const TokenMetadata: {
|
|
2835
|
+
/** `baseUrl` is the registry origin; registry logo URLs are root-relative. */
|
|
2836
|
+
fromDto: (dto: NabuTokenDto, baseUrl: string) => TokenMetadata;
|
|
2837
|
+
/**
|
|
2838
|
+
* Maps the complete registry snapshot to every token it lists across the
|
|
2839
|
+
* chains this SDK models, skipping native coins and chains outside
|
|
2840
|
+
* {@link EthereumChain} (e.g. Solana) rather than failing on them — the
|
|
2841
|
+
* registry may serve chains ahead of the SDK's type surface.
|
|
2842
|
+
*/
|
|
2843
|
+
fromRegistryDto: (dto: NabuRegistryDto, baseUrl: string) => TokenMetadata[];
|
|
2844
|
+
/**
|
|
2845
|
+
* Maps a chain snapshot to the tokens it lists, skipping the chain's native
|
|
2846
|
+
* coin (`kind: 'COIN'`, no contract address).
|
|
2847
|
+
*/
|
|
2848
|
+
fromChainAssetsDto: (dto: NabuChainAssetsDto, baseUrl: string) => TokenMetadata[];
|
|
2849
|
+
};
|
|
2850
|
+
|
|
2851
|
+
/**
|
|
2852
|
+
* Token display metadata — name, symbol, decimals, and logos — from
|
|
2853
|
+
* CoinList's public token registry, keyed by {@link TokenIdentifier} (the
|
|
2854
|
+
* same chain + address pairs `Offer.tokens` carries).
|
|
2855
|
+
*
|
|
2856
|
+
* Unlike the other namespaces, this one is public: no method requires an
|
|
2857
|
+
* authenticated user, and nothing here touches the CoinList API — reads go to
|
|
2858
|
+
* the registry's CDN.
|
|
2859
|
+
*/
|
|
2860
|
+
interface TokensNamespace {
|
|
2861
|
+
/**
|
|
2862
|
+
* Fetches metadata for one token. Returns `null` when the registry does not
|
|
2863
|
+
* list the token — the registry is curated, so callers must fall back to
|
|
2864
|
+
* their own display defaults rather than treat this as an error.
|
|
2865
|
+
*/
|
|
2866
|
+
get(token: TokenIdentifier): Promise<TokenMetadata | null>;
|
|
2867
|
+
/**
|
|
2868
|
+
* Fetches every token the registry lists, in one request: the complete
|
|
2869
|
+
* snapshot with no `chain`, or one chain's snapshot with it. Prefer this
|
|
2870
|
+
* over calling {@link get} in a loop when displaying a catalogue — two
|
|
2871
|
+
* hundred tokens across three chains is still a single download.
|
|
2872
|
+
*
|
|
2873
|
+
* The complete snapshot spans every chain the registry knows; tokens on
|
|
2874
|
+
* chains this SDK does not model (e.g. Solana) are left out of the result.
|
|
2875
|
+
*
|
|
2876
|
+
* Unlike {@link get}, a missing snapshot throws rather than returning `[]`:
|
|
2877
|
+
* the registry always publishes the complete snapshot and one per chain it
|
|
2878
|
+
* knows, so an absence is a deployment problem, not an empty catalogue.
|
|
2879
|
+
*/
|
|
2880
|
+
list(chain?: EthereumChain): Promise<TokenMetadata[]>;
|
|
2881
|
+
}
|
|
2882
|
+
declare class TokensNamespaceImpl implements TokensNamespace {
|
|
2883
|
+
private readonly api;
|
|
2884
|
+
private readonly log;
|
|
2885
|
+
/**
|
|
2886
|
+
* Takes the registry origin rather than a `SharedNamespaceContext`: the
|
|
2887
|
+
* registry is unauthenticated and on its own host, so the frontline sender
|
|
2888
|
+
* and the auth check would both be dead weight here.
|
|
2889
|
+
*/
|
|
2890
|
+
constructor(baseUrl: string, logger?: Logger | null);
|
|
2891
|
+
get(token: TokenIdentifier): Promise<TokenMetadata | null>;
|
|
2892
|
+
list(chain?: EthereumChain): Promise<TokenMetadata[]>;
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
interface Config {
|
|
2896
|
+
/** OAuth2 public identifier. */
|
|
2897
|
+
readonly clientId: ClientId;
|
|
2898
|
+
/**
|
|
2899
|
+
* OAuth2 redirect URI. Recommended to point to a frontend page where
|
|
2900
|
+
* {@link CoinListClient#completeOauth} can be called to complete the PKCE
|
|
2901
|
+
* flow on the client side.
|
|
2902
|
+
*/
|
|
2903
|
+
readonly redirectUri: RedirectUri;
|
|
2904
|
+
/**
|
|
2905
|
+
* Recommended to leave undefined. Used to change the CoinList environment;
|
|
2906
|
+
* default is production.
|
|
2907
|
+
*/
|
|
2908
|
+
readonly baseUrl?: string;
|
|
2909
|
+
/**
|
|
2910
|
+
* Recommended to leave undefined. Overrides the base URL of the public
|
|
2911
|
+
* token registry backing `coinlist.tokens`; default is the production
|
|
2912
|
+
* registry.
|
|
2913
|
+
*/
|
|
2914
|
+
readonly tokensBaseUrl?: string;
|
|
2915
|
+
/**
|
|
2916
|
+
* Where the SDK reports what it is doing. **Omit it and the SDK logs nothing
|
|
2917
|
+
* at all** - no `console` fallback, at any level, on any codepath. Supply
|
|
2918
|
+
* one and every request, every classified failure and every hook state
|
|
2919
|
+
* transition is reported at the level your logger asks for.
|
|
2920
|
+
*
|
|
2921
|
+
* Absent, the SDK says nothing at all - there is no fallback to `console`,
|
|
2922
|
+
* at any level, on any codepath.
|
|
2923
|
+
*
|
|
2924
|
+
* **Running the SDK's logging in production is not advised.** The safest
|
|
2925
|
+
* posture is to leave this undefined outside development, staging and
|
|
2926
|
+
* incident reproduction: a seam that emits nothing cannot disclose anything,
|
|
2927
|
+
* and that property does not depend on the SDK continuing to get redaction
|
|
2928
|
+
* right.
|
|
2929
|
+
*
|
|
2930
|
+
* If you do run one there, run it at `'info'` or above and know what that
|
|
2931
|
+
* does and does not buy you. Those levels are **redacted by construction**:
|
|
2932
|
+
* they carry only SDK-authored classification and server-authored
|
|
2933
|
+
* identifiers, and the type system holds that line rather than a convention -
|
|
2934
|
+
* an event at those levels accepts scalar fields only, so a body, a DTO or
|
|
2935
|
+
* an operation's parameters cannot be put on one. What the SDK does **not**
|
|
2936
|
+
* give you is a warranty that the result is safe for your environment. The
|
|
2937
|
+
* mechanism is checkable and stated; the conclusion depends on your sink,
|
|
2938
|
+
* your retention and your threat model, and it is yours to draw.
|
|
2939
|
+
*
|
|
2940
|
+
* **`'debug'` is not.** It reports request and response bodies, full URLs,
|
|
2941
|
+
* headers and operation parameters verbatim - bearer tokens, KYC answers,
|
|
2942
|
+
* tax-document fields, wallet signatures - and **the SDK does not redact**.
|
|
2943
|
+
* Run it on a developer's machine, in tests, and in beta or staging
|
|
2944
|
+
* environments where the data flowing through is not real customer data.
|
|
2945
|
+
* The shipped implementations make that structural: built with
|
|
2946
|
+
* `isDev: false`, `'debug'` does not typecheck. Either way, filtering,
|
|
2947
|
+
* redaction and retention at your sink are yours, not the SDK's.
|
|
2948
|
+
*
|
|
2949
|
+
* Every method you implement here **must be total**: the SDK calls them on
|
|
2950
|
+
* the codepath of the work they report and does not catch them, so a logger
|
|
2951
|
+
* that throws fails the operation it was describing.
|
|
2952
|
+
*
|
|
2953
|
+
* See {@link Logger} for the full contract, and {@link pinoClientLogger} or
|
|
2954
|
+
* {@link pinoServerLogger} for a ready-made implementation over pino.
|
|
2955
|
+
*/
|
|
2956
|
+
readonly logger?: Logger;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
export { type OndoQuoteSize as $, AuthorizationCode as A, BlockchainAmount as B, CodeVerifier as C, type OfferType as D, type Erc20Namespace as E, Offer as F, RequirementStatusInfo as G, type RequirementType as H, type RequirementStatusValue as I, OfferOptionAddress as J, RequirementId as K, type Logger as L, type KycLevelName as M, DocumentSubmission as N, OfferId as O, Participation as P, type WalletChallengeType as Q, type RequirementsNamespace as R, type SharedNamespaceContext as S, type TokensNamespace as T, type PinoLoggerOptions as U, OndoTradingStatus as V, type WalletError as W, AssetDecimals as X, type BuildOndoBuyParams as Y, type BuildOndoSellParams as Z, OndoQuote as _, EthereumChain as a, Milestone as a$, OfferOptionAddressId as a0, TokenMetadata as a1, type TokenIdentifier as a2, type DebugEvent as a3, type FrontlineEventId as a4, HttpError as a5, type HttpResponse as a6, KycToken as a7, type LogBinding as a8, type LogBindings as a9, type BuildOndoSwapParamsCore as aA, Chain as aB, ClientId as aC, CodeChallenge as aD, ConnectExternalWalletParams as aE, type CreateKycTokenParams as aF, CreateParticipationParams as aG, CreateWalletOwnershipChallengeParams as aH, Cursor as aI, type DocumentFormType as aJ, type DocumentSubmissionStatus as aK, type DocumentType as aL, ETHEREUM_CHAINS as aM, Erc20NamespaceImpl as aN, FaqItem as aO, type GetOndoQuoteParams as aP, type GetOndoTradingStatusParams as aQ, type GetSwapAuthorizationParams as aR, type GetSwapPreviewParams as aS, type GetTokenAllowanceParams as aT, type GetTokenBalanceParams as aU, HexEncodedTransactionData as aV, Iso2CountryCode as aW, Link as aX, type ListOptionAddressesParams as aY, MAX_ASSET_DECIMALS as aZ, MAX_UINT_256 as a_, type LogCause as aa, type LogLevel as ab, type LogScope as ac, type LogValue as ad, type ProductionLogLevel as ae, RedactedWalletError as af, type RequestId as ag, type SafeEvent as ah, type SafeFields as ai, type UnredactedFields as aj, OAuthSession as ak, ClientCredentialsOAuth as al, ClientSecret as am, type Sender as an, PaginationParams as ao, PaginatedResponse as ap, type Uint256 as aq, KnownAssetSymbol as ar, DecimalString as as, SwapStatus as at, type Newtype as au, type AllowWalletParams as av, AllowWalletResponse as aw, Asset as ax, AssetCode as ay, Blockchain as az, EvmContractAddress as b, OAuthRefreshToken as b0, OfferOption as b1, OfferOptionSlug as b2, OfferSlug as b3, OfferToken as b4, OffersNamespaceImpl as b5, type OndoQuoteDuration as b6, type OndoSellOutcome as b7, PKCEState as b8, type PaginatedResponseDto as b9, type TokenRole as bA, TokensNamespaceImpl as bB, type Tx as bC, WalletAddress as bD, WalletOwnershipChallenge as bE, type WalletProtocol as bF, WalletsNamespaceImpl as bG, apiErrorCode as bH, assertUint256 as bI, parseUint256 as bJ, ParticipationId as ba, type ParticipationStatus as bb, ParticipationsPaginationParams as bc, Pii as bd, PiiAddress as be, PiiJurisdiction as bf, type PiiKind as bg, type QueryParamValue as bh, type QueryParamValues as bi, RedirectUri as bj, type RemoveOptionAddressParams as bk, type RequirementActionNeededReason as bl, SOLANA_CHAINS as bm, STABLE_DECIMALS as bn, SolanaChain as bo, type SubmitDocumentParams as bp, SwapAuthorization as bq, type SwapContractRef as br, SwapPreview as bs, TermItem as bt, Ticker as bu, TokenAllowance as bv, TokenBalance as bw, TokenLogo as bx, type TokenLogoImage as by, TokenLogoUrl as bz, type CoinListTokenSaleNamespace as c, OfferOptionId as d, AssetId as e, CoinListTokenSaleNamespaceImpl as f, type OndoNamespace as g, AssetSymbol as h, OndoBuyTransaction as i, OndoSellTransaction as j, type OndoSwapTransactionCore as k, type OrderBookSide as l, OndoNamespaceImpl as m, type SuperstateSwapNamespace as n, type WalletsNamespace as o, Bps as p, EvmWalletAddress as q, SuperstateSwapNamespaceImpl as r, Requirement as s, RequirementsNamespaceImpl as t, type Config as u, type OAuthAccessToken as v, type OffersNamespace as w, StablecoinSymbol as x, type Erc20Asset as y, OfferDetail as z };
|