@rhinestone/deposit-modal 0.13.0 → 0.14.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.
Files changed (57) hide show
  1. package/README.md +43 -2
  2. package/bridge-transcript.json +653 -0
  3. package/dist/ClaimModal-IKTJU43Y.cjs +13 -0
  4. package/dist/ClaimModal-SEKNWRMA.mjs +13 -0
  5. package/dist/{DepositModalReown-YNNHLAV2.cjs → DepositModalReown-46LPVFB6.cjs} +16 -15
  6. package/dist/{DepositModalReown-3H75G3XQ.mjs → DepositModalReown-Q2JMLT47.mjs} +6 -5
  7. package/dist/WithdrawModal-5ICGD4HJ.mjs +12 -0
  8. package/dist/WithdrawModal-VP6PMIRO.cjs +12 -0
  9. package/dist/{chunk-GACIGCSN.cjs → chunk-6KG642KH.cjs} +1 -1
  10. package/dist/{chunk-RAADLTSW.cjs → chunk-7ICSHJFE.cjs} +179 -138
  11. package/dist/{chunk-COCBCQQC.mjs → chunk-7SR7ENVJ.mjs} +46 -5
  12. package/dist/{chunk-OLCD75JK.mjs → chunk-CFKC77SV.mjs} +451 -131
  13. package/dist/{chunk-EOMT5LKX.mjs → chunk-IN77XSWO.mjs} +526 -3
  14. package/dist/{chunk-FZ5FZFIG.mjs → chunk-K4H6TGBE.mjs} +1 -1
  15. package/dist/{chunk-DSIZNRWA.mjs → chunk-KTUVSKR4.mjs} +979 -360
  16. package/dist/{chunk-HOGZKHHY.cjs → chunk-LZFRL2AL.cjs} +3 -3
  17. package/dist/{chunk-7N77GIP4.cjs → chunk-MTFJSE52.cjs} +465 -171
  18. package/dist/{chunk-LTMMETAB.mjs → chunk-PKML3XVS.mjs} +404 -110
  19. package/dist/{chunk-ZMT4ATHR.cjs → chunk-V2OBGLJD.cjs} +564 -41
  20. package/dist/{chunk-XYJFEN5D.mjs → chunk-WUJIKCFU.mjs} +1 -1
  21. package/dist/{chunk-CVGNCUVU.cjs → chunk-X2IPAPXU.cjs} +22 -13
  22. package/dist/{chunk-2G2EIN4A.cjs → chunk-YCQZJQO6.cjs} +1272 -653
  23. package/dist/{chunk-5NUIKYSF.cjs → chunk-YWMWI7PZ.cjs} +458 -138
  24. package/dist/{chunk-YREVFB64.mjs → chunk-ZEO6ADM3.mjs} +16 -7
  25. package/dist/claim.cjs +6 -6
  26. package/dist/claim.d.cts +3 -3
  27. package/dist/claim.d.ts +3 -3
  28. package/dist/claim.mjs +5 -5
  29. package/dist/constants.cjs +2 -2
  30. package/dist/constants.d.cts +1 -1
  31. package/dist/constants.d.ts +1 -1
  32. package/dist/constants.mjs +1 -1
  33. package/dist/deposit.cjs +6 -6
  34. package/dist/deposit.d.cts +2 -2
  35. package/dist/deposit.d.ts +2 -2
  36. package/dist/deposit.mjs +5 -5
  37. package/dist/embed.cjs +310 -102
  38. package/dist/embed.d.cts +7 -1
  39. package/dist/embed.d.ts +7 -1
  40. package/dist/embed.mjs +285 -77
  41. package/dist/index.cjs +9 -9
  42. package/dist/index.d.cts +1 -1
  43. package/dist/index.d.ts +1 -1
  44. package/dist/index.mjs +8 -8
  45. package/dist/types-Bho4OA03.d.ts +982 -0
  46. package/dist/types-DP_3KwlD.d.cts +982 -0
  47. package/dist/withdraw.cjs +5 -5
  48. package/dist/withdraw.d.cts +3 -3
  49. package/dist/withdraw.d.ts +3 -3
  50. package/dist/withdraw.mjs +4 -4
  51. package/package.json +28 -7
  52. package/dist/ClaimModal-CREZO27I.mjs +0 -11
  53. package/dist/ClaimModal-JRIA32U2.cjs +0 -11
  54. package/dist/WithdrawModal-NVRX44IZ.mjs +0 -10
  55. package/dist/WithdrawModal-YYSBPCJJ.cjs +0 -10
  56. package/dist/types-B89I8_8H.d.ts +0 -638
  57. package/dist/types-nnDR4tqA.d.cts +0 -638
package/dist/embed.cjs CHANGED
@@ -1,18 +1,18 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunk2G2EIN4Acjs = require('./chunk-2G2EIN4A.cjs');
3
+ var _chunkYCQZJQO6cjs = require('./chunk-YCQZJQO6.cjs');
4
4
 
5
5
 
6
- var _chunkRAADLTSWcjs = require('./chunk-RAADLTSW.cjs');
7
- require('./chunk-CVGNCUVU.cjs');
8
- require('./chunk-HOGZKHHY.cjs');
6
+ var _chunk7ICSHJFEcjs = require('./chunk-7ICSHJFE.cjs');
7
+ require('./chunk-X2IPAPXU.cjs');
8
+ require('./chunk-LZFRL2AL.cjs');
9
9
 
