@chipi-stack/backend 14.15.1 → 14.17.0

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { shortString, hash, CallData, ec, RpcProvider, Account, num, CairoCustomEnum, CairoOption, CairoOptionVariant, cairo, typedData, uint256 } from 'starknet';
2
- import { SHHH_KIND_GAS_OVERHEAD, isValidApiKey, ChipiAuthError, STARKNET_NETWORKS, API_VERSIONING, validateErrorResponse, ChipiApiError, handleApiError, getWalletTypeFromClassHash, WALLET_CLASS_HASHES, WALLET_RPC_ENDPOINTS, SHHH_VERIFIER_CLASS_HASHES, API_ENDPOINTS, ChipiTransactionError, formatAmount, SKU_CONTRACTS, CARRIER_IDS, SERVICE_TYPES, ChipiSessionError, SESSION_ERRORS, SESSION_ENTRYPOINTS, SESSION_DEFAULTS, withRpcFallback, CONTRACT_ADDRESSES, TOKEN_DECIMALS } from '@chipi-stack/shared';
2
+ import { SHHH_VERIFIER_CLASS_HASHES, SHHH_KIND_GAS_OVERHEAD, isValidApiKey, ChipiAuthError, STARKNET_NETWORKS, API_VERSIONING, validateErrorResponse, ChipiApiError, handleApiError, getWalletTypeFromClassHash, WALLET_CLASS_HASHES, WALLET_RPC_ENDPOINTS, API_ENDPOINTS, ChipiTransactionError, formatAmount, SKU_CONTRACTS, CARRIER_IDS, SERVICE_TYPES, ChipiSessionError, SESSION_ERRORS, SESSION_ENTRYPOINTS, SESSION_DEFAULTS, withRpcFallback, CONTRACT_ADDRESSES, TOKEN_DECIMALS } from '@chipi-stack/shared';
3
3
  import CryptoES from 'crypto-es';
4
4
  import { randomBytes } from 'crypto';
5
5
  import { STARKNET_CONTRACTS, Chain } from '@chipi-stack/types';
@@ -168,9 +168,9 @@ function assertValidV2Snip12Envelope(envelope) {
168
168
  }
169
169
  return envelope[1];
170
170
  }
