@chipi-stack/chipi-react 14.15.0 → 14.16.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/hooks.mjs CHANGED
@@ -20346,6 +20346,41 @@ function hexEq(a, b) {
20346
20346
  return a === b;
20347
20347
  }
20348
20348
  }
20349
+ function parseCapAmount(value, field, token) {
20350
+ try {
20351
+ const v = typeof value === "bigint" ? value : BigInt(String(value).trim());
20352
+ if (v < 0n) throw new Error("negative");
20353
+ return v;
20354
+ } catch {
20355
+ throw new Error(
20356
+ `session_spend_cap_invalid: ${field} for token ${token} must be a non-negative integer in base units (got "${String(value)}")`
20357
+ );
20358
+ }
20359
+ }
20360
+ function toSpendingPolicies(caps, lifetimeSeconds) {
20361
+ return caps.map((cap) => {
20362
+ const policy = "maxPerWindow" in cap ? {
20363
+ token: cap.token,
20364
+ maxPerCall: parseCapAmount(cap.maxPerCall, "maxPerCall", cap.token),
20365
+ maxPerWindow: parseCapAmount(cap.maxPerWindow, "maxPerWindow", cap.token),
20366
+ windowSeconds: cap.windowSeconds
20367
+ } : (() => {
20368
+ const amount = parseCapAmount(cap.amount, "amount", cap.token);
20369
+ return {
20370
+ token: cap.token,
20371
+ maxPerCall: amount,
20372
+ maxPerWindow: amount,
20373
+ windowSeconds: Math.max(1, lifetimeSeconds)
20374
+ };
20375
+ })();
20376
+ if (policy.maxPerWindow === 0n) {
20377
+ throw new Error(
20378
+ `session_spend_cap_zero: the cap for token ${cap.token} resolves to maxPerWindow = 0, which means unlimited on-chain. Use a positive cap.`
20379
+ );
20380
+ }
20381
+ return policy;
20382
+ });
20383
+ }
20349
20384
  function sessionCovers(policy, calls) {
20350
20385
  if (!policy?.allowedCalls?.length) return false;
20351
20386
  return calls.every(
@@ -20360,6 +20395,10 @@ function useChipiWalletObject(config3) {
20360
20395
  const { signTypedDataAsync } = useSignTypedData();
20361
20396
  const { createSessionKeyAsync } = useCreateSessionKey();
20362
20397
  const { addSessionKeyToContractAsync } = useAddSessionKeyToContract();
20398
+ const { chipiSDK } = useChipiContext();
20399
+ const sdk = useRef(chipiSDK);
20400
+ sdk.current = chipiSDK;
20401
+ const warnedMissingApproval = useRef(false);
20363
20402
  const cfg = useRef(config3);
20364
20403
  cfg.current = config3;
20365
20404
  const requireWallet = () => {
@@ -20372,28 +20411,33 @@ function useChipiWalletObject(config3) {
20372
20411
  if (policy.validUntil <= nowSec()) throw new Error("session_policy_expired");
20373
20412
  const c = cfg.current;
20374
20413
  const wallet = requireWallet();
20414
+ const lifetimeSeconds = Math.max(1, policy.validUntil - nowSec());
20415
+ const spendingPolicies = policy.spendCaps?.length ? toSpendingPolicies(policy.spendCaps, lifetimeSeconds) : [];
20375
20416
  const encryptKey = await c.getEncryptKey();
20376
20417
  const session = await createSessionKeyAsync({
20377
20418
  encryptKey,
20378
- durationSeconds: Math.max(1, policy.validUntil - nowSec())
20419
+ durationSeconds: lifetimeSeconds
20379
20420
  });
20380
20421
  const bearerToken = await c.getBearerToken();
20381
- await addSessionKeyToContractAsync({
20382
- params: {
20383
- encryptKey,
20384
- wallet,
20385
- sessionConfig: {
20386
- sessionPublicKey: session.publicKey,
20387
- validUntil: policy.validUntil,
20388
- maxCalls: 1e3,
20389
- // selectors; empty = all entrypoints allowed
20390
- allowedEntrypoints: policy.allowedCalls.map(
20391
- (a) => hash_exports.getSelectorFromName(a.entrypoint)
20392
- )
20393
- }
20394
- },
20395
- bearerToken
20396
- });
20422
+ const params = {
20423
+ encryptKey,
20424
+ wallet,
20425
+ sessionConfig: {
20426
+ sessionPublicKey: session.publicKey,
20427
+ validUntil: policy.validUntil,
20428
+ maxCalls: 1e3,
20429
+ // Selectors; empty = all entrypoints allowed. On-chain this is a
20430
+ // per-selector whitelist, NOT scoped to allowedCalls' contracts.
20431
+ allowedEntrypoints: policy.allowedCalls.map(
20432
+ (a) => hash_exports.getSelectorFromName(a.entrypoint)
20433
+ )
20434
+ }
20435
+ };
20436
+ if (spendingPolicies.length > 0) {
20437
+ await sdk.current.sessions.setupSession({ ...params, spendingPolicies }, bearerToken);
20438
+ } else {
20439
+ await addSessionKeyToContractAsync({ params, bearerToken });
20440
+ }
20397
20441
  return session;
20398
20442
  },
20399
20443
  [createSessionKeyAsync, addSessionKeyToContractAsync]
@@ -20438,7 +20482,17 @@ function useChipiWalletObject(config3) {
20438
20482
  createSession: async (policy) => {
20439
20483
  await createSession(policy);
20440
20484
  },
20441
- requestApproval: (req) => cfg.current.requestApproval?.(req) ?? Promise.resolve(true)
20485
+ requestApproval: (req) => {
20486
+ const gate = cfg.current.requestApproval;
20487
+ if (gate) return gate(req);
20488
+ if (!warnedMissingApproval.current) {
20489
+ warnedMissingApproval.current = true;
20490
+ console.warn(
20491
+ "[ChipiSDK:Connect] No `requestApproval` was provided to useChipiWalletObject, so every approval (connect, execute, signTypedData, session) is denied. Pass `requestApproval` to show the user an approval UI and resolve true/false."
20492
+ );
20493
+ }
20494
+ return Promise.resolve(false);
20495
+ }
20442
20496
  }),
20443
20497
  [callAnyContractAsync, executeWithSessionAsync, signTypedDataAsync, createSession]
20444
20498
  );