10
10
 
11
- var _chunkZMT4ATHRcjs = require('./chunk-ZMT4ATHR.cjs');
11
+ var _chunkV2OBGLJDcjs = require('./chunk-V2OBGLJD.cjs');
12
12
 
13
13
 
14
14
 
15
- var _chunkGACIGCSNcjs = require('./chunk-GACIGCSN.cjs');
15
+ var _chunk6KG642KHcjs = require('./chunk-6KG642KH.cjs');
16
16
  require('./chunk-DW2EQA2U.cjs');
17
17
 
18
18
 
@@ -38,7 +38,16 @@ var BRIDGE_METHOD = {
38
38
  SIGN_RECOVERY: "host.signRecovery",
39
39
  /** Page→host: show a payment page outside the web view. Gated by
40
40
  * `CAPABILITY.OPEN_URL`. */
41
- OPEN_URL: "host.openUrl"
41
+ OPEN_URL: "host.openUrl",
42
+ /**
43
+ * Page→host, from a SUB-FRAME. Gated by `CAPABILITY.PROBE_FRAME_SCOPE`.
44
+ *
45
+ * The one request a host is meant to ignore. See `frame-scope.ts`: the page
46
+ * sends it from a frame that is not the main one, and a host that answers has
47
+ * proved it acts on sub-frame traffic — which means it would act on a wallet
48
+ * request from there too.
49
+ */
50
+ PROBE_FRAME_SCOPE: "bridge.probeFrameScope"
42
51
  };