171
- function _tryDecodeShortString(felt) {
171
+ function _tryDecodeShortString(felt2) {
172
172
  try {
173
- return shortString.decodeShortString("0x" + felt.toString(16));
173
+ return shortString.decodeShortString("0x" + felt2.toString(16));
174
174
  } catch {
175
175
  return null;
176
176
  }
@@ -194,14 +194,20 @@ function buildThresholdEnvelope(args) {
194
194
  );
195
195
  }
196
196
  seenOwners.add(key);
197
- out.push(BigInt(env.length));
198
- for (const felt of env) {
199
- if (felt < 0n) {
197
+ if (env.length < 3) {
198
+ throw new Error(
199
+ `THRESH: inner envelope ${i} must have at least [tag, owner_id, kind_tag]; got ${env.length} felts`
200
+ );
201
+ }
202
+ const frame = env.slice(1);
203
+ out.push(BigInt(frame.length));
204
+ for (const felt2 of frame) {
205
+ if (felt2 < 0n) {
200
206
  throw new RangeError(
201
207
  `THRESH: envelope ${i} contains negative felt (cannot serialize as felt252)`
202
208
  );
203
209
  }
204
- out.push(felt);
210
+ out.push(felt2);
205
211
  }
206
212
  }
207
213
  return out;
@@ -234,15 +240,26 @@ function parseThresholdEnvelope(envelope) {
234
240
  `THRESH: inner ${i} would overflow envelope (env_len ${envLen}, cursor ${cursor}, total ${envelope.length})`
235
241
  );
236
242
  }
237
- const inner = envelope.slice(cursor, cursor + envLen);
238
- for (const felt of inner) {
239
- if (felt < 0n) {
243
+ const frame = envelope.slice(cursor, cursor + envLen);
244
+ for (const felt2 of frame) {
245
+ if (felt2 < 0n) {
240
246
  throw new RangeError(
241
247
  `THRESH: inner ${i} contains negative felt (cannot serialize as felt252)`
242
248
  );
243
249
  }
244
250
  }
245
- const ownerId = assertValidV2Snip12Envelope(inner);
251
+ const ownerId = frame[0];
252
+ if (ownerId >= 0x100000000n) {
253
+ if (ownerId === V2_THRESHOLD_TAG) {
254
+ throw new Error(
255
+ `THRESH: inner ${i}: nested threshold envelopes are not allowed; inner frames are [owner_id, kind_tag, ...payload]`
256
+ );
257
+ }
258
+ throw new Error(
259
+ `THRESH: inner ${i} owner_id 0x${ownerId.toString(16)} is not a u32; inner frames are [owner_id, kind_tag, ...payload] with no V2_SNIP12 tag`
260
+ );
261
+ }
262
+ const inner = [V2_SNIP12_TAG, ...frame];
246
263
  const key = ownerId.toString();
247
264
  if (seenOwners.has(key)) {
248
265
  throw new Error(
@@ -545,6 +562,7 @@ var init_stark = __esm({
545
562
  var execute_paymaster_raw_exports = {};
546
563
  __export(execute_paymaster_raw_exports, {
547
564
  executeShhhSponsoredRaw: () => executeShhhSponsoredRaw,
565
+ newOeNonce: () => newOeNonce,
548
566
  resolveShhhChainId: () => resolveShhhChainId,
549
567
  serializeExecuteFromOutsideV2Calldata: () => serializeExecuteFromOutsideV2Calldata
550
568
  });
@@ -882,13 +900,26 @@ function unwrapPrepareResponse(response) {
882
900
  apiMessage ?? "Invalid response from /transactions/prepare-typed-data: typedData is missing"
883
901
  );
884
902
  }
903
+ function feltEquals(value, expected) {
904
+ try {
905
+ return BigInt(value) === expected;
906
+ } catch {
907
+ return false;
908
+ }
909
+ }
885
910
  function normalizeSignature(signature) {
886
911
  if (Array.isArray(signature)) {
887
912
  if (signature.length < 2) {
888
913
  throw new Error(`Array signature must have at least 2 elements, got ${signature.length}`);
889
914
  }
890
- const r = signature[0];
891
- const s = signature[1];
915
+ const isArgentSingle = signature.length === 5 && feltEquals(signature[0], 1n) && feltEquals(signature[1], 0n);
916
+ if (signature.length !== 2 && !isArgentSingle) {
917
+ throw new Error(
918
+ `Unsupported ${signature.length}-felt signature: expected [r, s] or Argent [1, 0, pubkey, r, s].`
919
+ );
920
+ }
921
+ const r = isArgentSingle ? signature[3] : signature[0];
922
+ const s = isArgentSingle ? signature[4] : signature[1];
892
923
  if (r == null || s == null) {
893
924
  throw new Error(`Signature elements must not be null/undefined. Got r=${r}, s=${s}`);
894
925
  }
@@ -1603,7 +1634,10 @@ var ChipiWallets = class {
1603
1634
  publicKey,
1604
1635
  walletType,
1605
1636
  starkKeyPubAX,
1606
- ...customClassHash && { classHash: customClassHash },
1637
+ // The class the address above was computed with. SHHH always
1638
+ // names it: chipi-back's default for clients that name none is
1639
+ // the class SDKs up to 14.16 used (V8.4), not ours.
1640
+ ...(customClassHash || isShhh) && { classHash: accountClassHash },
1607
1641
  // SHHH: tell chipi-back which signer kind + pubkey felts
1608
1642
  // produced this deployment so it can validate against the
1609
1643
  // expected SHHH constructor shape and populate the new
@@ -1615,6 +1649,11 @@ var ChipiWallets = class {
1615
1649
  }
1616
1650
  });
1617
1651
  const { typedData: typedData2, accountClassHash: accountClassHashResponse } = typedDataResponse;
1652
+ if (isShhh && (!accountClassHashResponse || BigInt(accountClassHashResponse) !== BigInt(accountClassHash))) {
1653
+ throw new Error(
1654
+ `prepare-creation returned class ${accountClassHashResponse ?? "(none)"}, but the wallet address was computed with ${accountClassHash}. Not deploying.`
1655
+ );
1656
+ }
1618
1657
  let userSignaturePayload;
1619
1658
  if (isShhh) {
1620
1659
  userSignaturePayload = {
@@ -1953,9 +1992,9 @@ var ChipiTransactions = class {
1953
1992
  /**
1954
1993
  * Get on-chain transaction status
1955
1994
  */
1956
- async getTransactionStatus(hash11, bearerToken) {
1995
+ async getTransactionStatus(hash13, bearerToken) {
1957
1996
  return this.client.get({
1958
- endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash11}/status`,
1997
+ endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash13}/status`,
1959
1998
  bearerToken
1960
1999
  });
1961
2000
  }
@@ -2133,14 +2172,14 @@ function normalizeEntrypoints(entrypoints) {
2133
2172
  return entrypoints.map((entry) => {
2134
2173
  const value = String(entry).trim();
2135
2174
  if (HEX_FELT.test(value) || DECIMAL_FELT.test(value)) {
2136
- const felt = BigInt(value);
2137
- if (felt >= FIELD_PRIME) {
2175
+ const felt2 = BigInt(value);
2176
+ if (felt2 >= FIELD_PRIME) {
2138
2177
  throw new ChipiSessionError(
2139
2178
  `Session entrypoint ${value} is not a valid felt (>= field prime).`,
2140
2179
  SESSION_ERRORS.SESSION_ENTRYPOINT_NOT_ALLOWED
2141
2180
  );
2142
2181
  }
2143
- return num.toHex(felt);
2182
+ return num.toHex(felt2);
2144
2183
  }
2145
2184
  if (CAIRO_IDENTIFIER.test(value)) {
2146
2185
  return hash.getSelectorFromName(value);
@@ -3542,6 +3581,122 @@ var ChipiAi = class {
3542
3581
  });
3543
3582
  }
3544
3583
  };
3584
+ var STARKNET_SIGNATURE_VALID = "0x56414c4944";
3585
+ function toFeltHex(value) {
3586
+ return num.toHex(BigInt(value));
3587
+ }
3588
+ function normalizeStarknetAddress(address) {
3589
+ return `0x${BigInt(address).toString(16).padStart(64, "0")}`;
3590
+ }
3591
+ function isContractNotFound(err) {
3592
+ const e = err;
3593
+ if (e?.baseError?.code === 20 || e?.code === 20) return true;
3594
+ return /contract not found/i.test(e?.message ?? String(err));
3595
+ }
3596
+ async function isValidStarknetSignature(provider, accountAddress, messageHash, signature) {
3597
+ try {
3598
+ const sig = signature.map(toFeltHex);
3599
+ const result = await provider.callContract({
3600
+ contractAddress: normalizeStarknetAddress(accountAddress),
3601
+ entrypoint: "is_valid_signature",
3602
+ calldata: [toFeltHex(messageHash), toFeltHex(sig.length), ...sig]
3603
+ });
3604
+ const first = result?.[0];
3605
+ if (first !== void 0 && BigInt(first) === BigInt(STARKNET_SIGNATURE_VALID)) {
3606
+ return { valid: true };
3607
+ }
3608
+ return { valid: false, reason: "INVALID_SIGNATURE" };
3609
+ } catch (err) {
3610
+ if (isContractNotFound(err)) return { valid: false, reason: "ACCOUNT_NOT_DEPLOYED" };
3611
+ return {
3612
+ valid: false,
3613
+ reason: "INVALID_SIGNATURE",
3614
+ detail: err instanceof Error ? err.message : String(err)
3615
+ };
3616
+ }
3617
+ }
3618
+ var COUNTERFACTUAL_ACCOUNT_CLASSES = {
3619
+ /** OpenZeppelin AccountUpgradeable 3.0 (Bramble's default account). */
3620
+ OPENZEPPELIN_V3: "0x01d1777db36cdd06dd62cfde77b1b6ae06412af95d57a13dc40ac77b8a702381",
3621
+ /** Argent X / Ready 0.4 (`WALLET_CLASS_HASHES.READY`). */
3622
+ ARGENT_V0_4: "0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f"
3623
+ };
3624
+ function starkVerify(r, s, messageHash, publicKey) {
3625
+ const x = BigInt(publicKey).toString(16).padStart(64, "0");
3626
+ const sig = new ec.starkCurve.Signature(BigInt(r), BigInt(s));
3627
+ for (const prefix of ["02", "03"]) {
3628
+ try {
3629
+ if (ec.starkCurve.verify(sig, toFeltHex(messageHash), prefix + x)) return true;
3630
+ } catch {
3631
+ }
3632
+ }
3633
+ return false;
3634
+ }
3635
+ function verifyUndeployedStarknetSignature(deployment, messageHash, signature) {
3636
+ const classHash = normalizeStarknetAddress(deployment.class_hash);
3637
+ const calldata = deployment.calldata.map(toFeltHex);
3638
+ const sig = signature.map(toFeltHex);
3639
+ let publicKey;
3640
+ let r;
3641
+ let s;
3642
+ if (classHash === COUNTERFACTUAL_ACCOUNT_CLASSES.OPENZEPPELIN_V3) {
3643
+ if (calldata.length !== 1 || sig.length !== 2) {
3644
+ return { valid: false, reason: "INVALID_SIGNATURE" };
3645
+ }
3646
+ [publicKey] = calldata;
3647
+ [r, s] = sig;
3648
+ } else if (classHash === COUNTERFACTUAL_ACCOUNT_CLASSES.ARGENT_V0_4) {
3649
+ if (calldata.length !== 3 || BigInt(calldata[0]) !== 0n || BigInt(calldata[2]) !== 1n) {
3650
+ return { valid: false, reason: "UNSUPPORTED_ACCOUNT_CLASS" };
3651
+ }
3652
+ if (sig.length !== 5 || BigInt(sig[0]) !== 1n || BigInt(sig[1]) !== 0n) {
3653
+ return { valid: false, reason: "INVALID_SIGNATURE" };
3654
+ }
3655
+ if (BigInt(sig[2]) !== BigInt(calldata[1])) {
3656
+ return { valid: false, reason: "INVALID_SIGNATURE" };
3657
+ }
3658
+ publicKey = calldata[1];
3659
+ [, , , r, s] = sig;
3660
+ } else {
3661
+ return { valid: false, reason: "UNSUPPORTED_ACCOUNT_CLASS" };
3662
+ }
3663
+ const expected = hash.calculateContractAddressFromHash(
3664
+ toFeltHex(deployment.salt),
3665
+ classHash,
3666
+ calldata,
3667
+ 0
3668
+ );
3669
+ if (normalizeStarknetAddress(expected) !== normalizeStarknetAddress(deployment.address)) {
3670
+ return { valid: false, reason: "ADDRESS_MISMATCH" };
3671
+ }
3672
+ return starkVerify(r, s, messageHash, publicKey) ? { valid: true } : { valid: false, reason: "INVALID_SIGNATURE" };
3673
+ }
3674
+
3675
+ // src/x402/facilitator.ts
3676
+ var TRANSFER_SELECTOR2 = BigInt(hash.getSelectorFromName("transfer"));
3677
+ function shhhTransferMatches(oeCalldata, payload) {
3678
+ try {
3679
+ const felts = oeCalldata.map((v) => BigInt(v));
3680
+ const [, , , executeBefore, callsLen] = felts;
3681
+ if (callsLen !== 1n) return { ok: false, reason: "SHHH payment must be exactly one transfer" };
3682
+ const [to, selector, len, recipient, low, high] = felts.slice(5, 11);
3683
+ if (to !== BigInt(payload.asset) || selector !== TRANSFER_SELECTOR2 || len !== 3n) {
3684
+ return { ok: false, reason: "SHHH payment call is not a transfer of the payment asset" };
3685
+ }
3686
+ if (recipient !== BigInt(payload.toAddress)) {
3687
+ return { ok: false, reason: "SHHH payment pays a different recipient" };
3688
+ }
3689
+ if (low + (high << 128n) !== BigInt(payload.amount)) {
3690
+ return { ok: false, reason: "SHHH payment amount differs from the declared amount" };
3691
+ }
3692
+ if (executeBefore <= BigInt(Math.floor(Date.now() / 1e3))) {
3693
+ return { ok: false, reason: "SHHH payment has expired (execute_before in the past)" };
3694
+ }
3695
+ return { ok: true };
3696
+ } catch {
3697
+ return { ok: false, reason: "Malformed SHHH oeCalldata" };
3698
+ }
3699
+ }
3545
3700
  var InMemoryNonceStore = class {
3546
3701
  constructor() {
3547
3702
  this.used = /* @__PURE__ */ new Set();
@@ -3584,11 +3739,18 @@ var X402Facilitator = class _X402Facilitator {
3584
3739
  * Verify a payment signature is valid (doesn't execute the transfer).
3585
3740
  *
3586
3741
  * Checks:
3587
- * 1. Nonce has not been used (replay protection)
3588
- * 2. Payment has not expired (validUntil > now)
3589
- * 3. Asset is USDC mainnet
3590
- * 4. Amount is positive
3591
- * 5. Addresses are non-empty
3742
+ * 1. x402 version is 1
3743
+ * 2. Network is starknet-mainnet
3744
+ * 3. Nonce has not been used (replay protection)
3745
+ * 4. Payment has not expired (validUntil > now)
3746
+ * 5. Asset is USDC mainnet
3747
+ * 6. Amount is positive
3748
+ * 7. Addresses are non-empty
3749
+ * 8. Signature: with a `provider`, the payer account's `is_valid_signature`
3750
+ * must return 'VALID'. Without one, only its presence is checked (not a
3751
+ * cryptographic check). SHHH payloads must sign exactly one transfer
3752
+ * of `amount` of `asset` to `toAddress`; their signature is checked
3753
+ * on-chain at settle.
3592
3754
  */
3593
3755
  async verify(payment) {
3594
3756
  const { payload } = payment;
@@ -3644,6 +3806,8 @@ var X402Facilitator = class _X402Facilitator {
3644
3806
  if (!Array.isArray(oeCalldata) || oeCalldata.length === 0) {
3645
3807
  return { valid: false, reason: "Missing SHHH oeCalldata" };
3646
3808
  }
3809
+ const bound = shhhTransferMatches(oeCalldata, payment.payload);
3810
+ if (!bound.ok) return { valid: false, reason: bound.reason };
3647
3811
  return { valid: true };
3648
3812
  }
3649
3813
  if (!this.provider) {
@@ -3664,22 +3828,25 @@ var X402Facilitator = class _X402Facilitator {
3664
3828
  valid_until: String(payload.validUntil),
3665
3829
  nonce: payload.nonce
3666
3830
  });
3667
- const msgHash = typedData.getMessageHash(paymentTypedData, payload.fromAddress);
3831
+ let msgHash;
3668
3832
  try {
3669
- const result = await this.provider.callContract({
3670
- contractAddress: payload.fromAddress,
3671
- entrypoint: "is_valid_signature",
3672
- calldata: [msgHash, "2", payload.signature.r, payload.signature.s]
3673
- });
3674
- const VALID = "0x56414c4944";
3675
- if (result[0] === VALID || result[0] === BigInt(VALID).toString()) {
3676
- return { valid: true };
3677
- }
3678
- return { valid: false, reason: "Invalid SNIP-12 signature" };
3833
+ msgHash = typedData.getMessageHash(paymentTypedData, payload.fromAddress);
3679
3834
  } catch (err) {
3680
3835
  const message = err instanceof Error ? err.message : String(err);
3681
- return { valid: false, reason: `Signature verification failed: ${message}` };
3836
+ return { valid: false, reason: `Malformed payment: ${message}` };
3837
+ }
3838
+ const check = await isValidStarknetSignature(this.provider, payload.fromAddress, msgHash, [
3839
+ payload.signature.r,
3840
+ payload.signature.s
3841
+ ]);
3842
+ if (check.valid) return { valid: true };
3843
+ if (check.reason === "ACCOUNT_NOT_DEPLOYED") {
3844
+ return { valid: false, reason: "Payer account is not deployed" };
3682
3845
  }
3846
+ return {
3847
+ valid: false,
3848
+ reason: check.detail ? `Signature verification failed: ${check.detail}` : "Invalid SNIP-12 signature"
3849
+ };
3683
3850
  }
3684
3851
  /**
3685
3852
  * Settle a verified payment by executing the USDC transfer via paymaster.
@@ -3808,7 +3975,7 @@ var signTypedData = async ({
3808
3975
  throw error;
3809
3976
  }
3810
3977
  };
3811
- function toFeltHex(x) {
3978
+ function toFeltHex2(x) {
3812
3979
  return "0x" + x.toString(16).padStart(64, "0");
3813
3980
  }
3814
3981
  var signTypedDataArray = async ({
@@ -3838,7 +4005,7 @@ var signTypedDataArray = async ({
3838
4005
  messageHash,
3839
4006
  ownerIndex: 0n
3840
4007
  });
3841
- return envelope.map(toFeltHex);
4008
+ return envelope.map(toFeltHex2);
3842
4009
  }
3843
4010
  const provider = new RpcProvider({ nodeUrl: WALLET_RPC_ENDPOINTS[walletType] });
3844
4011
  const account = new Account({ provider, address: wallet.publicKey, signer: privateKeyDecrypted });
@@ -3846,144 +4013,643 @@ var signTypedDataArray = async ({
3846
4013
  return [r, s];
3847
4014
  };
3848
4015
 
3849
- // src/chipi-sdk.ts
3850
- var ChipiSDK = class {
3851
- constructor(config) {
3852
- this.client = new ChipiClient(config);
3853
- this.nodeUrl = config.nodeUrl || STARKNET_NETWORKS.MAINNET;
3854
- this.apiSecretKey = config.apiSecretKey;
3855
- this.wallets = new ChipiWallets(this.client);
3856
- this.transactions = new ChipiTransactions(this.client);
3857
- this.skuPurchases = new ChipiSkuPurchases(this.client);
3858
- this.skus = new ChipiSkus(this.client);
3859
- this.sessions = new ChipiSessions(this.client);
3860
- this.exchanges = new ChipiExchanges(this.client);
3861
- this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
3862
- this.ai = new ChipiAi(this.client, config.apiSecretKey, this.sessions);
3863
- this.executeTransaction = this.executeTransaction.bind(this);
3864
- this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
3865
- this.transfer = this.transfer.bind(this);
3866
- this.approve = this.approve.bind(this);
3867
- this.callAnyContract = this.callAnyContract.bind(this);
3868
- this.createWallet = this.createWallet.bind(this);
3869
- this.recordSendTransaction = this.recordSendTransaction.bind(this);
3870
- this.purchaseSku = this.purchaseSku.bind(this);
3871
- this.getUsdAmount = this.getUsdAmount.bind(this);
3872
- this.signTypedData = this.signTypedData.bind(this);
3873
- this.signTypedDataArray = this.signTypedDataArray.bind(this);
3874
- this.createPaymasterAdapter = this.createPaymasterAdapter.bind(this);
3875
- this.createX402Facilitator = this.createX402Facilitator.bind(this);
4016
+ // src/shhh/execute-external-owner.ts
4017
+ init_oe();
4018
+ init_execute_paymaster_raw();
4019
+ init_stark();
4020
+
4021
+ // src/shhh/signers/stark-snip12.ts
4022
+ init_compute_wallet_address();
4023
+ init_oe();
4024
+ var ROLE_OWNER = BigInt(shortString.encodeShortString("OWNER"));
4025
+ var ROLE_GUARDIAN = BigInt(shortString.encodeShortString("GUARDIAN"));
4026
+ var OP_ADD_OWNER = BigInt(shortString.encodeShortString("ADD_OWNER"));
4027
+ var OP_REMOVE_OWNER = BigInt(shortString.encodeShortString("REMOVE_OWNER"));
4028
+ var OP_ROTATE_OWNER = BigInt(shortString.encodeShortString("ROTATE_OWNER"));
4029
+ var OP_SET_THRESHOLD = BigInt(shortString.encodeShortString("SET_THRESHOLD"));
4030
+ var OP_ADD_VERIFIER_CLASS = BigInt(shortString.encodeShortString("ADD_VERIFIER"));
4031
+ var TIMELOCK_SECONDS = {
4032
+ ADD_OWNER: 172800,
4033
+ // 48h
4034
+ REMOVE_OWNER: 86400,
4035
+ // 24h
4036
+ ROTATE_OWNER: 86400,
4037
+ // 24h
4038
+ SET_THRESHOLD: 172800,
4039
+ // 48h
4040
+ ADD_VERIFIER: 172800,
4041
+ // 48h
4042
+ REMOVE_VERIFIER: 86400,
4043
+ // 24h
4044
+ ADD_GUARDIAN: 86400,
4045
+ // 24h
4046
+ REMOVE_GUARDIAN: 86400,
4047
+ // 24h
4048
+ RECOVERY: 604800
4049
+ // 7d — `TIMELOCK_RECOVERY`, the headline UX gate
4050
+ };
4051
+ var DEFAULT_OP_EXPIRY_SECONDS = 1209600;
4052
+ function _felt2(x, field = "felt") {
4053
+ const v = typeof x === "bigint" ? x : BigInt(x);
4054
+ if (v < 0n) {
4055
+ throw new RangeError(`${field} must be a non-negative felt; got ${v.toString()}`);
3876
4056
  }
3877
- /**
3878
- * Resolve bearer token - uses provided token or falls back to apiSecretKey
3879
- */
3880
- resolveBearerToken(bearerToken) {
3881
- const token = bearerToken ?? this.apiSecretKey;
3882
- if (!token) {
3883
- throw new Error(
3884
- "Authentication required: either pass a bearerToken or configure the SDK with an apiSecretKey"
4057
+ return v;
4058
+ }
4059
+ function _encodeOwnerInput(input) {
4060
+ if (input.weight < 0) {
4061
+ throw new RangeError(`NewOwnerInput.weight must be non-negative; got ${input.weight}`);
4062
+ }
4063
+ const kindFelt = _felt2(BigInt(shortString.encodeShortString(input.kind)), "kind");
4064
+ const roleFelt = input.role === "OWNER" ? ROLE_OWNER : ROLE_GUARDIAN;
4065
+ const pubkey = input.pubkeyBytes.map((p, i) => _felt2(p, `pubkeyBytes[${i}]`));
4066
+ return [
4067
+ kindFelt,
4068
+ BigInt(pubkey.length),
4069
+ ...pubkey,
4070
+ roleFelt,
4071
+ BigInt(input.weight),
4072
+ _felt2(BigInt(shortString.encodeShortString(input.label)), "label")
4073
+ ];
4074
+ }
4075
+ function _call(walletAddress, entrypoint, calldata) {
4076
+ for (let i = 0; i < calldata.length; i++) {
4077
+ if (calldata[i] < 0n) {
4078
+ throw new RangeError(
4079
+ `calldata[${i}] must be a non-negative felt; got ${calldata[i].toString()}`
3885
4080
  );
3886
4081
  }
3887
- return token;
3888
- }
3889
- /**
3890
- * Create a PaymasterAdapter for use with TxBuilder.sendSponsored().
3891
- *
3892
- * @example
3893
- * ```typescript
3894
- * const sdk = new ChipiServerSDK({ apiPublicKey: "pk_...", apiSecretKey: "sk_..." });
3895
- * const paymaster = sdk.createPaymasterAdapter();
3896
- *
3897
- * const txHash = await new TxBuilder(account, { paymaster })
3898
- * .transfer(USDC, [{ to, amount }])
3899
- * .sendSponsored(); // gasless!
3900
- * ```
3901
- */
3902
- createPaymasterAdapter(bearerToken) {
3903
- const token = this.resolveBearerToken(bearerToken);
3904
- return new ChipiPaymasterAdapter(this.client, token);
3905
- }
3906
- /**
3907
- * Create an X402Facilitator for verifying and settling x402 payments.
3908
- *
3909
- * @example
3910
- * ```typescript
3911
- * const facilitator = sdk.createX402Facilitator();
3912
- *
3913
- * // With custom nonce store (Redis)
3914
- * const facilitator = sdk.createX402Facilitator(bearerToken, {
3915
- * nonceStore: {
3916
- * has: async (nonce) => (await redis.sismember("x402:nonces", nonce)) === 1,
3917
- * consume: async (nonce) => (await redis.sadd("x402:nonces", nonce)) === 1,
3918
- * },
3919
- * });
3920
- * ```
3921
- */
3922
- createX402Facilitator(bearerToken, config) {
3923
- const token = this.resolveBearerToken(bearerToken);
3924
- return new X402Facilitator(this.client, token, config);
3925
- }
3926
- /**
3927
- * Execute a gasless transaction
3928
- */
3929
- async executeTransaction({
3930
- params,
3931
- bearerToken
3932
- }) {
3933
- return this.transactions.executeTransaction({
3934
- params,
3935
- bearerToken: this.resolveBearerToken(bearerToken)
3936
- });
3937
- }
3938
- /**
3939
- * Execute a gasless transaction using a session key.
3940
- *
3941
- * This uses the 4-element session signature format instead of owner signature.
3942
- * The session must be:
3943
- * 1. Generated via `sessions.createSessionKey()`
3944
- * 2. Registered on-chain via `sessions.addSessionKeyToContract()`
3945
- *
3946
- * CHIPI wallets only - will throw if wallet type is not CHIPI.
3947
- *
3948
- * @example
3949
- * ```typescript
3950
- * // 1. Create session key (store externally)
3951
- * const session = sdk.sessions.createSessionKey({ encryptKey });
3952
- *
3953
- * // 2. Register on contract (one-time)
3954
- * await sdk.sessions.addSessionKeyToContract({
3955
- * encryptKey,
3956
- * wallet,
3957
- * sessionConfig: {
3958
- * sessionPublicKey: session.publicKey,
3959
- * validUntil: session.validUntil,
3960
- * maxCalls: 1000,
3961
- * allowedEntrypoints: []
3962
- * }
3963
- * }, bearerToken);
3964
- *
3965
- * // 3. Execute transactions with session (no owner key needed)
3966
- * const txHash = await sdk.executeTransactionWithSession({
3967
- * params: { encryptKey, wallet, session, calls },
3968
- * bearerToken
3969
- * });
3970
- * ```
3971
- */
3972
- async executeTransactionWithSession({
3973
- params,
3974
- bearerToken
3975
- }) {
3976
- return this.sessions.executeTransactionWithSession(
3977
- params,
3978
- this.resolveBearerToken(bearerToken)
3979
- );
3980
4082
  }
3981
- /**
3982
- * Sign SNIP-12 typed data without executing a transaction.
3983
- *
3984
- * Purely local operation: decrypt private key → sign → return { r, s }.
3985
- * No API calls are made. Useful for x402 payment signatures and other
3986
- * off-chain signing flows.
4083
+ return {
4084
+ contractAddress: typeof walletAddress === "bigint" ? "0x" + walletAddress.toString(16) : walletAddress,
4085
+ entrypoint,
4086
+ calldata: calldata.map((v) => "0x" + v.toString(16))
4087
+ };
4088
+ }
4089
+ function buildProposeAddOwnerCall(args) {
4090
+ const calldata = [BigInt(args.proposer), ..._encodeOwnerInput(args.newOwner)];
4091
+ return _call(args.walletAddress, "propose_add_owner", calldata);
4092
+ }
4093
+ function buildExecuteAddOwnerCall(args) {
4094
+ const calldata = [_felt2(args.opId), ..._encodeOwnerInput(args.newOwner)];
4095
+ return _call(args.walletAddress, "execute_add_owner", calldata);
4096
+ }
4097
+ function buildProposeRemoveOwnerCall(args) {
4098
+ return _call(args.walletAddress, "propose_remove_owner", [
4099
+ BigInt(args.proposer),
4100
+ BigInt(args.ownerId)
4101
+ ]);
4102
+ }
4103
+ function buildExecuteRemoveOwnerCall(args) {
4104
+ return _call(args.walletAddress, "execute_remove_owner", [
4105
+ _felt2(args.opId),
4106
+ BigInt(args.ownerId)
4107
+ ]);
4108
+ }
4109
+ function buildProposeRotateOwnerCall(args) {
4110
+ return _call(args.walletAddress, "propose_rotate_owner", [
4111
+ BigInt(args.proposer),
4112
+ BigInt(args.ownerId),
4113
+ BigInt(args.newPubkeyBytes.length),
4114
+ ...args.newPubkeyBytes
4115
+ ]);
4116
+ }
4117
+ function buildExecuteRotateOwnerCall(args) {
4118
+ return _call(args.walletAddress, "execute_rotate_owner", [
4119
+ _felt2(args.opId),
4120
+ BigInt(args.ownerId),
4121
+ BigInt(args.newPubkeyBytes.length),
4122
+ ...args.newPubkeyBytes
4123
+ ]);
4124
+ }
4125
+ function buildProposeSetThresholdCall(args) {
4126
+ return _call(args.walletAddress, "propose_set_threshold", [
4127
+ BigInt(args.proposer),
4128
+ BigInt(args.newThreshold)
4129
+ ]);
4130
+ }
4131
+ function buildExecuteSetThresholdCall(args) {
4132
+ return _call(args.walletAddress, "execute_set_threshold", [
4133
+ _felt2(args.opId),
4134
+ BigInt(args.newThreshold)
4135
+ ]);
4136
+ }
4137
+ function buildCancelPendingOpCall(args) {
4138
+ return _call(args.walletAddress, "cancel_pending_op", [_felt2(args.opId)]);
4139
+ }
4140
+ function _verifierClassHash(kind, classHash) {
4141
+ const h = classHash ?? SHHH_VERIFIER_CLASS_HASHES[kind];
4142
+ if (!h) throw new Error(`No verifier class hash known for kind "${kind}".`);
4143
+ return _felt2(h, "classHash");
4144
+ }
4145
+ function buildProposeAddVerifierClassCall(args) {
4146
+ const kindFelt = BigInt(shortString.encodeShortString(args.kind));
4147
+ return _call(args.walletAddress, "propose_add_verifier_class", [
4148
+ BigInt(args.proposer),
4149
+ kindFelt,
4150
+ _verifierClassHash(args.kind, args.classHash)
4151
+ ]);
4152
+ }
4153
+ function buildExecuteAddVerifierClassCall(args) {
4154
+ const kindFelt = BigInt(shortString.encodeShortString(args.kind));
4155
+ return _call(args.walletAddress, "execute_add_verifier_class", [
4156
+ _felt2(args.opId),
4157
+ kindFelt,
4158
+ _verifierClassHash(args.kind, args.classHash)
4159
+ ]);
4160
+ }
4161
+ function buildInitiateRecoveryCall(args) {
4162
+ const calldata = [BigInt(args.proposer), ..._encodeOwnerInput(args.newOwner)];
4163
+ return _call(args.walletAddress, "initiate_recovery", calldata);
4164
+ }
4165
+ function buildCancelRecoveryCall(args) {
4166
+ return _call(args.walletAddress, "cancel_recovery", [BigInt(args.ownerId)]);
4167
+ }
4168
+ function buildFinalizeRecoveryCall(args) {
4169
+ return _call(args.walletAddress, "finalize_recovery", _encodeOwnerInput(args.newOwner));
4170
+ }
4171
+ var VIEW_SELECTORS = {
4172
+ get_pending_op: hash.getSelectorFromName("get_pending_op"),
4173
+ get_pending_recovery: hash.getSelectorFromName("get_pending_recovery"),
4174
+ get_owner: hash.getSelectorFromName("get_owner")
4175
+ };
4176
+ function _toSecondsBigInt(value, field) {
4177
+ if (typeof value === "bigint") return value;
4178
+ if (!Number.isFinite(value)) {
4179
+ throw new TypeError(`${field} must be a finite timestamp; got ${value}`);
4180
+ }
4181
+ return BigInt(Math.floor(value));
4182
+ }
4183
+ function isReadyToExecute(validAfterSecs, nowSecs) {
4184
+ return _toSecondsBigInt(nowSecs, "nowSecs") >= _toSecondsBigInt(validAfterSecs, "validAfterSecs");
4185
+ }
4186
+ function secondsUntilExecutable(validAfterSecs, nowSecs) {
4187
+ const remaining = _toSecondsBigInt(validAfterSecs, "validAfterSecs") - _toSecondsBigInt(nowSecs, "nowSecs");
4188
+ return remaining <= 0n ? 0 : Number(remaining);
4189
+ }
4190
+ function _decodeShort(value) {
4191
+ const v = BigInt(value);
4192
+ return v === 0n ? "" : shortString.decodeShortString(num.toHex(v));
4193
+ }
4194
+ function _view(provider, walletAddress, entrypoint, calldata = []) {
4195
+ return provider.callContract({
4196
+ contractAddress: typeof walletAddress === "bigint" ? num.toHex(walletAddress) : walletAddress,
4197
+ entrypoint,
4198
+ calldata: calldata.map((v) => num.toHex(BigInt(v)))
4199
+ });
4200
+ }
4201
+ async function readShhhOwners(provider, walletAddress) {
4202
+ const [countFelt] = await _view(provider, walletAddress, "owner_count");
4203
+ const count = Number(BigInt(countFelt));
4204
+ const owners = [];
4205
+ for (let id = 0; id < count; id++) {
4206
+ owners.push(decodeShhhOwnerRecord(id, await _view(provider, walletAddress, "get_owner", [id])));
4207
+ }
4208
+ return owners;
4209
+ }
4210
+ function decodeShhhOwnerRecord(ownerId, felts) {
4211
+ if (felts.length < 9) {
4212
+ throw new Error(`get_owner returned ${felts.length} felts; expected 9 (OwnerRecord).`);
4213
+ }
4214
+ return {
4215
+ ownerId,
4216
+ kind: _decodeShort(felts[0]),
4217
+ pubkeyHash: BigInt(felts[1]),
4218
+ role: _decodeShort(felts[4]),
4219
+ weight: Number(BigInt(felts[5])),
4220
+ addedAt: Number(BigInt(felts[6])),
4221
+ label: _decodeShort(felts[7]),
4222
+ revoked: BigInt(felts[8]) !== 0n
4223
+ };
4224
+ }
4225
+ async function readVerifierClass(provider, walletAddress, kind) {
4226
+ const [h] = await _view(provider, walletAddress, "get_verifier_class", [
4227
+ BigInt(shortString.encodeShortString(kind))
4228
+ ]);
4229
+ return BigInt(h ?? 0);
4230
+ }
4231
+ async function readPendingRecovery(provider, walletAddress) {
4232
+ const r = await _view(provider, walletAddress, "get_pending_recovery");
4233
+ return {
4234
+ initiatedAt: Number(BigInt(r[0])),
4235
+ validAfter: Number(BigInt(r[1])),
4236
+ newOwnerHash: BigInt(r[2]),
4237
+ isActive: BigInt(r[3]) !== 0n
4238
+ };
4239
+ }
4240
+ var OP_PROPOSED_KEY = BigInt(hash.getSelectorFromName("OpProposed"));
4241
+ function parseOpProposedEvents(events, walletAddress) {
4242
+ const wallet = walletAddress === void 0 ? void 0 : BigInt(walletAddress);
4243
+ return events.filter(
4244
+ (e) => e.keys.length >= 3 && BigInt(e.keys[0]) === OP_PROPOSED_KEY && (wallet === void 0 || e.from_address !== void 0 && BigInt(e.from_address) === wallet)
4245
+ ).map((e) => ({
4246
+ opId: BigInt(e.keys[1]),
4247
+ opKind: _decodeShort(e.keys[2]),
4248
+ proposer: Number(BigInt(e.data[0])),
4249
+ payload: BigInt(e.data[1]),
4250
+ validAfter: Number(BigInt(e.data[2])),
4251
+ expiresAt: Number(BigInt(e.data[3]))
4252
+ }));
4253
+ }
4254
+
4255
+ // src/shhh/signers/stark-snip12.ts
4256
+ var STARK_SNIP12_KIND_TAG = "STARK_SNIP12";
4257
+ var STARK_KIND_TAG_FELT2 = BigInt(shortString.encodeShortString("STARK"));
4258
+ var V2_SNIP12_FELT = BigInt(shortString.encodeShortString("V2_SNIP12"));
4259
+ function domainChainId(chainId) {
4260
+ if (typeof chainId === "string" && !chainId.startsWith("0x")) return chainId;
4261
+ return shortString.decodeShortString(toFeltHex(chainId));
4262
+ }
4263
+ function felt(value) {
4264
+ return BigInt(value);
4265
+ }
4266
+ function starkSnip12ApprovalTypedData(params) {
4267
+ return {
4268
+ types: {
4269
+ StarknetDomain: [
4270
+ { name: "name", type: "shortstring" },
4271
+ { name: "version", type: "shortstring" },
4272
+ { name: "chainId", type: "shortstring" },
4273
+ { name: "revision", type: "shortstring" }
4274
+ ],
4275
+ Approval: [
4276
+ { name: "Wallet", type: "ContractAddress" },
4277
+ { name: "Hash", type: "felt" }
4278
+ ]
4279
+ },
4280
+ primaryType: "Approval",
4281
+ domain: {
4282
+ name: "Shhh",
4283
+ version: "1",
4284
+ chainId: domainChainId(params.chainId ?? "SN_MAIN"),
4285
+ revision: "1"
4286
+ },
4287
+ message: {
4288
+ Wallet: normalizeStarknetAddress(params.walletAddress),
4289
+ Hash: toFeltHex(params.messageHash)
4290
+ }
4291
+ };
4292
+ }
4293
+ function starkSnip12ApprovalHash(params) {
4294
+ const td = starkSnip12ApprovalTypedData(params);
4295
+ return BigInt(typedData.getMessageHash(td, normalizeStarknetAddress(params.signerAddress)));
4296
+ }
4297
+ function starkSnip12PubkeyFelts(starkPubkey, signerAddress) {
4298
+ const pub = felt(starkPubkey);
4299
+ const account = BigInt(normalizeStarknetAddress(signerAddress));
4300
+ if (pub === 0n || account === 0n) {
4301
+ throw new Error("starkSnip12PubkeyFelts: the key and the account address must be non-zero.");
4302
+ }
4303
+ return [pub, account];
4304
+ }
4305
+ function starkSnip12OwnerCommitment(starkPubkey, signerAddress) {
4306
+ return ownerCommitment(
4307
+ BigInt(shortString.encodeShortString(STARK_SNIP12_KIND_TAG)),
4308
+ starkSnip12PubkeyFelts(starkPubkey, signerAddress)
4309
+ );
4310
+ }
4311
+ function parseStarknetWalletSignature(signature) {
4312
+ const sig = signature.map((v) => felt(v));
4313
+ if (sig.length === 2) return { r: sig[0], s: sig[1] };
4314
+ if (sig.length === 5 && sig[0] === 1n && sig[1] === 0n) {
4315
+ return { pubkey: sig[2], r: sig[3], s: sig[4] };
4316
+ }
4317
+ if (sig.length === 5 && sig[0] === V2_SNIP12_FELT && sig[2] === STARK_KIND_TAG_FELT2) {
4318
+ return { shhhOwnerId: sig[1], r: sig[3], s: sig[4] };
4319
+ }
4320
+ throw new Error(
4321
+ `This wallet returned a ${sig.length}-felt signature that isn't a single STARK key (multisig, hardware or passkey signers aren't supported as a SHHH co-owner yet).`
4322
+ );
4323
+ }
4324
+ function starkVerifyX(r, s, msgHash, pubkeyX) {
4325
+ const x = pubkeyX.toString(16).padStart(64, "0");
4326
+ const sig = new ec.starkCurve.Signature(r, s);
4327
+ for (const prefix of ["02", "03"]) {
4328
+ try {
4329
+ if (ec.starkCurve.verify(sig, toFeltHex(msgHash), prefix + x)) return true;
4330
+ } catch {
4331
+ }
4332
+ }
4333
+ return false;
4334
+ }
4335
+ function verifyStarkSnip12Approval(params) {
4336
+ const { r, s } = parseStarknetWalletSignature(params.signature);
4337
+ const h = starkSnip12ApprovalHash(params);
4338
+ return starkVerifyX(r, s, h, felt(params.starkPubkey));
4339
+ }
4340
+ function buildStarkSnip12Envelope(params) {
4341
+ if (params.ownerIndex < 0n || params.ownerIndex >= 0x100000000n) {
4342
+ throw new Error(
4343
+ `buildStarkSnip12Envelope: ownerIndex ${params.ownerIndex} is out of u32 range. Pass the owner's index in the owner_set, not its commitment.`
4344
+ );
4345
+ }
4346
+ const { r, s } = parseStarknetWalletSignature(params.signature);
4347
+ return wrapV2Snip12Envelope({
4348
+ ownerId: params.ownerIndex,
4349
+ kindTag: STARK_SNIP12_KIND_TAG,
4350
+ payload: [r, s]
4351
+ });
4352
+ }
4353
+ function recoverStarkKeys(r, s, msgHash) {
4354
+ const out = [];
4355
+ for (const bit of [0, 1]) {
4356
+ try {
4357
+ const point = new ec.starkCurve.Signature(r, s).addRecoveryBit(bit).recoverPublicKey(msgHash.toString(16).padStart(64, "0"));
4358
+ out.push(point.toAffine().x);
4359
+ } catch {
4360
+ }
4361
+ }
4362
+ return out;
4363
+ }
4364
+ async function tryCall(provider, contractAddress, entrypoint, calldata = []) {
4365
+ try {
4366
+ return await provider.callContract({ contractAddress, entrypoint, calldata });
4367
+ } catch {
4368
+ return null;
4369
+ }
4370
+ }
4371
+ async function resolveStarkSnip12Signer(params) {
4372
+ const signer = normalizeStarknetAddress(params.signerAddress);
4373
+ const parsed = parseStarknetWalletSignature(params.signature);
4374
+ const approvalHash = starkSnip12ApprovalHash(params);
4375
+ const candidates = [];
4376
+ if (parsed.pubkey !== void 0) candidates.push(parsed.pubkey);
4377
+ if (parsed.shhhOwnerId !== void 0) {
4378
+ const felts = await tryCall(params.provider, signer, "get_owner", [
4379
+ toFeltHex(parsed.shhhOwnerId)
4380
+ ]);
4381
+ const record = felts && felts.length >= 9 ? decodeShhhOwnerRecord(0, felts) : null;
4382
+ if (record && !record.revoked && record.kind === "STARK" && record.role === "OWNER") {
4383
+ for (const key2 of recoverStarkKeys(parsed.r, parsed.s, approvalHash)) {
4384
+ if (ownerCommitment(STARK_KIND_TAG_FELT2, [key2]) === record.pubkeyHash) candidates.push(key2);
4385
+ }
4386
+ }
4387
+ if (candidates.length === 0) {
4388
+ throw new Error(
4389
+ `Couldn't confirm the Chipi wallet's signer: owner ${parsed.shhhOwnerId} of ${signer} is not an active STARK owner whose key made this signature.`
4390
+ );
4391
+ }
4392
+ }
4393
+ if (params.deploymentData && normalizeStarknetAddress(params.deploymentData.address) === signer) {
4394
+ const cls = normalizeStarknetAddress(params.deploymentData.class_hash);
4395
+ const cd = params.deploymentData.calldata;
4396
+ if (cls === COUNTERFACTUAL_ACCOUNT_CLASSES.OPENZEPPELIN_V3 && cd.length === 1) {
4397
+ candidates.push(felt(cd[0]));
4398
+ }
4399
+ if (cls === COUNTERFACTUAL_ACCOUNT_CLASSES.ARGENT_V0_4 && cd.length === 3) {
4400
+ candidates.push(felt(cd[1]));
4401
+ }
4402
+ }
4403
+ if (candidates.length === 0) {
4404
+ const oz = await tryCall(params.provider, signer, "get_public_key");
4405
+ if (oz && oz.length >= 1) candidates.push(felt(oz[0]));
4406
+ }
4407
+ if (candidates.length === 0) {
4408
+ const signers = await tryCall(params.provider, signer, "get_signers");
4409
+ if (signers && signers.length >= 1) {
4410
+ const starkLen = Number(BigInt(signers[0]));
4411
+ const rest = signers.slice(1 + starkLen);
4412
+ const onlyStark = rest.every((v) => BigInt(v) === 0n);
4413
+ if (starkLen === 1 && onlyStark) candidates.push(felt(signers[1]));
4414
+ }
4415
+ }
4416
+ const key = candidates.find((k) => starkVerifyX(parsed.r, parsed.s, approvalHash, k));
4417
+ if (key === void 0) {
4418
+ throw new Error(
4419
+ "Couldn't confirm which key signs for this wallet. It may use a hardware or passkey signer, a multisig, or an account type we don't read yet."
4420
+ );
4421
+ }
4422
+ return { starkPubkey: key, pubkeyFelts: starkSnip12PubkeyFelts(key, signer) };
4423
+ }
4424
+
4425
+ // src/shhh/execute-external-owner.ts
4426
+ function prepareExternalOwnerExecution(params) {
4427
+ const walletAddress = normalizeStarknetAddress(params.walletAddress);
4428
+ const outsideExecution = buildOutsideExecution({
4429
+ nonce: params.nonce ?? newOeNonce(),
4430
+ calls: params.calls,
4431
+ caller: ANY_CALLER_FELT
4432
+ });
4433
+ const chainId = resolveShhhChainId({ override: params.chainId });
4434
+ const messageHash = computeOeHash(outsideExecution, walletAddress, chainId);
4435
+ const typedData2 = starkSnip12ApprovalTypedData({ walletAddress, messageHash, chainId });
4436
+ return { walletAddress, outsideExecution, messageHash, typedData: typedData2, chainId };
4437
+ }
4438
+ async function submitExternalOwnerExecution(params) {
4439
+ const { prepared } = params;
4440
+ if (params.signer && !verifyStarkSnip12Approval({
4441
+ walletAddress: prepared.walletAddress,
4442
+ messageHash: prepared.messageHash,
4443
+ signerAddress: params.signer.address,
4444
+ starkPubkey: params.signer.starkPubkey,
4445
+ signature: params.signature,
4446
+ chainId: prepared.chainId
4447
+ })) {
4448
+ throw new Error(
4449
+ "The signature doesn't match this wallet's registered key. Sign with the same wallet and account you added."
4450
+ );
4451
+ }
4452
+ const envelope = buildStarkSnip12Envelope({
4453
+ signature: params.signature,
4454
+ ownerIndex: BigInt(params.ownerIndex)
4455
+ });
4456
+ const calldata = serializeExecuteFromOutsideV2Calldata({
4457
+ outsideExecution: prepared.outsideExecution,
4458
+ signature: envelope
4459
+ });
4460
+ const response = await params.client.post({
4461
+ endpoint: "/transactions/execute-sponsored-raw",
4462
+ bearerToken: params.bearerToken,
4463
+ body: {
4464
+ accountAddress: prepared.walletAddress,
4465
+ calldata,
4466
+ ...params.externalUserId ? { externalUserId: params.externalUserId } : {}
4467
+ }
4468
+ });
4469
+ if (!response?.transactionHash) {
4470
+ throw new Error(
4471
+ "execute-sponsored-raw response missing transactionHash. Check the chipi-back logs for upstream paymaster errors."
4472
+ );
4473
+ }
4474
+ return response.transactionHash;
4475
+ }
4476
+ async function executeShhhWithExternalSigner(params) {
4477
+ const prepared = prepareExternalOwnerExecution(params);
4478
+ const signature = await params.signTypedData(prepared.typedData);
4479
+ return submitExternalOwnerExecution({ ...params, prepared, signature });
4480
+ }
4481
+ async function executeShhhWithStarkKey(params) {
4482
+ const walletAddress = normalizeStarknetAddress(params.walletAddress);
4483
+ const outsideExecution = buildOutsideExecution({
4484
+ nonce: params.nonce ?? newOeNonce(),
4485
+ calls: params.calls,
4486
+ caller: ANY_CALLER_FELT
4487
+ });
4488
+ const chainId = resolveShhhChainId({ override: params.chainId });
4489
+ const messageHash = computeOeHash(outsideExecution, walletAddress, chainId);
4490
+ const signature = buildStarkEnvelope({
4491
+ privateKey: params.privateKey,
4492
+ messageHash,
4493
+ ownerIndex: BigInt(params.ownerIndex)
4494
+ });
4495
+ const calldata = serializeExecuteFromOutsideV2Calldata({ outsideExecution, signature });
4496
+ const response = await params.client.post({
4497
+ endpoint: "/transactions/execute-sponsored-raw",
4498
+ bearerToken: params.bearerToken,
4499
+ body: {
4500
+ accountAddress: walletAddress,
4501
+ calldata,
4502
+ signerKind: "STARK",
4503
+ ...params.externalUserId ? { externalUserId: params.externalUserId } : {}
4504
+ }
4505
+ });
4506
+ if (!response?.transactionHash) {
4507
+ throw new Error(
4508
+ "execute-sponsored-raw response missing transactionHash. Check the chipi-back logs for upstream paymaster errors."
4509
+ );
4510
+ }
4511
+ return response.transactionHash;
4512
+ }
4513
+
4514
+ // src/chipi-sdk.ts
4515
+ var ChipiSDK = class {
4516
+ constructor(config) {
4517
+ this.client = new ChipiClient(config);
4518
+ this.nodeUrl = config.nodeUrl || STARKNET_NETWORKS.MAINNET;
4519
+ this.apiSecretKey = config.apiSecretKey;
4520
+ this.wallets = new ChipiWallets(this.client);
4521
+ this.transactions = new ChipiTransactions(this.client);
4522
+ this.skuPurchases = new ChipiSkuPurchases(this.client);
4523
+ this.skus = new ChipiSkus(this.client);
4524
+ this.sessions = new ChipiSessions(this.client);
4525
+ this.exchanges = new ChipiExchanges(this.client);
4526
+ this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
4527
+ this.ai = new ChipiAi(this.client, config.apiSecretKey, this.sessions);
4528
+ this.executeTransaction = this.executeTransaction.bind(this);
4529
+ this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
4530
+ this.transfer = this.transfer.bind(this);
4531
+ this.approve = this.approve.bind(this);
4532
+ this.callAnyContract = this.callAnyContract.bind(this);
4533
+ this.createWallet = this.createWallet.bind(this);
4534
+ this.recordSendTransaction = this.recordSendTransaction.bind(this);
4535
+ this.purchaseSku = this.purchaseSku.bind(this);
4536
+ this.getUsdAmount = this.getUsdAmount.bind(this);
4537
+ this.signTypedData = this.signTypedData.bind(this);
4538
+ this.signTypedDataArray = this.signTypedDataArray.bind(this);
4539
+ this.executeWithExternalSigner = this.executeWithExternalSigner.bind(this);
4540
+ this.createPaymasterAdapter = this.createPaymasterAdapter.bind(this);
4541
+ this.createX402Facilitator = this.createX402Facilitator.bind(this);
4542
+ }
4543
+ /**
4544
+ * Resolve bearer token - uses provided token or falls back to apiSecretKey
4545
+ */
4546
+ resolveBearerToken(bearerToken) {
4547
+ const token = bearerToken ?? this.apiSecretKey;
4548
+ if (!token) {
4549
+ throw new Error(
4550
+ "Authentication required: either pass a bearerToken or configure the SDK with an apiSecretKey"
4551
+ );
4552
+ }
4553
+ return token;
4554
+ }
4555
+ /**
4556
+ * Create a PaymasterAdapter for use with TxBuilder.sendSponsored().
4557
+ *
4558
+ * @example
4559
+ * ```typescript
4560
+ * const sdk = new ChipiServerSDK({ apiPublicKey: "pk_...", apiSecretKey: "sk_..." });
4561
+ * const paymaster = sdk.createPaymasterAdapter();
4562
+ *
4563
+ * const txHash = await new TxBuilder(account, { paymaster })
4564
+ * .transfer(USDC, [{ to, amount }])
4565
+ * .sendSponsored(); // gasless!
4566
+ * ```
4567
+ */
4568
+ createPaymasterAdapter(bearerToken) {
4569
+ const token = this.resolveBearerToken(bearerToken);
4570
+ return new ChipiPaymasterAdapter(this.client, token);
4571
+ }
4572
+ /**
4573
+ * Create an X402Facilitator for verifying and settling x402 payments.
4574
+ *
4575
+ * @example
4576
+ * ```typescript
4577
+ * const facilitator = sdk.createX402Facilitator();
4578
+ *
4579
+ * // With custom nonce store (Redis)
4580
+ * const facilitator = sdk.createX402Facilitator(bearerToken, {
4581
+ * nonceStore: {
4582
+ * has: async (nonce) => (await redis.sismember("x402:nonces", nonce)) === 1,
4583
+ * consume: async (nonce) => (await redis.sadd("x402:nonces", nonce)) === 1,
4584
+ * },
4585
+ * });
4586
+ * ```
4587
+ */
4588
+ createX402Facilitator(bearerToken, config) {
4589
+ const token = this.resolveBearerToken(bearerToken);
4590
+ return new X402Facilitator(this.client, token, config);
4591
+ }
4592
+ /**
4593
+ * Execute a gasless transaction
4594
+ */
4595
+ async executeTransaction({
4596
+ params,
4597
+ bearerToken
4598
+ }) {
4599
+ return this.transactions.executeTransaction({
4600
+ params,
4601
+ bearerToken: this.resolveBearerToken(bearerToken)
4602
+ });
4603
+ }
4604
+ /**
4605
+ * Execute a gasless transaction using a session key.
4606
+ *
4607
+ * This uses the 4-element session signature format instead of owner signature.
4608
+ * The session must be:
4609
+ * 1. Generated via `sessions.createSessionKey()`
4610
+ * 2. Registered on-chain via `sessions.addSessionKeyToContract()`
4611
+ *
4612
+ * CHIPI wallets only - will throw if wallet type is not CHIPI.
4613
+ *
4614
+ * @example
4615
+ * ```typescript
4616
+ * // 1. Create session key (store externally)
4617
+ * const session = sdk.sessions.createSessionKey({ encryptKey });
4618
+ *
4619
+ * // 2. Register on contract (one-time)
4620
+ * await sdk.sessions.addSessionKeyToContract({
4621
+ * encryptKey,
4622
+ * wallet,
4623
+ * sessionConfig: {
4624
+ * sessionPublicKey: session.publicKey,
4625
+ * validUntil: session.validUntil,
4626
+ * maxCalls: 1000,
4627
+ * allowedEntrypoints: []
4628
+ * }
4629
+ * }, bearerToken);
4630
+ *
4631
+ * // 3. Execute transactions with session (no owner key needed)
4632
+ * const txHash = await sdk.executeTransactionWithSession({
4633
+ * params: { encryptKey, wallet, session, calls },
4634
+ * bearerToken
4635
+ * });
4636
+ * ```
4637
+ */
4638
+ async executeTransactionWithSession({
4639
+ params,
4640
+ bearerToken
4641
+ }) {
4642
+ return this.sessions.executeTransactionWithSession(
4643
+ params,
4644
+ this.resolveBearerToken(bearerToken)
4645
+ );
4646
+ }
4647
+ /**
4648
+ * Sign SNIP-12 typed data without executing a transaction.
4649
+ *
4650
+ * Purely local operation: decrypt private key → sign → return { r, s }.
4651
+ * No API calls are made. Useful for x402 payment signatures and other
4652
+ * off-chain signing flows.
3987
4653
  *
3988
4654
  * @example
3989
4655
  * ```typescript
@@ -4007,6 +4673,39 @@ var ChipiSDK = class {
4007
4673
  async signTypedDataArray({ params }) {
4008
4674
  return signTypedDataArray({ params });
4009
4675
  }
4676
+ /**
4677
+ * Run calls on a SHHH wallet, signed by an external Starknet wallet that is
4678
+ * one of its `STARK_SNIP12` owners (Bramble, Braavos, Ready/Argent, OZ, or
4679
+ * another Chipi wallet). The wallet signs an `Approval` typed data through
4680
+ * `signTypedData` (its `wallet_signTypedData`); Chipi's paymaster relays the
4681
+ * outside execution gaslessly. Returns the tx hash: wait for it.
4682
+ *
4683
+ * @example
4684
+ * ```typescript
4685
+ * // Bramble approves an agent session on the user's Chipi wallet.
4686
+ * const bramble = window.starknet_bramble;
4687
+ * const txHash = await sdk.executeWithExternalSigner({
4688
+ * params: {
4689
+ * walletAddress: wallet.publicKey,
4690
+ * ownerIndex: 1, // Bramble's index in the wallet's owner set
4691
+ * calls: buildSessionSetupCalls(wallet.publicKey, sessionConfig, policies),
4692
+ * signTypedData: (typedData) =>
4693
+ * bramble.request({ type: "wallet_signTypedData", params: typedData }),
4694
+ * },
4695
+ * bearerToken,
4696
+ * });
4697
+ * ```
4698
+ */
4699
+ async executeWithExternalSigner({
4700
+ params,
4701
+ bearerToken
4702
+ }) {
4703
+ return executeShhhWithExternalSigner({
4704
+ ...params,
4705
+ client: this.client,
4706
+ bearerToken: this.resolveBearerToken(bearerToken)
4707
+ });
4708
+ }
4010
4709
  /**
4011
4710
  * Transfer tokens
4012
4711
  */
@@ -4123,8 +4822,8 @@ var ChipiSDK = class {
4123
4822
  /**
4124
4823
  * Get on-chain transaction status (supports polling for confirmation)
4125
4824
  */
4126
- async getTransactionStatus(hash11, bearerToken) {
4127
- return this.transactions.getTransactionStatus(hash11, this.resolveBearerToken(bearerToken));
4825
+ async getTransactionStatus(hash13, bearerToken) {
4826
+ return this.transactions.getTransactionStatus(hash13, this.resolveBearerToken(bearerToken));
4128
4827
  }
4129
4828
  /**
4130
4829
  * Prepare a wallet upgrade (e.g., READY → CHIPI or CHIPI v29 → v33).
@@ -4496,12 +5195,135 @@ function x402Middleware(config) {
4496
5195
  next();
4497
5196
  };
4498
5197
  }
5198
+ var SIWS_DOMAIN_NAME = "Sign in with Starknet";
5199
+ var SIWS_DOMAIN_VERSION = "1";
5200
+ var SIWS_CHAIN_ID = "SN_MAIN";
5201
+ var DEFAULT_STATEMENT = "Sign in. This request costs nothing and moves no funds.";
5202
+ function assertPrintableAscii(field, value) {
5203
+ if (!/^[\x20-\x7e]*$/.test(value)) {
5204
+ throw new Error(`SIWS ${field} must be single-line printable ASCII`);
5205
+ }
5206
+ }
5207
+ function createStarknetSignInTypedData(params) {
5208
+ const message = {
5209
+ domain: params.domain,
5210
+ address: normalizeStarknetAddress(params.address),
5211
+ statement: params.statement ?? DEFAULT_STATEMENT,
5212
+ uri: params.uri,
5213
+ nonce: params.nonce,
5214
+ issuedAt: params.issuedAt ?? Math.floor(Date.now() / 1e3),
5215
+ expirationTime: params.expirationTime
5216
+ };
5217
+ for (const field of ["domain", "statement", "uri", "nonce"]) {
5218
+ assertPrintableAscii(field, message[field]);
5219
+ }
5220
+ if (!/^[A-Za-z0-9]{8,}$/.test(message.nonce)) {
5221
+ throw new Error("SIWS nonce must be at least 8 letters or digits");
5222
+ }
5223
+ if (!Number.isInteger(message.issuedAt) || !Number.isInteger(message.expirationTime)) {
5224
+ throw new Error("SIWS times must be whole unix seconds");
5225
+ }
5226
+ if (message.expirationTime <= message.issuedAt) {
5227
+ throw new Error("SIWS expirationTime must be after issuedAt");
5228
+ }
5229
+ return {
5230
+ types: {
5231
+ StarknetDomain: [
5232
+ { name: "name", type: "shortstring" },
5233
+ { name: "version", type: "shortstring" },
5234
+ { name: "chainId", type: "shortstring" },
5235
+ { name: "revision", type: "shortstring" }
5236
+ ],
5237
+ SignIn: [
5238
+ { name: "domain", type: "string" },
5239
+ { name: "address", type: "ContractAddress" },
5240
+ { name: "statement", type: "string" },
5241
+ { name: "uri", type: "string" },
5242
+ { name: "nonce", type: "string" },
5243
+ { name: "issuedAt", type: "timestamp" },
5244
+ { name: "expirationTime", type: "timestamp" }
5245
+ ]
5246
+ },
5247
+ primaryType: "SignIn",
5248
+ domain: {
5249
+ name: SIWS_DOMAIN_NAME,
5250
+ version: SIWS_DOMAIN_VERSION,
5251
+ chainId: SIWS_CHAIN_ID,
5252
+ revision: "1"
5253
+ },
5254
+ message: { ...message }
5255
+ };
5256
+ }
5257
+ var MAX_SKEW_SECONDS = 60;
5258
+ var SIWS_CHAIN_ID_FELT = BigInt(shortString.encodeShortString(SIWS_CHAIN_ID));
5259
+ function isMainnetChainId(chainId) {
5260
+ if (chainId === SIWS_CHAIN_ID) return true;
5261
+ if (typeof chainId === "bigint") return chainId === SIWS_CHAIN_ID_FELT;
5262
+ if (typeof chainId !== "string" || !/^(0x[0-9a-f]+|[0-9]+)$/i.test(chainId)) return false;
5263
+ return BigInt(chainId) === SIWS_CHAIN_ID_FELT;
5264
+ }
5265
+ async function verifyStarknetSignIn(params) {
5266
+ const { typedData: typedData2, signature, provider, expected, deploymentData } = params;
5267
+ const raw = typedData2?.message;
5268
+ if (!raw || !Array.isArray(signature) || signature.length === 0) {
5269
+ return { ok: false, reason: "MALFORMED" };
5270
+ }
5271
+ if (!isMainnetChainId(typedData2.domain?.chainId)) return { ok: false, reason: "WRONG_CHAIN" };
5272
+ let canonical;
5273
+ let message;
5274
+ try {
5275
+ canonical = createStarknetSignInTypedData({
5276
+ domain: String(raw.domain),
5277
+ uri: String(raw.uri),
5278
+ address: String(raw.address),
5279
+ nonce: String(raw.nonce),
5280
+ statement: String(raw.statement),
5281
+ issuedAt: Number(raw.issuedAt),
5282
+ expirationTime: Number(raw.expirationTime)
5283
+ });
5284
+ message = canonical.message;
5285
+ } catch {
5286
+ return { ok: false, reason: "MALFORMED" };
5287
+ }
5288
+ if (message.domain !== expected.domain) return { ok: false, reason: "WRONG_DOMAIN" };
5289
+ if (message.uri !== expected.uri) return { ok: false, reason: "WRONG_URI" };
5290
+ if (message.nonce !== expected.nonce) return { ok: false, reason: "WRONG_NONCE" };
5291
+ const now = expected.now ?? Math.floor(Date.now() / 1e3);
5292
+ if (now >= message.expirationTime) return { ok: false, reason: "EXPIRED" };
5293
+ if (message.issuedAt > now + MAX_SKEW_SECONDS) return { ok: false, reason: "NOT_YET_VALID" };
5294
+ const messageHash = typedData.getMessageHash(canonical, message.address);
5295
+ const onChain = await isValidStarknetSignature(provider, message.address, messageHash, signature);
5296
+ if (onChain.valid) return { ok: true, address: message.address, message };
5297
+ if (onChain.reason !== "ACCOUNT_NOT_DEPLOYED") return { ok: false, reason: "INVALID_SIGNATURE" };
5298
+ if (!deploymentData) return { ok: false, reason: "ACCOUNT_NOT_DEPLOYED" };
5299
+ if (normalizeStarknetAddress(deploymentData.address) !== message.address) {
5300
+ return { ok: false, reason: "ADDRESS_MISMATCH" };
5301
+ }
5302
+ const offChain = verifyUndeployedStarknetSignature(deploymentData, messageHash, signature);
5303
+ return offChain.valid ? { ok: true, address: message.address, message } : { ok: false, reason: offChain.reason };
5304
+ }
4499
5305
 
4500
5306
  // src/shhh/index.ts
4501
5307
  init_snip12_hash();
4502
5308
  init_compute_wallet_address();
4503
5309
  init_oe();
4504
5310
  init_stark();
5311
+ function isClassHashNotFound(err) {
5312
+ const e = err;
5313
+ if (e?.baseError?.code === 28 || e?.code === 28) return true;
5314
+ return /class hash not found/i.test(e?.message ?? String(err));
5315
+ }
5316
+ async function isShhhVerifierDeclared(provider, kind, classHash = SHHH_VERIFIER_CLASS_HASHES[kind]) {
5317
+ try {
5318
+ await provider.getClassByHash(classHash);
5319
+ return true;
5320
+ } catch (err) {
5321
+ if (isClassHashNotFound(err)) return false;
5322
+ throw err;
5323
+ }
5324
+ }
5325
+
5326
+ // src/shhh/index.ts
4505
5327
  init_ed25519();
4506
5328
 
4507
5329
  // src/shhh/signers/eip191.ts
@@ -5169,150 +5991,6 @@ async function buildJwtAppleSubEnvelopeFromTestKey(params) {
5169
5991
  });
5170
5992
  return { envelope, pubkey, idToken };
5171
5993
  }
5172
- var ROLE_OWNER = BigInt(shortString.encodeShortString("OWNER"));
5173
- var ROLE_GUARDIAN = BigInt(shortString.encodeShortString("GUARDIAN"));
5174
- var OP_ADD_OWNER = BigInt(shortString.encodeShortString("ADD_OWNER"));
5175
- var OP_REMOVE_OWNER = BigInt(shortString.encodeShortString("REMOVE_OWNER"));
5176
- var OP_ROTATE_OWNER = BigInt(shortString.encodeShortString("ROTATE_OWNER"));
5177
- var OP_SET_THRESHOLD = BigInt(shortString.encodeShortString("SET_THRESHOLD"));
5178
- var TIMELOCK_SECONDS = {
5179
- ADD_OWNER: 172800,
5180
- // 48h
5181
- REMOVE_OWNER: 86400,
5182
- // 24h
5183
- ROTATE_OWNER: 86400,
5184
- // 24h
5185
- SET_THRESHOLD: 172800,
5186
- // 48h
5187
- ADD_VERIFIER: 172800,
5188
- // 48h
5189
- REMOVE_VERIFIER: 86400,
5190
- // 24h
5191
- ADD_GUARDIAN: 86400,
5192
- // 24h
5193
- REMOVE_GUARDIAN: 86400,
5194
- // 24h
5195
- RECOVERY: 604800
5196
- // 7d — `TIMELOCK_RECOVERY`, the headline UX gate
5197
- };
5198
- var DEFAULT_OP_EXPIRY_SECONDS = 1209600;
5199
- function _felt2(x, field = "felt") {
5200
- const v = typeof x === "bigint" ? x : BigInt(x);
5201
- if (v < 0n) {
5202
- throw new RangeError(`${field} must be a non-negative felt; got ${v.toString()}`);
5203
- }
5204
- return v;
5205
- }
5206
- function _encodeOwnerInput(input) {
5207
- if (input.weight < 0) {
5208
- throw new RangeError(`NewOwnerInput.weight must be non-negative; got ${input.weight}`);
5209
- }
5210
- const kindFelt = _felt2(BigInt(shortString.encodeShortString(input.kind)), "kind");
5211
- const roleFelt = input.role === "OWNER" ? ROLE_OWNER : ROLE_GUARDIAN;
5212
- const pubkey = input.pubkeyBytes.map((p, i) => _felt2(p, `pubkeyBytes[${i}]`));
5213
- return [
5214
- kindFelt,
5215
- BigInt(pubkey.length),
5216
- ...pubkey,
5217
- roleFelt,
5218
- BigInt(input.weight),
5219
- _felt2(BigInt(shortString.encodeShortString(input.label)), "label")
5220
- ];
5221
- }
5222
- function _call(walletAddress, entrypoint, calldata) {
5223
- for (let i = 0; i < calldata.length; i++) {
5224
- if (calldata[i] < 0n) {
5225
- throw new RangeError(
5226
- `calldata[${i}] must be a non-negative felt; got ${calldata[i].toString()}`
5227
- );
5228
- }
5229
- }
5230
- return {
5231
- contractAddress: typeof walletAddress === "bigint" ? "0x" + walletAddress.toString(16) : walletAddress,
5232
- entrypoint,
5233
- calldata: calldata.map((v) => "0x" + v.toString(16))
5234
- };
5235
- }
5236
- function buildProposeAddOwnerCall(args) {
5237
- const calldata = [BigInt(args.proposer), ..._encodeOwnerInput(args.newOwner)];
5238
- return _call(args.walletAddress, "propose_add_owner", calldata);
5239
- }
5240
- function buildExecuteAddOwnerCall(args) {
5241
- const calldata = [_felt2(args.opId), ..._encodeOwnerInput(args.newOwner)];
5242
- return _call(args.walletAddress, "execute_add_owner", calldata);
5243
- }
5244
- function buildProposeRemoveOwnerCall(args) {
5245
- return _call(args.walletAddress, "propose_remove_owner", [
5246
- BigInt(args.proposer),
5247
- BigInt(args.ownerId)
5248
- ]);
5249
- }
5250
- function buildExecuteRemoveOwnerCall(args) {
5251
- return _call(args.walletAddress, "execute_remove_owner", [
5252
- _felt2(args.opId),
5253
- BigInt(args.ownerId)
5254
- ]);
5255
- }
5256
- function buildProposeRotateOwnerCall(args) {
5257
- return _call(args.walletAddress, "propose_rotate_owner", [
5258
- BigInt(args.proposer),
5259
- BigInt(args.ownerId),
5260
- BigInt(args.newPubkeyBytes.length),
5261
- ...args.newPubkeyBytes
5262
- ]);
5263
- }
5264
- function buildExecuteRotateOwnerCall(args) {
5265
- return _call(args.walletAddress, "execute_rotate_owner", [
5266
- _felt2(args.opId),
5267
- BigInt(args.ownerId),
5268
- BigInt(args.newPubkeyBytes.length),
5269
- ...args.newPubkeyBytes
5270
- ]);
5271
- }
5272
- function buildProposeSetThresholdCall(args) {
5273
- return _call(args.walletAddress, "propose_set_threshold", [
5274
- BigInt(args.proposer),
5275
- BigInt(args.newThreshold)
5276
- ]);
5277
- }
5278
- function buildExecuteSetThresholdCall(args) {
5279
- return _call(args.walletAddress, "execute_set_threshold", [
5280
- _felt2(args.opId),
5281
- BigInt(args.newThreshold)
5282
- ]);
5283
- }
5284
- function buildCancelPendingOpCall(args) {
5285
- return _call(args.walletAddress, "cancel_pending_op", [_felt2(args.opId)]);
5286
- }
5287
- function buildInitiateRecoveryCall(args) {
5288
- const calldata = [BigInt(args.proposer), ..._encodeOwnerInput(args.newOwner)];
5289
- return _call(args.walletAddress, "initiate_recovery", calldata);
5290
- }
5291
- function buildCancelRecoveryCall(args) {
5292
- return _call(args.walletAddress, "cancel_recovery", [BigInt(args.ownerId)]);
5293
- }
5294
- function buildFinalizeRecoveryCall(args) {
5295
- return _call(args.walletAddress, "finalize_recovery", _encodeOwnerInput(args.newOwner));
5296
- }
5297
- var VIEW_SELECTORS = {
5298
- get_pending_op: hash.getSelectorFromName("get_pending_op"),
5299
- get_pending_recovery: hash.getSelectorFromName("get_pending_recovery"),
5300
- get_owner: hash.getSelectorFromName("get_owner")
5301
- };
5302
- function _toSecondsBigInt(value, field) {
5303
- if (typeof value === "bigint") return value;
5304
- if (!Number.isFinite(value)) {
5305
- throw new TypeError(`${field} must be a finite timestamp; got ${value}`);
5306
- }
5307
- return BigInt(Math.floor(value));
5308
- }
5309
- function isReadyToExecute(validAfterSecs, nowSecs) {
5310
- return _toSecondsBigInt(nowSecs, "nowSecs") >= _toSecondsBigInt(validAfterSecs, "validAfterSecs");
5311
- }
5312
- function secondsUntilExecutable(validAfterSecs, nowSecs) {
5313
- const remaining = _toSecondsBigInt(validAfterSecs, "validAfterSecs") - _toSecondsBigInt(nowSecs, "nowSecs");
5314
- return remaining <= 0n ? 0 : Number(remaining);
5315
- }
5316
5994
 
5317
5995
  // src/shhh/index.ts
5318
5996
  init_threshold();
@@ -5394,6 +6072,6 @@ function submitViaAccount(funded) {
5394
6072
  };
5395
6073
  }
5396
6074
 
5397
- export { ANY_CALLER_FELT, APPLE_ISSUER, BOOTSTRAP_DOMAIN_SEPARATOR, ChipiAi, ChipiBrowserSDK, ChipiClient, ChipiPaymasterAdapter, ChipiSDK, ChipiServerSDK, ChipiSessions, ChipiSkuPurchases, ChipiSkus, ChipiTransactions, ChipiTreasury, ChipiWallets, DEFAULT_OP_EXPIRY_SECONDS, ISIGNER_CANONICAL_LABEL, ISIGNER_ID, ISRC9_V2_ID, MAX_OE_VALIDITY_WINDOW_SECONDS, MIN_THRESHOLD_OWNERS, OE_DOMAIN_NAME, OE_DOMAIN_REVISION, OE_DOMAIN_VERSION, OP_ADD_OWNER, OP_REMOVE_OWNER, OP_ROTATE_OWNER, OP_SET_THRESHOLD, ROLE_GUARDIAN, ROLE_OWNER, SIG_VERSION_V1_HEX_ASCII, SIG_VERSION_V2_SNIP12, SIG_VERSION_V2_THRESHOLD, STARKNET_MESSAGE_PREFIX, SessionTxVerifier, ShhhAccount, TIMELOCK_SECONDS, VIEW_SELECTORS, X402Facilitator, X402ShhhClient, assertValidV2Snip12Envelope, buildAddSessionKeyCall, buildBootstrapSignedCall, buildCancelPendingOpCall, buildCancelRecoveryCall, buildEd25519Envelope, buildEd25519EnvelopeFromSignature, buildEip191EnvelopeFromPrivateKey, buildEip191EnvelopeFromSignature, buildExecuteAddOwnerCall, buildExecuteRemoveOwnerCall, buildExecuteRotateOwnerCall, buildExecuteSetThresholdCall, buildFinalizeRecoveryCall, buildInitiateRecoveryCall, buildJwtAppleSubEnvelopeFromTestKey, buildJwtAppleSubEnvelopeFromTokenResponse, buildMigrationCalls, buildOutsideExecution, buildProposeAddOwnerCall, buildProposeRemoveOwnerCall, buildProposeRotateOwnerCall, buildProposeSetThresholdCall, buildRemoveSpendingPolicyCall, buildRevokeSessionKeyCall, buildSessionSetupCalls, buildSetSpendingPolicyCall, buildStarkEnvelope, buildThresholdEnvelope, buildWebAuthnEnvelopeFromAssertion, buildWebAuthnEnvelopeFromPrivateKey, byteArrayToFelts, computeAddressSalt, computeBootstrapMessage, computeISignerId, computeOeHash, computeShhhAddress, computeSnip12Hash, decryptPrivateKey, ed25519OwnerId, ed25519OwnerPubkeyParam, ed25519PubkeyFelts, ed25519SignedBytes, eip191OwnerId, eip191OwnerPubkeyParam, eip191PubkeyFelts, encryptPrivateKey, estimateThresholdGasOverhead, executeShhhSponsoredRaw, hashCall, hashCalls, hashOutsideExecutionStruct, hashStarknetDomain, isReadyToExecute, isThinkDecision, jwtAppleSubHash, jwtAppleSubOwnerId, jwtAppleSubPubkeyFelts, labelToFelt, locateSubClaim, messageHashToNonceB64url, migrateChipiWalletToShhh, normalizeEntrypoints, ownerCommitment, parseAppleIdToken, parseDerEcdsaSignature, parseEip191Signature, parseThresholdEnvelope, resolveShhhChainId, secondsUntilExecutable, serializeExecuteFromOutsideV2Calldata, signBootstrapMessage, signTypedData, signTypedDataArray, snip12HashToHexAsciiBytes, starkOwnerId, starkPubkeyFelts, submitViaAccount, validateSpendingPolicyConfig, waitForTransaction, webauthnOwnerId, webauthnOwnerPubkeyParam, webauthnPubkeyFelts, wrapV2Snip12Envelope, wrapV2ThresholdEnvelope, x402Middleware };
6075
+ export { ANY_CALLER_FELT, APPLE_ISSUER, BOOTSTRAP_DOMAIN_SEPARATOR, COUNTERFACTUAL_ACCOUNT_CLASSES, ChipiAi, ChipiBrowserSDK, ChipiClient, ChipiPaymasterAdapter, ChipiSDK, ChipiServerSDK, ChipiSessions, ChipiSkuPurchases, ChipiSkus, ChipiTransactions, ChipiTreasury, ChipiWallets, DEFAULT_OP_EXPIRY_SECONDS, ISIGNER_CANONICAL_LABEL, ISIGNER_ID, ISRC9_V2_ID, MAX_OE_VALIDITY_WINDOW_SECONDS, MIN_THRESHOLD_OWNERS, OE_DOMAIN_NAME, OE_DOMAIN_REVISION, OE_DOMAIN_VERSION, OP_ADD_OWNER, OP_ADD_VERIFIER_CLASS, OP_REMOVE_OWNER, OP_ROTATE_OWNER, OP_SET_THRESHOLD, ROLE_GUARDIAN, ROLE_OWNER, SIG_VERSION_V1_HEX_ASCII, SIG_VERSION_V2_SNIP12, SIG_VERSION_V2_THRESHOLD, SIWS_CHAIN_ID, SIWS_DOMAIN_NAME, SIWS_DOMAIN_VERSION, STARKNET_MESSAGE_PREFIX, STARKNET_SIGNATURE_VALID, STARK_SNIP12_KIND_TAG, SessionTxVerifier, ShhhAccount, TIMELOCK_SECONDS, VIEW_SELECTORS, X402Facilitator, X402ShhhClient, assertValidV2Snip12Envelope, buildAddSessionKeyCall, buildBootstrapSignedCall, buildCancelPendingOpCall, buildCancelRecoveryCall, buildEd25519Envelope, buildEd25519EnvelopeFromSignature, buildEip191EnvelopeFromPrivateKey, buildEip191EnvelopeFromSignature, buildExecuteAddOwnerCall, buildExecuteAddVerifierClassCall, buildExecuteRemoveOwnerCall, buildExecuteRotateOwnerCall, buildExecuteSetThresholdCall, buildFinalizeRecoveryCall, buildInitiateRecoveryCall, buildJwtAppleSubEnvelopeFromTestKey, buildJwtAppleSubEnvelopeFromTokenResponse, buildMigrationCalls, buildOutsideExecution, buildProposeAddOwnerCall, buildProposeAddVerifierClassCall, buildProposeRemoveOwnerCall, buildProposeRotateOwnerCall, buildProposeSetThresholdCall, buildRemoveSpendingPolicyCall, buildRevokeSessionKeyCall, buildSessionSetupCalls, buildSetSpendingPolicyCall, buildStarkEnvelope, buildStarkSnip12Envelope, buildThresholdEnvelope, buildWebAuthnEnvelopeFromAssertion, buildWebAuthnEnvelopeFromPrivateKey, byteArrayToFelts, computeAddressSalt, computeBootstrapMessage, computeISignerId, computeOeHash, computeShhhAddress, computeSnip12Hash, createStarknetSignInTypedData, decryptPrivateKey, ed25519OwnerId, ed25519OwnerPubkeyParam, ed25519PubkeyFelts, ed25519SignedBytes, eip191OwnerId, eip191OwnerPubkeyParam, eip191PubkeyFelts, encryptPrivateKey, estimateThresholdGasOverhead, executeShhhSponsoredRaw, executeShhhWithExternalSigner, executeShhhWithStarkKey, hashCall, hashCalls, hashOutsideExecutionStruct, hashStarknetDomain, isReadyToExecute, isShhhVerifierDeclared, isThinkDecision, isValidStarknetSignature, jwtAppleSubHash, jwtAppleSubOwnerId, jwtAppleSubPubkeyFelts, labelToFelt, locateSubClaim, messageHashToNonceB64url, migrateChipiWalletToShhh, normalizeEntrypoints, normalizeStarknetAddress, ownerCommitment, parseAppleIdToken, parseDerEcdsaSignature, parseEip191Signature, parseOpProposedEvents, parseStarknetWalletSignature, parseThresholdEnvelope, prepareExternalOwnerExecution, readPendingRecovery, readShhhOwners, readVerifierClass, resolveShhhChainId, resolveStarkSnip12Signer, secondsUntilExecutable, serializeExecuteFromOutsideV2Calldata, signBootstrapMessage, signTypedData, signTypedDataArray, snip12HashToHexAsciiBytes, starkOwnerId, starkPubkeyFelts, starkSnip12ApprovalHash, starkSnip12ApprovalTypedData, starkSnip12OwnerCommitment, starkSnip12PubkeyFelts, submitExternalOwnerExecution, submitViaAccount, validateSpendingPolicyConfig, verifyStarkSnip12Approval, verifyStarknetSignIn, verifyUndeployedStarknetSignature, waitForTransaction, webauthnOwnerId, webauthnOwnerPubkeyParam, webauthnPubkeyFelts, wrapV2Snip12Envelope, wrapV2ThresholdEnvelope, x402Middleware };
5398
6076
  //# sourceMappingURL=index.mjs.map
5399
6077
  //# sourceMappingURL=index.mjs.map