@capxul/sdk 2.8.2 → 3.0.2
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/dist/OAuthBearerAuthClient-BxTiv8dg.d.mts +19 -0
- package/dist/OAuthBearerAuthClient-DfS4QOg7.mjs +211 -0
- package/dist/{InMemoryAuthCacheAdapter-BrEN-men.mjs → clock-m_aHLaNm.mjs} +1111 -14
- package/dist/{create-capxul-client-BKJHefmA.mjs → create-capxul-client-Ch_pfcoR.mjs} +114 -1016
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +7 -23
- package/dist/node/index.d.mts +3 -2
- package/dist/node/index.mjs +3 -2
- package/dist/{observation-D-oCDlMS.d.mts → observation-B3PCugGC.d.mts} +14 -65
- package/dist/{signer-BdDgF200.d.mts → signer-BpjdawiY.d.mts} +87 -3
- package/dist/testing/index.d.mts +1 -1
- package/dist/testing/index.mjs +2 -22
- package/package.json +7 -7
|
@@ -1,4 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { concat, encodeAbiParameters, encodeFunctionData, encodePacked, getContractAddress, keccak256, padHex, stringToHex, toBytes, toEventSelector, toFunctionSelector, toFunctionSignature } from "viem";
|
|
2
|
+
import { Context, Data, Effect, Layer, Result } from "effect";
|
|
3
|
+
//#region ../errors/src/secret-material.ts
|
|
4
|
+
const SENSITIVE_MATERIAL_PATTERNS = [
|
|
5
|
+
/(?:^|[^a-fA-F0-9])(?<!0[xX])[a-fA-F0-9]{64}(?:$|[^a-fA-F0-9])/u,
|
|
6
|
+
/eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/u,
|
|
7
|
+
/(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/iu,
|
|
8
|
+
/\bBearer\s+[^\s,;]+/iu,
|
|
9
|
+
/https?:\/\/[^\s"']+?\/v[0-9]\/[A-Za-z0-9_-]{16,}/iu,
|
|
10
|
+
/\b(?:api[ _-]?key|access[ _-]?token|token|secret|password|passphrase|private[ _-]?key|authorization|cookie|signature|request[ _-]?body|credential|otp|one[ _-]?time[ _-]?(?:password|code)|verification[ _-]?code)\b\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;&]+)/iu
|
|
11
|
+
];
|
|
12
|
+
const MASKS = [
|
|
13
|
+
[/\bBearer\s+[^\s,;]+/giu, "Bearer [REDACTED]"],
|
|
14
|
+
[/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]"],
|
|
15
|
+
[/(^|[^a-fA-F0-9])(?<!0[xX])[a-fA-F0-9]{64}(?=$|[^a-fA-F0-9])/gu, "$1[REDACTED]"],
|
|
16
|
+
[/(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/giu, "[REDACTED]"],
|
|
17
|
+
[/(https?:\/\/[^\s"']+?\/v[0-9]\/)[A-Za-z0-9_-]{16,}/giu, "$1[REDACTED]"],
|
|
18
|
+
[/\b(api[ _-]?key|access[ _-]?token|token|secret|password|passphrase|private[ _-]?key|authorization|cookie|signature|request[ _-]?body|credential|otp|one[ _-]?time[ _-]?(?:password|code)|verification[ _-]?code)\b\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;&]+)/giu, "$1=[REDACTED]"]
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Reject: does the value carry any known secret material? Best effort — callers
|
|
22
|
+
* drop the whole value on a match; a false negative is a leak, a false positive
|
|
23
|
+
* merely omits an observation field.
|
|
24
|
+
*/
|
|
25
|
+
function containsSensitiveMaterial(value) {
|
|
26
|
+
return SENSITIVE_MATERIAL_PATTERNS.some((pattern) => pattern.test(value));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Mask: return the value with every known secret rewritten to `[REDACTED]`,
|
|
30
|
+
* preserving surrounding text. Used where a value must still be shown (log
|
|
31
|
+
* lines, provider messages, PostHog rows) but must not carry live credentials.
|
|
32
|
+
*/
|
|
33
|
+
function redactSecrets(value) {
|
|
34
|
+
let text = value;
|
|
35
|
+
for (const [pattern, replacement] of MASKS) text = text.replace(pattern, replacement);
|
|
36
|
+
return text;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
2
39
|
//#region ../errors/src/chain-cause.ts
|
|
3
40
|
/**
|
|
4
41
|
* Why an operation failed — the one flat vocabulary. The first four are the
|
|
@@ -21,6 +58,9 @@ const FAILURE_MODES = [
|
|
|
21
58
|
"insufficient-allowance",
|
|
22
59
|
"rejected",
|
|
23
60
|
"unauthorized",
|
|
61
|
+
"forbidden",
|
|
62
|
+
"bad-request",
|
|
63
|
+
"method-unsupported",
|
|
24
64
|
"unknown"
|
|
25
65
|
];
|
|
26
66
|
function isFailureMode(value) {
|
|
@@ -37,6 +77,33 @@ const CHAIN_UPSTREAMS = [
|
|
|
37
77
|
function isChainUpstream(value) {
|
|
38
78
|
return typeof value === "string" && CHAIN_UPSTREAMS.includes(value);
|
|
39
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* The response headers that name a refusal or let provider support find the
|
|
82
|
+
* request. Nothing else crosses: a header can carry a session or a key.
|
|
83
|
+
*/
|
|
84
|
+
const RESPONSE_HEADER_ALLOWLIST = [
|
|
85
|
+
"retry-after",
|
|
86
|
+
"www-authenticate",
|
|
87
|
+
"content-type",
|
|
88
|
+
"x-request-id",
|
|
89
|
+
"cf-ray",
|
|
90
|
+
"x-ratelimit-remaining",
|
|
91
|
+
"x-ratelimit-reset",
|
|
92
|
+
"server"
|
|
93
|
+
];
|
|
94
|
+
const RESPONSE_HEADER_VALUE_MAX = 128;
|
|
95
|
+
/**
|
|
96
|
+
* The allow-listed headers of one answer, masked and bounded. `read` is
|
|
97
|
+
* `Headers.get` or a lookup into a decoded record. Empty when none is present.
|
|
98
|
+
*/
|
|
99
|
+
function boundedResponseHeaders(read) {
|
|
100
|
+
const headers = {};
|
|
101
|
+
for (const name of RESPONSE_HEADER_ALLOWLIST) {
|
|
102
|
+
const value = read(name);
|
|
103
|
+
if (typeof value === "string" && value.length > 0) headers[name] = boundedEvidence(value, RESPONSE_HEADER_VALUE_MAX);
|
|
104
|
+
}
|
|
105
|
+
return headers;
|
|
106
|
+
}
|
|
40
107
|
const PROVIDER_MESSAGE_MAX = 300;
|
|
41
108
|
const METHOD_MAX = 64;
|
|
42
109
|
const REVERT_NAME_MAX = 64;
|
|
@@ -44,19 +111,9 @@ const REVERT_ARG_KEY_MAX = 32;
|
|
|
44
111
|
const REVERT_ARG_VALUE_MAX = 128;
|
|
45
112
|
const REVERT_ARGS_MAX = 8;
|
|
46
113
|
const SELECTOR_RE = /^0x(?:[0-9a-fA-F]{8})?$/u;
|
|
47
|
-
const MASKS = [
|
|
48
|
-
[/\bBearer\s+[^\s,;]+/giu, "Bearer [REDACTED]"],
|
|
49
|
-
[/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]"],
|
|
50
|
-
[/\b0x[a-fA-F0-9]{40,}\b/gu, "[REDACTED]"],
|
|
51
|
-
[/(^|[^a-fA-F0-9])[a-fA-F0-9]{64}(?=$|[^a-fA-F0-9])/gu, "$1[REDACTED]"],
|
|
52
|
-
[/(?:(?:sk|pk|rk)_(?:live|test)|(?:phc|phx|ghp|gho|ghu|ghs|ghr|whsec)_|github_pat_|xox[baprs]-|AKIA[0-9A-Z]{16}|AIza)[A-Za-z0-9_-]*/giu, "[REDACTED]"],
|
|
53
|
-
[/(https?:\/\/[^\s"']+?\/v[0-9]\/)[A-Za-z0-9_-]{16,}/giu, "$1[REDACTED]"],
|
|
54
|
-
[/\b(api[ _-]?key|access[ _-]?token|token|secret|password|passphrase|private[ _-]?key|authorization|cookie|signature|credential|otp)\b\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;&]+)/giu, "$1=[REDACTED]"]
|
|
55
|
-
];
|
|
56
114
|
/** Mask credential-shaped content, then cap the length. Total on any string. */
|
|
57
115
|
function boundedEvidence(value, max) {
|
|
58
|
-
|
|
59
|
-
for (const [pattern, replacement] of MASKS) text = text.replace(pattern, replacement);
|
|
116
|
+
const text = redactSecrets(value);
|
|
60
117
|
return text.length <= max ? text : text.slice(0, max);
|
|
61
118
|
}
|
|
62
119
|
function isRecord(value) {
|
|
@@ -98,8 +155,36 @@ function decodeChainCause(value) {
|
|
|
98
155
|
const revert = decodeRevert(value.revert);
|
|
99
156
|
if (revert !== null) cause.revert = revert;
|
|
100
157
|
if (typeof value.providerMessage === "string") cause.providerMessage = boundedEvidence(value.providerMessage, PROVIDER_MESSAGE_MAX);
|
|
158
|
+
const attempts = decodeAttempts(value.attempts);
|
|
159
|
+
if (attempts !== null) cause.attempts = attempts;
|
|
160
|
+
if (isRecord(value.responseHeaders)) {
|
|
161
|
+
const raw = value.responseHeaders;
|
|
162
|
+
const headers = boundedResponseHeaders((name) => {
|
|
163
|
+
const header = raw[name];
|
|
164
|
+
return typeof header === "string" ? header : null;
|
|
165
|
+
});
|
|
166
|
+
if (Object.keys(headers).length > 0) cause.responseHeaders = headers;
|
|
167
|
+
}
|
|
101
168
|
return cause;
|
|
102
169
|
}
|
|
170
|
+
/** The attempt sequence, bounded. A malformed entry drops the sequence, never the cause. */
|
|
171
|
+
function decodeAttempts(value) {
|
|
172
|
+
if (!Array.isArray(value)) return null;
|
|
173
|
+
const attempts = [];
|
|
174
|
+
for (const entry of value.slice(0, 5)) {
|
|
175
|
+
if (!isRecord(entry) || !isChainUpstream(entry.upstream) || !isFailureMode(entry.mode)) return null;
|
|
176
|
+
const duration = entry.durationMs;
|
|
177
|
+
if (typeof duration !== "number" || !Number.isFinite(duration) || duration < 0) return null;
|
|
178
|
+
attempts.push({
|
|
179
|
+
upstream: entry.upstream,
|
|
180
|
+
mode: entry.mode,
|
|
181
|
+
...typeof entry.httpStatus === "number" && Number.isInteger(entry.httpStatus) ? { httpStatus: entry.httpStatus } : {},
|
|
182
|
+
...typeof entry.rpcCode === "number" && Number.isInteger(entry.rpcCode) ? { rpcCode: entry.rpcCode } : {},
|
|
183
|
+
durationMs: Math.round(duration)
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return attempts.length === 0 ? null : attempts;
|
|
187
|
+
}
|
|
103
188
|
/**
|
|
104
189
|
* The cause as flat PostHog properties. Same keys from every producer, so one
|
|
105
190
|
* filter (`failure_mode = 'rate-limited'`) finds the gateway's, the backend's,
|
|
@@ -118,7 +203,15 @@ function chainCauseProperties(chain) {
|
|
|
118
203
|
chain_revert_selector: chain.revert.selector,
|
|
119
204
|
chain_revert_args: chain.revert.args
|
|
120
205
|
},
|
|
121
|
-
...chain.providerMessage === void 0 ? {} : { chain_provider_message: chain.providerMessage }
|
|
206
|
+
...chain.providerMessage === void 0 ? {} : { chain_provider_message: chain.providerMessage },
|
|
207
|
+
...chain.attempts === void 0 ? {} : { chain_attempts: chain.attempts.map((attempt) => ({
|
|
208
|
+
upstream: attempt.upstream,
|
|
209
|
+
failure_mode: attempt.mode,
|
|
210
|
+
...attempt.httpStatus === void 0 ? {} : { http_status: attempt.httpStatus },
|
|
211
|
+
...attempt.rpcCode === void 0 ? {} : { rpc_code: attempt.rpcCode },
|
|
212
|
+
duration_ms: attempt.durationMs
|
|
213
|
+
})) },
|
|
214
|
+
...chain.responseHeaders === void 0 ? {} : { chain_response_headers: chain.responseHeaders }
|
|
122
215
|
};
|
|
123
216
|
}
|
|
124
217
|
/**
|
|
@@ -174,6 +267,18 @@ function revertSummaryText(revert) {
|
|
|
174
267
|
return `${revert.name}(${args})`;
|
|
175
268
|
}
|
|
176
269
|
/**
|
|
270
|
+
* The evidence behind the one word, for an issue name: ` (HTTP 403)` or
|
|
271
|
+
* ` (JSON-RPC -32000)`. Empty when the cause carries neither. The status
|
|
272
|
+
* names the provider's front door and the code names the node's verdict;
|
|
273
|
+
* `forbidden` alone made an operator open the issue to learn it was a 403.
|
|
274
|
+
*/
|
|
275
|
+
function chainEvidenceLabel(chain) {
|
|
276
|
+
if (chain === void 0) return "";
|
|
277
|
+
if (chain.httpStatus !== void 0 && chain.httpStatus !== 200) return ` (HTTP ${String(chain.httpStatus)})`;
|
|
278
|
+
if (chain.rpcCode !== void 0) return ` (JSON-RPC ${String(chain.rpcCode)})`;
|
|
279
|
+
return "";
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
177
282
|
* The error-tracking fingerprint for a failure: the code, the one-word cause,
|
|
178
283
|
* and the operation. PostHog groups `$exception` rows by this value, so one
|
|
179
284
|
* issue is one cause at one operation instead of every provider failure in
|
|
@@ -652,6 +757,978 @@ function invalidValueReason(prefix, raw) {
|
|
|
652
757
|
return `${prefix}: ${String(raw)}`;
|
|
653
758
|
}
|
|
654
759
|
//#endregion
|
|
760
|
+
//#region ../config/src/tokens.ts
|
|
761
|
+
/** `TestUSDC` ("USDX") — Base Sepolia, 6 decimals, open `mint`. (Canon §1.) */
|
|
762
|
+
const USDX_ADDRESS_BASE_SEPOLIA = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
|
|
763
|
+
USDX_ADDRESS_BASE_SEPOLIA.toLowerCase();
|
|
764
|
+
//#endregion
|
|
765
|
+
//#region ../config/src/org-payments.ts
|
|
766
|
+
/** Zodiac MultiSendCallOnly module on Base Sepolia. */
|
|
767
|
+
const MULTI_SEND_CALL_ONLY = "0x9641d764fc13c8b624c04430c7356c1c7c8102e2";
|
|
768
|
+
//#endregion
|
|
769
|
+
//#region ../config/src/safe.ts
|
|
770
|
+
const BASE_SEPOLIA_CHAIN_ID = 84532;
|
|
771
|
+
const SAFE_PROXY_FACTORY = "0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67";
|
|
772
|
+
const SAFE_L2_SINGLETON = "0x29fcB43b46531BcA003ddC8FCB67FFE91900C762";
|
|
773
|
+
const SAFE_MODULE_SETUP = "0x2dd68b007B46fBe91B9A7c3EDa5A7a1063cB5b47";
|
|
774
|
+
const SAFE_4337_MODULE = "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226";
|
|
775
|
+
const MULTI_SEND = "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526";
|
|
776
|
+
/**
|
|
777
|
+
* The Capxul bootstrap owner — the sole `setup()` owner of every unclaimed
|
|
778
|
+
* personal Safe under derivation v2. This address is part of the CREATE2
|
|
779
|
+
* preimage of EVERY personal Safe address: treat it exactly like
|
|
780
|
+
* `SAFE_PROXY_FACTORY` (changing it is a derivation-version event → v3).
|
|
781
|
+
* The private key lives backend-only (`CAPXUL_BOOTSTRAP_OWNER_PRIVATE_KEY`)
|
|
782
|
+
* and signs exactly one kind of operation: the claim userOp that deploys the
|
|
783
|
+
* Safe and swaps this owner out for the user's signer (PRD #462). The earlier
|
|
784
|
+
* ClaimGuard derivation-v3 placeholder (#461) is closed; future mainnet-scale
|
|
785
|
+
* hardening should be filed against the current payments/claim architecture.
|
|
786
|
+
*/
|
|
787
|
+
const CAPXUL_BOOTSTRAP_OWNER = "0x425fca96f4a3e18fb80974e38096b5da460f2704";
|
|
788
|
+
const SAFE_PROXY_CREATION_CODE = "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564";
|
|
789
|
+
/**
|
|
790
|
+
* Normalize an email for use as a Capxul Safe salt input.
|
|
791
|
+
*
|
|
792
|
+
* Trims surrounding whitespace and lowercases the address so that
|
|
793
|
+
* `" User+Demo@Example.COM "` and `"user+demo@example.com"` derive
|
|
794
|
+
* the same `safeAddress`. This is the canonical normalization rule —
|
|
795
|
+
* any future change here would shift every existing user's Safe
|
|
796
|
+
* address, so the rule is pinned by the fixture matrix in
|
|
797
|
+
* `packages/config/tests/safe-address-conformance.test.ts`.
|
|
798
|
+
*
|
|
799
|
+
* @param email - The raw email address to normalize
|
|
800
|
+
* @returns The trimmed, lowercased email
|
|
801
|
+
*/
|
|
802
|
+
function normalizeSafeSaltEmail(email) {
|
|
803
|
+
return email.trim().toLowerCase();
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Compute the deterministic Safe salt nonce for a `(namespace, email)`
|
|
807
|
+
* pair. The salt nonce is the `bigint` reading of
|
|
808
|
+
* `keccak256(namespace + ":" + normalizeSafeSaltEmail(email))`.
|
|
809
|
+
*
|
|
810
|
+
* Namespace defaults to `CAPXUL_SAFE_SALT_NAMESPACE`
|
|
811
|
+
* (`"capxul:staging:email:v1"`) — the current Capxul scheme. Pass a
|
|
812
|
+
* different namespace only for pinned pre-v2 artifacts
|
|
813
|
+
* (`CAPXUL_SAFE_SALT_NAMESPACE_V1`, faucet Safe) or when bumping the scheme.
|
|
814
|
+
*
|
|
815
|
+
* @param input.email - The email to derive the salt nonce from
|
|
816
|
+
* @param input.namespace - Optional namespace override (defaults to `CAPXUL_SAFE_SALT_NAMESPACE`)
|
|
817
|
+
* @returns The Capxul-namespaced salt nonce as a `bigint`
|
|
818
|
+
*/
|
|
819
|
+
function computeCapxulSafeSaltNonce(input) {
|
|
820
|
+
const namespace = input.namespace ?? "capxul:staging:email:v1";
|
|
821
|
+
const normalizedEmail = normalizeSafeSaltEmail(input.email);
|
|
822
|
+
return BigInt(keccak256(toBytes(`${namespace}:${normalizedEmail}`)));
|
|
823
|
+
}
|
|
824
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
825
|
+
const safeSetupAbi = [{
|
|
826
|
+
type: "function",
|
|
827
|
+
name: "setup",
|
|
828
|
+
stateMutability: "nonpayable",
|
|
829
|
+
inputs: [
|
|
830
|
+
{
|
|
831
|
+
name: "_owners",
|
|
832
|
+
type: "address[]"
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
name: "_threshold",
|
|
836
|
+
type: "uint256"
|
|
837
|
+
},
|
|
838
|
+
{
|
|
839
|
+
name: "to",
|
|
840
|
+
type: "address"
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
name: "data",
|
|
844
|
+
type: "bytes"
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
name: "fallbackHandler",
|
|
848
|
+
type: "address"
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
name: "paymentToken",
|
|
852
|
+
type: "address"
|
|
853
|
+
},
|
|
854
|
+
{
|
|
855
|
+
name: "payment",
|
|
856
|
+
type: "uint256"
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
name: "paymentReceiver",
|
|
860
|
+
type: "address"
|
|
861
|
+
}
|
|
862
|
+
],
|
|
863
|
+
outputs: []
|
|
864
|
+
}];
|
|
865
|
+
const enableModulesAbi = [{
|
|
866
|
+
type: "function",
|
|
867
|
+
name: "enableModules",
|
|
868
|
+
stateMutability: "nonpayable",
|
|
869
|
+
inputs: [{
|
|
870
|
+
name: "modules",
|
|
871
|
+
type: "address[]"
|
|
872
|
+
}],
|
|
873
|
+
outputs: []
|
|
874
|
+
}];
|
|
875
|
+
const multiSendAbi = [{
|
|
876
|
+
type: "function",
|
|
877
|
+
name: "multiSend",
|
|
878
|
+
stateMutability: "payable",
|
|
879
|
+
inputs: [{
|
|
880
|
+
name: "transactions",
|
|
881
|
+
type: "bytes"
|
|
882
|
+
}],
|
|
883
|
+
outputs: []
|
|
884
|
+
}];
|
|
885
|
+
function buildCapxulSafeInitializer(owner) {
|
|
886
|
+
const enableModulesCall = encodeFunctionData({
|
|
887
|
+
abi: enableModulesAbi,
|
|
888
|
+
functionName: "enableModules",
|
|
889
|
+
args: [[SAFE_4337_MODULE]]
|
|
890
|
+
});
|
|
891
|
+
const enableModulesByteLen = BigInt((enableModulesCall.length - 2) / 2);
|
|
892
|
+
const multiSendPayload = encodePacked([
|
|
893
|
+
"uint8",
|
|
894
|
+
"address",
|
|
895
|
+
"uint256",
|
|
896
|
+
"uint256",
|
|
897
|
+
"bytes"
|
|
898
|
+
], [
|
|
899
|
+
1,
|
|
900
|
+
SAFE_MODULE_SETUP,
|
|
901
|
+
0n,
|
|
902
|
+
enableModulesByteLen,
|
|
903
|
+
enableModulesCall
|
|
904
|
+
]);
|
|
905
|
+
const setupData = encodeFunctionData({
|
|
906
|
+
abi: multiSendAbi,
|
|
907
|
+
functionName: "multiSend",
|
|
908
|
+
args: [multiSendPayload]
|
|
909
|
+
});
|
|
910
|
+
return encodeFunctionData({
|
|
911
|
+
abi: safeSetupAbi,
|
|
912
|
+
functionName: "setup",
|
|
913
|
+
args: [
|
|
914
|
+
[owner],
|
|
915
|
+
1n,
|
|
916
|
+
MULTI_SEND,
|
|
917
|
+
setupData,
|
|
918
|
+
SAFE_4337_MODULE,
|
|
919
|
+
ZERO_ADDRESS,
|
|
920
|
+
0n,
|
|
921
|
+
ZERO_ADDRESS
|
|
922
|
+
]
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
const ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
|
|
926
|
+
function validateAndNormalizeAddress(field, value) {
|
|
927
|
+
const address = value.toLowerCase();
|
|
928
|
+
if (!ADDRESS_REGEX.test(address)) throw Errors.invalidInput(field, `must be 0x + 40 hex chars, got ${value}`);
|
|
929
|
+
return address;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Pure derivation of the Capxul personal Safe address — **v2: email only**
|
|
933
|
+
* (PRD #462). The Safe v1.4.1 (SafeL2) + 4337-module initializer's sole owner
|
|
934
|
+
* is the fixed `CAPXUL_BOOTSTRAP_OWNER`, so the address is a pure function of
|
|
935
|
+
* the (normalized) email and exists before any user signer does. The user's
|
|
936
|
+
* signer is installed at claim time via `swapOwner` — signer rotation can
|
|
937
|
+
* never move the address (org-domain rule D7, now system-wide).
|
|
938
|
+
*
|
|
939
|
+
* Returns the lowercased `0x` + 40 hex string (raw — no brand applied so this
|
|
940
|
+
* function is callable from both `@capxul/config` consumers that don't have
|
|
941
|
+
* `@capxul/types` available, and from packages that re-brand at their own
|
|
942
|
+
* boundary).
|
|
943
|
+
*
|
|
944
|
+
* Algorithm: exactly mirrors `permissionless.toSafeSmartAccount({ version:
|
|
945
|
+
* "1.4.1", safeSingletonAddress: SAFE_L2_SINGLETON, owners: [BOOTSTRAP] })`
|
|
946
|
+
* + the Capxul-canonical module setup (delegatecall into
|
|
947
|
+
* `SafeModuleSetup.enableModules([SAFE_4337_MODULE])` via the MultiSend lane
|
|
948
|
+
* during proxy setup). The proxy creation code is pinned at
|
|
949
|
+
* `SAFE_PROXY_CREATION_CODE`; the salt is Capxul-namespaced (v2) via
|
|
950
|
+
* `computeCapxulSafeSaltNonce({ email })`.
|
|
951
|
+
*
|
|
952
|
+
* Canonical: SDK deployment adapters and
|
|
953
|
+
* `packages/backend/convex/smartAccount/mutations.ts:provision` import this
|
|
954
|
+
* function; the conformance test at
|
|
955
|
+
* `packages/config/tests/safe-address-conformance.test.ts` pins the matrix.
|
|
956
|
+
*/
|
|
957
|
+
function deriveCapxulSafeAddress(input) {
|
|
958
|
+
return deriveCapxulSafeAddressForOwner({
|
|
959
|
+
ownerAddress: CAPXUL_BOOTSTRAP_OWNER,
|
|
960
|
+
email: input.email
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Owner-parametrized derivation core. Two callers only:
|
|
965
|
+
* 1. `deriveCapxulSafeAddress` (canonical v2: owner = bootstrap, namespace v2);
|
|
966
|
+
* 2. the backend faucet Safe (`testUsdcMint.ts`: owner = deployer EOA,
|
|
967
|
+
* namespace pinned to `CAPXUL_SAFE_SALT_NAMESPACE_V1` so its deployed
|
|
968
|
+
* address never moves).
|
|
969
|
+
* Do NOT introduce new owner-parametrized lanes — per-user owners in the
|
|
970
|
+
* derivation is exactly the v1 mistake v2 removes.
|
|
971
|
+
*/
|
|
972
|
+
function deriveCapxulSafeAddressForOwner(input) {
|
|
973
|
+
const initializer = buildCapxulSafeInitializer(validateAndNormalizeAddress("ownerAddress", input.ownerAddress));
|
|
974
|
+
const saltNonce = computeCapxulSafeSaltNonce(input.namespace === void 0 ? { email: input.email } : {
|
|
975
|
+
email: input.email,
|
|
976
|
+
namespace: input.namespace
|
|
977
|
+
});
|
|
978
|
+
const salt = keccak256(encodePacked(["bytes32", "uint256"], [keccak256(initializer), saltNonce]));
|
|
979
|
+
const deploymentCode = concat([SAFE_PROXY_CREATION_CODE, encodeAbiParameters([{ type: "uint256" }], [BigInt(SAFE_L2_SINGLETON)])]);
|
|
980
|
+
return getContractAddress({
|
|
981
|
+
opcode: "CREATE2",
|
|
982
|
+
from: SAFE_PROXY_FACTORY,
|
|
983
|
+
salt,
|
|
984
|
+
bytecodeHash: keccak256(deploymentCode)
|
|
985
|
+
}).toLowerCase();
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Normalize a raw email for binding id + Safe salt derivation.
|
|
989
|
+
* Delegates to {@link normalizeSafeSaltEmail} so binding resolution and
|
|
990
|
+
* `deriveCapxulSafeAddress` never drift apart.
|
|
991
|
+
*/
|
|
992
|
+
function normalizeBindingEmail(email) {
|
|
993
|
+
return normalizeSafeSaltEmail(email);
|
|
994
|
+
}
|
|
995
|
+
//#endregion
|
|
996
|
+
//#region ../config/src/capxul-payments-v2.ts
|
|
997
|
+
/** The exact compiled CapxulPaymentsV2 ABI. */
|
|
998
|
+
const CAPXUL_PAYMENTS_V2_ABI = [
|
|
999
|
+
{
|
|
1000
|
+
type: "function",
|
|
1001
|
+
name: "cancel",
|
|
1002
|
+
inputs: [{
|
|
1003
|
+
name: "commitmentId",
|
|
1004
|
+
type: "uint256",
|
|
1005
|
+
internalType: "uint256"
|
|
1006
|
+
}, {
|
|
1007
|
+
name: "documentHash",
|
|
1008
|
+
type: "bytes32",
|
|
1009
|
+
internalType: "bytes32"
|
|
1010
|
+
}],
|
|
1011
|
+
outputs: [],
|
|
1012
|
+
stateMutability: "nonpayable"
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
type: "function",
|
|
1016
|
+
name: "claim",
|
|
1017
|
+
inputs: [{
|
|
1018
|
+
name: "commitmentId",
|
|
1019
|
+
type: "uint256",
|
|
1020
|
+
internalType: "uint256"
|
|
1021
|
+
}],
|
|
1022
|
+
outputs: [],
|
|
1023
|
+
stateMutability: "nonpayable"
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
type: "function",
|
|
1027
|
+
name: "claimableAmount",
|
|
1028
|
+
inputs: [{
|
|
1029
|
+
name: "commitmentId",
|
|
1030
|
+
type: "uint256",
|
|
1031
|
+
internalType: "uint256"
|
|
1032
|
+
}],
|
|
1033
|
+
outputs: [{
|
|
1034
|
+
name: "",
|
|
1035
|
+
type: "uint256",
|
|
1036
|
+
internalType: "uint256"
|
|
1037
|
+
}],
|
|
1038
|
+
stateMutability: "view"
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
type: "function",
|
|
1042
|
+
name: "commitments",
|
|
1043
|
+
inputs: [{
|
|
1044
|
+
name: "",
|
|
1045
|
+
type: "uint256",
|
|
1046
|
+
internalType: "uint256"
|
|
1047
|
+
}],
|
|
1048
|
+
outputs: [
|
|
1049
|
+
{
|
|
1050
|
+
name: "settlementId",
|
|
1051
|
+
type: "bytes32",
|
|
1052
|
+
internalType: "bytes32"
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
name: "creator",
|
|
1056
|
+
type: "address",
|
|
1057
|
+
internalType: "address"
|
|
1058
|
+
},
|
|
1059
|
+
{
|
|
1060
|
+
name: "recipient",
|
|
1061
|
+
type: "address",
|
|
1062
|
+
internalType: "address"
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
name: "token",
|
|
1066
|
+
type: "address",
|
|
1067
|
+
internalType: "address"
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
name: "totalAmount",
|
|
1071
|
+
type: "uint256",
|
|
1072
|
+
internalType: "uint256"
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
name: "claimed",
|
|
1076
|
+
type: "uint256",
|
|
1077
|
+
internalType: "uint256"
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
name: "startTime",
|
|
1081
|
+
type: "uint48",
|
|
1082
|
+
internalType: "uint48"
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
name: "cliffTime",
|
|
1086
|
+
type: "uint48",
|
|
1087
|
+
internalType: "uint48"
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
name: "endTime",
|
|
1091
|
+
type: "uint48",
|
|
1092
|
+
internalType: "uint48"
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
name: "kind",
|
|
1096
|
+
type: "uint16",
|
|
1097
|
+
internalType: "uint16"
|
|
1098
|
+
},
|
|
1099
|
+
{
|
|
1100
|
+
name: "documentHash",
|
|
1101
|
+
type: "bytes32",
|
|
1102
|
+
internalType: "bytes32"
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
name: "cancelled",
|
|
1106
|
+
type: "bool",
|
|
1107
|
+
internalType: "bool"
|
|
1108
|
+
}
|
|
1109
|
+
],
|
|
1110
|
+
stateMutability: "view"
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
type: "function",
|
|
1114
|
+
name: "createCommitment",
|
|
1115
|
+
inputs: [{
|
|
1116
|
+
name: "input",
|
|
1117
|
+
type: "tuple",
|
|
1118
|
+
internalType: "struct CapxulPaymentsV2.CommitmentInput",
|
|
1119
|
+
components: [
|
|
1120
|
+
{
|
|
1121
|
+
name: "settlementId",
|
|
1122
|
+
type: "bytes32",
|
|
1123
|
+
internalType: "bytes32"
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
name: "recipient",
|
|
1127
|
+
type: "address",
|
|
1128
|
+
internalType: "address"
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
name: "token",
|
|
1132
|
+
type: "address",
|
|
1133
|
+
internalType: "address"
|
|
1134
|
+
},
|
|
1135
|
+
{
|
|
1136
|
+
name: "totalAmount",
|
|
1137
|
+
type: "uint256",
|
|
1138
|
+
internalType: "uint256"
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
name: "startTime",
|
|
1142
|
+
type: "uint48",
|
|
1143
|
+
internalType: "uint48"
|
|
1144
|
+
},
|
|
1145
|
+
{
|
|
1146
|
+
name: "cliffTime",
|
|
1147
|
+
type: "uint48",
|
|
1148
|
+
internalType: "uint48"
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
name: "endTime",
|
|
1152
|
+
type: "uint48",
|
|
1153
|
+
internalType: "uint48"
|
|
1154
|
+
},
|
|
1155
|
+
{
|
|
1156
|
+
name: "kind",
|
|
1157
|
+
type: "uint16",
|
|
1158
|
+
internalType: "uint16"
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
name: "documentHash",
|
|
1162
|
+
type: "bytes32",
|
|
1163
|
+
internalType: "bytes32"
|
|
1164
|
+
}
|
|
1165
|
+
]
|
|
1166
|
+
}],
|
|
1167
|
+
outputs: [{
|
|
1168
|
+
name: "commitmentId",
|
|
1169
|
+
type: "uint256",
|
|
1170
|
+
internalType: "uint256"
|
|
1171
|
+
}],
|
|
1172
|
+
stateMutability: "nonpayable"
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
type: "function",
|
|
1176
|
+
name: "nextCommitmentId",
|
|
1177
|
+
inputs: [],
|
|
1178
|
+
outputs: [{
|
|
1179
|
+
name: "",
|
|
1180
|
+
type: "uint256",
|
|
1181
|
+
internalType: "uint256"
|
|
1182
|
+
}],
|
|
1183
|
+
stateMutability: "view"
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
type: "function",
|
|
1187
|
+
name: "redirect",
|
|
1188
|
+
inputs: [
|
|
1189
|
+
{
|
|
1190
|
+
name: "commitmentId",
|
|
1191
|
+
type: "uint256",
|
|
1192
|
+
internalType: "uint256"
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
name: "recipient",
|
|
1196
|
+
type: "address",
|
|
1197
|
+
internalType: "address"
|
|
1198
|
+
},
|
|
1199
|
+
{
|
|
1200
|
+
name: "documentHash",
|
|
1201
|
+
type: "bytes32",
|
|
1202
|
+
internalType: "bytes32"
|
|
1203
|
+
}
|
|
1204
|
+
],
|
|
1205
|
+
outputs: [],
|
|
1206
|
+
stateMutability: "nonpayable"
|
|
1207
|
+
},
|
|
1208
|
+
{
|
|
1209
|
+
type: "function",
|
|
1210
|
+
name: "send",
|
|
1211
|
+
inputs: [{
|
|
1212
|
+
name: "item",
|
|
1213
|
+
type: "tuple",
|
|
1214
|
+
internalType: "struct CapxulPaymentsV2.PaymentItem",
|
|
1215
|
+
components: [
|
|
1216
|
+
{
|
|
1217
|
+
name: "settlementId",
|
|
1218
|
+
type: "bytes32",
|
|
1219
|
+
internalType: "bytes32"
|
|
1220
|
+
},
|
|
1221
|
+
{
|
|
1222
|
+
name: "recipient",
|
|
1223
|
+
type: "address",
|
|
1224
|
+
internalType: "address"
|
|
1225
|
+
},
|
|
1226
|
+
{
|
|
1227
|
+
name: "token",
|
|
1228
|
+
type: "address",
|
|
1229
|
+
internalType: "address"
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
name: "amount",
|
|
1233
|
+
type: "uint256",
|
|
1234
|
+
internalType: "uint256"
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
name: "kind",
|
|
1238
|
+
type: "uint16",
|
|
1239
|
+
internalType: "uint16"
|
|
1240
|
+
},
|
|
1241
|
+
{
|
|
1242
|
+
name: "documentHash",
|
|
1243
|
+
type: "bytes32",
|
|
1244
|
+
internalType: "bytes32"
|
|
1245
|
+
}
|
|
1246
|
+
]
|
|
1247
|
+
}],
|
|
1248
|
+
outputs: [],
|
|
1249
|
+
stateMutability: "nonpayable"
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
type: "function",
|
|
1253
|
+
name: "sendBatch",
|
|
1254
|
+
inputs: [{
|
|
1255
|
+
name: "items",
|
|
1256
|
+
type: "tuple[]",
|
|
1257
|
+
internalType: "struct CapxulPaymentsV2.PaymentItem[]",
|
|
1258
|
+
components: [
|
|
1259
|
+
{
|
|
1260
|
+
name: "settlementId",
|
|
1261
|
+
type: "bytes32",
|
|
1262
|
+
internalType: "bytes32"
|
|
1263
|
+
},
|
|
1264
|
+
{
|
|
1265
|
+
name: "recipient",
|
|
1266
|
+
type: "address",
|
|
1267
|
+
internalType: "address"
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
name: "token",
|
|
1271
|
+
type: "address",
|
|
1272
|
+
internalType: "address"
|
|
1273
|
+
},
|
|
1274
|
+
{
|
|
1275
|
+
name: "amount",
|
|
1276
|
+
type: "uint256",
|
|
1277
|
+
internalType: "uint256"
|
|
1278
|
+
},
|
|
1279
|
+
{
|
|
1280
|
+
name: "kind",
|
|
1281
|
+
type: "uint16",
|
|
1282
|
+
internalType: "uint16"
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
name: "documentHash",
|
|
1286
|
+
type: "bytes32",
|
|
1287
|
+
internalType: "bytes32"
|
|
1288
|
+
}
|
|
1289
|
+
]
|
|
1290
|
+
}],
|
|
1291
|
+
outputs: [],
|
|
1292
|
+
stateMutability: "nonpayable"
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
type: "function",
|
|
1296
|
+
name: "vestedAmount",
|
|
1297
|
+
inputs: [{
|
|
1298
|
+
name: "commitmentId",
|
|
1299
|
+
type: "uint256",
|
|
1300
|
+
internalType: "uint256"
|
|
1301
|
+
}],
|
|
1302
|
+
outputs: [{
|
|
1303
|
+
name: "",
|
|
1304
|
+
type: "uint256",
|
|
1305
|
+
internalType: "uint256"
|
|
1306
|
+
}],
|
|
1307
|
+
stateMutability: "view"
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
type: "event",
|
|
1311
|
+
name: "CommitmentCancelled",
|
|
1312
|
+
inputs: [
|
|
1313
|
+
{
|
|
1314
|
+
name: "commitmentId",
|
|
1315
|
+
type: "uint256",
|
|
1316
|
+
indexed: true,
|
|
1317
|
+
internalType: "uint256"
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
name: "settlementId",
|
|
1321
|
+
type: "bytes32",
|
|
1322
|
+
indexed: true,
|
|
1323
|
+
internalType: "bytes32"
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
name: "creator",
|
|
1327
|
+
type: "address",
|
|
1328
|
+
indexed: true,
|
|
1329
|
+
internalType: "address"
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: "vestedUnclaimed",
|
|
1333
|
+
type: "uint256",
|
|
1334
|
+
indexed: false,
|
|
1335
|
+
internalType: "uint256"
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
name: "unvestedReturned",
|
|
1339
|
+
type: "uint256",
|
|
1340
|
+
indexed: false,
|
|
1341
|
+
internalType: "uint256"
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
name: "documentHash",
|
|
1345
|
+
type: "bytes32",
|
|
1346
|
+
indexed: false,
|
|
1347
|
+
internalType: "bytes32"
|
|
1348
|
+
}
|
|
1349
|
+
],
|
|
1350
|
+
anonymous: false
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
type: "event",
|
|
1354
|
+
name: "CommitmentCreated",
|
|
1355
|
+
inputs: [
|
|
1356
|
+
{
|
|
1357
|
+
name: "commitmentId",
|
|
1358
|
+
type: "uint256",
|
|
1359
|
+
indexed: true,
|
|
1360
|
+
internalType: "uint256"
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
name: "settlementId",
|
|
1364
|
+
type: "bytes32",
|
|
1365
|
+
indexed: true,
|
|
1366
|
+
internalType: "bytes32"
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
name: "creator",
|
|
1370
|
+
type: "address",
|
|
1371
|
+
indexed: true,
|
|
1372
|
+
internalType: "address"
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
name: "recipient",
|
|
1376
|
+
type: "address",
|
|
1377
|
+
indexed: false,
|
|
1378
|
+
internalType: "address"
|
|
1379
|
+
},
|
|
1380
|
+
{
|
|
1381
|
+
name: "token",
|
|
1382
|
+
type: "address",
|
|
1383
|
+
indexed: false,
|
|
1384
|
+
internalType: "address"
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
name: "totalAmount",
|
|
1388
|
+
type: "uint256",
|
|
1389
|
+
indexed: false,
|
|
1390
|
+
internalType: "uint256"
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
name: "startTime",
|
|
1394
|
+
type: "uint48",
|
|
1395
|
+
indexed: false,
|
|
1396
|
+
internalType: "uint48"
|
|
1397
|
+
},
|
|
1398
|
+
{
|
|
1399
|
+
name: "cliffTime",
|
|
1400
|
+
type: "uint48",
|
|
1401
|
+
indexed: false,
|
|
1402
|
+
internalType: "uint48"
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
name: "endTime",
|
|
1406
|
+
type: "uint48",
|
|
1407
|
+
indexed: false,
|
|
1408
|
+
internalType: "uint48"
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
name: "kind",
|
|
1412
|
+
type: "uint16",
|
|
1413
|
+
indexed: false,
|
|
1414
|
+
internalType: "uint16"
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
name: "documentHash",
|
|
1418
|
+
type: "bytes32",
|
|
1419
|
+
indexed: false,
|
|
1420
|
+
internalType: "bytes32"
|
|
1421
|
+
}
|
|
1422
|
+
],
|
|
1423
|
+
anonymous: false
|
|
1424
|
+
},
|
|
1425
|
+
{
|
|
1426
|
+
type: "event",
|
|
1427
|
+
name: "CommitmentRedirected",
|
|
1428
|
+
inputs: [
|
|
1429
|
+
{
|
|
1430
|
+
name: "commitmentId",
|
|
1431
|
+
type: "uint256",
|
|
1432
|
+
indexed: true,
|
|
1433
|
+
internalType: "uint256"
|
|
1434
|
+
},
|
|
1435
|
+
{
|
|
1436
|
+
name: "settlementId",
|
|
1437
|
+
type: "bytes32",
|
|
1438
|
+
indexed: true,
|
|
1439
|
+
internalType: "bytes32"
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
name: "oldRecipient",
|
|
1443
|
+
type: "address",
|
|
1444
|
+
indexed: true,
|
|
1445
|
+
internalType: "address"
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
name: "newRecipient",
|
|
1449
|
+
type: "address",
|
|
1450
|
+
indexed: false,
|
|
1451
|
+
internalType: "address"
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
name: "documentHash",
|
|
1455
|
+
type: "bytes32",
|
|
1456
|
+
indexed: false,
|
|
1457
|
+
internalType: "bytes32"
|
|
1458
|
+
}
|
|
1459
|
+
],
|
|
1460
|
+
anonymous: false
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
type: "event",
|
|
1464
|
+
name: "FundsClaimed",
|
|
1465
|
+
inputs: [
|
|
1466
|
+
{
|
|
1467
|
+
name: "commitmentId",
|
|
1468
|
+
type: "uint256",
|
|
1469
|
+
indexed: true,
|
|
1470
|
+
internalType: "uint256"
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
name: "settlementId",
|
|
1474
|
+
type: "bytes32",
|
|
1475
|
+
indexed: true,
|
|
1476
|
+
internalType: "bytes32"
|
|
1477
|
+
},
|
|
1478
|
+
{
|
|
1479
|
+
name: "recipient",
|
|
1480
|
+
type: "address",
|
|
1481
|
+
indexed: true,
|
|
1482
|
+
internalType: "address"
|
|
1483
|
+
},
|
|
1484
|
+
{
|
|
1485
|
+
name: "amount",
|
|
1486
|
+
type: "uint256",
|
|
1487
|
+
indexed: false,
|
|
1488
|
+
internalType: "uint256"
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
name: "documentHash",
|
|
1492
|
+
type: "bytes32",
|
|
1493
|
+
indexed: false,
|
|
1494
|
+
internalType: "bytes32"
|
|
1495
|
+
}
|
|
1496
|
+
],
|
|
1497
|
+
anonymous: false
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
type: "event",
|
|
1501
|
+
name: "PaymentSent",
|
|
1502
|
+
inputs: [
|
|
1503
|
+
{
|
|
1504
|
+
name: "settlementId",
|
|
1505
|
+
type: "bytes32",
|
|
1506
|
+
indexed: true,
|
|
1507
|
+
internalType: "bytes32"
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
name: "sender",
|
|
1511
|
+
type: "address",
|
|
1512
|
+
indexed: true,
|
|
1513
|
+
internalType: "address"
|
|
1514
|
+
},
|
|
1515
|
+
{
|
|
1516
|
+
name: "recipient",
|
|
1517
|
+
type: "address",
|
|
1518
|
+
indexed: true,
|
|
1519
|
+
internalType: "address"
|
|
1520
|
+
},
|
|
1521
|
+
{
|
|
1522
|
+
name: "token",
|
|
1523
|
+
type: "address",
|
|
1524
|
+
indexed: false,
|
|
1525
|
+
internalType: "address"
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
name: "amount",
|
|
1529
|
+
type: "uint256",
|
|
1530
|
+
indexed: false,
|
|
1531
|
+
internalType: "uint256"
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
name: "kind",
|
|
1535
|
+
type: "uint16",
|
|
1536
|
+
indexed: false,
|
|
1537
|
+
internalType: "uint16"
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
name: "documentHash",
|
|
1541
|
+
type: "bytes32",
|
|
1542
|
+
indexed: false,
|
|
1543
|
+
internalType: "bytes32"
|
|
1544
|
+
}
|
|
1545
|
+
],
|
|
1546
|
+
anonymous: false
|
|
1547
|
+
},
|
|
1548
|
+
{
|
|
1549
|
+
type: "error",
|
|
1550
|
+
name: "AlreadyCancelled",
|
|
1551
|
+
inputs: []
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
type: "error",
|
|
1555
|
+
name: "AlreadyClaimed",
|
|
1556
|
+
inputs: []
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
type: "error",
|
|
1560
|
+
name: "DocumentHashMismatch",
|
|
1561
|
+
inputs: [{
|
|
1562
|
+
name: "expected",
|
|
1563
|
+
type: "bytes32",
|
|
1564
|
+
internalType: "bytes32"
|
|
1565
|
+
}, {
|
|
1566
|
+
name: "supplied",
|
|
1567
|
+
type: "bytes32",
|
|
1568
|
+
internalType: "bytes32"
|
|
1569
|
+
}]
|
|
1570
|
+
},
|
|
1571
|
+
{
|
|
1572
|
+
type: "error",
|
|
1573
|
+
name: "InvalidTimeParams",
|
|
1574
|
+
inputs: []
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
type: "error",
|
|
1578
|
+
name: "NotCreator",
|
|
1579
|
+
inputs: []
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
type: "error",
|
|
1583
|
+
name: "NotRecipient",
|
|
1584
|
+
inputs: []
|
|
1585
|
+
},
|
|
1586
|
+
{
|
|
1587
|
+
type: "error",
|
|
1588
|
+
name: "NothingToClaim",
|
|
1589
|
+
inputs: []
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
type: "error",
|
|
1593
|
+
name: "SettlementIdConsumed",
|
|
1594
|
+
inputs: [{
|
|
1595
|
+
name: "settlementId",
|
|
1596
|
+
type: "bytes32",
|
|
1597
|
+
internalType: "bytes32"
|
|
1598
|
+
}]
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
type: "error",
|
|
1602
|
+
name: "TokenCallReturnedFalse",
|
|
1603
|
+
inputs: [{
|
|
1604
|
+
name: "token",
|
|
1605
|
+
type: "address",
|
|
1606
|
+
internalType: "address"
|
|
1607
|
+
}]
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
type: "error",
|
|
1611
|
+
name: "TokenHasNoCode",
|
|
1612
|
+
inputs: [{
|
|
1613
|
+
name: "token",
|
|
1614
|
+
type: "address",
|
|
1615
|
+
internalType: "address"
|
|
1616
|
+
}]
|
|
1617
|
+
},
|
|
1618
|
+
{
|
|
1619
|
+
type: "error",
|
|
1620
|
+
name: "ZeroAddress",
|
|
1621
|
+
inputs: []
|
|
1622
|
+
},
|
|
1623
|
+
{
|
|
1624
|
+
type: "error",
|
|
1625
|
+
name: "ZeroAmount",
|
|
1626
|
+
inputs: []
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
type: "error",
|
|
1630
|
+
name: "ZeroDocumentHash",
|
|
1631
|
+
inputs: []
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
type: "error",
|
|
1635
|
+
name: "ZeroSettlementId",
|
|
1636
|
+
inputs: []
|
|
1637
|
+
}
|
|
1638
|
+
];
|
|
1639
|
+
/** Immutable CapxulPaymentsV2 deployment on Base Sepolia. */
|
|
1640
|
+
const CAPXUL_PAYMENTS_V2_ADDRESS = "0x7a5c25aB7ce91d7a475B71cd1ec33E230291f8a4";
|
|
1641
|
+
//#endregion
|
|
1642
|
+
//#region ../config/src/route.ts
|
|
1643
|
+
/** USDX on Base Sepolia — the only settlement token in v1. */
|
|
1644
|
+
const USDX_BASE_SEPOLIA_TOKEN = {
|
|
1645
|
+
chainId: BASE_SEPOLIA_CHAIN_ID,
|
|
1646
|
+
address: USDX_ADDRESS_BASE_SEPOLIA,
|
|
1647
|
+
decimals: 6
|
|
1648
|
+
};
|
|
1649
|
+
USDX_BASE_SEPOLIA_TOKEN.chainId;
|
|
1650
|
+
USDX_BASE_SEPOLIA_TOKEN.chainId;
|
|
1651
|
+
10n ** BigInt(6);
|
|
1652
|
+
function normalizeOrgRoleLabel(label) {
|
|
1653
|
+
const normalized = label.trim().replace(/\s+/g, " ");
|
|
1654
|
+
if (normalized.length === 0) throw Errors.invalidInput("role.label", "must be a non-empty role label");
|
|
1655
|
+
return normalized;
|
|
1656
|
+
}
|
|
1657
|
+
function orgRoleKeyForLabel(label) {
|
|
1658
|
+
return keccak256(toBytes(normalizeOrgRoleLabel(label).toLowerCase()));
|
|
1659
|
+
}
|
|
1660
|
+
padHex(stringToHex("FM_DAILY"), {
|
|
1661
|
+
size: 32,
|
|
1662
|
+
dir: "right"
|
|
1663
|
+
}), padHex(stringToHex("TL_DAILY"), {
|
|
1664
|
+
size: 32,
|
|
1665
|
+
dir: "right"
|
|
1666
|
+
});
|
|
1667
|
+
padHex(concat([MULTI_SEND_CALL_ONLY, "0x8d80ff0a"]), {
|
|
1668
|
+
dir: "right",
|
|
1669
|
+
size: 32
|
|
1670
|
+
});
|
|
1671
|
+
function paymentsV2Signature(name) {
|
|
1672
|
+
const item = CAPXUL_PAYMENTS_V2_ABI.find((candidate) => candidate.type === "function" && candidate.name === name);
|
|
1673
|
+
if (item === void 0) throw new Error(`CapxulPaymentsV2 ABI has no ${name} function`);
|
|
1674
|
+
return toFunctionSignature(item);
|
|
1675
|
+
}
|
|
1676
|
+
paymentsV2Signature("send");
|
|
1677
|
+
paymentsV2Signature("sendBatch");
|
|
1678
|
+
paymentsV2Signature("createCommitment");
|
|
1679
|
+
paymentsV2Signature("cancel");
|
|
1680
|
+
paymentsV2Signature("redirect");
|
|
1681
|
+
new Map([
|
|
1682
|
+
["assignRoles(address,bytes32[],bool[])", "AssignRoles(address,bytes32[],bool[])"],
|
|
1683
|
+
["allowTarget(bytes32,address,uint8)", "AllowTarget(bytes32,address,uint8)"],
|
|
1684
|
+
["scopeTarget(bytes32,address)", "ScopeTarget(bytes32,address)"],
|
|
1685
|
+
["revokeTarget(bytes32,address)", "RevokeTarget(bytes32,address)"],
|
|
1686
|
+
["allowFunction(bytes32,address,bytes4,uint8)", "AllowFunction(bytes32,address,bytes4,uint8)"],
|
|
1687
|
+
["scopeFunction(bytes32,address,bytes4,(uint8,uint8,uint8,bytes)[],uint8)", "ScopeFunction(bytes32,address,bytes4,(uint8,uint8,uint8,bytes)[],uint8)"],
|
|
1688
|
+
["revokeFunction(bytes32,address,bytes4)", "RevokeFunction(bytes32,address,bytes4)"],
|
|
1689
|
+
["setAllowance(bytes32,uint128,uint128,uint128,uint64,uint64)", "SetAllowance(bytes32,uint128,uint128,uint128,uint64,uint64)"]
|
|
1690
|
+
].map(([functionSignature, eventSignature]) => [toFunctionSelector(functionSignature), toEventSelector(eventSignature)]));
|
|
1691
|
+
//#endregion
|
|
1692
|
+
//#region src/ports/auth-client.ts
|
|
1693
|
+
var AuthClientError = class extends Data.TaggedError("AuthClientError") {};
|
|
1694
|
+
var AuthClientPortTag = class extends Context.Service()("@capxul/sdk/ports/AuthClientPort") {};
|
|
1695
|
+
//#endregion
|
|
1696
|
+
//#region src/adapters/auth-client/effect-port.ts
|
|
1697
|
+
function authClientPortFromPromiseAdapter(adapter) {
|
|
1698
|
+
return {
|
|
1699
|
+
canSendOtp: (input, options) => fromResult("canSendOtp", () => adapter.canSendOtp(input, options)),
|
|
1700
|
+
sendOtp: (input, options) => fromResult("sendOtp", () => adapter.sendOtp(input, options)),
|
|
1701
|
+
verifyOtp: (input, options) => fromResult("verifyOtp", () => adapter.verifyOtp(input, options)),
|
|
1702
|
+
getSession: (options) => fromResult("getSession", () => adapter.getSession(options)),
|
|
1703
|
+
signOut: (options) => fromResult("signOut", () => adapter.signOut(options)),
|
|
1704
|
+
getConvexJwt: (options) => fromResult("getConvexJwt", () => adapter.getConvexJwt(options))
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
function fromResult(operation, run) {
|
|
1708
|
+
return Effect.tryPromise({
|
|
1709
|
+
try: run,
|
|
1710
|
+
catch: (cause) => new AuthClientError({
|
|
1711
|
+
operation,
|
|
1712
|
+
kind: "thrown",
|
|
1713
|
+
cause
|
|
1714
|
+
})
|
|
1715
|
+
}).pipe(Effect.flatMap((result) => result.ok ? Effect.succeed(result.value) : Effect.fail(new AuthClientError({
|
|
1716
|
+
operation,
|
|
1717
|
+
kind: errorKind(result.error),
|
|
1718
|
+
cause: result.error
|
|
1719
|
+
}))));
|
|
1720
|
+
}
|
|
1721
|
+
function errorKind(error) {
|
|
1722
|
+
if (error.code === "CANCELLED") return "cancelled";
|
|
1723
|
+
if (error.code === "NETWORK_ERROR") return "network";
|
|
1724
|
+
if (error.code === "INVALID_INPUT" || error.code === "OTP_EXPIRED") return "validation";
|
|
1725
|
+
return "provider";
|
|
1726
|
+
}
|
|
1727
|
+
//#endregion
|
|
1728
|
+
//#region src/ports/clock.ts
|
|
1729
|
+
var ClockError = class extends Data.TaggedError("ClockError") {};
|
|
1730
|
+
var ClockPortTag = class extends Context.Service()("@capxul/sdk/ports/ClockPort") {};
|
|
1731
|
+
//#endregion
|
|
655
1732
|
//#region src/ports/auth-cache.ts
|
|
656
1733
|
var AuthCacheError = class extends Data.TaggedError("AuthCacheError") {};
|
|
657
1734
|
var AuthCachePortTag = class extends Context.Service()("@capxul/sdk/ports/AuthCachePort") {};
|
|
@@ -760,4 +1837,24 @@ Layer.effect(AuthCachePortTag, Effect.sync(() => new InMemoryAuthCacheAdapter())
|
|
|
760
1837
|
cause
|
|
761
1838
|
}))));
|
|
762
1839
|
//#endregion
|
|
763
|
-
|
|
1840
|
+
//#region src/adapters/_shared/clock.ts
|
|
1841
|
+
async function readClockNow(clock) {
|
|
1842
|
+
try {
|
|
1843
|
+
const result = await Effect.runPromise(Effect.result(clock.now));
|
|
1844
|
+
if (Result.isFailure(result)) return {
|
|
1845
|
+
ok: false,
|
|
1846
|
+
error: Errors.providerError("clock", "now", result.failure)
|
|
1847
|
+
};
|
|
1848
|
+
return {
|
|
1849
|
+
ok: true,
|
|
1850
|
+
value: result.success
|
|
1851
|
+
};
|
|
1852
|
+
} catch (cause) {
|
|
1853
|
+
return {
|
|
1854
|
+
ok: false,
|
|
1855
|
+
error: Errors.providerError("clock", "now", cause)
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
//#endregion
|
|
1860
|
+
export { CHAIN_UPSTREAMS as $, toBudgetId as A, toOrgId as B, ZERO_BYTES32 as C, toAllowedOrigin as D, toAddress as E, toEmail as F, toRoleKey as G, toPayrollGroupId as H, toEpochMs as I, CAPXUL_ERROR_CODES as J, toSessionToken as K, toEpochSeconds as L, toCountryCode as M, toCurrencyCode as N, toAppId as O, toDurationMs as P, isCapxulError as Q, toJwtToken as R, WEI_RE as S, toAccountId as T, toPayrollRunId as U, toPartyId as V, toPublishableKey as W, EXPECTED_OPERATION_OUTCOMES as X, CapxulError as Y, Errors as Z, deriveCapxulSafeAddress as _, parseCachedJwt as a, failureFingerprint as at, EVM_ADDRESS_RE as b, ClockError as c, revertSummaryText as ct, AuthClientError as d, FAILURE_MODES as et, AuthClientPortTag as f, BASE_SEPOLIA_CHAIN_ID as g, normalizeBindingEmail as h, parseAuthSession as i, decodeChainCause as it, toChainId as j, toAuthUserId as k, ClockPortTag as l, containsSensitiveMaterial as lt, CAPXUL_PAYMENTS_V2_ADDRESS as m, InMemoryAuthCacheAdapter as n, chainCauseProperties as nt, AuthCacheError as o, isChainUpstream as ot, orgRoleKeyForLabel as p, decodeConvexError as q, BrowserAuthCacheAdapter as r, chainEvidenceLabel as rt, AuthCachePortTag as s, isFailureMode as st, readClockNow as t, boundedResponseHeaders as tt, authClientPortFromPromiseAdapter as u, redactSecrets as ut, APP_ID_RE as v, currencySymbolFor as w, SUPPORTED_CURRENCY_CODES as x, BYTES32_RE as y, toKycTier as z };
|