43
52
  var HOST_METHOD = {
44
53
  /** Host→page: Android's hardware back and iOS's interactive swipe. Answers
@@ -48,8 +57,24 @@ var HOST_METHOD = {
48
57
  var CAPABILITY = {
49
58
  SEND_TRANSACTION: BRIDGE_METHOD.SEND_TRANSACTION,
50
59
  SIGN_RECOVERY: BRIDGE_METHOD.SIGN_RECOVERY,
51
- OPEN_URL: BRIDGE_METHOD.OPEN_URL
60
+ OPEN_URL: BRIDGE_METHOD.OPEN_URL,
61
+ PROBE_FRAME_SCOPE: BRIDGE_METHOD.PROBE_FRAME_SCOPE
52
62
  };
63
+ var PAGE_EVENT = {
64
+ READY: "ready",
65
+ LIFECYCLE: "lifecycle",
66
+ ANALYTICS: "analytics",
67
+ ERROR: "error",
68
+ UI_STATE: "ui.state",
69
+ WALLET_CONNECT_REQUESTED: "wallet.connectRequested",
70
+ WALLET_DISCONNECT_REQUESTED: "wallet.disconnectRequested",
71
+ DISMISS_REQUESTED: "dismissRequested"
72
+ };
73
+ var PASSTHROUGH_EVENTS = [
74
+ PAGE_EVENT.LIFECYCLE,
75
+ PAGE_EVENT.ANALYTICS,
76
+ PAGE_EVENT.ERROR
77
+ ];
53
78
  var ALLOWED_WALLET_METHODS = [
54
79
  "eth_chainId",
55
80
  "eth_accounts",
@@ -265,7 +290,9 @@ function createBridgeTransport(options) {
265
290
  channel.post(JSON.stringify(frame));
266
291
  }
267
292
  function notifyPending() {
268
- _optionalChain([options, 'access', _3 => _3.onPendingChange, 'optionalCall', _4 => _4(pending.size)]);
293
+ let counted = 0;
294
+ for (const [, entry] of pending) if (entry.counted) counted += 1;
295
+ _optionalChain([options, 'access', _3 => _3.onPendingChange, 'optionalCall', _4 => _4(counted)]);
269
296
  }
270
297
  function forgetPending(id) {
271
298
  const entry = pending.get(id);
@@ -358,58 +385,71 @@ function createBridgeTransport(options) {
358
385
  });
359
386
  }
360
387
  }
361
- return {
362
- stats,
363
- request(method, params, requestOptions) {
364
- if (closed) {
365
- return Promise.reject(
388
+ function issue(method, params, requestOptions, post, counted) {
389
+ if (closed) {
390
+ return Promise.reject(
391
+ new BridgeRequestError(
392
+ bridgeError(
393
+ BridgeErrorCode.CHANNEL_CLOSED,
394
+ "The connection to the app closed."
395
+ )
396
+ )
397
+ );
398
+ }
399
+ counter += 1;
400
+ const id = `${sessionId}.${counter}`;
401
+ const timeoutMs = _nullishCoalesce(_optionalChain([requestOptions, 'optionalAccess', _5 => _5.timeoutMs]), () => ( defaultTimeoutMs));
402
+ return new Promise((resolve, reject) => {
403
+ const timer = timeoutMs > 0 ? setTimeout(() => {
404
+ forgetPending(id);
405
+ reject(
366
406
  new BridgeRequestError(
407
+ _optionalChain([requestOptions, 'optionalAccess', _6 => _6.uncertainOnTimeout]) ? bridgeError(
408
+ BridgeErrorCode.SUBMISSION_UNCERTAIN,
409
+ "The app did not confirm whether the transaction was sent."
410
+ ) : bridgeError(
411
+ BridgeErrorCode.REQUEST_TIMEOUT,
412
+ "The app did not respond."
413
+ )
414
+ )
415
+ );
416
+ }, timeoutMs) : void 0;
417
+ pending.set(id, {
418
+ resolve,
419
+ reject,
420
+ timer,
421
+ counted
422
+ });
423
+ notifyPending();
424
+ try {
425
+ post(JSON.stringify({ kind: "request", id, method, params }));
426
+ } catch (error) {
427
+ forgetPending(id);
428
+ if (timer !== void 0) clearTimeout(timer);
429
+ reject(
430
+ error instanceof NoHostChannelError ? new BridgeRequestError(
367
431
  bridgeError(
368
432
  BridgeErrorCode.CHANNEL_CLOSED,
369
433
  "The connection to the app closed."
370
434
  )
371
- )
435
+ ) : error
372
436
  );
373
437
  }
374
- counter += 1;
375
- const id = `${sessionId}.${counter}`;
376
- const timeoutMs = _nullishCoalesce(_optionalChain([requestOptions, 'optionalAccess', _5 => _5.timeoutMs]), () => ( defaultTimeoutMs));
377
- return new Promise((resolve, reject) => {
378
- const timer = timeoutMs > 0 ? setTimeout(() => {
379
- forgetPending(id);
380
- reject(
381
- new BridgeRequestError(
382
- _optionalChain([requestOptions, 'optionalAccess', _6 => _6.uncertainOnTimeout]) ? bridgeError(
383
- BridgeErrorCode.SUBMISSION_UNCERTAIN,
384
- "The app did not confirm whether the transaction was sent."
385
- ) : bridgeError(
386
- BridgeErrorCode.REQUEST_TIMEOUT,
387
- "The app did not respond."
388
- )
389
- )
390
- );
391
- }, timeoutMs) : void 0;
392
- pending.set(id, {
393
- resolve,
394
- reject,
395
- timer
396
- });
397
- notifyPending();
398
- try {
399
- send({ kind: "request", id, method, params });
400
- } catch (error) {
401
- forgetPending(id);
402
- if (timer !== void 0) clearTimeout(timer);
403
- reject(
404
- error instanceof NoHostChannelError ? new BridgeRequestError(
405
- bridgeError(
406
- BridgeErrorCode.CHANNEL_CLOSED,
407
- "The connection to the app closed."
408
- )
409
- ) : error
410
- );
411
- }
412
- });
438
+ });
439
+ }
440
+ return {
441
+ stats,
442
+ request(method, params, requestOptions) {
443
+ return issue(
444
+ method,
445
+ params,
446
+ requestOptions,
447
+ (json) => channel.post(json),
448
+ true
449
+ );
450
+ },
451
+ requestVia(post, method, params, requestOptions) {
452
+ return issue(method, params, requestOptions, post, false);
413
453
  },
414
454
  emit(type, payload) {
415
455
  if (closed) return;
@@ -444,6 +484,106 @@ function createBridgeTransport(options) {
444
484
  };
445
485
  }
446
486
 
487
+ // src/core/bridge/frame-scope.ts
488
+ var PROBE_TIMEOUT_MS = 750;
489
+ var FRAME_OPEN_TIMEOUT_MS = 150;
490
+ var PROBE_MARKER_ID = "rs-frame-probe";
491
+ function subFramePosters(inner) {
492
+ const posters = [];
493
+ const push = (candidate) => {
494
+ const channel = candidate;
495
+ if (typeof _optionalChain([channel, 'optionalAccess', _7 => _7.postMessage]) !== "function") return;
496
+ const post = channel.postMessage;
497
+ posters.push((json) => post.call(channel, json));
498
+ };
499
+ push(inner[PAGE_TO_HOST_CHANNEL]);
500
+ push(inner.ReactNativeWebView);
501
+ const webkit = inner.webkit;
502
+ const handlers = _optionalChain([webkit, 'optionalAccess', _8 => _8.messageHandlers]);
503
+ if (handlers && typeof handlers === "object") {
504
+ for (const name of Object.keys(handlers)) push(handlers[name]);
505
+ }
506
+ return posters;
507
+ }
508
+ function openProbeFrame(doc) {
509
+ return new Promise((resolve) => {
510
+ let frame;
511
+ try {
512
+ frame = doc.createElement("iframe");
513
+ } catch (e3) {
514
+ resolve(void 0);
515
+ return;
516
+ }
517
+ frame.setAttribute("aria-hidden", "true");
518
+ frame.setAttribute("title", "");
519
+ frame.style.cssText = "position:absolute;width:0;height:0;border:0;visibility:hidden";
520
+ let settled = false;
521
+ const done = (win) => {
522
+ if (settled) return;
523
+ settled = true;
524
+ if (!win) {
525
+ frame.remove();
526
+ resolve(void 0);
527
+ return;
528
+ }
529
+ resolve({ win, close: () => frame.remove() });
530
+ };
531
+ frame.addEventListener("load", () => {
532
+ if (!_optionalChain([frame, 'access', _9 => _9.contentDocument, 'optionalAccess', _10 => _10.getElementById, 'call', _11 => _11(PROBE_MARKER_ID)])) return;
533
+ done(_nullishCoalesce(frame.contentWindow, () => ( void 0)));
534
+ });
535
+ frame.addEventListener("error", () => done(void 0));
536
+ setTimeout(() => done(void 0), FRAME_OPEN_TIMEOUT_MS);
537
+ try {
538
+ frame.srcdoc = `<!doctype html><meta charset=utf-8><i id=${PROBE_MARKER_ID}></i>`;
539
+ doc.body.appendChild(frame);
540
+ } catch (e4) {
541
+ frame.remove();
542
+ done(void 0);
543
+ }
544
+ });
545
+ }
546
+ async function probeChannelScope(options) {
547
+ const doc = options.doc;
548
+ if (!_optionalChain([doc, 'optionalAccess', _12 => _12.body])) return "unknown";
549
+ const frame = await (_nullishCoalesce(options.openFrame, () => ( openProbeFrame)))(doc);
550
+ if (!frame) return "unknown";
551
+ try {
552
+ const posters = subFramePosters(frame.win);
553
+ if (posters.length === 0) return "main-frame";
554
+ let delivered = 0;
555
+ try {
556
+ await options.issue((json) => {
557
+ for (const post of posters) {
558
+ try {
559
+ post(json);
560
+ delivered += 1;
561
+ } catch (e5) {
562
+ }
563
+ }
564
+ });
565
+ return "all-frames";
566
+ } catch (error) {
567
+ if (delivered === 0) return "unknown";
568
+ if (isBridgeCode(error, BridgeErrorCode.REQUEST_TIMEOUT)) {
569
+ return "main-frame";
570
+ }
571
+ if (isBridgeCode(error, BridgeErrorCode.CHANNEL_CLOSED)) return "unknown";
572
+ if (isBridgeRequestError(error)) return "all-frames";
573
+ return "unknown";
574
+ }
575
+ } finally {
576
+ frame.close();
577
+ }
578
+ }
579
+ var CHANNEL_SCOPE_ADVICE = `[rhinestone] This app answered ${BRIDGE_METHOD.PROBE_FRAME_SCOPE} sent from a sub-frame, so any frame in its web view can drive the wallet. Fix it natively: drop a message unless frameInfo.isMainFrame (iOS) or onPostMessage's isMainFrame (Android). Scoping the ${PAGE_TO_HOST_CHANNEL} shim is not enough \u2014 the primitive under it is in every frame regardless. Wallet, withdraw and claim are withheld until then.`;
580
+ var advised = false;
581
+ function adviseOnChannelScope(scope) {
582
+ if (scope !== "all-frames" || advised) return;
583
+ advised = true;
584
+ console.error(CHANNEL_SCOPE_ADVICE);
585
+ }
586
+
447
587
  // src/core/bridge/validate.ts
448
588
  function isRecord2(value) {
449
589
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -515,7 +655,7 @@ var SWITCH_CONFIRMATION_TIMEOUT_MS = 15e3;
515
655
  var HASH_PATTERN = /^0x[0-9a-fA-F]{64}$/;
516
656
  var HEX_PATTERN = /^0x[0-9a-fA-F]*$/;
517
657
  function evmAccount(state) {
518
- return _optionalChain([state, 'access', _7 => _7.accounts, 'access', _8 => _8.find, 'call', _9 => _9((account) => account.caip10.startsWith("eip155:")), 'optionalAccess', _10 => _10.caip10]);
658
+ return _optionalChain([state, 'access', _13 => _13.accounts, 'access', _14 => _14.find, 'call', _15 => _15((account) => account.caip10.startsWith("eip155:")), 'optionalAccess', _16 => _16.caip10]);
519
659
  }
520
660
  function evmAddressFrom(state) {
521
661
  const caip10 = evmAccount(state);
@@ -555,7 +695,7 @@ function assertResultShape(method, result) {
555
695
  `${method}: ${detail}`
556
696
  )
557
697
  );
558
- throw SUBMITTING_WALLET_METHODS.includes(method) ? _chunkRAADLTSWcjs.markSubmissionUncertain.call(void 0, error) : error;
698
+ throw SUBMITTING_WALLET_METHODS.includes(method) ? _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0, error) : error;
559
699
  };
560
700
  switch (method) {
561
701
  case "eth_sendTransaction":
@@ -607,7 +747,7 @@ function createBridgedWalletSession(options) {
607
747
  );
608
748
  } catch (error) {
609
749
  if (submitting && isBridgeRequestError(error) && error.code === -32603) {
610
- throw _chunkRAADLTSWcjs.markSubmissionUncertain.call(void 0,
750
+ throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0,
611
751
  new BridgeRequestError(
612
752
  bridgeError(
613
753
  BridgeErrorCode.SUBMISSION_UNCERTAIN,
@@ -618,7 +758,7 @@ function createBridgedWalletSession(options) {
618
758
  );
619
759
  }
620
760
  if (submitting && isBridgeCode(error, BridgeErrorCode.SUBMISSION_UNCERTAIN)) {
621
- throw _chunkRAADLTSWcjs.markSubmissionUncertain.call(void 0, error);
761
+ throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0, error);
622
762
  }
623
763
  throw error;
624
764
  }
@@ -659,7 +799,7 @@ function createBridgedWalletSession(options) {
659
799
  stateWaiters.delete(waiter);
660
800
  reject(
661
801
  new Error(
662
- `Switch to ${_nullishCoalesce(_optionalChain([resolveChain, 'call', _11 => _11(chainId), 'optionalAccess', _12 => _12.name]), () => ( _chunk4KCSH4T3cjs.getChainName.call(void 0, chainId)))} in your wallet to continue`
802
+ `Switch to ${_nullishCoalesce(_optionalChain([resolveChain, 'call', _17 => _17(chainId), 'optionalAccess', _18 => _18.name]), () => ( _chunk4KCSH4T3cjs.getChainName.call(void 0, chainId)))} in your wallet to continue`
663
803
  )
664
804
  );
665
805
  }, SWITCH_CONFIRMATION_TIMEOUT_MS);
@@ -714,7 +854,7 @@ function createBridgedWalletSession(options) {
714
854
  applyWalletState(next) {
715
855
  state = next;
716
856
  for (const waiter of [...stateWaiters]) waiter(next);
717
- _optionalChain([options, 'access', _13 => _13.onStateChange, 'optionalCall', _14 => _14(next)]);
857
+ _optionalChain([options, 'access', _19 => _19.onStateChange, 'optionalCall', _20 => _20(next)]);
718
858
  }
719
859
  };
720
860
  }
@@ -737,7 +877,7 @@ async function connectToHost(options) {
737
877
  });
738
878
  const params = {
739
879
  protocol: PROTOCOL_VERSION,
740
- modalVersion: _chunkGACIGCSNcjs.MODAL_VERSION
880
+ modalVersion: _chunk6KG642KHcjs.MODAL_VERSION
741
881
  };
742
882
  let raw;
743
883
  try {
@@ -769,8 +909,32 @@ async function connectToHost(options) {
769
909
  transport.on("session.configure", (payload) => {
770
910
  if (typeof payload !== "object" || payload === null) return;
771
911
  config = payload;
772
- _optionalChain([options, 'access', _15 => _15.onConfig, 'optionalCall', _16 => _16(config)]);
912
+ _optionalChain([options, 'access', _21 => _21.onConfig, 'optionalCall', _22 => _22(config)]);
773
913
  });
914
+ const probeable = hello.capabilities.includes(CAPABILITY.PROBE_FRAME_SCOPE);
915
+ let channelScope = probeable ? "probing" : "unknown";
916
+ let announceSettled = () => {
917
+ };
918
+ const channelScopeSettled = probeable ? new Promise((resolve) => {
919
+ announceSettled = resolve;
920
+ }) : Promise.resolve(channelScope);
921
+ const settleScope = (next) => {
922
+ channelScope = next;
923
+ adviseOnChannelScope(next);
924
+ _optionalChain([options, 'access', _23 => _23.onChannelScope, 'optionalCall', _24 => _24(next)]);
925
+ announceSettled(next);
926
+ };
927
+ if (probeable) {
928
+ void probeChannelScope({
929
+ doc: options.probeDocument !== void 0 ? options.probeDocument : globalThis.document,
930
+ issue: (post) => transport.requestVia(
931
+ post,
932
+ BRIDGE_METHOD.PROBE_FRAME_SCOPE,
933
+ {},
934
+ { timeoutMs: PROBE_TIMEOUT_MS }
935
+ )
936
+ }).then(settleScope).catch(() => settleScope("unknown"));
937
+ }
774
938
  return {
775
939
  transport,
776
940
  hello,
@@ -778,6 +942,10 @@ async function connectToHost(options) {
778
942
  get config() {
779
943
  return config;
780
944
  },
945
+ get channelScope() {
946
+ return channelScope;
947
+ },
948
+ channelScopeSettled,
781
949
  close() {
782
950
  transport.close();
783
951
  }
@@ -795,12 +963,12 @@ async function requestHostTransfer(transport, params) {
795
963
  );
796
964
  } catch (error) {
797
965
  if (error instanceof Error && isBridgeCode(error, BridgeErrorCode.SUBMISSION_UNCERTAIN)) {
798
- throw _chunkRAADLTSWcjs.markSubmissionUncertain.call(void 0, error);
966
+ throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0, error);
799
967
  }
800
968
  throw error;
801
969
  }
802
- if (!isTxHash(_optionalChain([result, 'optionalAccess', _17 => _17.txHash]))) {
803
- throw _chunkRAADLTSWcjs.markSubmissionUncertain.call(void 0,
970
+ if (!isTxHash(_optionalChain([result, 'optionalAccess', _25 => _25.txHash]))) {
971
+ throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0,
804
972
  new Error(
805
973
  "The app did not return a transaction hash. Check your activity before trying again."
806
974
  )
@@ -814,7 +982,7 @@ async function requestHostRecoverySignature(transport, params) {
814
982
  params,
815
983
  { timeoutMs: USER_APPROVAL_TIMEOUT_MS }
816
984
  );
817
- if (!isHex(_optionalChain([result, 'optionalAccess', _18 => _18.signature]))) {
985
+ if (!isHex(_optionalChain([result, 'optionalAccess', _26 => _26.signature]))) {
818
986
  throw new Error("The app did not return a signature.");
819
987
  }
820
988
  return result.signature;
@@ -823,7 +991,7 @@ async function requestHostBrowser(transport, url) {
823
991
  let parsed;
824
992
  try {
825
993
  parsed = new URL(url);
826
- } catch (e3) {
994
+ } catch (e6) {
827
995
  throw new Error("The payment page address could not be read.");
828
996
  }
829
997
  if (parsed.protocol !== "https:") {
@@ -875,8 +1043,8 @@ function uiStateFor(input) {
875
1043
  var VIEWPORT_HEIGHT_PROPERTY = "--rs-embed-viewport-height";
876
1044
  function trackVisualViewport(win) {
877
1045
  const target = win;
878
- const viewport = _optionalChain([target, 'optionalAccess', _19 => _19.visualViewport]);
879
- const style = _optionalChain([target, 'optionalAccess', _20 => _20.document, 'optionalAccess', _21 => _21.documentElement, 'optionalAccess', _22 => _22.style]);
1046
+ const viewport = _optionalChain([target, 'optionalAccess', _27 => _27.visualViewport]);
1047
+ const style = _optionalChain([target, 'optionalAccess', _28 => _28.document, 'optionalAccess', _29 => _29.documentElement, 'optionalAccess', _30 => _30.style]);
880
1048
  if (!viewport || !style) return () => {
881
1049
  };
882
1050
  const apply = () => {
@@ -898,10 +1066,10 @@ var UNKNOWN_SCREEN = "unknown";
898
1066
  // src/embed.tsx
899
1067
  var _jsxruntime = require('react/jsx-runtime');
900
1068
  var WithdrawModal = _react.lazy.call(void 0,
901
- () => Promise.resolve().then(() => _interopRequireWildcard(require("./WithdrawModal-YYSBPCJJ.cjs"))).then((m) => ({ default: m.WithdrawModal }))
1069
+ () => Promise.resolve().then(() => _interopRequireWildcard(require("./WithdrawModal-VP6PMIRO.cjs"))).then((m) => ({ default: m.WithdrawModal }))
902
1070
  );
903
1071
  var ClaimModal = _react.lazy.call(void 0,
904
- () => Promise.resolve().then(() => _interopRequireWildcard(require("./ClaimModal-JRIA32U2.cjs"))).then((m) => ({ default: m.ClaimModal }))
1072
+ () => Promise.resolve().then(() => _interopRequireWildcard(require("./ClaimModal-IKTJU43Y.cjs"))).then((m) => ({ default: m.ClaimModal }))
905
1073
  );
906
1074
  function missingField(config, keys) {
907
1075
  const missing = keys.find(
@@ -925,7 +1093,19 @@ function missingCapability(capabilities, needed, mode) {
925
1093
  message: `This app cannot run ${mode}: it does not implement ${needed}.`
926
1094
  };
927
1095
  }
928
- function refusal(config, capabilities) {
1096
+ var UNSCOPED_CHANNEL_CODE = "EMBED_CHANNEL_UNSCOPED";
1097
+ var UNSCOPED_REQUEST_MESSAGE = "This app cannot complete the request: every frame in its web view can reach the bridge channel.";
1098
+ function unscopedRefusal(mode) {
1099
+ return {
1100
+ code: UNSCOPED_CHANNEL_CODE,
1101
+ message: `This app cannot run ${mode}: every frame in its web view can reach the bridge channel, so the page will not send it a signing request.`
1102
+ };
1103
+ }
1104
+ function refusal(config, capabilities, channelScope) {
1105
+ if (channelScope === "all-frames") {
1106
+ if (config.mode === "withdraw") return unscopedRefusal("a withdrawal");
1107
+ if (config.mode === "claim") return unscopedRefusal("a claim");
1108
+ }
929
1109
  switch (config.mode) {
930
1110
  case "deposit": {
931
1111
  const missing = missingField(config, [
@@ -1011,6 +1191,7 @@ function sanitizeConfig(config) {
1011
1191
  enableQrTransfer: bool(config.enableQrTransfer),
1012
1192
  enableGaslessDeposit: bool(config.enableGaslessDeposit),
1013
1193
  enableExchangeConnect: bool(config.enableExchangeConnect),
1194
+ enableAnalyticsIngest: bool(config.enableAnalyticsIngest),
1014
1195
  fiatMethods: obj(config.fiatMethods),
1015
1196
  assetMigrations: obj(config.assetMigrations),
1016
1197
  initialAssetMigration: str(
@@ -1033,7 +1214,7 @@ function onrampUnavailable(config, capabilities) {
1033
1214
  message: `Fiat and exchange funding are hidden: this app does not implement ${CAPABILITY.OPEN_URL}.`
1034
1215
  };
1035
1216
  }
1036
- function toModalProps(config, canOpenExternally) {
1217
+ function toModalProps(config, canOpenExternally, walletWithheld) {
1037
1218
  return {
1038
1219
  isOpen: true,
1039
1220
  // Native draws the sheet. Inline is what stops the page drawing a scrim
@@ -1055,11 +1236,15 @@ function toModalProps(config, canOpenExternally) {
1055
1236
  outputTokenRules: config.outputTokenRules,
1056
1237
  rejectUnmapped: config.rejectUnmapped,
1057
1238
  forceRegister: config.forceRegister,
1058
- enableWallet: config.enableWallet,
1239
+ // Explicit `false`, not an absent flag: `DepositFlow` defaults
1240
+ // `enableWallet` to true, so leaving it undefined would offer the wallet
1241
+ // row on exactly the host it is being withheld from.
1242
+ enableWallet: walletWithheld ? false : config.enableWallet,
1059
1243
  enableFiatOnramp: canOpenExternally && config.enableFiatOnramp,
1060
1244
  enableQrTransfer: config.enableQrTransfer,
1061
1245
  enableGaslessDeposit: config.enableGaslessDeposit,
1062
1246
  enableExchangeConnect: canOpenExternally && config.enableExchangeConnect,
1247
+ enableAnalyticsIngest: config.enableAnalyticsIngest,
1063
1248
  fiatMethods: config.fiatMethods,
1064
1249
  assetMigrations: config.assetMigrations,
1065
1250
  initialAssetMigration: config.initialAssetMigration,
@@ -1072,6 +1257,7 @@ function DepositEmbed({ target, onFatal }) {
1072
1257
  const [session, setSession] = _react.useState.call(void 0, null);
1073
1258
  const [config, setConfig] = _react.useState.call(void 0, null);
1074
1259
  const [walletPending, setWalletPending] = _react.useState.call(void 0, false);
1260
+ const [channelScope, setChannelScope] = _react.useState.call(void 0, "unknown");
1075
1261
  const pendingRef = _react.useRef.call(void 0, false);
1076
1262
  const completedRef = _react.useRef.call(void 0, false);
1077
1263
  const uiRef = _react.useRef.call(void 0, {
@@ -1099,6 +1285,9 @@ function DepositEmbed({ target, onFatal }) {
1099
1285
  onPendingChange: (pending) => {
1100
1286
  pendingRef.current = pending > 0;
1101
1287
  if (live) setWalletPending(pending > 0);
1288
+ },
1289
+ onChannelScope: (scope) => {
1290
+ if (live) setChannelScope(scope);
1102
1291
  }
1103
1292
  });
1104
1293
  if (!live) {
@@ -1114,30 +1303,31 @@ function DepositEmbed({ target, onFatal }) {
1114
1303
  return { handled: true };
1115
1304
  }
1116
1305
  const back = uiRef.current.back;
1117
- _optionalChain([back, 'optionalCall', _23 => _23()]);
1306
+ _optionalChain([back, 'optionalCall', _31 => _31()]);
1118
1307
  return { handled: Boolean(back) };
1119
1308
  });
1120
- _chunkGACIGCSNcjs.setEmbedHost.call(void 0, next.hello.host);
1309
+ _chunk6KG642KHcjs.setEmbedHost.call(void 0, next.hello.host);
1121
1310
  setSession(next);
1311
+ setChannelScope(next.channelScope);
1122
1312
  setConfig(sanitizeConfig(next.hello.config));
1123
- void _chunkZMT4ATHRcjs.primeRuntimeChains.call(void 0, next.hello.config.backendUrl).then((result) => {
1313
+ void _chunkV2OBGLJDcjs.primeRuntimeChains.call(void 0, next.hello.config.backendUrl).then((result) => {
1124
1314
  chains = result;
1125
1315
  });
1126
1316
  } catch (error) {
1127
- if (live) _optionalChain([onFatalRef, 'access', _24 => _24.current, 'optionalCall', _25 => _25(error)]);
1317
+ if (live) _optionalChain([onFatalRef, 'access', _32 => _32.current, 'optionalCall', _33 => _33(error)]);
1128
1318
  }
1129
1319
  })();
1130
1320
  return () => {
1131
1321
  live = false;
1132
- _optionalChain([opened, 'optionalAccess', _26 => _26.close, 'call', _27 => _27()]);
1133
- _chunkGACIGCSNcjs.setEmbedHost.call(void 0, null);
1322
+ _optionalChain([opened, 'optionalAccess', _34 => _34.close, 'call', _35 => _35()]);
1323
+ _chunk6KG642KHcjs.setEmbedHost.call(void 0, null);
1134
1324
  };
1135
1325
  }, [target]);
1136
1326
  const handleUiState = _react.useCallback.call(void 0,
1137
1327
  (state) => {
1138
1328
  if (isHomeScreen(state.screen)) completedRef.current = false;
1139
1329
  uiRef.current = state;
1140
- _optionalChain([session, 'optionalAccess', _28 => _28.transport, 'access', _29 => _29.emit, 'call', _30 => _30(
1330
+ _optionalChain([session, 'optionalAccess', _36 => _36.transport, 'access', _37 => _37.emit, 'call', _38 => _38(
1141
1331
  "ui.state",
1142
1332
  uiStateFor({ ...state, walletRequestPending: walletPending })
1143
1333
  )]);
@@ -1158,16 +1348,30 @@ function DepositEmbed({ target, onFatal }) {
1158
1348
  uiStateFor({ ...uiRef.current, walletRequestPending: walletPending })
1159
1349
  );
1160
1350
  }, [session, walletPending]);
1161
- const refused = config && session ? refusal(config, session.hello.capabilities) : null;
1351
+ const refused = config && session ? refusal(config, session.hello.capabilities, channelScope) : null;
1352
+ const walletWithheld = channelScope === "all-frames" || channelScope === "probing";
1353
+ const refuseIfUnscoped = _react.useCallback.call(void 0, async () => {
1354
+ if (!session) throw new Error("The app is not connected.");
1355
+ const scope = await session.channelScopeSettled;
1356
+ if (scope === "all-frames") throw new Error(UNSCOPED_REQUEST_MESSAGE);
1357
+ }, [session]);
1162
1358
  _react.useEffect.call(void 0, () => {
1163
1359
  if (!session || !refused) return;
1164
1360
  session.transport.emit("error", refused);
1165
- }, [session, _optionalChain([refused, 'optionalAccess', _31 => _31.code]), _optionalChain([refused, 'optionalAccess', _32 => _32.message])]);
1361
+ }, [session, _optionalChain([refused, 'optionalAccess', _39 => _39.code]), _optionalChain([refused, 'optionalAccess', _40 => _40.message])]);
1166
1362
  const onrampHidden = config && session && !refused ? onrampUnavailable(config, session.hello.capabilities) : null;
1167
1363
  _react.useEffect.call(void 0, () => {
1168
1364
  if (!session || !onrampHidden) return;
1169
1365
  session.transport.emit("error", onrampHidden);
1170
- }, [session, _optionalChain([onrampHidden, 'optionalAccess', _33 => _33.code]), _optionalChain([onrampHidden, 'optionalAccess', _34 => _34.message])]);
1366
+ }, [session, _optionalChain([onrampHidden, 'optionalAccess', _41 => _41.code]), _optionalChain([onrampHidden, 'optionalAccess', _42 => _42.message])]);
1367
+ const walletHidden = session && !refused && channelScope === "all-frames" ? {
1368
+ code: UNSCOPED_CHANNEL_CODE,
1369
+ message: "Wallet funding is hidden: every frame in this app's web view can reach the bridge channel. Scope the injected channel to the main frame."
1370
+ } : null;
1371
+ _react.useEffect.call(void 0, () => {
1372
+ if (!session || !walletHidden) return;
1373
+ session.transport.emit("error", walletHidden);
1374
+ }, [session, _optionalChain([walletHidden, 'optionalAccess', _43 => _43.code]), _optionalChain([walletHidden, 'optionalAccess', _44 => _44.message])]);
1171
1375
  if (!session || !config || refused) return null;
1172
1376
  const ready = config;
1173
1377
  const { transport } = session;
@@ -1177,6 +1381,7 @@ function DepositEmbed({ target, onFatal }) {
1177
1381
  inline: true,
1178
1382
  className: "rs-embed",
1179
1383
  backendUrl: ready.backendUrl,
1384
+ enableAnalyticsIngest: ready.enableAnalyticsIngest,
1180
1385
  theme: config.theme,
1181
1386
  uiConfig: config.uiConfig,
1182
1387
  debug: config.debug,
@@ -1200,15 +1405,18 @@ function DepositEmbed({ target, onFatal }) {
1200
1405
  recipient: ready.recipient,
1201
1406
  defaultAmount: ready.defaultAmount,
1202
1407
  forceRegister: ready.forceRegister,
1203
- onSendTransaction: async (request) => ({
1204
- txHash: await requestHostTransfer(transport, {
1205
- chainId: request.chainId,
1206
- token: request.token,
1207
- amount: request.amount.toString(),
1208
- to: request.to,
1209
- from: ready.accountAddress
1210
- })
1211
- }),
1408
+ onSendTransaction: async (request) => {
1409
+ await refuseIfUnscoped();
1410
+ return {
1411
+ txHash: await requestHostTransfer(transport, {
1412
+ chainId: request.chainId,
1413
+ token: request.token,
1414
+ amount: request.amount.toString(),
1415
+ to: request.to,
1416
+ from: ready.accountAddress
1417
+ })
1418
+ };
1419
+ },
1212
1420
  onUiState: handleUiState,
1213
1421
  onLifecycle: (event) => {
1214
1422
  if (event.type === "complete") completedRef.current = true;
@@ -1224,16 +1432,15 @@ function DepositEmbed({ target, onFatal }) {
1224
1432
  ...shared,
1225
1433
  defaultTxHash: ready.defaultTxHash,
1226
1434
  defaultRefundDestination: ready.defaultDestination,
1227
- signRecovery: async ({ chainId, signer, depositId, destination }) => (
1228
- // The fields, not the struct: the host holds the canonical domain
1229
- // and types, so this cannot become a request to sign anything else.
1230
- await requestHostRecoverySignature(transport, {
1435
+ signRecovery: async ({ chainId, signer, depositId, destination }) => {
1436
+ await refuseIfUnscoped();
1437
+ return await requestHostRecoverySignature(transport, {
1231
1438
  chainId,
1232
1439
  signer,
1233
1440
  depositId,
1234
1441
  destination
1235
- })
1236
- ),
1442
+ });
1443
+ },
1237
1444
  onUiState: handleUiState,
1238
1445
  onLifecycle: (event) => {
1239
1446
  if (event.type === "complete") completedRef.current = true;
@@ -1243,11 +1450,12 @@ function DepositEmbed({ target, onFatal }) {
1243
1450
  ) });
1244
1451
  }
1245
1452
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1246
- _chunk2G2EIN4Acjs.DepositModalInner,
1453
+ _chunkYCQZJQO6cjs.DepositModalInner,
1247
1454
  {
1248
- ...toModalProps(ready, canOpenExternally),
1455
+ ...toModalProps(ready, canOpenExternally, walletWithheld),
1249
1456
  openExternally: canOpenExternally ? openExternally : void 0,
1250
- walletSession: session.wallet.session,
1457
+ walletSession: walletWithheld ? void 0 : session.wallet.session,
1458
+ walletIntegration: "host_supplied",
1251
1459
  hasWalletClientProp: false,
1252
1460
  onUiState: handleUiState,
1253
1461
  onReady: () => session.transport.emit("ready"),