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