@capxul/sdk 0.1.0-alpha.8 → 0.2.0-alpha.3
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/CHANGELOG.md +122 -0
- package/README.md +45 -0
- package/dist/{client-DDAVWtzJ.d.cts → client-B_Z3ThFO.d.cts} +231 -42
- package/dist/{client-ByzDfG98.d.ts → client-pMBRFcsz.d.ts} +231 -42
- package/dist/client.cjs +1678 -406
- package/dist/client.d.cts +4 -4
- package/dist/client.d.ts +4 -4
- package/dist/client.js +1678 -406
- package/dist/{errors-QHD5Tlok.d.ts → errors-CwhCWGxm.d.ts} +1 -1
- package/dist/{errors-GgKrSUKp.d.cts → errors-rqxuUhQP.d.cts} +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/errors.d.ts +2 -2
- package/dist/index.cjs +1735 -394
- package/dist/index.d.cts +90 -40
- package/dist/index.d.ts +90 -40
- package/dist/index.js +1733 -396
- package/dist/{next-action-DkrwXYay.d.cts → next-action-CTGl8wpy.d.cts} +2 -2
- package/dist/{next-action-DkrwXYay.d.ts → next-action-CTGl8wpy.d.ts} +2 -2
- package/dist/{types-hfcOE7Oi.d.cts → types-Brucpq0Z.d.cts} +63 -8
- package/dist/{types-PM4AQRLP.d.ts → types-V_D7qjxY.d.ts} +63 -8
- package/dist/webhooks.cjs +1 -1
- package/dist/webhooks.d.cts +2 -2
- package/dist/webhooks.d.ts +2 -2
- package/dist/webhooks.js +1 -1
- package/package.json +7 -5
package/dist/client.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { componentsGeneric, anyApi } from 'convex/server';
|
|
2
|
-
import { getAddress, parseUnits, createPublicClient, http, encodeFunctionData } from 'viem';
|
|
3
2
|
import { toSafeSmartAccount } from 'permissionless/accounts';
|
|
3
|
+
import { getAddress, parseUnits, createPublicClient, http, encodeFunctionData } from 'viem';
|
|
4
4
|
import { entryPoint07Address, createPaymasterClient, createBundlerClient } from 'viem/account-abstraction';
|
|
5
5
|
import { baseSepolia } from 'viem/chains';
|
|
6
|
+
import { deriveSafeAddress as deriveSafeAddress$1, defaultSafeDeriveConfig } from '@repo/safe-derive';
|
|
7
|
+
import { ConvexHttpClient } from 'convex/browser';
|
|
6
8
|
import { setup, fromPromise, assign } from 'xstate';
|
|
7
9
|
|
|
8
10
|
// src/_generated/api.js
|
|
@@ -120,6 +122,159 @@ function identify(userId, traits) {
|
|
|
120
122
|
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
// ../config/src/chain.ts
|
|
126
|
+
var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
|
|
127
|
+
var TEST_USDC_ADDRESS = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
|
|
128
|
+
var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
|
|
129
|
+
|
|
130
|
+
// ../config/src/timing.ts
|
|
131
|
+
var FLOW_INVOKE_TIMEOUT_MS = 3e4;
|
|
132
|
+
|
|
133
|
+
// ../config/src/errors.ts
|
|
134
|
+
var CapxulError2 = class extends Error {
|
|
135
|
+
code;
|
|
136
|
+
details;
|
|
137
|
+
correlationId;
|
|
138
|
+
layer;
|
|
139
|
+
constructor(code, message, options) {
|
|
140
|
+
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
141
|
+
this.code = code;
|
|
142
|
+
this.details = options?.details;
|
|
143
|
+
this.correlationId = options?.correlationId;
|
|
144
|
+
this.layer = options?.layer;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var Errors = {
|
|
148
|
+
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
149
|
+
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
150
|
+
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
151
|
+
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
152
|
+
openfortApi: (operation, cause) => new CapxulError2(
|
|
153
|
+
"PROVIDER_ERROR",
|
|
154
|
+
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
155
|
+
{ cause, details: { provider: "openfort", operation } }
|
|
156
|
+
),
|
|
157
|
+
shieldApi: (status, detail) => new CapxulError2(
|
|
158
|
+
"PROVIDER_ERROR",
|
|
159
|
+
`Shield API error (${status}): ${detail}`,
|
|
160
|
+
{ details: { provider: "shield", status } }
|
|
161
|
+
),
|
|
162
|
+
providerError: (provider, operation, cause) => (
|
|
163
|
+
// Public `message` is redacted to a fixed shape so provider-side
|
|
164
|
+
// exception text never leaks to the client. The original `cause`
|
|
165
|
+
// is preserved on `Error.cause` for server-side debugging via
|
|
166
|
+
// observability sinks (Sentry, console traces).
|
|
167
|
+
new CapxulError2(
|
|
168
|
+
"PROVIDER_ERROR",
|
|
169
|
+
`Provider error: ${provider} ${operation}`,
|
|
170
|
+
{ cause, details: { provider, operation } }
|
|
171
|
+
)
|
|
172
|
+
),
|
|
173
|
+
invalidInput: (field, reason) => new CapxulError2(
|
|
174
|
+
"INVALID_INPUT",
|
|
175
|
+
`Invalid ${field}: ${reason}`,
|
|
176
|
+
{ details: { field, reason } }
|
|
177
|
+
),
|
|
178
|
+
playerNotFound: (playerId) => new CapxulError2(
|
|
179
|
+
"PLAYER_NOT_FOUND",
|
|
180
|
+
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
181
|
+
),
|
|
182
|
+
accountNotFound: (accountId) => new CapxulError2(
|
|
183
|
+
"ACCOUNT_NOT_FOUND",
|
|
184
|
+
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
185
|
+
),
|
|
186
|
+
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
187
|
+
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
188
|
+
notFound: (resource, id) => new CapxulError2(
|
|
189
|
+
"NOT_FOUND",
|
|
190
|
+
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
191
|
+
),
|
|
192
|
+
idempotencyConflict: (details) => new CapxulError2(
|
|
193
|
+
"IDEMPOTENCY_CONFLICT",
|
|
194
|
+
"Idempotency key was already used for a different request",
|
|
195
|
+
{ details }
|
|
196
|
+
),
|
|
197
|
+
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
198
|
+
details
|
|
199
|
+
}),
|
|
200
|
+
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
201
|
+
details: { ...details }
|
|
202
|
+
}),
|
|
203
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
204
|
+
/**
|
|
205
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
206
|
+
* boundary the actor cannot cross under their current state. Two
|
|
207
|
+
* variants share this code:
|
|
208
|
+
*
|
|
209
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
210
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
211
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
212
|
+
* `details.rail` + `details.currentKind`.
|
|
213
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
214
|
+
* the required tier. Carries `details.requiredTier`.
|
|
215
|
+
*
|
|
216
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
217
|
+
* proceed until verification advances"); the `details.*` keys
|
|
218
|
+
* differentiate the route.
|
|
219
|
+
*/
|
|
220
|
+
verificationRequired: (details) => {
|
|
221
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
222
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
223
|
+
details: { ...details }
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// ../config/src/safe.ts
|
|
229
|
+
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
230
|
+
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
231
|
+
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
232
|
+
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
233
|
+
|
|
234
|
+
// ../config/src/org-roles.ts
|
|
235
|
+
function roleKeyFromLabel(label) {
|
|
236
|
+
const bytes = new TextEncoder().encode(label);
|
|
237
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
238
|
+
return "0x" + hex.padEnd(64, "0");
|
|
239
|
+
}
|
|
240
|
+
roleKeyFromLabel("OWNER");
|
|
241
|
+
roleKeyFromLabel("FINANCE_MANAGER");
|
|
242
|
+
roleKeyFromLabel("PAYMENTS_OPERATOR");
|
|
243
|
+
async function buildSafeAccount(signer, chain) {
|
|
244
|
+
try {
|
|
245
|
+
const publicClient = createPublicClient({
|
|
246
|
+
chain: baseSepolia,
|
|
247
|
+
transport: http(chain.rpcUrl)
|
|
248
|
+
});
|
|
249
|
+
return await toSafeSmartAccount({
|
|
250
|
+
client: publicClient,
|
|
251
|
+
entryPoint: { address: entryPoint07Address, version: "0.7" },
|
|
252
|
+
version: "1.4.1",
|
|
253
|
+
owners: [signer],
|
|
254
|
+
saltNonce: computeSaltNonce(signer.address),
|
|
255
|
+
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
256
|
+
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
257
|
+
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
258
|
+
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
259
|
+
safeModules: [],
|
|
260
|
+
setupTransactions: []
|
|
261
|
+
});
|
|
262
|
+
} catch (cause) {
|
|
263
|
+
throw new CapxulError({
|
|
264
|
+
code: "NETWORK_ERROR",
|
|
265
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
266
|
+
cause,
|
|
267
|
+
details: { chainId: chain.chainId }
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function computeSaltNonce(ownerAddress) {
|
|
272
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
273
|
+
}
|
|
274
|
+
function deriveSafeAddress(signerAddress) {
|
|
275
|
+
return deriveSafeAddress$1(signerAddress, defaultSafeDeriveConfig);
|
|
276
|
+
}
|
|
277
|
+
|
|
123
278
|
// ../platform-kernel/src/ids.ts
|
|
124
279
|
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
125
280
|
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
@@ -132,12 +287,24 @@ function makePrefixedIdConstructor(prefix, fieldName) {
|
|
|
132
287
|
return raw;
|
|
133
288
|
};
|
|
134
289
|
}
|
|
290
|
+
var toSafeId = makePrefixedIdConstructor(
|
|
291
|
+
"safe",
|
|
292
|
+
"safeId"
|
|
293
|
+
);
|
|
294
|
+
var toTreasuryId = makePrefixedIdConstructor(
|
|
295
|
+
"try",
|
|
296
|
+
"treasuryId"
|
|
297
|
+
);
|
|
135
298
|
var toOperationId = makePrefixedIdConstructor(
|
|
136
299
|
"op",
|
|
137
300
|
"operationId"
|
|
138
301
|
);
|
|
139
302
|
var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
|
|
140
303
|
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
304
|
+
var toSubAccountId = makePrefixedIdConstructor(
|
|
305
|
+
"sub",
|
|
306
|
+
"subAccountId"
|
|
307
|
+
);
|
|
141
308
|
|
|
142
309
|
// src/core/external-accounts.ts
|
|
143
310
|
function brandExternalAccount(raw) {
|
|
@@ -154,13 +321,13 @@ function brandExternalAccount(raw) {
|
|
|
154
321
|
function createExternalAccountsClient(config = {}) {
|
|
155
322
|
return {
|
|
156
323
|
retrieve: async (externalAccountId) => {
|
|
157
|
-
if (!config.
|
|
324
|
+
if (!config._data) {
|
|
158
325
|
return stub(
|
|
159
326
|
"externalAccounts.retrieve"
|
|
160
327
|
);
|
|
161
328
|
}
|
|
162
329
|
const [err, raw] = await tryCatch(
|
|
163
|
-
config.
|
|
330
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
164
331
|
externalAccountId
|
|
165
332
|
})
|
|
166
333
|
);
|
|
@@ -182,11 +349,11 @@ function createExternalAccountsClient(config = {}) {
|
|
|
182
349
|
return [null, brandExternalAccount(raw)];
|
|
183
350
|
},
|
|
184
351
|
remove: async (externalAccountId) => {
|
|
185
|
-
if (!config.
|
|
352
|
+
if (!config._data) {
|
|
186
353
|
return stub("externalAccounts.remove");
|
|
187
354
|
}
|
|
188
355
|
const [err] = await tryCatch(
|
|
189
|
-
config.
|
|
356
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
190
357
|
externalAccountId
|
|
191
358
|
})
|
|
192
359
|
);
|
|
@@ -201,17 +368,203 @@ function createExternalAccountsClient(config = {}) {
|
|
|
201
368
|
};
|
|
202
369
|
}
|
|
203
370
|
|
|
371
|
+
// src/core/sub-accounts.ts
|
|
372
|
+
function malformedWireError(reason, raw) {
|
|
373
|
+
return new CapxulError({
|
|
374
|
+
code: "PROVIDER_ERROR",
|
|
375
|
+
message: `convex brandSubAccount failed: ${reason}`,
|
|
376
|
+
details: {
|
|
377
|
+
provider: "convex",
|
|
378
|
+
operation: "brandSubAccount",
|
|
379
|
+
reason,
|
|
380
|
+
// PII discipline (`.claude/rules/posthog.md`): user-authored
|
|
381
|
+
// strings on the wire (`name`, `purpose`) are customer-confidential
|
|
382
|
+
// — sub-account names like "Q3 Acquisition Reserve" or
|
|
383
|
+
// "Vendor ABC payments" must not flow into telemetry. We emit a
|
|
384
|
+
// structural keys-only sample via a strict ALLOWLIST so any future
|
|
385
|
+
// wire-shape addition (e.g. `recipientEmail`, `tags`) is dropped
|
|
386
|
+
// by construction rather than leaked through a denylist gap.
|
|
387
|
+
sample: safeSampleShape(raw)
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
function safeSampleShape(raw) {
|
|
392
|
+
if (raw === null || typeof raw !== "object") {
|
|
393
|
+
return { type: typeof raw };
|
|
394
|
+
}
|
|
395
|
+
const r = raw;
|
|
396
|
+
const balance = r.balance;
|
|
397
|
+
return {
|
|
398
|
+
object: typeof r.object === "string" ? r.object : typeof r.object,
|
|
399
|
+
idPresent: typeof r.id === "string" && r.id.length > 0,
|
|
400
|
+
// First 4 chars only — enough to distinguish "sub_" prefixed IDs
|
|
401
|
+
// from accidental other resource IDs without leaking the full ID.
|
|
402
|
+
idPrefix: typeof r.id === "string" ? r.id.slice(0, 4) : void 0,
|
|
403
|
+
parentKind: r.parent !== null && typeof r.parent === "object" ? r.parent.kind : typeof r.parent,
|
|
404
|
+
status: r.status,
|
|
405
|
+
hasName: typeof r.name === "string",
|
|
406
|
+
hasPurpose: r.purpose !== void 0,
|
|
407
|
+
balanceShape: balance !== null && typeof balance === "object" ? Object.keys(balance).sort() : typeof balance,
|
|
408
|
+
createdAtType: typeof r.createdAt,
|
|
409
|
+
updatedAtType: typeof r.updatedAt
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function isMoneyShape(v) {
|
|
413
|
+
if (typeof v !== "object" || v === null) return false;
|
|
414
|
+
const m = v;
|
|
415
|
+
return typeof m.value === "string" && typeof m.currency === "string";
|
|
416
|
+
}
|
|
417
|
+
function isParentShape(v) {
|
|
418
|
+
if (typeof v !== "object" || v === null) return false;
|
|
419
|
+
const p = v;
|
|
420
|
+
return (p.kind === "account" || p.kind === "organization") && typeof p.id === "string";
|
|
421
|
+
}
|
|
422
|
+
function isFiniteNonNegativeInteger(v) {
|
|
423
|
+
return typeof v === "number" && Number.isFinite(v) && Number.isInteger(v) && v >= 0;
|
|
424
|
+
}
|
|
425
|
+
function validateWireSubAccount(raw) {
|
|
426
|
+
if (typeof raw !== "object" || raw === null) {
|
|
427
|
+
return { ok: false, reason: "not an object" };
|
|
428
|
+
}
|
|
429
|
+
const r = raw;
|
|
430
|
+
if (r.object !== "sub_account") {
|
|
431
|
+
return { ok: false, reason: `object must be "sub_account" (got ${String(r.object)})` };
|
|
432
|
+
}
|
|
433
|
+
if (typeof r.id !== "string" || r.id.length === 0) {
|
|
434
|
+
return { ok: false, reason: "id must be a non-empty string" };
|
|
435
|
+
}
|
|
436
|
+
if (!isParentShape(r.parent)) {
|
|
437
|
+
return { ok: false, reason: "parent must be { kind: 'account' | 'organization', id: string }" };
|
|
438
|
+
}
|
|
439
|
+
if (typeof r.name !== "string") {
|
|
440
|
+
return { ok: false, reason: "name must be a string" };
|
|
441
|
+
}
|
|
442
|
+
if (r.purpose !== void 0 && typeof r.purpose !== "string") {
|
|
443
|
+
return { ok: false, reason: "purpose must be a string when present" };
|
|
444
|
+
}
|
|
445
|
+
if (r.status !== "active" && r.status !== "archived") {
|
|
446
|
+
return { ok: false, reason: `status must be "active" | "archived" (got ${String(r.status)})` };
|
|
447
|
+
}
|
|
448
|
+
if (!isMoneyShape(r.balance)) {
|
|
449
|
+
return { ok: false, reason: "balance must be { value: string, currency: string }" };
|
|
450
|
+
}
|
|
451
|
+
if (!isFiniteNonNegativeInteger(r.createdAt)) {
|
|
452
|
+
return { ok: false, reason: "createdAt must be a finite non-negative integer (epoch ms)" };
|
|
453
|
+
}
|
|
454
|
+
if (r.updatedAt !== void 0 && !isFiniteNonNegativeInteger(r.updatedAt)) {
|
|
455
|
+
return { ok: false, reason: "updatedAt must be a finite non-negative integer when present" };
|
|
456
|
+
}
|
|
457
|
+
return { ok: true, value: r };
|
|
458
|
+
}
|
|
459
|
+
function brandSubAccount(raw) {
|
|
460
|
+
const result = validateWireSubAccount(raw);
|
|
461
|
+
if (!result.ok) {
|
|
462
|
+
throw malformedWireError(result.reason, raw);
|
|
463
|
+
}
|
|
464
|
+
const wire = result.value;
|
|
465
|
+
return {
|
|
466
|
+
object: wire.object,
|
|
467
|
+
id: toSubAccountId(wire.id),
|
|
468
|
+
parent: wire.parent,
|
|
469
|
+
name: wire.name,
|
|
470
|
+
...wire.purpose !== void 0 ? { purpose: wire.purpose } : {},
|
|
471
|
+
status: wire.status,
|
|
472
|
+
balance: wire.balance,
|
|
473
|
+
createdAt: new Date(wire.createdAt).toISOString()
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function tryBrandSubAccount(raw) {
|
|
477
|
+
try {
|
|
478
|
+
return [null, brandSubAccount(raw)];
|
|
479
|
+
} catch (err) {
|
|
480
|
+
if (err instanceof CapxulError && err.code === "PROVIDER_ERROR") {
|
|
481
|
+
return [err, null];
|
|
482
|
+
}
|
|
483
|
+
return [
|
|
484
|
+
malformedWireError(
|
|
485
|
+
err instanceof Error ? err.message : String(err),
|
|
486
|
+
raw
|
|
487
|
+
),
|
|
488
|
+
null
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function createSubAccountsClient(config = {}) {
|
|
493
|
+
return {
|
|
494
|
+
retrieve: async (subAccountId) => {
|
|
495
|
+
if (!config._data) {
|
|
496
|
+
return stub("subAccounts.retrieve");
|
|
497
|
+
}
|
|
498
|
+
const [err, raw] = await tryCatch(
|
|
499
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
500
|
+
subAccountId
|
|
501
|
+
})
|
|
502
|
+
);
|
|
503
|
+
if (err) {
|
|
504
|
+
return [
|
|
505
|
+
fromConvexError(err),
|
|
506
|
+
null
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
if (!raw) {
|
|
510
|
+
return [
|
|
511
|
+
new CapxulError({
|
|
512
|
+
code: "NOT_FOUND",
|
|
513
|
+
message: `sub_account ${subAccountId} not found`
|
|
514
|
+
}),
|
|
515
|
+
null
|
|
516
|
+
];
|
|
517
|
+
}
|
|
518
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
519
|
+
if (brandErr) {
|
|
520
|
+
return [brandErr, null];
|
|
521
|
+
}
|
|
522
|
+
return [null, branded];
|
|
523
|
+
},
|
|
524
|
+
remove: async (subAccountId) => {
|
|
525
|
+
if (!config._data) {
|
|
526
|
+
return stub("subAccounts.remove");
|
|
527
|
+
}
|
|
528
|
+
const [err, raw] = await tryCatch(
|
|
529
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
530
|
+
subAccountId
|
|
531
|
+
})
|
|
532
|
+
);
|
|
533
|
+
if (err) {
|
|
534
|
+
return [
|
|
535
|
+
fromConvexError(err),
|
|
536
|
+
null
|
|
537
|
+
];
|
|
538
|
+
}
|
|
539
|
+
if (!raw) {
|
|
540
|
+
return [
|
|
541
|
+
new CapxulError({
|
|
542
|
+
code: "NOT_FOUND",
|
|
543
|
+
message: `sub_account ${subAccountId} not found`
|
|
544
|
+
}),
|
|
545
|
+
null
|
|
546
|
+
];
|
|
547
|
+
}
|
|
548
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
549
|
+
if (brandErr) {
|
|
550
|
+
return [brandErr, null];
|
|
551
|
+
}
|
|
552
|
+
return [null, branded];
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
204
557
|
// src/core/accounts.ts
|
|
205
558
|
function createAccountExternalAccountsClient(config) {
|
|
206
559
|
return {
|
|
207
560
|
create: async (input) => {
|
|
208
|
-
if (!config.
|
|
561
|
+
if (!config._data) {
|
|
209
562
|
return stub(
|
|
210
563
|
"accounts.externalAccounts.create"
|
|
211
564
|
);
|
|
212
565
|
}
|
|
213
566
|
const [err, raw] = await tryCatch(
|
|
214
|
-
config.
|
|
567
|
+
config._data.mutation(
|
|
215
568
|
api.externalAccounts.mutations.createPersonal,
|
|
216
569
|
{
|
|
217
570
|
kind: input.kind,
|
|
@@ -249,13 +602,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
249
602
|
];
|
|
250
603
|
},
|
|
251
604
|
list: async (input) => {
|
|
252
|
-
if (!config.
|
|
605
|
+
if (!config._data) {
|
|
253
606
|
return stub(
|
|
254
607
|
"accounts.externalAccounts.list"
|
|
255
608
|
);
|
|
256
609
|
}
|
|
257
610
|
const [err, result] = await tryCatch(
|
|
258
|
-
config.
|
|
611
|
+
config._data.query(api.externalAccounts.queries.listPersonal, {
|
|
259
612
|
limit: input.limit,
|
|
260
613
|
cursor: input.cursor
|
|
261
614
|
})
|
|
@@ -278,13 +631,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
278
631
|
];
|
|
279
632
|
},
|
|
280
633
|
retrieve: async (externalAccountId) => {
|
|
281
|
-
if (!config.
|
|
634
|
+
if (!config._data) {
|
|
282
635
|
return stub(
|
|
283
636
|
"accounts.externalAccounts.retrieve"
|
|
284
637
|
);
|
|
285
638
|
}
|
|
286
639
|
const [err, raw] = await tryCatch(
|
|
287
|
-
config.
|
|
640
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
288
641
|
externalAccountId
|
|
289
642
|
})
|
|
290
643
|
);
|
|
@@ -311,11 +664,11 @@ function createAccountExternalAccountsClient(config) {
|
|
|
311
664
|
];
|
|
312
665
|
},
|
|
313
666
|
remove: async (externalAccountId) => {
|
|
314
|
-
if (!config.
|
|
667
|
+
if (!config._data) {
|
|
315
668
|
return stub("accounts.externalAccounts.remove");
|
|
316
669
|
}
|
|
317
670
|
const [err] = await tryCatch(
|
|
318
|
-
config.
|
|
671
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
319
672
|
externalAccountId
|
|
320
673
|
})
|
|
321
674
|
);
|
|
@@ -329,41 +682,189 @@ function createAccountExternalAccountsClient(config) {
|
|
|
329
682
|
}
|
|
330
683
|
};
|
|
331
684
|
}
|
|
332
|
-
function
|
|
685
|
+
function createAccountSubAccountsClient(config) {
|
|
333
686
|
return {
|
|
334
|
-
|
|
335
|
-
if (!config.
|
|
336
|
-
return stub(
|
|
337
|
-
|
|
338
|
-
try {
|
|
339
|
-
const account = await config.data.query(
|
|
340
|
-
api.openfort.queries.getMyAccount,
|
|
341
|
-
{}
|
|
687
|
+
create: async (input) => {
|
|
688
|
+
if (!config._data) {
|
|
689
|
+
return stub(
|
|
690
|
+
"accounts.subAccounts.create"
|
|
342
691
|
);
|
|
343
|
-
if (account.id !== accountId) {
|
|
344
|
-
return [
|
|
345
|
-
new CapxulError({
|
|
346
|
-
code: "PERMISSION_DENIED",
|
|
347
|
-
message: "accounts.retrieve currently supports the authenticated caller's own account only.",
|
|
348
|
-
details: {
|
|
349
|
-
requestedAccountId: accountId,
|
|
350
|
-
authenticatedAccountId: account.id
|
|
351
|
-
}
|
|
352
|
-
}),
|
|
353
|
-
null
|
|
354
|
-
];
|
|
355
|
-
}
|
|
356
|
-
return [null, account];
|
|
357
|
-
} catch (cause) {
|
|
358
|
-
return [fromConvexError(cause), null];
|
|
359
|
-
}
|
|
360
|
-
},
|
|
361
|
-
lookup: async () => stub("accounts.lookup"),
|
|
362
|
-
update: async (input) => {
|
|
363
|
-
if (!config.data) {
|
|
364
|
-
return stub("accounts.update");
|
|
365
692
|
}
|
|
366
|
-
|
|
693
|
+
const [err, raw] = await tryCatch(
|
|
694
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
695
|
+
parent: { kind: "account", id: input.accountId },
|
|
696
|
+
name: input.name,
|
|
697
|
+
purpose: input.purpose
|
|
698
|
+
})
|
|
699
|
+
);
|
|
700
|
+
if (err) {
|
|
701
|
+
return [
|
|
702
|
+
fromConvexError(err),
|
|
703
|
+
null
|
|
704
|
+
];
|
|
705
|
+
}
|
|
706
|
+
if (!raw) {
|
|
707
|
+
return [
|
|
708
|
+
new CapxulError({
|
|
709
|
+
code: "NOT_FOUND",
|
|
710
|
+
message: "sub_account creation returned no resource"
|
|
711
|
+
}),
|
|
712
|
+
null
|
|
713
|
+
];
|
|
714
|
+
}
|
|
715
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
716
|
+
if (brandErr) {
|
|
717
|
+
return [
|
|
718
|
+
brandErr,
|
|
719
|
+
null
|
|
720
|
+
];
|
|
721
|
+
}
|
|
722
|
+
return [null, branded];
|
|
723
|
+
},
|
|
724
|
+
list: async (input) => {
|
|
725
|
+
if (!config._data) {
|
|
726
|
+
return stub(
|
|
727
|
+
"accounts.subAccounts.list"
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
const [err, rows] = await tryCatch(
|
|
731
|
+
config._data.query(api.subAccounts.queries.listByAccount, {
|
|
732
|
+
accountId: input.accountId
|
|
733
|
+
})
|
|
734
|
+
);
|
|
735
|
+
if (err) {
|
|
736
|
+
return [
|
|
737
|
+
fromConvexError(err),
|
|
738
|
+
null
|
|
739
|
+
];
|
|
740
|
+
}
|
|
741
|
+
const branded = [];
|
|
742
|
+
for (const row of rows) {
|
|
743
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
744
|
+
if (brandErr) {
|
|
745
|
+
return [
|
|
746
|
+
brandErr,
|
|
747
|
+
null
|
|
748
|
+
];
|
|
749
|
+
}
|
|
750
|
+
branded.push(value);
|
|
751
|
+
}
|
|
752
|
+
return [
|
|
753
|
+
null,
|
|
754
|
+
{
|
|
755
|
+
object: "list",
|
|
756
|
+
data: branded,
|
|
757
|
+
page: { hasMore: false }
|
|
758
|
+
}
|
|
759
|
+
];
|
|
760
|
+
},
|
|
761
|
+
retrieve: async (subAccountId) => {
|
|
762
|
+
if (!config._data) {
|
|
763
|
+
return stub(
|
|
764
|
+
"accounts.subAccounts.retrieve"
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
const [err, raw] = await tryCatch(
|
|
768
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
769
|
+
subAccountId
|
|
770
|
+
})
|
|
771
|
+
);
|
|
772
|
+
if (err) {
|
|
773
|
+
return [
|
|
774
|
+
fromConvexError(err),
|
|
775
|
+
null
|
|
776
|
+
];
|
|
777
|
+
}
|
|
778
|
+
if (!raw) {
|
|
779
|
+
return [
|
|
780
|
+
new CapxulError({
|
|
781
|
+
code: "NOT_FOUND",
|
|
782
|
+
message: `sub_account ${subAccountId} not found`
|
|
783
|
+
}),
|
|
784
|
+
null
|
|
785
|
+
];
|
|
786
|
+
}
|
|
787
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
788
|
+
if (brandErr) {
|
|
789
|
+
return [
|
|
790
|
+
brandErr,
|
|
791
|
+
null
|
|
792
|
+
];
|
|
793
|
+
}
|
|
794
|
+
return [null, branded];
|
|
795
|
+
},
|
|
796
|
+
remove: async (subAccountId) => {
|
|
797
|
+
if (!config._data) {
|
|
798
|
+
return stub(
|
|
799
|
+
"accounts.subAccounts.remove"
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
const [err, raw] = await tryCatch(
|
|
803
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
804
|
+
subAccountId
|
|
805
|
+
})
|
|
806
|
+
);
|
|
807
|
+
if (err) {
|
|
808
|
+
return [
|
|
809
|
+
fromConvexError(err),
|
|
810
|
+
null
|
|
811
|
+
];
|
|
812
|
+
}
|
|
813
|
+
if (!raw) {
|
|
814
|
+
return [
|
|
815
|
+
new CapxulError({
|
|
816
|
+
code: "NOT_FOUND",
|
|
817
|
+
message: `sub_account ${subAccountId} not found`
|
|
818
|
+
}),
|
|
819
|
+
null
|
|
820
|
+
];
|
|
821
|
+
}
|
|
822
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
823
|
+
if (brandErr) {
|
|
824
|
+
return [
|
|
825
|
+
brandErr,
|
|
826
|
+
null
|
|
827
|
+
];
|
|
828
|
+
}
|
|
829
|
+
return [null, branded];
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
function createAccountsClient(config = {}) {
|
|
834
|
+
return {
|
|
835
|
+
retrieve: async (accountId) => {
|
|
836
|
+
if (!config._data) {
|
|
837
|
+
return stub("accounts.retrieve");
|
|
838
|
+
}
|
|
839
|
+
try {
|
|
840
|
+
const account = await config._data.query(
|
|
841
|
+
api.openfort.queries.getMyAccount,
|
|
842
|
+
{}
|
|
843
|
+
);
|
|
844
|
+
if (account.id !== accountId) {
|
|
845
|
+
return [
|
|
846
|
+
new CapxulError({
|
|
847
|
+
code: "PERMISSION_DENIED",
|
|
848
|
+
message: "accounts.retrieve currently supports the authenticated caller's own account only.",
|
|
849
|
+
details: {
|
|
850
|
+
requestedAccountId: accountId,
|
|
851
|
+
authenticatedAccountId: account.id
|
|
852
|
+
}
|
|
853
|
+
}),
|
|
854
|
+
null
|
|
855
|
+
];
|
|
856
|
+
}
|
|
857
|
+
return [null, account];
|
|
858
|
+
} catch (cause) {
|
|
859
|
+
return [fromConvexError(cause), null];
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
lookup: async () => stub("accounts.lookup"),
|
|
863
|
+
update: async (input) => {
|
|
864
|
+
if (!config._data) {
|
|
865
|
+
return stub("accounts.update");
|
|
866
|
+
}
|
|
867
|
+
if (input.countryCode !== void 0) {
|
|
367
868
|
return [
|
|
368
869
|
new CapxulError({
|
|
369
870
|
code: "INVALID_INPUT",
|
|
@@ -374,7 +875,7 @@ function createAccountsClient(config = {}) {
|
|
|
374
875
|
];
|
|
375
876
|
}
|
|
376
877
|
try {
|
|
377
|
-
const current = await config.
|
|
878
|
+
const current = await config._data.query(
|
|
378
879
|
api.openfort.queries.getMyAccount,
|
|
379
880
|
{}
|
|
380
881
|
);
|
|
@@ -391,11 +892,11 @@ function createAccountsClient(config = {}) {
|
|
|
391
892
|
null
|
|
392
893
|
];
|
|
393
894
|
}
|
|
394
|
-
await config.
|
|
895
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
395
896
|
displayName: input.name,
|
|
396
897
|
username: input.username
|
|
397
898
|
});
|
|
398
|
-
const updated = await config.
|
|
899
|
+
const updated = await config._data.query(
|
|
399
900
|
api.openfort.queries.getMyAccount,
|
|
400
901
|
{}
|
|
401
902
|
);
|
|
@@ -405,7 +906,7 @@ function createAccountsClient(config = {}) {
|
|
|
405
906
|
}
|
|
406
907
|
},
|
|
407
908
|
provisionPersonal: async (input) => {
|
|
408
|
-
if (!config.
|
|
909
|
+
if (!config._data) {
|
|
409
910
|
return stub(
|
|
410
911
|
"accounts.provisionPersonal"
|
|
411
912
|
);
|
|
@@ -420,17 +921,17 @@ function createAccountsClient(config = {}) {
|
|
|
420
921
|
];
|
|
421
922
|
}
|
|
422
923
|
try {
|
|
423
|
-
await config.
|
|
924
|
+
await config._data.mutation(
|
|
424
925
|
api.safe.mutations.provisionLocalPersonalAccount,
|
|
425
926
|
{
|
|
426
927
|
displayName: input.displayName,
|
|
427
928
|
username: input.username,
|
|
428
929
|
countryCode: input.countryCode,
|
|
429
930
|
eoaAddress: input.signerProvider.signerAddress,
|
|
430
|
-
safeAddress: input.signerProvider.
|
|
931
|
+
safeAddress: deriveSafeAddress(input.signerProvider.signerAddress)
|
|
431
932
|
}
|
|
432
933
|
);
|
|
433
|
-
const account = await config.
|
|
934
|
+
const account = await config._data.query(
|
|
434
935
|
api.openfort.queries.getMyAccount,
|
|
435
936
|
{}
|
|
436
937
|
);
|
|
@@ -453,11 +954,11 @@ function createAccountsClient(config = {}) {
|
|
|
453
954
|
},
|
|
454
955
|
safes: {
|
|
455
956
|
retrieve: async (safeId) => {
|
|
456
|
-
if (!config.
|
|
957
|
+
if (!config._data) {
|
|
457
958
|
return stub("accounts.safes.retrieve");
|
|
458
959
|
}
|
|
459
960
|
try {
|
|
460
|
-
const safe = await config.
|
|
961
|
+
const safe = await config._data.query(
|
|
461
962
|
api.safe.queries.retrieveAccountSafe,
|
|
462
963
|
{ safeId }
|
|
463
964
|
);
|
|
@@ -484,19 +985,50 @@ function createAccountsClient(config = {}) {
|
|
|
484
985
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
485
986
|
},
|
|
486
987
|
externalAccounts: createAccountExternalAccountsClient(config),
|
|
487
|
-
subAccounts:
|
|
488
|
-
create: async () => stub("accounts.subAccounts.create"),
|
|
489
|
-
list: async () => stub("accounts.subAccounts.list"),
|
|
490
|
-
retrieve: async () => stub("accounts.subAccounts.retrieve"),
|
|
491
|
-
remove: async () => stub("accounts.subAccounts.remove")
|
|
492
|
-
},
|
|
988
|
+
subAccounts: createAccountSubAccountsClient(config),
|
|
493
989
|
balanceLedger: {
|
|
494
|
-
list: async () =>
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
990
|
+
list: async (input) => {
|
|
991
|
+
if (!config._data) {
|
|
992
|
+
return stub(
|
|
993
|
+
"accounts.balanceLedger.list"
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
try {
|
|
997
|
+
const accountId = input.accountId.replace(/^acct_/, "");
|
|
998
|
+
const page = await config._data.query(
|
|
999
|
+
api.balanceLedger.queries.listForAccount,
|
|
1000
|
+
{ accountId, limit: input.limit, cursor: input.cursor }
|
|
1001
|
+
);
|
|
1002
|
+
return [null, page];
|
|
1003
|
+
} catch (cause) {
|
|
1004
|
+
return [fromConvexError(cause), null];
|
|
1005
|
+
}
|
|
1006
|
+
},
|
|
1007
|
+
retrieve: async (entryId) => {
|
|
1008
|
+
if (!config._data) {
|
|
1009
|
+
return stub(
|
|
1010
|
+
"accounts.balanceLedger.retrieve"
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
try {
|
|
1014
|
+
const entry = await config._data.query(
|
|
1015
|
+
api.balanceLedger.queries.retrieve,
|
|
1016
|
+
{ entryId }
|
|
1017
|
+
);
|
|
1018
|
+
if (!entry) {
|
|
1019
|
+
return [
|
|
1020
|
+
new CapxulError({
|
|
1021
|
+
code: "NOT_FOUND",
|
|
1022
|
+
message: `balance_ledger_entry ${entryId} not found`
|
|
1023
|
+
}),
|
|
1024
|
+
null
|
|
1025
|
+
];
|
|
1026
|
+
}
|
|
1027
|
+
return [null, entry];
|
|
1028
|
+
} catch (cause) {
|
|
1029
|
+
return [fromConvexError(cause), null];
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
500
1032
|
}
|
|
501
1033
|
};
|
|
502
1034
|
}
|
|
@@ -510,129 +1042,21 @@ function createApiKeysClient() {
|
|
|
510
1042
|
revoke: async () => stub("apiKeys.revoke")
|
|
511
1043
|
};
|
|
512
1044
|
}
|
|
1045
|
+
function createDefaultDataClient(convexUrl, jwt) {
|
|
1046
|
+
const client = new ConvexHttpClient(convexUrl);
|
|
1047
|
+
client.setAuth(jwt);
|
|
1048
|
+
return client;
|
|
1049
|
+
}
|
|
513
1050
|
|
|
514
|
-
//
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
var CapxulError2 = class extends Error {
|
|
524
|
-
code;
|
|
525
|
-
details;
|
|
526
|
-
correlationId;
|
|
527
|
-
layer;
|
|
528
|
-
constructor(code, message, options) {
|
|
529
|
-
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
530
|
-
this.code = code;
|
|
531
|
-
this.details = options?.details;
|
|
532
|
-
this.correlationId = options?.correlationId;
|
|
533
|
-
this.layer = options?.layer;
|
|
534
|
-
}
|
|
535
|
-
};
|
|
536
|
-
var Errors = {
|
|
537
|
-
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
538
|
-
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
539
|
-
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
540
|
-
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
541
|
-
openfortApi: (operation, cause) => new CapxulError2(
|
|
542
|
-
"PROVIDER_ERROR",
|
|
543
|
-
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
544
|
-
{ cause, details: { provider: "openfort", operation } }
|
|
545
|
-
),
|
|
546
|
-
shieldApi: (status, detail) => new CapxulError2(
|
|
547
|
-
"PROVIDER_ERROR",
|
|
548
|
-
`Shield API error (${status}): ${detail}`,
|
|
549
|
-
{ details: { provider: "shield", status } }
|
|
550
|
-
),
|
|
551
|
-
providerError: (provider, operation, cause) => new CapxulError2(
|
|
552
|
-
"PROVIDER_ERROR",
|
|
553
|
-
`${provider} ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
554
|
-
{ cause, details: { provider, operation } }
|
|
555
|
-
),
|
|
556
|
-
invalidInput: (field, reason) => new CapxulError2(
|
|
557
|
-
"INVALID_INPUT",
|
|
558
|
-
`Invalid ${field}: ${reason}`,
|
|
559
|
-
{ details: { field, reason } }
|
|
560
|
-
),
|
|
561
|
-
playerNotFound: (playerId) => new CapxulError2(
|
|
562
|
-
"PLAYER_NOT_FOUND",
|
|
563
|
-
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
564
|
-
),
|
|
565
|
-
accountNotFound: (accountId) => new CapxulError2(
|
|
566
|
-
"ACCOUNT_NOT_FOUND",
|
|
567
|
-
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
568
|
-
),
|
|
569
|
-
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
570
|
-
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
571
|
-
notFound: (resource, id) => new CapxulError2(
|
|
572
|
-
"NOT_FOUND",
|
|
573
|
-
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
574
|
-
),
|
|
575
|
-
idempotencyConflict: (details) => new CapxulError2(
|
|
576
|
-
"IDEMPOTENCY_CONFLICT",
|
|
577
|
-
"Idempotency key was already used for a different request",
|
|
578
|
-
{ details }
|
|
579
|
-
),
|
|
580
|
-
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
581
|
-
details
|
|
582
|
-
}),
|
|
583
|
-
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
584
|
-
details: { ...details }
|
|
585
|
-
}),
|
|
586
|
-
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
587
|
-
/**
|
|
588
|
-
* Verification gate. Surfaced when a request hits a verification
|
|
589
|
-
* boundary the actor cannot cross under their current state. Two
|
|
590
|
-
* variants share this code:
|
|
591
|
-
*
|
|
592
|
-
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
593
|
-
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
594
|
-
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
595
|
-
* `details.rail` + `details.currentKind`.
|
|
596
|
-
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
597
|
-
* the required tier. Carries `details.requiredTier`.
|
|
598
|
-
*
|
|
599
|
-
* Code is shared because both expose the same UX shape ("you cannot
|
|
600
|
-
* proceed until verification advances"); the `details.*` keys
|
|
601
|
-
* differentiate the route.
|
|
602
|
-
*/
|
|
603
|
-
verificationRequired: (details) => {
|
|
604
|
-
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
605
|
-
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
606
|
-
details: { ...details }
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
// ../config/src/safe.ts
|
|
612
|
-
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
613
|
-
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
614
|
-
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
615
|
-
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
616
|
-
|
|
617
|
-
// ../config/src/org-roles.ts
|
|
618
|
-
function roleKeyFromLabel(label) {
|
|
619
|
-
const bytes = new TextEncoder().encode(label);
|
|
620
|
-
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
621
|
-
return "0x" + hex.padEnd(64, "0");
|
|
622
|
-
}
|
|
623
|
-
roleKeyFromLabel("OWNER");
|
|
624
|
-
roleKeyFromLabel("FINANCE_MANAGER");
|
|
625
|
-
roleKeyFromLabel("TEAM_LEAD");
|
|
626
|
-
|
|
627
|
-
// src/transport.ts
|
|
628
|
-
function makeHttpTransport(config) {
|
|
629
|
-
switch (config.mode) {
|
|
630
|
-
case "build-time-urls":
|
|
631
|
-
return makeBuildTimeUrlsTransport(config);
|
|
632
|
-
case "publishable-key":
|
|
633
|
-
return makePublishableKeyTransport(config);
|
|
634
|
-
default:
|
|
635
|
-
return assertNever(config);
|
|
1051
|
+
// src/transport.ts
|
|
1052
|
+
function makeHttpTransport(config) {
|
|
1053
|
+
switch (config.mode) {
|
|
1054
|
+
case "build-time-urls":
|
|
1055
|
+
return makeBuildTimeUrlsTransport(config);
|
|
1056
|
+
case "publishable-key":
|
|
1057
|
+
return makePublishableKeyTransport(config);
|
|
1058
|
+
default:
|
|
1059
|
+
return assertNever(config);
|
|
636
1060
|
}
|
|
637
1061
|
}
|
|
638
1062
|
function createLifecycle(initial) {
|
|
@@ -953,7 +1377,7 @@ function readNonEmptyString(value) {
|
|
|
953
1377
|
|
|
954
1378
|
// src/core/auth.ts
|
|
955
1379
|
function createAuthClient(config = {}) {
|
|
956
|
-
let dataClient = config.
|
|
1380
|
+
let dataClient = config._data ?? null;
|
|
957
1381
|
const sessionStore = config.auth?.sessionStore ?? createMemorySessionStore();
|
|
958
1382
|
const getTransport = createTransportProvider(config);
|
|
959
1383
|
return {
|
|
@@ -1009,11 +1433,20 @@ function createAuthClient(config = {}) {
|
|
|
1009
1433
|
).toISOString()
|
|
1010
1434
|
};
|
|
1011
1435
|
sessionStore.set(session);
|
|
1012
|
-
if (
|
|
1436
|
+
if (!dataClient) {
|
|
1013
1437
|
try {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1438
|
+
const convexUrl = transport.convexUrl;
|
|
1439
|
+
if (!convexUrl || !session.convexJwt) {
|
|
1440
|
+
return [
|
|
1441
|
+
new CapxulError({
|
|
1442
|
+
code: "NETWORK_ERROR",
|
|
1443
|
+
message: "Cannot create data client: missing convex URL or JWT."
|
|
1444
|
+
}),
|
|
1445
|
+
null
|
|
1446
|
+
];
|
|
1447
|
+
}
|
|
1448
|
+
dataClient = createDefaultDataClient(convexUrl, session.convexJwt);
|
|
1449
|
+
mutableConfig(config)._data = dataClient;
|
|
1017
1450
|
} catch (cause) {
|
|
1018
1451
|
return [
|
|
1019
1452
|
new CapxulError({
|
|
@@ -1024,14 +1457,89 @@ function createAuthClient(config = {}) {
|
|
|
1024
1457
|
null
|
|
1025
1458
|
];
|
|
1026
1459
|
}
|
|
1460
|
+
} else {
|
|
1461
|
+
const injected = dataClient;
|
|
1462
|
+
if (typeof injected.refreshAuth === "function") {
|
|
1463
|
+
injected.refreshAuth();
|
|
1464
|
+
} else if (typeof injected.setAuth === "function" && session.convexJwt) {
|
|
1465
|
+
injected.setAuth(session.convexJwt);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
transport.markAuthenticated({ dataClient });
|
|
1469
|
+
if (!dataClient) {
|
|
1470
|
+
return [
|
|
1471
|
+
new CapxulError({
|
|
1472
|
+
code: "NOT_AUTHENTICATED",
|
|
1473
|
+
message: "Auth bootstrap requires an authenticated Convex data client."
|
|
1474
|
+
}),
|
|
1475
|
+
null
|
|
1476
|
+
];
|
|
1477
|
+
}
|
|
1478
|
+
try {
|
|
1479
|
+
const resolution = await dataClient.mutation(
|
|
1480
|
+
api.authBootstrap.resolveAfterOtp,
|
|
1481
|
+
{
|
|
1482
|
+
email: session.email,
|
|
1483
|
+
sessionToken: session.token
|
|
1484
|
+
}
|
|
1485
|
+
);
|
|
1486
|
+
if (resolution.kind === "existing_member") {
|
|
1487
|
+
return [null, { ...resolution, session }];
|
|
1488
|
+
}
|
|
1489
|
+
return [null, { ...resolution, session }];
|
|
1490
|
+
} catch (cause) {
|
|
1491
|
+
return [fromConvexError(cause), null];
|
|
1492
|
+
}
|
|
1493
|
+
},
|
|
1494
|
+
completeBootstrap: async (input) => {
|
|
1495
|
+
const session = sessionStore.get();
|
|
1496
|
+
const data = dataClient ?? config._data;
|
|
1497
|
+
if (!session || !data) {
|
|
1498
|
+
return [
|
|
1499
|
+
new CapxulError({
|
|
1500
|
+
code: "INVALID_INPUT",
|
|
1501
|
+
message: "completeBootstrap requires the OTP-verified session that issued the bootstrap token."
|
|
1502
|
+
}),
|
|
1503
|
+
null
|
|
1504
|
+
];
|
|
1505
|
+
}
|
|
1506
|
+
const signerAddress = config.signer?.address;
|
|
1507
|
+
if (!signerAddress) {
|
|
1508
|
+
return [
|
|
1509
|
+
new CapxulError({
|
|
1510
|
+
code: "INVALID_INPUT",
|
|
1511
|
+
message: "completeBootstrap requires a signer to be configured on the client."
|
|
1512
|
+
}),
|
|
1513
|
+
null
|
|
1514
|
+
];
|
|
1515
|
+
}
|
|
1516
|
+
try {
|
|
1517
|
+
const safeAddress = deriveSafeAddress(signerAddress);
|
|
1518
|
+
const result = await data.mutation(api.authBootstrap.completeBootstrap, {
|
|
1519
|
+
bootstrapToken: input.bootstrapToken,
|
|
1520
|
+
sessionToken: session.token,
|
|
1521
|
+
username: input.username,
|
|
1522
|
+
displayName: input.displayName,
|
|
1523
|
+
countryCode: input.countryCode,
|
|
1524
|
+
signerProvider: {
|
|
1525
|
+
kind: "local-private-key",
|
|
1526
|
+
signerAddress,
|
|
1527
|
+
safeAddress
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
return [null, { kind: "authenticated", session, ...result }];
|
|
1531
|
+
} catch (cause) {
|
|
1532
|
+
return [
|
|
1533
|
+
fromConvexError(cause),
|
|
1534
|
+
null
|
|
1535
|
+
];
|
|
1027
1536
|
}
|
|
1028
|
-
return [null, session];
|
|
1029
1537
|
},
|
|
1030
1538
|
getSession: async () => [null, sessionStore.get()],
|
|
1031
1539
|
signOut: async () => {
|
|
1032
1540
|
sessionStore.clear();
|
|
1033
1541
|
dataClient = null;
|
|
1034
|
-
mutableConfig(config).
|
|
1542
|
+
mutableConfig(config)._data = void 0;
|
|
1035
1543
|
const transport = getTransport();
|
|
1036
1544
|
transport?.clearAuth();
|
|
1037
1545
|
return [null, void 0];
|
|
@@ -1102,6 +1610,9 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
1102
1610
|
}
|
|
1103
1611
|
return [null, text ? JSON.parse(text) : void 0];
|
|
1104
1612
|
} catch (cause) {
|
|
1613
|
+
if (cause instanceof CapxulError) {
|
|
1614
|
+
return [cause, null];
|
|
1615
|
+
}
|
|
1105
1616
|
return [
|
|
1106
1617
|
new CapxulError({
|
|
1107
1618
|
code: "NETWORK_ERROR",
|
|
@@ -1140,7 +1651,7 @@ function parseBetterAuthError(text) {
|
|
|
1140
1651
|
}
|
|
1141
1652
|
}
|
|
1142
1653
|
function isCapxulErrorCode2(code) {
|
|
1143
|
-
return code === "NOT_AUTHENTICATED" || code === "EMAIL_DELIVERY_FAILED" || code === "INVALID_INPUT" || code === "RATE_LIMITED" || code === "NETWORK_ERROR" || code === "API_KEY_INVALID" || code === "API_KEY_EXPIRED";
|
|
1654
|
+
return code === "NOT_AUTHENTICATED" || code === "EMAIL_DELIVERY_FAILED" || code === "INVALID_INPUT" || code === "RATE_LIMITED" || code === "NETWORK_ERROR" || code === "API_KEY_INVALID" || code === "API_KEY_EXPIRED" || code === "INTERNAL_ERROR" || code === "ENV_MISSING" || code === "UNKNOWN" || code === "PROVIDER_ERROR";
|
|
1144
1655
|
}
|
|
1145
1656
|
async function exchangeConvexToken(transport, config, token, signal) {
|
|
1146
1657
|
const path = config.auth?.convexTokenUrl ?? "/convex/token";
|
|
@@ -1170,6 +1681,9 @@ async function exchangeConvexToken(transport, config, token, signal) {
|
|
|
1170
1681
|
}
|
|
1171
1682
|
return [null, body.token];
|
|
1172
1683
|
} catch (cause) {
|
|
1684
|
+
if (cause instanceof CapxulError) {
|
|
1685
|
+
return [cause, null];
|
|
1686
|
+
}
|
|
1173
1687
|
return [
|
|
1174
1688
|
new CapxulError({
|
|
1175
1689
|
code: "NETWORK_ERROR",
|
|
@@ -1206,11 +1720,11 @@ function createOrgDocumentsClient() {
|
|
|
1206
1720
|
function createMeClient(config = {}) {
|
|
1207
1721
|
return {
|
|
1208
1722
|
get: async () => {
|
|
1209
|
-
if (!config.
|
|
1723
|
+
if (!config._data) {
|
|
1210
1724
|
return stub("me.get");
|
|
1211
1725
|
}
|
|
1212
1726
|
try {
|
|
1213
|
-
const account = await config.
|
|
1727
|
+
const account = await config._data.query(
|
|
1214
1728
|
api.openfort.queries.getMyAccount,
|
|
1215
1729
|
{}
|
|
1216
1730
|
);
|
|
@@ -1220,7 +1734,7 @@ function createMeClient(config = {}) {
|
|
|
1220
1734
|
}
|
|
1221
1735
|
},
|
|
1222
1736
|
update: async (input) => {
|
|
1223
|
-
if (!config.
|
|
1737
|
+
if (!config._data) {
|
|
1224
1738
|
return stub("me.update");
|
|
1225
1739
|
}
|
|
1226
1740
|
if (input.countryCode !== void 0) {
|
|
@@ -1234,11 +1748,11 @@ function createMeClient(config = {}) {
|
|
|
1234
1748
|
];
|
|
1235
1749
|
}
|
|
1236
1750
|
try {
|
|
1237
|
-
await config.
|
|
1751
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
1238
1752
|
displayName: input.name,
|
|
1239
1753
|
username: input.username
|
|
1240
1754
|
});
|
|
1241
|
-
const account = await config.
|
|
1755
|
+
const account = await config._data.query(
|
|
1242
1756
|
api.openfort.queries.getMyAccount,
|
|
1243
1757
|
{}
|
|
1244
1758
|
);
|
|
@@ -1253,11 +1767,11 @@ function createMeClient(config = {}) {
|
|
|
1253
1767
|
// src/core/operations.ts
|
|
1254
1768
|
function createOperationsClient(config = {}) {
|
|
1255
1769
|
const retrieve = async (operationId) => {
|
|
1256
|
-
if (!config.
|
|
1770
|
+
if (!config._data) {
|
|
1257
1771
|
return stub("operations.retrieve");
|
|
1258
1772
|
}
|
|
1259
1773
|
try {
|
|
1260
|
-
const operation = await config.
|
|
1774
|
+
const operation = await config._data.query(api.operations.queries.retrieve, {
|
|
1261
1775
|
operationId
|
|
1262
1776
|
});
|
|
1263
1777
|
if (!operation) {
|
|
@@ -1274,7 +1788,7 @@ function createOperationsClient(config = {}) {
|
|
|
1274
1788
|
return {
|
|
1275
1789
|
retrieve,
|
|
1276
1790
|
wait: async (operationId, input = {}) => {
|
|
1277
|
-
if (!config.
|
|
1791
|
+
if (!config._data) {
|
|
1278
1792
|
return stub("operations.wait");
|
|
1279
1793
|
}
|
|
1280
1794
|
const until = new Set(
|
|
@@ -1309,49 +1823,22 @@ function toTokenUnits(value, decimals = 6) {
|
|
|
1309
1823
|
return parseUnits(value, decimals);
|
|
1310
1824
|
}
|
|
1311
1825
|
|
|
1312
|
-
// src/
|
|
1313
|
-
function
|
|
1826
|
+
// src/core/token-registry.ts
|
|
1827
|
+
function resolvePaymentToken(currency) {
|
|
1314
1828
|
const normalized = currency.trim().toUpperCase();
|
|
1315
1829
|
if (normalized === "USD" || normalized === "USDC") {
|
|
1316
|
-
return
|
|
1830
|
+
return {
|
|
1831
|
+
address: TEST_USDC_ADDRESS.toLowerCase(),
|
|
1832
|
+
decimals: 6,
|
|
1833
|
+
symbol: "USDC"
|
|
1834
|
+
};
|
|
1317
1835
|
}
|
|
1318
1836
|
throw new CapxulError({
|
|
1319
|
-
code: "
|
|
1320
|
-
message: `Currency ${currency} is not
|
|
1837
|
+
code: "NOT_IMPLEMENTED",
|
|
1838
|
+
message: `Currency ${currency} is not yet supported by the token registry.`,
|
|
1321
1839
|
details: { currency: normalized }
|
|
1322
1840
|
});
|
|
1323
1841
|
}
|
|
1324
|
-
async function buildSafeAccount(signer, chain) {
|
|
1325
|
-
try {
|
|
1326
|
-
const publicClient = createPublicClient({
|
|
1327
|
-
chain: baseSepolia,
|
|
1328
|
-
transport: http(chain.rpcUrl)
|
|
1329
|
-
});
|
|
1330
|
-
return await toSafeSmartAccount({
|
|
1331
|
-
client: publicClient,
|
|
1332
|
-
entryPoint: { address: entryPoint07Address, version: "0.7" },
|
|
1333
|
-
version: "1.4.1",
|
|
1334
|
-
owners: [signer],
|
|
1335
|
-
saltNonce: computeSaltNonce(signer.address),
|
|
1336
|
-
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
1337
|
-
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
1338
|
-
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
1339
|
-
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
1340
|
-
safeModules: [],
|
|
1341
|
-
setupTransactions: []
|
|
1342
|
-
});
|
|
1343
|
-
} catch (cause) {
|
|
1344
|
-
throw new CapxulError({
|
|
1345
|
-
code: "NETWORK_ERROR",
|
|
1346
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
1347
|
-
cause,
|
|
1348
|
-
details: { chainId: chain.chainId }
|
|
1349
|
-
});
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
function computeSaltNonce(ownerAddress) {
|
|
1353
|
-
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
1354
|
-
}
|
|
1355
1842
|
function createCapxulBundler(config) {
|
|
1356
1843
|
const paymaster = createPaymasterClient({
|
|
1357
1844
|
transport: http(config.rpcUrl)
|
|
@@ -1458,13 +1945,13 @@ async function transferAsOwner(config, params) {
|
|
|
1458
1945
|
function createPaymentsClient(config = {}) {
|
|
1459
1946
|
return {
|
|
1460
1947
|
create: async (input) => {
|
|
1461
|
-
if (!config.
|
|
1948
|
+
if (!config._data || !config.signer || !config.signing) {
|
|
1462
1949
|
return stub("payments.create");
|
|
1463
1950
|
}
|
|
1464
1951
|
let created = null;
|
|
1465
1952
|
let submitted = null;
|
|
1466
1953
|
try {
|
|
1467
|
-
created = await config.
|
|
1954
|
+
created = await config._data.mutation(api.payments.mutations.create, {
|
|
1468
1955
|
to: input.to,
|
|
1469
1956
|
amount: input.amount,
|
|
1470
1957
|
reference: input.reference,
|
|
@@ -1472,15 +1959,21 @@ function createPaymentsClient(config = {}) {
|
|
|
1472
1959
|
source: input.source
|
|
1473
1960
|
});
|
|
1474
1961
|
if (!created) {
|
|
1475
|
-
return [
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1962
|
+
return [
|
|
1963
|
+
new CapxulError({
|
|
1964
|
+
code: "NETWORK_ERROR",
|
|
1965
|
+
message: "payments.create returned no payment resource"
|
|
1966
|
+
}),
|
|
1967
|
+
null
|
|
1968
|
+
];
|
|
1479
1969
|
}
|
|
1480
1970
|
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1481
1971
|
return [null, created];
|
|
1482
1972
|
}
|
|
1483
|
-
const currentSigner = await config.
|
|
1973
|
+
const currentSigner = await config._data.query(
|
|
1974
|
+
api.safe.queries.getMySignerAddress,
|
|
1975
|
+
{}
|
|
1976
|
+
);
|
|
1484
1977
|
if (!currentSigner?.address) {
|
|
1485
1978
|
throw new CapxulError({
|
|
1486
1979
|
code: "PERMISSION_DENIED",
|
|
@@ -1499,9 +1992,12 @@ function createPaymentsClient(config = {}) {
|
|
|
1499
1992
|
}
|
|
1500
1993
|
});
|
|
1501
1994
|
}
|
|
1502
|
-
const submission = await config.
|
|
1503
|
-
|
|
1504
|
-
|
|
1995
|
+
const submission = await config._data.query(
|
|
1996
|
+
api.payments.queries.prepareSubmission,
|
|
1997
|
+
{
|
|
1998
|
+
paymentId: created.id
|
|
1999
|
+
}
|
|
2000
|
+
);
|
|
1505
2001
|
if (!submission?.recipientAddress) {
|
|
1506
2002
|
throw new CapxulError({
|
|
1507
2003
|
code: "NETWORK_ERROR",
|
|
@@ -1509,15 +2005,16 @@ function createPaymentsClient(config = {}) {
|
|
|
1509
2005
|
details: { paymentId: created.id }
|
|
1510
2006
|
});
|
|
1511
2007
|
}
|
|
2008
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1512
2009
|
const transfer = await transferAsOwner(
|
|
1513
2010
|
{
|
|
1514
2011
|
signer: config.signer,
|
|
1515
2012
|
signing: config.signing
|
|
1516
2013
|
},
|
|
1517
2014
|
{
|
|
1518
|
-
tokenAddress:
|
|
2015
|
+
tokenAddress: token.address,
|
|
1519
2016
|
recipientAddress: submission.recipientAddress,
|
|
1520
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2017
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1521
2018
|
}
|
|
1522
2019
|
);
|
|
1523
2020
|
if (!transfer.success) {
|
|
@@ -1535,7 +2032,7 @@ function createPaymentsClient(config = {}) {
|
|
|
1535
2032
|
txHash: transfer.txHash,
|
|
1536
2033
|
userOpHash: transfer.userOpHash
|
|
1537
2034
|
};
|
|
1538
|
-
await config.
|
|
2035
|
+
await config._data.mutation(api.payments.mutations.recordSubmitted, {
|
|
1539
2036
|
paymentId: created.id,
|
|
1540
2037
|
txHash: transfer.txHash,
|
|
1541
2038
|
userOpHash: transfer.userOpHash,
|
|
@@ -1545,43 +2042,65 @@ function createPaymentsClient(config = {}) {
|
|
|
1545
2042
|
} catch (cause) {
|
|
1546
2043
|
const error = mapCreateError(fromConvexError(cause));
|
|
1547
2044
|
if (created?.id && created.status === "processing" && !submitted) {
|
|
1548
|
-
await bestEffortMarkFailed({
|
|
2045
|
+
await bestEffortMarkFailed({ _data: config._data }, created.id, error);
|
|
1549
2046
|
}
|
|
1550
2047
|
if (submitted && created?.id) {
|
|
1551
|
-
return [
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
2048
|
+
return [
|
|
2049
|
+
new CapxulError({
|
|
2050
|
+
code: "NETWORK_ERROR",
|
|
2051
|
+
message: "Payment was submitted on-chain, but backend submission tracking failed.",
|
|
2052
|
+
cause,
|
|
2053
|
+
details: {
|
|
2054
|
+
paymentId: created.id,
|
|
2055
|
+
txHash: submitted.txHash,
|
|
2056
|
+
userOpHash: submitted.userOpHash
|
|
2057
|
+
}
|
|
2058
|
+
}),
|
|
2059
|
+
null
|
|
2060
|
+
];
|
|
1561
2061
|
}
|
|
1562
2062
|
return [error, null];
|
|
1563
2063
|
}
|
|
1564
2064
|
},
|
|
1565
2065
|
retrieve: async (paymentId) => {
|
|
1566
|
-
if (!config.
|
|
2066
|
+
if (!config._data) {
|
|
1567
2067
|
return stub("payments.retrieve");
|
|
1568
2068
|
}
|
|
1569
2069
|
try {
|
|
1570
|
-
const payment = await config.
|
|
1571
|
-
|
|
1572
|
-
|
|
2070
|
+
const payment = await config._data.query(
|
|
2071
|
+
api.payments.queries.retrieve,
|
|
2072
|
+
{
|
|
2073
|
+
paymentId
|
|
2074
|
+
}
|
|
2075
|
+
);
|
|
1573
2076
|
if (!payment) {
|
|
1574
|
-
return [
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
2077
|
+
return [
|
|
2078
|
+
new CapxulError({
|
|
2079
|
+
code: "NOT_FOUND",
|
|
2080
|
+
message: `payment ${paymentId} not found`
|
|
2081
|
+
}),
|
|
2082
|
+
null
|
|
2083
|
+
];
|
|
1578
2084
|
}
|
|
1579
2085
|
return [null, payment];
|
|
1580
2086
|
} catch (cause) {
|
|
1581
2087
|
return [fromConvexError(cause), null];
|
|
1582
2088
|
}
|
|
1583
2089
|
},
|
|
1584
|
-
list: async () =>
|
|
2090
|
+
list: async (input) => {
|
|
2091
|
+
if (!config._data) {
|
|
2092
|
+
return stub("payments.list");
|
|
2093
|
+
}
|
|
2094
|
+
try {
|
|
2095
|
+
const page = await config._data.query(api.payments.queries.list, {
|
|
2096
|
+
limit: input?.limit,
|
|
2097
|
+
cursor: input?.cursor
|
|
2098
|
+
});
|
|
2099
|
+
return [null, page];
|
|
2100
|
+
} catch (cause) {
|
|
2101
|
+
return [fromConvexError(cause), null];
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
1585
2104
|
};
|
|
1586
2105
|
}
|
|
1587
2106
|
function createOrgPaymentsClient() {
|
|
@@ -1595,7 +2114,7 @@ function createOrgPaymentsClient() {
|
|
|
1595
2114
|
}
|
|
1596
2115
|
async function bestEffortMarkFailed(config, paymentId, error) {
|
|
1597
2116
|
try {
|
|
1598
|
-
await config.
|
|
2117
|
+
await config._data.mutation(api.payments.mutations.markFailed, {
|
|
1599
2118
|
paymentId,
|
|
1600
2119
|
errorCode: error.code,
|
|
1601
2120
|
errorMessage: error.message,
|
|
@@ -1652,11 +2171,11 @@ function createOrgTransfersClient() {
|
|
|
1652
2171
|
function createWithdrawalsClient(config = {}) {
|
|
1653
2172
|
return {
|
|
1654
2173
|
create: async (input) => {
|
|
1655
|
-
if (!config.
|
|
2174
|
+
if (!config._data) {
|
|
1656
2175
|
return stub("withdrawals.create");
|
|
1657
2176
|
}
|
|
1658
2177
|
const [createErr, createdRaw] = await tryCatch(
|
|
1659
|
-
config.
|
|
2178
|
+
config._data.mutation(api.withdrawals.mutations.create, {
|
|
1660
2179
|
amount: input.amount,
|
|
1661
2180
|
destination: {
|
|
1662
2181
|
externalAccountId: input.destination.externalAccountId
|
|
@@ -1686,18 +2205,18 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1686
2205
|
return [null, created];
|
|
1687
2206
|
}
|
|
1688
2207
|
const [signerErr, currentSigner] = await tryCatch(
|
|
1689
|
-
config.
|
|
2208
|
+
config._data.query(api.safe.queries.getMySignerAddress, {})
|
|
1690
2209
|
);
|
|
1691
2210
|
if (signerErr) {
|
|
1692
2211
|
return await handleSubmissionFailure(
|
|
1693
|
-
{
|
|
2212
|
+
{ _data: config._data },
|
|
1694
2213
|
created.id,
|
|
1695
2214
|
mapCreateError2(fromConvexError(signerErr))
|
|
1696
2215
|
);
|
|
1697
2216
|
}
|
|
1698
2217
|
if (!currentSigner?.address) {
|
|
1699
2218
|
return await handleSubmissionFailure(
|
|
1700
|
-
{
|
|
2219
|
+
{ _data: config._data },
|
|
1701
2220
|
created.id,
|
|
1702
2221
|
new CapxulError({
|
|
1703
2222
|
code: "PERMISSION_DENIED",
|
|
@@ -1708,7 +2227,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1708
2227
|
}
|
|
1709
2228
|
if (getAddress(currentSigner.address) !== getAddress(config.signer.address)) {
|
|
1710
2229
|
return await handleSubmissionFailure(
|
|
1711
|
-
{
|
|
2230
|
+
{ _data: config._data },
|
|
1712
2231
|
created.id,
|
|
1713
2232
|
new CapxulError({
|
|
1714
2233
|
code: "PERMISSION_DENIED",
|
|
@@ -1722,13 +2241,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1722
2241
|
);
|
|
1723
2242
|
}
|
|
1724
2243
|
const [prepErr, submission] = await tryCatch(
|
|
1725
|
-
config.
|
|
2244
|
+
config._data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1726
2245
|
withdrawalId: created.id
|
|
1727
2246
|
})
|
|
1728
2247
|
);
|
|
1729
2248
|
if (prepErr) {
|
|
1730
2249
|
return await handleSubmissionFailure(
|
|
1731
|
-
{
|
|
2250
|
+
{ _data: config._data },
|
|
1732
2251
|
created.id,
|
|
1733
2252
|
mapCreateError2(fromConvexError(prepErr))
|
|
1734
2253
|
);
|
|
@@ -1736,7 +2255,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1736
2255
|
const destinationAddress = submission?.destinationAddress;
|
|
1737
2256
|
if (!submission || !destinationAddress) {
|
|
1738
2257
|
return await handleSubmissionFailure(
|
|
1739
|
-
{
|
|
2258
|
+
{ _data: config._data },
|
|
1740
2259
|
created.id,
|
|
1741
2260
|
new CapxulError({
|
|
1742
2261
|
code: "NETWORK_ERROR",
|
|
@@ -1745,6 +2264,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1745
2264
|
})
|
|
1746
2265
|
);
|
|
1747
2266
|
}
|
|
2267
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1748
2268
|
const [transferErr, transferOk] = await tryCatch(
|
|
1749
2269
|
transferAsOwner(
|
|
1750
2270
|
{
|
|
@@ -1752,22 +2272,22 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1752
2272
|
signing: config.signing
|
|
1753
2273
|
},
|
|
1754
2274
|
{
|
|
1755
|
-
tokenAddress:
|
|
2275
|
+
tokenAddress: token.address,
|
|
1756
2276
|
recipientAddress: destinationAddress,
|
|
1757
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2277
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1758
2278
|
}
|
|
1759
2279
|
)
|
|
1760
2280
|
);
|
|
1761
2281
|
if (transferErr) {
|
|
1762
2282
|
return await handleSubmissionFailure(
|
|
1763
|
-
{
|
|
2283
|
+
{ _data: config._data },
|
|
1764
2284
|
created.id,
|
|
1765
2285
|
mapCreateError2(fromConvexError(transferErr))
|
|
1766
2286
|
);
|
|
1767
2287
|
}
|
|
1768
2288
|
if (!transferOk.success) {
|
|
1769
2289
|
return await handleSubmissionFailure(
|
|
1770
|
-
{
|
|
2290
|
+
{ _data: config._data },
|
|
1771
2291
|
created.id,
|
|
1772
2292
|
new CapxulError({
|
|
1773
2293
|
code: "NETWORK_ERROR",
|
|
@@ -1781,7 +2301,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1781
2301
|
);
|
|
1782
2302
|
}
|
|
1783
2303
|
const [recordErr] = await tryCatch(
|
|
1784
|
-
config.
|
|
2304
|
+
config._data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1785
2305
|
withdrawalId: created.id,
|
|
1786
2306
|
txHash: transferOk.txHash,
|
|
1787
2307
|
userOpHash: transferOk.userOpHash
|
|
@@ -1805,11 +2325,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1805
2325
|
return [null, created];
|
|
1806
2326
|
},
|
|
1807
2327
|
retrieve: async (withdrawalId) => {
|
|
1808
|
-
if (!config.
|
|
2328
|
+
if (!config._data) {
|
|
1809
2329
|
return stub("withdrawals.retrieve");
|
|
1810
2330
|
}
|
|
1811
2331
|
const [err, raw] = await tryCatch(
|
|
1812
|
-
config.
|
|
2332
|
+
config._data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1813
2333
|
);
|
|
1814
2334
|
if (err) {
|
|
1815
2335
|
return [fromConvexError(err), null];
|
|
@@ -1827,11 +2347,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1827
2347
|
return [null, withdrawal];
|
|
1828
2348
|
},
|
|
1829
2349
|
list: async (input) => {
|
|
1830
|
-
if (!config.
|
|
2350
|
+
if (!config._data) {
|
|
1831
2351
|
return stub("withdrawals.list");
|
|
1832
2352
|
}
|
|
1833
2353
|
const [err, raw] = await tryCatch(
|
|
1834
|
-
config.
|
|
2354
|
+
config._data.query(api.withdrawals.queries.list, {
|
|
1835
2355
|
limit: input?.limit,
|
|
1836
2356
|
cursor: input?.cursor
|
|
1837
2357
|
})
|
|
@@ -1842,13 +2362,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1842
2362
|
return [null, raw];
|
|
1843
2363
|
},
|
|
1844
2364
|
recordCompleted: async (input) => {
|
|
1845
|
-
if (!config.
|
|
2365
|
+
if (!config._data) {
|
|
1846
2366
|
return stub(
|
|
1847
2367
|
"withdrawals.recordCompleted"
|
|
1848
2368
|
);
|
|
1849
2369
|
}
|
|
1850
2370
|
const [err] = await tryCatch(
|
|
1851
|
-
config.
|
|
2371
|
+
config._data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
1852
2372
|
withdrawalId: input.withdrawalId,
|
|
1853
2373
|
txHash: input.txHash
|
|
1854
2374
|
})
|
|
@@ -1873,13 +2393,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1873
2393
|
* orchestration ships in W3+.
|
|
1874
2394
|
*/
|
|
1875
2395
|
create: async (input) => {
|
|
1876
|
-
if (!config.
|
|
2396
|
+
if (!config._data) {
|
|
1877
2397
|
return stub(
|
|
1878
2398
|
"organizations.withdrawals.create"
|
|
1879
2399
|
);
|
|
1880
2400
|
}
|
|
1881
2401
|
const [err, raw] = await tryCatch(
|
|
1882
|
-
config.
|
|
2402
|
+
config._data.mutation(api.withdrawals.mutations.createOrg, {
|
|
1883
2403
|
organizationId: input.organizationId,
|
|
1884
2404
|
amount: input.amount,
|
|
1885
2405
|
destination: {
|
|
@@ -1906,13 +2426,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1906
2426
|
return [null, created];
|
|
1907
2427
|
},
|
|
1908
2428
|
retrieve: async (input) => {
|
|
1909
|
-
if (!config.
|
|
2429
|
+
if (!config._data) {
|
|
1910
2430
|
return stub(
|
|
1911
2431
|
"organizations.withdrawals.retrieve"
|
|
1912
2432
|
);
|
|
1913
2433
|
}
|
|
1914
2434
|
const [err, raw] = await tryCatch(
|
|
1915
|
-
config.
|
|
2435
|
+
config._data.query(api.withdrawals.queries.retrieve, {
|
|
1916
2436
|
withdrawalId: input.withdrawalId
|
|
1917
2437
|
})
|
|
1918
2438
|
);
|
|
@@ -1942,13 +2462,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1942
2462
|
return [null, withdrawal];
|
|
1943
2463
|
},
|
|
1944
2464
|
list: async (input) => {
|
|
1945
|
-
if (!config.
|
|
2465
|
+
if (!config._data) {
|
|
1946
2466
|
return stub(
|
|
1947
2467
|
"organizations.withdrawals.list"
|
|
1948
2468
|
);
|
|
1949
2469
|
}
|
|
1950
2470
|
const [err, raw] = await tryCatch(
|
|
1951
|
-
config.
|
|
2471
|
+
config._data.query(api.withdrawals.queries.listOrg, {
|
|
1952
2472
|
organizationId: input.organizationId,
|
|
1953
2473
|
limit: input.limit,
|
|
1954
2474
|
cursor: input.cursor
|
|
@@ -1967,7 +2487,7 @@ async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
|
1967
2487
|
}
|
|
1968
2488
|
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
1969
2489
|
await tryCatch(
|
|
1970
|
-
config.
|
|
2490
|
+
config._data.mutation(api.withdrawals.mutations.markFailed, {
|
|
1971
2491
|
withdrawalId,
|
|
1972
2492
|
errorCode: error.code,
|
|
1973
2493
|
errorMessage: error.message
|
|
@@ -2046,13 +2566,13 @@ function createWebhookEventsClient() {
|
|
|
2046
2566
|
function createOrgExternalAccountsClient(config) {
|
|
2047
2567
|
return {
|
|
2048
2568
|
create: async (input) => {
|
|
2049
|
-
if (!config.
|
|
2569
|
+
if (!config._data) {
|
|
2050
2570
|
return stub(
|
|
2051
2571
|
"organizations.externalAccounts.create"
|
|
2052
2572
|
);
|
|
2053
2573
|
}
|
|
2054
2574
|
const [err, raw] = await tryCatch(
|
|
2055
|
-
config.
|
|
2575
|
+
config._data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
2056
2576
|
organizationId: input.organizationId,
|
|
2057
2577
|
kind: input.kind,
|
|
2058
2578
|
label: input.label,
|
|
@@ -2066,10 +2586,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2066
2586
|
})
|
|
2067
2587
|
);
|
|
2068
2588
|
if (err) {
|
|
2069
|
-
return [
|
|
2070
|
-
fromConvexError(err),
|
|
2071
|
-
null
|
|
2072
|
-
];
|
|
2589
|
+
return [fromConvexError(err), null];
|
|
2073
2590
|
}
|
|
2074
2591
|
if (!raw) {
|
|
2075
2592
|
return [
|
|
@@ -2080,21 +2597,16 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2080
2597
|
null
|
|
2081
2598
|
];
|
|
2082
2599
|
}
|
|
2083
|
-
return [
|
|
2084
|
-
null,
|
|
2085
|
-
brandExternalAccount(
|
|
2086
|
-
raw
|
|
2087
|
-
)
|
|
2088
|
-
];
|
|
2600
|
+
return [null, brandExternalAccount(raw)];
|
|
2089
2601
|
},
|
|
2090
2602
|
list: async (input) => {
|
|
2091
|
-
if (!config.
|
|
2603
|
+
if (!config._data) {
|
|
2092
2604
|
return stub(
|
|
2093
2605
|
"organizations.externalAccounts.list"
|
|
2094
2606
|
);
|
|
2095
2607
|
}
|
|
2096
2608
|
const [err, result] = await tryCatch(
|
|
2097
|
-
config.
|
|
2609
|
+
config._data.query(api.externalAccounts.queries.listOrg, {
|
|
2098
2610
|
organizationId: input.organizationId,
|
|
2099
2611
|
limit: input.limit,
|
|
2100
2612
|
cursor: input.cursor
|
|
@@ -2104,9 +2616,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2104
2616
|
return [fromConvexError(err), null];
|
|
2105
2617
|
}
|
|
2106
2618
|
const branded = result.data.map(
|
|
2107
|
-
(row) => brandExternalAccount(
|
|
2108
|
-
row
|
|
2109
|
-
)
|
|
2619
|
+
(row) => brandExternalAccount(row)
|
|
2110
2620
|
);
|
|
2111
2621
|
return [
|
|
2112
2622
|
null,
|
|
@@ -2118,17 +2628,66 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2118
2628
|
];
|
|
2119
2629
|
},
|
|
2120
2630
|
retrieve: async (input) => {
|
|
2121
|
-
if (!config.
|
|
2631
|
+
if (!config._data) {
|
|
2122
2632
|
return stub(
|
|
2123
2633
|
"organizations.externalAccounts.retrieve"
|
|
2124
2634
|
);
|
|
2125
2635
|
}
|
|
2126
2636
|
const [err, raw] = await tryCatch(
|
|
2127
|
-
config.
|
|
2637
|
+
config._data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
2638
|
+
organizationId: input.organizationId,
|
|
2639
|
+
externalAccountId: input.externalAccountId
|
|
2640
|
+
})
|
|
2641
|
+
);
|
|
2642
|
+
if (err) {
|
|
2643
|
+
return [fromConvexError(err), null];
|
|
2644
|
+
}
|
|
2645
|
+
if (!raw) {
|
|
2646
|
+
return [
|
|
2647
|
+
new CapxulError({
|
|
2648
|
+
code: "NOT_FOUND",
|
|
2649
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
2650
|
+
}),
|
|
2651
|
+
null
|
|
2652
|
+
];
|
|
2653
|
+
}
|
|
2654
|
+
return [null, brandExternalAccount(raw)];
|
|
2655
|
+
},
|
|
2656
|
+
remove: async (input) => {
|
|
2657
|
+
if (!config._data) {
|
|
2658
|
+
return stub("organizations.externalAccounts.remove");
|
|
2659
|
+
}
|
|
2660
|
+
const [err] = await tryCatch(
|
|
2661
|
+
config._data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
2128
2662
|
organizationId: input.organizationId,
|
|
2129
2663
|
externalAccountId: input.externalAccountId
|
|
2130
2664
|
})
|
|
2131
2665
|
);
|
|
2666
|
+
if (err) {
|
|
2667
|
+
return [fromConvexError(err), null];
|
|
2668
|
+
}
|
|
2669
|
+
return [null, void 0];
|
|
2670
|
+
}
|
|
2671
|
+
};
|
|
2672
|
+
}
|
|
2673
|
+
function createOrgSubAccountsClient(config) {
|
|
2674
|
+
return {
|
|
2675
|
+
create: async (input) => {
|
|
2676
|
+
if (!config._data) {
|
|
2677
|
+
return stub(
|
|
2678
|
+
"organizations.subAccounts.create"
|
|
2679
|
+
);
|
|
2680
|
+
}
|
|
2681
|
+
const [err, raw] = await tryCatch(
|
|
2682
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
2683
|
+
parent: {
|
|
2684
|
+
kind: "organization",
|
|
2685
|
+
id: input.organizationId
|
|
2686
|
+
},
|
|
2687
|
+
name: input.name,
|
|
2688
|
+
purpose: input.purpose
|
|
2689
|
+
})
|
|
2690
|
+
);
|
|
2132
2691
|
if (err) {
|
|
2133
2692
|
return [
|
|
2134
2693
|
fromConvexError(err),
|
|
@@ -2139,28 +2698,95 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2139
2698
|
return [
|
|
2140
2699
|
new CapxulError({
|
|
2141
2700
|
code: "NOT_FOUND",
|
|
2142
|
-
message:
|
|
2701
|
+
message: "sub_account creation returned no resource"
|
|
2143
2702
|
}),
|
|
2144
2703
|
null
|
|
2145
2704
|
];
|
|
2146
2705
|
}
|
|
2706
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
2707
|
+
if (brandErr) {
|
|
2708
|
+
return [brandErr, null];
|
|
2709
|
+
}
|
|
2710
|
+
return [null, branded];
|
|
2711
|
+
},
|
|
2712
|
+
list: async (input) => {
|
|
2713
|
+
if (!config._data) {
|
|
2714
|
+
return stub(
|
|
2715
|
+
"organizations.subAccounts.list"
|
|
2716
|
+
);
|
|
2717
|
+
}
|
|
2718
|
+
const [err, rows] = await tryCatch(
|
|
2719
|
+
config._data.query(api.subAccounts.queries.listByOrganization, {
|
|
2720
|
+
organizationId: input.organizationId
|
|
2721
|
+
})
|
|
2722
|
+
);
|
|
2723
|
+
if (err) {
|
|
2724
|
+
return [
|
|
2725
|
+
fromConvexError(err),
|
|
2726
|
+
null
|
|
2727
|
+
];
|
|
2728
|
+
}
|
|
2729
|
+
const branded = [];
|
|
2730
|
+
for (const row of rows) {
|
|
2731
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
2732
|
+
if (brandErr) {
|
|
2733
|
+
return [brandErr, null];
|
|
2734
|
+
}
|
|
2735
|
+
branded.push(value);
|
|
2736
|
+
}
|
|
2147
2737
|
return [
|
|
2148
2738
|
null,
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2739
|
+
{
|
|
2740
|
+
object: "list",
|
|
2741
|
+
data: branded,
|
|
2742
|
+
page: { hasMore: false }
|
|
2743
|
+
}
|
|
2152
2744
|
];
|
|
2153
2745
|
},
|
|
2746
|
+
retrieve: async (input) => {
|
|
2747
|
+
if (!config._data) {
|
|
2748
|
+
return stub(
|
|
2749
|
+
"organizations.subAccounts.retrieve"
|
|
2750
|
+
);
|
|
2751
|
+
}
|
|
2752
|
+
const [err, raw] = await tryCatch(
|
|
2753
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
2754
|
+
subAccountId: input.subAccountId
|
|
2755
|
+
})
|
|
2756
|
+
);
|
|
2757
|
+
if (err) {
|
|
2758
|
+
return [
|
|
2759
|
+
fromConvexError(err),
|
|
2760
|
+
null
|
|
2761
|
+
];
|
|
2762
|
+
}
|
|
2763
|
+
if (!raw) {
|
|
2764
|
+
return [
|
|
2765
|
+
new CapxulError({
|
|
2766
|
+
code: "NOT_FOUND",
|
|
2767
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
2768
|
+
}),
|
|
2769
|
+
null
|
|
2770
|
+
];
|
|
2771
|
+
}
|
|
2772
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
2773
|
+
if (brandErr) {
|
|
2774
|
+
return [
|
|
2775
|
+
brandErr,
|
|
2776
|
+
null
|
|
2777
|
+
];
|
|
2778
|
+
}
|
|
2779
|
+
return [null, branded];
|
|
2780
|
+
},
|
|
2154
2781
|
remove: async (input) => {
|
|
2155
|
-
if (!config.
|
|
2782
|
+
if (!config._data) {
|
|
2156
2783
|
return stub(
|
|
2157
|
-
"organizations.
|
|
2784
|
+
"organizations.subAccounts.remove"
|
|
2158
2785
|
);
|
|
2159
2786
|
}
|
|
2160
|
-
const [err] = await tryCatch(
|
|
2161
|
-
config.
|
|
2162
|
-
|
|
2163
|
-
externalAccountId: input.externalAccountId
|
|
2787
|
+
const [err, raw] = await tryCatch(
|
|
2788
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
2789
|
+
subAccountId: input.subAccountId
|
|
2164
2790
|
})
|
|
2165
2791
|
);
|
|
2166
2792
|
if (err) {
|
|
@@ -2169,74 +2795,399 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2169
2795
|
null
|
|
2170
2796
|
];
|
|
2171
2797
|
}
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2798
|
+
if (!raw) {
|
|
2799
|
+
return [
|
|
2800
|
+
new CapxulError({
|
|
2801
|
+
code: "NOT_FOUND",
|
|
2802
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
2803
|
+
}),
|
|
2804
|
+
null
|
|
2805
|
+
];
|
|
2806
|
+
}
|
|
2807
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
2808
|
+
if (brandErr) {
|
|
2809
|
+
return [
|
|
2810
|
+
brandErr,
|
|
2811
|
+
null
|
|
2812
|
+
];
|
|
2813
|
+
}
|
|
2814
|
+
return [null, branded];
|
|
2815
|
+
}
|
|
2816
|
+
};
|
|
2817
|
+
}
|
|
2818
|
+
function createOrganizationsClient(config = {}) {
|
|
2819
|
+
return {
|
|
2820
|
+
create: async (input) => {
|
|
2821
|
+
if (!config._data) {
|
|
2822
|
+
return stub("organizations.create");
|
|
2823
|
+
}
|
|
2824
|
+
if (input.country !== void 0) {
|
|
2825
|
+
return [
|
|
2826
|
+
new CapxulError({
|
|
2827
|
+
code: "INVALID_INPUT",
|
|
2828
|
+
message: "organizations.create does not support country yet \u2014 backend mutation only accepts name.",
|
|
2829
|
+
details: { field: "country" }
|
|
2830
|
+
}),
|
|
2831
|
+
null
|
|
2832
|
+
];
|
|
2833
|
+
}
|
|
2834
|
+
try {
|
|
2835
|
+
const orgId = await config._data.mutation(api.org.mutations.create, {
|
|
2836
|
+
name: input.name
|
|
2837
|
+
});
|
|
2838
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
2839
|
+
orgId
|
|
2840
|
+
});
|
|
2841
|
+
if (!org) {
|
|
2842
|
+
return [
|
|
2843
|
+
new CapxulError({
|
|
2844
|
+
code: "NETWORK_ERROR",
|
|
2845
|
+
message: "organization created but could not be retrieved"
|
|
2846
|
+
}),
|
|
2847
|
+
null
|
|
2848
|
+
];
|
|
2849
|
+
}
|
|
2850
|
+
return [null, org];
|
|
2851
|
+
} catch (cause) {
|
|
2852
|
+
return [fromConvexError(cause), null];
|
|
2853
|
+
}
|
|
2854
|
+
},
|
|
2855
|
+
retrieve: async (organizationId) => {
|
|
2856
|
+
if (!config._data) {
|
|
2857
|
+
return stub("organizations.retrieve");
|
|
2858
|
+
}
|
|
2859
|
+
try {
|
|
2860
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
2861
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
2862
|
+
orgId
|
|
2863
|
+
});
|
|
2864
|
+
if (!org) {
|
|
2865
|
+
return [
|
|
2866
|
+
new CapxulError({
|
|
2867
|
+
code: "NOT_FOUND",
|
|
2868
|
+
message: `organization ${organizationId} not found`
|
|
2869
|
+
}),
|
|
2870
|
+
null
|
|
2871
|
+
];
|
|
2872
|
+
}
|
|
2873
|
+
return [null, org];
|
|
2874
|
+
} catch (cause) {
|
|
2875
|
+
return [fromConvexError(cause), null];
|
|
2876
|
+
}
|
|
2877
|
+
},
|
|
2878
|
+
list: async (input) => {
|
|
2879
|
+
if (!config._data) {
|
|
2880
|
+
return stub("organizations.list");
|
|
2881
|
+
}
|
|
2882
|
+
try {
|
|
2883
|
+
const page = await config._data.query(api.org.queries.list, {
|
|
2884
|
+
limit: input?.limit,
|
|
2885
|
+
cursor: input?.cursor
|
|
2886
|
+
});
|
|
2887
|
+
const result = {
|
|
2888
|
+
object: "list",
|
|
2889
|
+
data: page.data,
|
|
2890
|
+
page: {
|
|
2891
|
+
hasMore: page.hasMore,
|
|
2892
|
+
cursor: page.nextCursor
|
|
2893
|
+
}
|
|
2894
|
+
};
|
|
2895
|
+
return [null, result];
|
|
2896
|
+
} catch (cause) {
|
|
2897
|
+
return [fromConvexError(cause), null];
|
|
2898
|
+
}
|
|
2899
|
+
},
|
|
2900
|
+
update: async (input) => {
|
|
2901
|
+
if (!config._data) {
|
|
2902
|
+
return stub("organizations.update");
|
|
2903
|
+
}
|
|
2904
|
+
try {
|
|
2905
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
2906
|
+
const org = await config._data.mutation(api.org.mutations.update, {
|
|
2907
|
+
orgId,
|
|
2908
|
+
name: input.name
|
|
2909
|
+
});
|
|
2910
|
+
if (!org) {
|
|
2911
|
+
return [
|
|
2912
|
+
new CapxulError({
|
|
2913
|
+
code: "NOT_FOUND",
|
|
2914
|
+
message: `organization ${input.organizationId} not found`
|
|
2915
|
+
}),
|
|
2916
|
+
null
|
|
2917
|
+
];
|
|
2918
|
+
}
|
|
2919
|
+
return [null, org];
|
|
2920
|
+
} catch (cause) {
|
|
2921
|
+
return [fromConvexError(cause), null];
|
|
2922
|
+
}
|
|
2923
|
+
},
|
|
2924
|
+
safes: {
|
|
2925
|
+
retrieve: async (input) => {
|
|
2926
|
+
if (!config._data) {
|
|
2927
|
+
return stub("organizations.safes.retrieve");
|
|
2928
|
+
}
|
|
2929
|
+
try {
|
|
2930
|
+
const safe = await config._data.query(
|
|
2931
|
+
api.safe.queries.retrieveOrganizationSafe,
|
|
2932
|
+
input
|
|
2933
|
+
);
|
|
2934
|
+
if (!safe) {
|
|
2935
|
+
return [
|
|
2936
|
+
new CapxulError({
|
|
2937
|
+
code: "NOT_FOUND",
|
|
2938
|
+
message: `safe ${input.safeId} not found`
|
|
2939
|
+
}),
|
|
2940
|
+
null
|
|
2941
|
+
];
|
|
2942
|
+
}
|
|
2943
|
+
return [null, safe];
|
|
2944
|
+
} catch (cause) {
|
|
2945
|
+
return [
|
|
2946
|
+
fromConvexError(cause),
|
|
2947
|
+
null
|
|
2948
|
+
];
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
},
|
|
2952
|
+
treasury: {
|
|
2953
|
+
retrieve: async (organizationId) => {
|
|
2954
|
+
if (!config._data) {
|
|
2955
|
+
return stub(
|
|
2956
|
+
"organizations.treasury.retrieve"
|
|
2957
|
+
);
|
|
2958
|
+
}
|
|
2959
|
+
try {
|
|
2960
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
2961
|
+
const raw = await config._data.query(
|
|
2962
|
+
api.safe.queries.getOrgTreasuryBalance,
|
|
2963
|
+
{ orgId }
|
|
2964
|
+
);
|
|
2965
|
+
if (!raw) {
|
|
2966
|
+
return [
|
|
2967
|
+
new CapxulError({
|
|
2968
|
+
code: "NOT_FOUND",
|
|
2969
|
+
message: `treasury for organization ${organizationId} not found`
|
|
2970
|
+
}),
|
|
2971
|
+
null
|
|
2972
|
+
];
|
|
2973
|
+
}
|
|
2974
|
+
const treasury = {
|
|
2975
|
+
object: "treasury",
|
|
2976
|
+
id: toTreasuryId(`try_${orgId}`),
|
|
2977
|
+
organizationId,
|
|
2978
|
+
status: "active",
|
|
2979
|
+
safeId: toSafeId(
|
|
2980
|
+
`safe_${raw.safeAddress.replace(/^0x/, "").toLowerCase()}`
|
|
2981
|
+
),
|
|
2982
|
+
totalBalance: { value: "0", currency: "USD" },
|
|
2983
|
+
positions: raw.tokens.map((t) => ({
|
|
2984
|
+
symbol: t.symbol,
|
|
2985
|
+
contractAddress: t.tokenAddress,
|
|
2986
|
+
amount: t.balance
|
|
2987
|
+
})),
|
|
2988
|
+
asOf: raw.lastUpdatedAt ? new Date(raw.lastUpdatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
2989
|
+
};
|
|
2990
|
+
return [null, treasury];
|
|
2991
|
+
} catch (cause) {
|
|
2992
|
+
return [
|
|
2993
|
+
fromConvexError(cause),
|
|
2994
|
+
null
|
|
2995
|
+
];
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
members: {
|
|
3000
|
+
list: async (input) => {
|
|
3001
|
+
if (!config._data?.action) {
|
|
3002
|
+
return stub("organizations.members.list");
|
|
3003
|
+
}
|
|
3004
|
+
try {
|
|
3005
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3006
|
+
const page = await config._data.action(api.org.actions.membersList, {
|
|
3007
|
+
organizationId: orgId,
|
|
3008
|
+
status: input.status,
|
|
3009
|
+
limit: input.limit,
|
|
3010
|
+
cursor: input.cursor
|
|
3011
|
+
});
|
|
3012
|
+
return [null, page];
|
|
3013
|
+
} catch (cause) {
|
|
3014
|
+
return [fromConvexError(cause), null];
|
|
3015
|
+
}
|
|
3016
|
+
},
|
|
3017
|
+
retrieve: async (input) => {
|
|
3018
|
+
if (!config._data?.action) {
|
|
3019
|
+
return stub("organizations.members.retrieve");
|
|
3020
|
+
}
|
|
3021
|
+
try {
|
|
3022
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3023
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3024
|
+
const member = await config._data.action(
|
|
3025
|
+
api.org.actions.retrieveMember,
|
|
3026
|
+
{
|
|
3027
|
+
organizationId: orgId,
|
|
3028
|
+
memberId
|
|
3029
|
+
}
|
|
3030
|
+
);
|
|
3031
|
+
return [null, member];
|
|
3032
|
+
} catch (cause) {
|
|
3033
|
+
return [fromConvexError(cause), null];
|
|
3034
|
+
}
|
|
3035
|
+
},
|
|
3036
|
+
invite: async (input) => {
|
|
3037
|
+
if (!config._data?.action) {
|
|
3038
|
+
return stub("organizations.members.invite");
|
|
3039
|
+
}
|
|
3040
|
+
try {
|
|
3041
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3042
|
+
const result = await config._data.action(
|
|
3043
|
+
api.org.actions.inviteMember,
|
|
3044
|
+
{
|
|
3045
|
+
organizationId: orgId,
|
|
3046
|
+
email: input.email,
|
|
3047
|
+
role: input.role
|
|
3048
|
+
}
|
|
3049
|
+
);
|
|
3050
|
+
return [null, result];
|
|
3051
|
+
} catch (cause) {
|
|
3052
|
+
return [fromConvexError(cause), null];
|
|
3053
|
+
}
|
|
3054
|
+
},
|
|
3055
|
+
accept: async (input) => {
|
|
3056
|
+
if (!config._data?.action) {
|
|
3057
|
+
return stub("organizations.members.accept");
|
|
3058
|
+
}
|
|
3059
|
+
try {
|
|
3060
|
+
const member = await config._data.action(
|
|
3061
|
+
api.org.actions.acceptInvitation,
|
|
3062
|
+
{ token: input.token }
|
|
3063
|
+
);
|
|
3064
|
+
return [null, member];
|
|
3065
|
+
} catch (cause) {
|
|
3066
|
+
return [fromConvexError(cause), null];
|
|
3067
|
+
}
|
|
3068
|
+
},
|
|
3069
|
+
updateRole: async (input) => {
|
|
3070
|
+
if (!config._data?.action) {
|
|
3071
|
+
return stub("organizations.members.updateRole");
|
|
3072
|
+
}
|
|
3073
|
+
try {
|
|
3074
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3075
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3076
|
+
const member = await config._data.action(
|
|
3077
|
+
api.org.actions.updateMemberRole,
|
|
3078
|
+
{
|
|
3079
|
+
organizationId: orgId,
|
|
3080
|
+
memberId,
|
|
3081
|
+
role: input.role
|
|
3082
|
+
}
|
|
3083
|
+
);
|
|
3084
|
+
return [null, member];
|
|
3085
|
+
} catch (cause) {
|
|
3086
|
+
return [fromConvexError(cause), null];
|
|
3087
|
+
}
|
|
3088
|
+
},
|
|
3089
|
+
revoke: async (input) => {
|
|
3090
|
+
if (!config._data?.action) {
|
|
3091
|
+
return stub("organizations.members.revoke");
|
|
3092
|
+
}
|
|
3093
|
+
try {
|
|
3094
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3095
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3096
|
+
const member = await config._data.action(
|
|
3097
|
+
api.org.actions.revokeMember,
|
|
3098
|
+
{
|
|
3099
|
+
organizationId: orgId,
|
|
3100
|
+
memberId
|
|
3101
|
+
}
|
|
3102
|
+
);
|
|
3103
|
+
return [null, member];
|
|
3104
|
+
} catch (cause) {
|
|
3105
|
+
return [fromConvexError(cause), null];
|
|
3106
|
+
}
|
|
3107
|
+
},
|
|
3108
|
+
remove: async (input) => {
|
|
3109
|
+
if (!config._data?.action) {
|
|
3110
|
+
return stub("organizations.members.remove");
|
|
3111
|
+
}
|
|
3112
|
+
try {
|
|
3113
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3114
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3115
|
+
await config._data.action(api.org.actions.removeMember, {
|
|
3116
|
+
organizationId: orgId,
|
|
3117
|
+
memberId
|
|
3118
|
+
});
|
|
3119
|
+
return [null, void 0];
|
|
3120
|
+
} catch (cause) {
|
|
3121
|
+
return [fromConvexError(cause), null];
|
|
3122
|
+
}
|
|
3123
|
+
},
|
|
3124
|
+
resend: async (input) => {
|
|
3125
|
+
if (!config._data?.action) {
|
|
3126
|
+
return stub("organizations.members.resend");
|
|
3127
|
+
}
|
|
3128
|
+
try {
|
|
3129
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3130
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3131
|
+
const result = await config._data.action(
|
|
3132
|
+
api.org.actions.resendInvitation,
|
|
3133
|
+
{
|
|
3134
|
+
organizationId: orgId,
|
|
3135
|
+
memberId
|
|
3136
|
+
}
|
|
3137
|
+
);
|
|
3138
|
+
return [null, result];
|
|
3139
|
+
} catch (cause) {
|
|
3140
|
+
return [fromConvexError(cause), null];
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
},
|
|
3144
|
+
apiKeys: createApiKeysClient(),
|
|
3145
|
+
subAccounts: createOrgSubAccountsClient(config),
|
|
3146
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
3147
|
+
balanceLedger: {
|
|
3148
|
+
list: async (input) => {
|
|
3149
|
+
if (!config._data) {
|
|
3150
|
+
return stub(
|
|
3151
|
+
"organizations.balanceLedger.list"
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
try {
|
|
3155
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3156
|
+
const page = await config._data.query(
|
|
3157
|
+
api.balanceLedger.queries.listForOrg,
|
|
3158
|
+
{ orgId, limit: input.limit, cursor: input.cursor }
|
|
3159
|
+
);
|
|
3160
|
+
return [null, page];
|
|
3161
|
+
} catch (cause) {
|
|
3162
|
+
return [fromConvexError(cause), null];
|
|
3163
|
+
}
|
|
3164
|
+
},
|
|
2183
3165
|
retrieve: async (input) => {
|
|
2184
|
-
if (!config.
|
|
2185
|
-
return stub(
|
|
3166
|
+
if (!config._data) {
|
|
3167
|
+
return stub(
|
|
3168
|
+
"organizations.balanceLedger.retrieve"
|
|
3169
|
+
);
|
|
2186
3170
|
}
|
|
2187
3171
|
try {
|
|
2188
|
-
const
|
|
2189
|
-
api.
|
|
2190
|
-
input
|
|
3172
|
+
const entry = await config._data.query(
|
|
3173
|
+
api.balanceLedger.queries.retrieve,
|
|
3174
|
+
{ entryId: input.entryId }
|
|
2191
3175
|
);
|
|
2192
|
-
if (!
|
|
3176
|
+
if (!entry) {
|
|
2193
3177
|
return [
|
|
2194
3178
|
new CapxulError({
|
|
2195
3179
|
code: "NOT_FOUND",
|
|
2196
|
-
message: `
|
|
3180
|
+
message: `balance_ledger_entry ${input.entryId} not found`
|
|
2197
3181
|
}),
|
|
2198
3182
|
null
|
|
2199
3183
|
];
|
|
2200
3184
|
}
|
|
2201
|
-
return [null,
|
|
3185
|
+
return [null, entry];
|
|
2202
3186
|
} catch (cause) {
|
|
2203
|
-
return [
|
|
2204
|
-
fromConvexError(cause),
|
|
2205
|
-
null
|
|
2206
|
-
];
|
|
3187
|
+
return [fromConvexError(cause), null];
|
|
2207
3188
|
}
|
|
2208
3189
|
}
|
|
2209
3190
|
},
|
|
2210
|
-
treasury: {
|
|
2211
|
-
retrieve: async () => stub("organizations.treasury.retrieve")
|
|
2212
|
-
},
|
|
2213
|
-
members: {
|
|
2214
|
-
list: async () => stub("organizations.members.list"),
|
|
2215
|
-
retrieve: async () => stub("organizations.members.retrieve"),
|
|
2216
|
-
invite: async () => stub("organizations.members.invite"),
|
|
2217
|
-
updateRole: async () => stub("organizations.members.updateRole"),
|
|
2218
|
-
remove: async () => stub("organizations.members.remove")
|
|
2219
|
-
},
|
|
2220
|
-
apiKeys: createApiKeysClient(),
|
|
2221
|
-
kybProfile: {
|
|
2222
|
-
start: async () => stub("organizations.kybProfile.start"),
|
|
2223
|
-
retrieve: async () => stub("organizations.kybProfile.retrieve")
|
|
2224
|
-
},
|
|
2225
|
-
subAccounts: {
|
|
2226
|
-
create: async () => stub("organizations.subAccounts.create"),
|
|
2227
|
-
list: async () => stub("organizations.subAccounts.list"),
|
|
2228
|
-
retrieve: async () => stub("organizations.subAccounts.retrieve"),
|
|
2229
|
-
remove: async () => stub("organizations.subAccounts.remove")
|
|
2230
|
-
},
|
|
2231
|
-
externalAccounts: createOrgExternalAccountsClient(config),
|
|
2232
|
-
balanceLedger: {
|
|
2233
|
-
list: async () => stub(
|
|
2234
|
-
"organizations.balanceLedger.list"
|
|
2235
|
-
),
|
|
2236
|
-
retrieve: async () => stub(
|
|
2237
|
-
"organizations.balanceLedger.retrieve"
|
|
2238
|
-
)
|
|
2239
|
-
},
|
|
2240
3191
|
payments: createOrgPaymentsClient(),
|
|
2241
3192
|
transfers: createOrgTransfersClient(),
|
|
2242
3193
|
withdrawals: createOrgWithdrawalsClient(config),
|
|
@@ -2246,14 +3197,6 @@ function createOrganizationsClient(config = {}) {
|
|
|
2246
3197
|
};
|
|
2247
3198
|
}
|
|
2248
3199
|
|
|
2249
|
-
// src/core/sub-accounts.ts
|
|
2250
|
-
function createSubAccountsClient() {
|
|
2251
|
-
return {
|
|
2252
|
-
retrieve: async () => stub("subAccounts.retrieve"),
|
|
2253
|
-
remove: async () => stub("subAccounts.remove")
|
|
2254
|
-
};
|
|
2255
|
-
}
|
|
2256
|
-
|
|
2257
3200
|
// src/core/token-transfers.ts
|
|
2258
3201
|
var toTokenTransferId = (raw) => {
|
|
2259
3202
|
if (typeof raw !== "string" || raw.length === 0) {
|
|
@@ -2272,11 +3215,11 @@ function brandRow(row) {
|
|
|
2272
3215
|
function createTokenTransfersClient(config = {}) {
|
|
2273
3216
|
return {
|
|
2274
3217
|
list: async (input) => {
|
|
2275
|
-
if (!config.
|
|
3218
|
+
if (!config._data) {
|
|
2276
3219
|
return stub("tokenTransfers.list");
|
|
2277
3220
|
}
|
|
2278
3221
|
try {
|
|
2279
|
-
const raw = await config.
|
|
3222
|
+
const raw = await config._data.query(
|
|
2280
3223
|
api.tokenTransfers.queries.list,
|
|
2281
3224
|
{
|
|
2282
3225
|
limit: input?.limit,
|
|
@@ -2310,11 +3253,11 @@ function createTokenTransfersClient(config = {}) {
|
|
|
2310
3253
|
}
|
|
2311
3254
|
},
|
|
2312
3255
|
retrieve: async (input) => {
|
|
2313
|
-
if (!config.
|
|
3256
|
+
if (!config._data) {
|
|
2314
3257
|
return stub("tokenTransfers.retrieve");
|
|
2315
3258
|
}
|
|
2316
3259
|
try {
|
|
2317
|
-
const raw = await config.
|
|
3260
|
+
const raw = await config._data.query(
|
|
2318
3261
|
api.tokenTransfers.queries.getByTxLogIndex,
|
|
2319
3262
|
{
|
|
2320
3263
|
txHash: input.txHash,
|
|
@@ -2384,7 +3327,7 @@ function createAuthFlowMachine(client) {
|
|
|
2384
3327
|
}),
|
|
2385
3328
|
verifyOtp: fromPromise(
|
|
2386
3329
|
async ({ input, signal }) => {
|
|
2387
|
-
const [error,
|
|
3330
|
+
const [error, result] = await client.auth.verifyOtp(
|
|
2388
3331
|
{
|
|
2389
3332
|
email: input.email,
|
|
2390
3333
|
otp: input.code
|
|
@@ -2392,7 +3335,14 @@ function createAuthFlowMachine(client) {
|
|
|
2392
3335
|
{ signal }
|
|
2393
3336
|
);
|
|
2394
3337
|
if (error) throw error;
|
|
2395
|
-
|
|
3338
|
+
if (result.kind === "bootstrap_required") {
|
|
3339
|
+
throw new CapxulError({
|
|
3340
|
+
code: "ACTION_REQUIRED",
|
|
3341
|
+
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
3342
|
+
details: { reason: result.reason }
|
|
3343
|
+
});
|
|
3344
|
+
}
|
|
3345
|
+
return result.session;
|
|
2396
3346
|
}
|
|
2397
3347
|
),
|
|
2398
3348
|
signOut: fromPromise(async () => {
|
|
@@ -2640,6 +3590,327 @@ function emailDomain(email) {
|
|
|
2640
3590
|
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2641
3591
|
return domain || "unknown";
|
|
2642
3592
|
}
|
|
3593
|
+
var initialContext = {
|
|
3594
|
+
email: null,
|
|
3595
|
+
code: null,
|
|
3596
|
+
username: null,
|
|
3597
|
+
bootstrapToken: null,
|
|
3598
|
+
bootstrapReason: null,
|
|
3599
|
+
session: null,
|
|
3600
|
+
account: null,
|
|
3601
|
+
safe: null,
|
|
3602
|
+
error: null
|
|
3603
|
+
};
|
|
3604
|
+
function createAuthBootstrapFlowMachine(client) {
|
|
3605
|
+
return setup({
|
|
3606
|
+
types: {},
|
|
3607
|
+
actors: {
|
|
3608
|
+
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
3609
|
+
const [error] = await client.auth.sendOtp(
|
|
3610
|
+
{ email: input.email },
|
|
3611
|
+
{ signal }
|
|
3612
|
+
);
|
|
3613
|
+
if (error) throw error;
|
|
3614
|
+
}),
|
|
3615
|
+
verifyOtp: fromPromise(
|
|
3616
|
+
async ({ input, signal }) => {
|
|
3617
|
+
const [error, result] = await client.auth.verifyOtp(
|
|
3618
|
+
{ email: input.email, otp: input.code },
|
|
3619
|
+
{ signal }
|
|
3620
|
+
);
|
|
3621
|
+
if (error) throw error;
|
|
3622
|
+
return result;
|
|
3623
|
+
}
|
|
3624
|
+
),
|
|
3625
|
+
completeBootstrap: fromPromise(async ({ input }) => {
|
|
3626
|
+
const [error, result] = await client.auth.completeBootstrap(input);
|
|
3627
|
+
if (error) throw error;
|
|
3628
|
+
return result;
|
|
3629
|
+
}),
|
|
3630
|
+
signOut: fromPromise(async () => {
|
|
3631
|
+
const [error] = await client.auth.signOut();
|
|
3632
|
+
if (error) throw error;
|
|
3633
|
+
})
|
|
3634
|
+
},
|
|
3635
|
+
actions: {
|
|
3636
|
+
trackOtpRequested: ({ context }) => {
|
|
3637
|
+
if (!context.email) return;
|
|
3638
|
+
track("auth_otp_requested", {
|
|
3639
|
+
email_domain: emailDomain2(context.email)
|
|
3640
|
+
});
|
|
3641
|
+
},
|
|
3642
|
+
trackFailed: ({ event }) => {
|
|
3643
|
+
track("auth_failed", {
|
|
3644
|
+
auth_type: "email_otp",
|
|
3645
|
+
reason: errorFromEvent2(event).code
|
|
3646
|
+
});
|
|
3647
|
+
},
|
|
3648
|
+
trackTimeoutFailed: () => {
|
|
3649
|
+
track("auth_failed", {
|
|
3650
|
+
auth_type: "email_otp",
|
|
3651
|
+
reason: "timeout"
|
|
3652
|
+
});
|
|
3653
|
+
},
|
|
3654
|
+
trackVerified: () => {
|
|
3655
|
+
track("auth_verified", { auth_type: "email_otp" });
|
|
3656
|
+
},
|
|
3657
|
+
trackBootstrapRequired: ({ context }) => {
|
|
3658
|
+
track("auth_verified", {
|
|
3659
|
+
auth_type: "email_otp",
|
|
3660
|
+
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
3661
|
+
});
|
|
3662
|
+
},
|
|
3663
|
+
identifyAndTrack: ({ context }) => {
|
|
3664
|
+
if (!context.session) return;
|
|
3665
|
+
identify(context.session.authUserId, {
|
|
3666
|
+
email_domain: emailDomain2(context.session.email)
|
|
3667
|
+
});
|
|
3668
|
+
track("auth_identified", {
|
|
3669
|
+
email_domain: emailDomain2(context.session.email)
|
|
3670
|
+
});
|
|
3671
|
+
},
|
|
3672
|
+
trackSignedOut: () => {
|
|
3673
|
+
track("auth_signed_out");
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
}).createMachine({
|
|
3677
|
+
id: "authBootstrap",
|
|
3678
|
+
initial: "email",
|
|
3679
|
+
context: initialContext,
|
|
3680
|
+
states: {
|
|
3681
|
+
email: {
|
|
3682
|
+
on: {
|
|
3683
|
+
ENTER_EMAIL: {
|
|
3684
|
+
actions: assign({
|
|
3685
|
+
email: ({ event }) => event.email,
|
|
3686
|
+
error: () => null
|
|
3687
|
+
})
|
|
3688
|
+
},
|
|
3689
|
+
REQUEST_OTP: { target: "sending_otp" }
|
|
3690
|
+
}
|
|
3691
|
+
},
|
|
3692
|
+
sending_otp: {
|
|
3693
|
+
invoke: {
|
|
3694
|
+
src: "sendOtp",
|
|
3695
|
+
input: ({ context }) => ({ email: requireEmail2(context) }),
|
|
3696
|
+
onDone: { target: "otp_requested", actions: "trackOtpRequested" },
|
|
3697
|
+
onError: {
|
|
3698
|
+
target: "otp_requested",
|
|
3699
|
+
actions: [
|
|
3700
|
+
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3701
|
+
"trackFailed"
|
|
3702
|
+
]
|
|
3703
|
+
}
|
|
3704
|
+
},
|
|
3705
|
+
after: {
|
|
3706
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3707
|
+
target: "otp_requested",
|
|
3708
|
+
actions: [
|
|
3709
|
+
assign({ error: () => timeoutError2("sending_otp") }),
|
|
3710
|
+
"trackTimeoutFailed"
|
|
3711
|
+
]
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
},
|
|
3715
|
+
otp_requested: {
|
|
3716
|
+
on: {
|
|
3717
|
+
ENTER_OTP: {
|
|
3718
|
+
actions: assign({
|
|
3719
|
+
code: ({ event }) => event.code,
|
|
3720
|
+
error: () => null
|
|
3721
|
+
})
|
|
3722
|
+
},
|
|
3723
|
+
VERIFY_OTP: { target: "verifying_otp" },
|
|
3724
|
+
BACK: { target: "email" },
|
|
3725
|
+
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3726
|
+
}
|
|
3727
|
+
},
|
|
3728
|
+
verifying_otp: {
|
|
3729
|
+
invoke: {
|
|
3730
|
+
src: "verifyOtp",
|
|
3731
|
+
input: ({ context }) => ({
|
|
3732
|
+
email: requireEmail2(context),
|
|
3733
|
+
code: requireCode(context)
|
|
3734
|
+
}),
|
|
3735
|
+
onDone: [
|
|
3736
|
+
{
|
|
3737
|
+
guard: ({ event }) => event.output.kind === "existing_member",
|
|
3738
|
+
target: "authenticated",
|
|
3739
|
+
actions: [
|
|
3740
|
+
assign({
|
|
3741
|
+
session: ({ event }) => event.output.session,
|
|
3742
|
+
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
3743
|
+
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
3744
|
+
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
3745
|
+
email: () => null,
|
|
3746
|
+
error: () => null
|
|
3747
|
+
}),
|
|
3748
|
+
"trackVerified",
|
|
3749
|
+
"identifyAndTrack"
|
|
3750
|
+
]
|
|
3751
|
+
},
|
|
3752
|
+
{
|
|
3753
|
+
target: "bootstrap_required",
|
|
3754
|
+
actions: [
|
|
3755
|
+
assign({
|
|
3756
|
+
session: ({ event }) => event.output.session,
|
|
3757
|
+
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
3758
|
+
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
3759
|
+
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
3760
|
+
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
3761
|
+
error: () => null
|
|
3762
|
+
}),
|
|
3763
|
+
"trackVerified",
|
|
3764
|
+
"trackBootstrapRequired"
|
|
3765
|
+
]
|
|
3766
|
+
}
|
|
3767
|
+
],
|
|
3768
|
+
onError: {
|
|
3769
|
+
target: "otp_requested",
|
|
3770
|
+
actions: [
|
|
3771
|
+
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3772
|
+
"trackFailed"
|
|
3773
|
+
]
|
|
3774
|
+
}
|
|
3775
|
+
},
|
|
3776
|
+
after: {
|
|
3777
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3778
|
+
target: "otp_requested",
|
|
3779
|
+
actions: [
|
|
3780
|
+
assign({ error: () => timeoutError2("verifying_otp") }),
|
|
3781
|
+
"trackTimeoutFailed"
|
|
3782
|
+
]
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
},
|
|
3786
|
+
bootstrap_required: {
|
|
3787
|
+
on: {
|
|
3788
|
+
ENTER_USERNAME: {
|
|
3789
|
+
actions: assign({
|
|
3790
|
+
username: ({ event }) => event.username,
|
|
3791
|
+
error: () => null
|
|
3792
|
+
})
|
|
3793
|
+
},
|
|
3794
|
+
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
3795
|
+
BACK: { target: "otp_requested" },
|
|
3796
|
+
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3797
|
+
}
|
|
3798
|
+
},
|
|
3799
|
+
completing_bootstrap: {
|
|
3800
|
+
invoke: {
|
|
3801
|
+
src: "completeBootstrap",
|
|
3802
|
+
input: ({ context }) => ({
|
|
3803
|
+
bootstrapToken: requireBootstrapToken(context),
|
|
3804
|
+
username: requireUsername(context)
|
|
3805
|
+
}),
|
|
3806
|
+
onDone: {
|
|
3807
|
+
target: "authenticated",
|
|
3808
|
+
actions: [
|
|
3809
|
+
assign({
|
|
3810
|
+
session: ({ event }) => event.output.session,
|
|
3811
|
+
account: ({ event }) => event.output.account,
|
|
3812
|
+
username: ({ event }) => event.output.username,
|
|
3813
|
+
safe: ({ event }) => event.output.safe,
|
|
3814
|
+
bootstrapToken: () => null,
|
|
3815
|
+
bootstrapReason: () => null,
|
|
3816
|
+
email: () => null,
|
|
3817
|
+
error: () => null
|
|
3818
|
+
}),
|
|
3819
|
+
"identifyAndTrack"
|
|
3820
|
+
]
|
|
3821
|
+
},
|
|
3822
|
+
onError: {
|
|
3823
|
+
target: "bootstrap_required",
|
|
3824
|
+
actions: [
|
|
3825
|
+
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3826
|
+
"trackFailed"
|
|
3827
|
+
]
|
|
3828
|
+
}
|
|
3829
|
+
},
|
|
3830
|
+
after: {
|
|
3831
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3832
|
+
target: "bootstrap_required",
|
|
3833
|
+
actions: [
|
|
3834
|
+
assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
3835
|
+
"trackTimeoutFailed"
|
|
3836
|
+
]
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
},
|
|
3840
|
+
authenticated: {
|
|
3841
|
+
on: {
|
|
3842
|
+
SIGN_OUT: { target: "signing_out" }
|
|
3843
|
+
}
|
|
3844
|
+
},
|
|
3845
|
+
signing_out: {
|
|
3846
|
+
invoke: {
|
|
3847
|
+
src: "signOut",
|
|
3848
|
+
onDone: {
|
|
3849
|
+
target: "email",
|
|
3850
|
+
actions: [
|
|
3851
|
+
assign(() => initialContext),
|
|
3852
|
+
"trackSignedOut"
|
|
3853
|
+
]
|
|
3854
|
+
},
|
|
3855
|
+
onError: {
|
|
3856
|
+
target: "error",
|
|
3857
|
+
actions: assign({ error: ({ event }) => errorFromEvent2(event) })
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
},
|
|
3861
|
+
error: {
|
|
3862
|
+
on: {
|
|
3863
|
+
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
});
|
|
3868
|
+
}
|
|
3869
|
+
function requireEmail2(context) {
|
|
3870
|
+
if (!context.email) {
|
|
3871
|
+
throw Errors.invalidInput("email", "Auth bootstrap requires an email.");
|
|
3872
|
+
}
|
|
3873
|
+
return context.email;
|
|
3874
|
+
}
|
|
3875
|
+
function requireCode(context) {
|
|
3876
|
+
if (!context.code) {
|
|
3877
|
+
throw Errors.invalidInput("code", "Auth bootstrap requires an OTP code.");
|
|
3878
|
+
}
|
|
3879
|
+
return context.code;
|
|
3880
|
+
}
|
|
3881
|
+
function requireBootstrapToken(context) {
|
|
3882
|
+
if (!context.bootstrapToken) {
|
|
3883
|
+
throw Errors.invalidInput(
|
|
3884
|
+
"bootstrapToken",
|
|
3885
|
+
"Auth bootstrap requires a continuation token."
|
|
3886
|
+
);
|
|
3887
|
+
}
|
|
3888
|
+
return context.bootstrapToken;
|
|
3889
|
+
}
|
|
3890
|
+
function requireUsername(context) {
|
|
3891
|
+
if (!context.username) {
|
|
3892
|
+
throw Errors.invalidInput("username", "Auth bootstrap requires a username.");
|
|
3893
|
+
}
|
|
3894
|
+
return context.username;
|
|
3895
|
+
}
|
|
3896
|
+
function errorFromEvent2(event) {
|
|
3897
|
+
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3898
|
+
if (cause instanceof CapxulError || cause instanceof CapxulError2) {
|
|
3899
|
+
return cause;
|
|
3900
|
+
}
|
|
3901
|
+
return Errors.providerError("auth", "bootstrap", cause);
|
|
3902
|
+
}
|
|
3903
|
+
function timeoutError2(state) {
|
|
3904
|
+
return Errors.providerError(
|
|
3905
|
+
"auth",
|
|
3906
|
+
"bootstrap",
|
|
3907
|
+
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3908
|
+
);
|
|
3909
|
+
}
|
|
3910
|
+
function emailDomain2(email) {
|
|
3911
|
+
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
3912
|
+
return domain || "unknown";
|
|
3913
|
+
}
|
|
2643
3914
|
function createProvisioningMachine(client) {
|
|
2644
3915
|
return setup({
|
|
2645
3916
|
types: {},
|
|
@@ -2667,7 +3938,7 @@ function createProvisioningMachine(client) {
|
|
|
2667
3938
|
const provider = context.input?.signerProvider;
|
|
2668
3939
|
if (!provider) return;
|
|
2669
3940
|
track("provisioning_safe_created", {
|
|
2670
|
-
safe_address: provider.
|
|
3941
|
+
safe_address: deriveSafeAddress(provider.signerAddress)
|
|
2671
3942
|
});
|
|
2672
3943
|
}
|
|
2673
3944
|
}
|
|
@@ -2712,13 +3983,13 @@ function createProvisioningMachine(client) {
|
|
|
2712
3983
|
},
|
|
2713
3984
|
onError: {
|
|
2714
3985
|
target: "error",
|
|
2715
|
-
actions: assign({ error: ({ event }) =>
|
|
3986
|
+
actions: assign({ error: ({ event }) => errorFromEvent3(event) })
|
|
2716
3987
|
}
|
|
2717
3988
|
},
|
|
2718
3989
|
after: {
|
|
2719
3990
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2720
3991
|
target: "error",
|
|
2721
|
-
actions: assign({ error: () =>
|
|
3992
|
+
actions: assign({ error: () => timeoutError3() })
|
|
2722
3993
|
}
|
|
2723
3994
|
}
|
|
2724
3995
|
},
|
|
@@ -2736,7 +4007,7 @@ function createProvisioningMachine(client) {
|
|
|
2736
4007
|
* this payload on its `onDone` transition and branches via guards
|
|
2737
4008
|
* on `event.output.error`.
|
|
2738
4009
|
*/
|
|
2739
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
4010
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError3() }
|
|
2740
4011
|
});
|
|
2741
4012
|
}
|
|
2742
4013
|
function requireProvisionInput(context) {
|
|
@@ -2748,13 +4019,13 @@ function requireProvisionInput(context) {
|
|
|
2748
4019
|
}
|
|
2749
4020
|
return context.input;
|
|
2750
4021
|
}
|
|
2751
|
-
function
|
|
4022
|
+
function errorFromEvent3(event) {
|
|
2752
4023
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
2753
4024
|
if (cause instanceof CapxulError) return cause;
|
|
2754
4025
|
if (cause instanceof CapxulError2) return cause;
|
|
2755
4026
|
return Errors.providerError("provisioning", "flow", cause);
|
|
2756
4027
|
}
|
|
2757
|
-
function
|
|
4028
|
+
function timeoutError3() {
|
|
2758
4029
|
return Errors.providerError(
|
|
2759
4030
|
"provisioning",
|
|
2760
4031
|
"flow",
|
|
@@ -2847,7 +4118,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
2847
4118
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
2848
4119
|
}),
|
|
2849
4120
|
assignChildThrown: assign({
|
|
2850
|
-
error: ({ event }) =>
|
|
4121
|
+
error: ({ event }) => errorFromEvent4(event)
|
|
2851
4122
|
}),
|
|
2852
4123
|
assignAccountFromChild: assign({
|
|
2853
4124
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -3009,7 +4280,7 @@ function extractChildAccountOrNull(event) {
|
|
|
3009
4280
|
if (output && "account" in output && output.account) return output.account;
|
|
3010
4281
|
return null;
|
|
3011
4282
|
}
|
|
3012
|
-
function
|
|
4283
|
+
function errorFromEvent4(event) {
|
|
3013
4284
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3014
4285
|
if (cause instanceof CapxulError) return cause;
|
|
3015
4286
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -3029,7 +4300,7 @@ function createCapxulClient(config = {}) {
|
|
|
3029
4300
|
tokenTransfers: createTokenTransfersClient(config),
|
|
3030
4301
|
withdrawals: createWithdrawalsClient(config),
|
|
3031
4302
|
documents: createDocumentsClient(),
|
|
3032
|
-
subAccounts: createSubAccountsClient(),
|
|
4303
|
+
subAccounts: createSubAccountsClient(config),
|
|
3033
4304
|
virtualAccounts: createVirtualAccountsClient(),
|
|
3034
4305
|
virtualCards: createVirtualCardsClient(),
|
|
3035
4306
|
externalAccounts: createExternalAccountsClient(config),
|
|
@@ -3041,6 +4312,7 @@ function createCapxulClient(config = {}) {
|
|
|
3041
4312
|
const client = clientWithoutFlows;
|
|
3042
4313
|
client.flows = {
|
|
3043
4314
|
auth: () => createAuthFlowMachine(client),
|
|
4315
|
+
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
3044
4316
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
3045
4317
|
provisioning: () => createProvisioningMachine(client)
|
|
3046
4318
|
};
|