@rhinestone/deposit-modal 0.12.2 → 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.
- package/README.md +73 -18
- package/bridge-transcript.json +653 -0
- package/dist/ClaimModal-IKTJU43Y.cjs +13 -0
- package/dist/ClaimModal-SEKNWRMA.mjs +13 -0
- package/dist/{DepositModalReown-VG66OTIU.cjs → DepositModalReown-46LPVFB6.cjs} +58 -35
- package/dist/{DepositModalReown-TEC3MEZ4.mjs → DepositModalReown-Q2JMLT47.mjs} +45 -22
- package/dist/{QRCode-WUC652SH.mjs → QRCode-5RGIZZHL.mjs} +1 -1
- package/dist/{QRCode-5DXFNKI2.cjs → QRCode-JKXG4RHN.cjs} +2 -2
- package/dist/WithdrawModal-5ICGD4HJ.mjs +12 -0
- package/dist/WithdrawModal-VP6PMIRO.cjs +12 -0
- package/dist/{chunk-O7BCVQ6L.cjs → chunk-4KCSH4T3.cjs} +157 -199
- package/dist/chunk-6KG642KH.cjs +31 -0
- package/dist/{chunk-PWLEBV5V.cjs → chunk-7ICSHJFE.cjs} +296 -220
- package/dist/{chunk-J46WDSRD.mjs → chunk-7SR7ENVJ.mjs} +165 -89
- package/dist/{chunk-2TPSF77V.mjs → chunk-CFKC77SV.mjs} +455 -261
- package/dist/{chunk-75DVGSAX.cjs → chunk-DW2EQA2U.cjs} +6 -3
- package/dist/{chunk-FXXUIK4E.mjs → chunk-IN77XSWO.mjs} +899 -153
- package/dist/chunk-K4H6TGBE.mjs +31 -0
- package/dist/{chunk-SDSKIJC7.mjs → chunk-KTUVSKR4.mjs} +2410 -1177
- package/dist/{chunk-HL5NUKZW.cjs → chunk-LZFRL2AL.cjs} +3 -3
- package/dist/{chunk-UQIJU6HV.cjs → chunk-MTFJSE52.cjs} +499 -191
- package/dist/{chunk-FLVLYO64.mjs → chunk-PKML3XVS.mjs} +430 -122
- package/dist/{chunk-4ZXQPFNU.mjs → chunk-RN5VKWI6.mjs} +4 -1
- package/dist/{chunk-BRYNGLDM.cjs → chunk-V2OBGLJD.cjs} +961 -215
- package/dist/{chunk-3STTWRAN.mjs → chunk-VUATPOWJ.mjs} +147 -189
- package/dist/{chunk-JE4R5VA3.mjs → chunk-WUJIKCFU.mjs} +1 -1
- package/dist/chunk-X2IPAPXU.cjs +163 -0
- package/dist/{chunk-OIN4CXCP.cjs → chunk-YCQZJQO6.cjs} +2343 -1110
- package/dist/{chunk-TM7VGHAG.cjs → chunk-YWMWI7PZ.cjs} +462 -268
- package/dist/chunk-ZEO6ADM3.mjs +163 -0
- package/dist/claim.cjs +7 -6
- package/dist/claim.d.cts +11 -3
- package/dist/claim.d.ts +11 -3
- package/dist/claim.mjs +6 -5
- package/dist/{constants-FuzG3h4m.d.cts → constants-DBrWhJWE.d.cts} +12 -7
- package/dist/{constants-FuzG3h4m.d.ts → constants-DBrWhJWE.d.ts} +12 -7
- package/dist/constants.cjs +3 -9
- package/dist/constants.d.cts +2 -3
- package/dist/constants.d.ts +2 -3
- package/dist/constants.mjs +4 -10
- package/dist/deposit.cjs +8 -8
- package/dist/deposit.d.cts +2 -2
- package/dist/deposit.d.ts +2 -2
- package/dist/deposit.mjs +7 -7
- package/dist/embed.cjs +1476 -0
- package/dist/embed.d.cts +183 -0
- package/dist/embed.d.ts +183 -0
- package/dist/embed.mjs +1476 -0
- package/dist/index.cjs +11 -16
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +14 -19
- package/dist/modal-ui-state-OD1RmKkK.d.cts +30 -0
- package/dist/modal-ui-state-OD1RmKkK.d.ts +30 -0
- package/dist/polymarket.cjs +17 -7
- package/dist/polymarket.mjs +13 -3
- package/dist/styles.css +124 -98
- package/dist/types-Bho4OA03.d.ts +982 -0
- package/dist/types-DP_3KwlD.d.cts +982 -0
- package/dist/withdraw.cjs +6 -6
- package/dist/withdraw.d.cts +11 -3
- package/dist/withdraw.d.ts +11 -3
- package/dist/withdraw.mjs +5 -5
- package/package.json +59 -6
- package/dist/chunk-IAGFDSNC.mjs +0 -11
- package/dist/chunk-L32UI7LA.cjs +0 -11
- package/dist/types-BO4iP6fG.d.cts +0 -612
- package/dist/types-oFblf65g.d.ts +0 -612
package/dist/embed.cjs
ADDED
|
@@ -0,0 +1,1476 @@
|
|
|
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
|
+
|
|
3
|
+
var _chunkYCQZJQO6cjs = require('./chunk-YCQZJQO6.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
var _chunk7ICSHJFEcjs = require('./chunk-7ICSHJFE.cjs');
|
|
7
|
+
require('./chunk-X2IPAPXU.cjs');
|
|
8
|
+
require('./chunk-LZFRL2AL.cjs');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
var _chunkV2OBGLJDcjs = require('./chunk-V2OBGLJD.cjs');
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
var _chunk6KG642KHcjs = require('./chunk-6KG642KH.cjs');
|
|
16
|
+
require('./chunk-DW2EQA2U.cjs');
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
var _chunk4KCSH4T3cjs = require('./chunk-4KCSH4T3.cjs');
|
|
21
|
+
|
|
22
|
+
// src/embed.tsx
|
|
23
|
+
var _react = require('react');
|
|
24
|
+
|
|
25
|
+
// src/core/bridge/protocol.ts
|
|
26
|
+
var PROTOCOL_VERSION = 2;
|
|
27
|
+
var PAGE_TO_HOST_CHANNEL = "rhinestoneBridge";
|
|
28
|
+
var HOST_TO_PAGE_CHANNEL = "__rhinestone_bridge";
|
|
29
|
+
var MAX_FRAME_LENGTH = 256 * 1024;
|
|
30
|
+
var BRIDGE_METHOD = {
|
|
31
|
+
/** Page→host, first frame of the session. Answers `HelloResult`. */
|
|
32
|
+
HELLO: "hello",
|
|
33
|
+
/** Page→host: a CAIP-27 wallet request, `Caip27Params`. */
|
|
34
|
+
WALLET_REQUEST: "wallet.request",
|
|
35
|
+
/** Page→host: withdraw's transfer. Gated by `CAPABILITY.SEND_TRANSACTION`. */
|
|
36
|
+
SEND_TRANSACTION: "host.sendTransaction",
|
|
37
|
+
/** Page→host: claim's signature. Gated by `CAPABILITY.SIGN_RECOVERY`. */
|
|
38
|
+
SIGN_RECOVERY: "host.signRecovery",
|
|
39
|
+
/** Page→host: show a payment page outside the web view. Gated by
|
|
40
|
+
* `CAPABILITY.OPEN_URL`. */
|
|
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"
|
|
51
|
+
};
|
|
52
|
+
var HOST_METHOD = {
|
|
53
|
+
/** Host→page: Android's hardware back and iOS's interactive swipe. Answers
|
|
54
|
+
* `UiBackResult`. */
|
|
55
|
+
BACK: "ui.back"
|
|
56
|
+
};
|
|
57
|
+
var CAPABILITY = {
|
|
58
|
+
SEND_TRANSACTION: BRIDGE_METHOD.SEND_TRANSACTION,
|
|
59
|
+
SIGN_RECOVERY: BRIDGE_METHOD.SIGN_RECOVERY,
|
|
60
|
+
OPEN_URL: BRIDGE_METHOD.OPEN_URL,
|
|
61
|
+
PROBE_FRAME_SCOPE: BRIDGE_METHOD.PROBE_FRAME_SCOPE
|
|
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
|
+
];
|
|
78
|
+
var ALLOWED_WALLET_METHODS = [
|
|
79
|
+
"eth_chainId",
|
|
80
|
+
"eth_accounts",
|
|
81
|
+
"eth_sendTransaction",
|
|
82
|
+
"wallet_sendTransaction",
|
|
83
|
+
"eth_signTypedData_v4",
|
|
84
|
+
"wallet_switchEthereumChain"
|
|
85
|
+
];
|
|
86
|
+
var SUBMITTING_WALLET_METHODS = [
|
|
87
|
+
"eth_sendTransaction",
|
|
88
|
+
"wallet_sendTransaction"
|
|
89
|
+
];
|
|
90
|
+
var BRIDGE_ERROR_DOMAIN = "bridge";
|
|
91
|
+
var BridgeErrorCode = {
|
|
92
|
+
/** The host has a wallet but cannot reach it — app not installed, session
|
|
93
|
+
* dropped mid-request. Distinct from 4900, which means not connected. */
|
|
94
|
+
WALLET_UNAVAILABLE: 1,
|
|
95
|
+
/**
|
|
96
|
+
* The host cannot say whether the transaction reached the network.
|
|
97
|
+
*
|
|
98
|
+
* An app switch can be killed by the OS between wallet submission and the
|
|
99
|
+
* return trip. Without a code for it the host must lie in one direction or
|
|
100
|
+
* the other, and the safe-looking lie — reporting failure — is the one that
|
|
101
|
+
* double-spends. The page shows its existing "status is uncertain" copy and
|
|
102
|
+
* must not offer a retry.
|
|
103
|
+
*/
|
|
104
|
+
SUBMISSION_UNCERTAIN: 2,
|
|
105
|
+
/** The page's own deadline expired. Raised page-side, never sent by a host. */
|
|
106
|
+
REQUEST_TIMEOUT: 3,
|
|
107
|
+
/** The channel went away with the request outstanding. */
|
|
108
|
+
CHANNEL_CLOSED: 4,
|
|
109
|
+
/** The host answered, but not with something the method can return — a null
|
|
110
|
+
* transaction hash, an `eth_accounts` that is not an array. */
|
|
111
|
+
MALFORMED_RESULT: 5
|
|
112
|
+
};
|
|
113
|
+
function bridgeError(code, message, data) {
|
|
114
|
+
return { domain: BRIDGE_ERROR_DOMAIN, code, message, data };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/core/bridge/channel.ts
|
|
118
|
+
var NoHostChannelError = class extends Error {
|
|
119
|
+
constructor() {
|
|
120
|
+
super(
|
|
121
|
+
`No host channel: window.${PAGE_TO_HOST_CHANNEL}.postMessage is not installed`
|
|
122
|
+
);
|
|
123
|
+
this.name = "NoHostChannelError";
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
function readHostChannel(target) {
|
|
127
|
+
const candidate = target[PAGE_TO_HOST_CHANNEL];
|
|
128
|
+
if (!candidate || typeof candidate.postMessage !== "function") {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
return candidate;
|
|
132
|
+
}
|
|
133
|
+
function createWindowChannel(target, onInvalidFrame) {
|
|
134
|
+
return {
|
|
135
|
+
post(json) {
|
|
136
|
+
const host = readHostChannel(target);
|
|
137
|
+
if (!host) throw new NoHostChannelError();
|
|
138
|
+
host.postMessage(json);
|
|
139
|
+
},
|
|
140
|
+
subscribe(onFrame) {
|
|
141
|
+
const receiver = (frame) => {
|
|
142
|
+
if (typeof frame !== "string") {
|
|
143
|
+
_optionalChain([onInvalidFrame, 'optionalCall', _ => _()]);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
onFrame(frame);
|
|
147
|
+
};
|
|
148
|
+
target[HOST_TO_PAGE_CHANNEL] = receiver;
|
|
149
|
+
return () => {
|
|
150
|
+
if (target[HOST_TO_PAGE_CHANNEL] === receiver) {
|
|
151
|
+
delete target[HOST_TO_PAGE_CHANNEL];
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/core/bridge/transport.ts
|
|
159
|
+
var _viem = require('viem');
|
|
160
|
+
|
|
161
|
+
// src/core/bridge/envelope.ts
|
|
162
|
+
function isRecord(value) {
|
|
163
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
164
|
+
}
|
|
165
|
+
function isFiniteNumber(value) {
|
|
166
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
167
|
+
}
|
|
168
|
+
function isNonEmptyString(value) {
|
|
169
|
+
return typeof value === "string" && value.length > 0;
|
|
170
|
+
}
|
|
171
|
+
function isBridgeError(value) {
|
|
172
|
+
if (!isRecord(value)) return false;
|
|
173
|
+
if (!isFiniteNumber(value.code)) return false;
|
|
174
|
+
if (typeof value.message !== "string") return false;
|
|
175
|
+
if (value.data !== void 0 && typeof value.data !== "string") return false;
|
|
176
|
+
if (value.domain !== void 0 && value.domain !== BRIDGE_ERROR_DOMAIN) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
function parseEnvelope(raw) {
|
|
182
|
+
if (raw.length > MAX_FRAME_LENGTH) return { ok: false, reason: "too-large" };
|
|
183
|
+
let value;
|
|
184
|
+
try {
|
|
185
|
+
value = JSON.parse(raw);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
return { ok: false, reason: "not-json" };
|
|
188
|
+
}
|
|
189
|
+
if (!isRecord(value)) return { ok: false, reason: "not-an-object" };
|
|
190
|
+
switch (value.kind) {
|
|
191
|
+
case "event": {
|
|
192
|
+
if (!isNonEmptyString(value.type)) {
|
|
193
|
+
return { ok: false, reason: "bad-event" };
|
|
194
|
+
}
|
|
195
|
+
return { ok: true, envelope: value };
|
|
196
|
+
}
|
|
197
|
+
case "request": {
|
|
198
|
+
if (!isNonEmptyString(value.id) || !isNonEmptyString(value.method)) {
|
|
199
|
+
return { ok: false, reason: "bad-request" };
|
|
200
|
+
}
|
|
201
|
+
return { ok: true, envelope: value };
|
|
202
|
+
}
|
|
203
|
+
case "response": {
|
|
204
|
+
if (!isNonEmptyString(value.id)) {
|
|
205
|
+
return { ok: false, reason: "bad-response" };
|
|
206
|
+
}
|
|
207
|
+
if (value.ok === true) {
|
|
208
|
+
if (!("result" in value)) {
|
|
209
|
+
return { ok: false, reason: "bad-response" };
|
|
210
|
+
}
|
|
211
|
+
return { ok: true, envelope: value };
|
|
212
|
+
}
|
|
213
|
+
if (value.ok === false && isBridgeError(value.error)) {
|
|
214
|
+
return { ok: true, envelope: value };
|
|
215
|
+
}
|
|
216
|
+
return { ok: false, reason: "bad-response" };
|
|
217
|
+
}
|
|
218
|
+
default:
|
|
219
|
+
return { ok: false, reason: "unknown-kind" };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/core/bridge/transport.ts
|
|
224
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
225
|
+
var USER_APPROVAL_TIMEOUT_MS = 18e4;
|
|
226
|
+
function emptyStats() {
|
|
227
|
+
return {
|
|
228
|
+
"too-large": 0,
|
|
229
|
+
"not-json": 0,
|
|
230
|
+
"not-an-object": 0,
|
|
231
|
+
"unknown-kind": 0,
|
|
232
|
+
"bad-event": 0,
|
|
233
|
+
"bad-request": 0,
|
|
234
|
+
"bad-response": 0,
|
|
235
|
+
"not-a-string": 0,
|
|
236
|
+
"unknown-event": 0,
|
|
237
|
+
"unknown-method": 0,
|
|
238
|
+
"unmatched-response": 0,
|
|
239
|
+
"duplicate-request": 0,
|
|
240
|
+
closed: 0
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
var BridgeRequestError = class extends _viem.BaseError {
|
|
244
|
+
constructor(error) {
|
|
245
|
+
super(error.message, { name: "BridgeRequestError" });
|
|
246
|
+
this.code = error.code;
|
|
247
|
+
this.domain = error.domain;
|
|
248
|
+
Object.defineProperty(this, "data", {
|
|
249
|
+
value: error.data,
|
|
250
|
+
enumerable: false,
|
|
251
|
+
writable: false
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
function isBridgeRequestError(error) {
|
|
256
|
+
return error instanceof BridgeRequestError;
|
|
257
|
+
}
|
|
258
|
+
function isBridgeCode(error, code) {
|
|
259
|
+
return isBridgeRequestError(error) && error.domain === BRIDGE_ERROR_DOMAIN && error.code === code;
|
|
260
|
+
}
|
|
261
|
+
function randomSessionId() {
|
|
262
|
+
const bytes = new Uint8Array(16);
|
|
263
|
+
const webcrypto = globalThis.crypto;
|
|
264
|
+
if (_optionalChain([webcrypto, 'optionalAccess', _2 => _2.getRandomValues])) {
|
|
265
|
+
webcrypto.getRandomValues(bytes);
|
|
266
|
+
} else {
|
|
267
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
268
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
272
|
+
}
|
|
273
|
+
var REPLAY_CACHE_SIZE = 32;
|
|
274
|
+
function createBridgeTransport(options) {
|
|
275
|
+
const { channel } = options;
|
|
276
|
+
const sessionId = _nullishCoalesce(options.sessionId, () => ( randomSessionId()));
|
|
277
|
+
const defaultTimeoutMs = _nullishCoalesce(options.defaultTimeoutMs, () => ( DEFAULT_REQUEST_TIMEOUT_MS));
|
|
278
|
+
const stats = emptyStats();
|
|
279
|
+
const pending = /* @__PURE__ */ new Map();
|
|
280
|
+
const inbound = /* @__PURE__ */ new Map();
|
|
281
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
282
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
283
|
+
let counter = 0;
|
|
284
|
+
let closed = false;
|
|
285
|
+
const unsubscribe = channel.subscribe(onFrame);
|
|
286
|
+
function drop(reason) {
|
|
287
|
+
stats[reason] += 1;
|
|
288
|
+
}
|
|
289
|
+
function send(frame) {
|
|
290
|
+
channel.post(JSON.stringify(frame));
|
|
291
|
+
}
|
|
292
|
+
function notifyPending() {
|
|
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)]);
|
|
296
|
+
}
|
|
297
|
+
function forgetPending(id) {
|
|
298
|
+
const entry = pending.get(id);
|
|
299
|
+
if (!entry) return void 0;
|
|
300
|
+
pending.delete(id);
|
|
301
|
+
notifyPending();
|
|
302
|
+
return entry;
|
|
303
|
+
}
|
|
304
|
+
function settle(id, settleWith) {
|
|
305
|
+
const entry = forgetPending(id);
|
|
306
|
+
if (!entry) {
|
|
307
|
+
drop("unmatched-response");
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (entry.timer !== void 0) clearTimeout(entry.timer);
|
|
311
|
+
settleWith(entry);
|
|
312
|
+
}
|
|
313
|
+
function onFrame(raw) {
|
|
314
|
+
if (closed) {
|
|
315
|
+
drop("closed");
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const parsed = parseEnvelope(raw);
|
|
319
|
+
if (!parsed.ok) {
|
|
320
|
+
drop(parsed.reason);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const envelope = parsed.envelope;
|
|
324
|
+
if (envelope.kind === "response") {
|
|
325
|
+
settle(envelope.id, (entry) => {
|
|
326
|
+
if (envelope.ok) entry.resolve(envelope.result);
|
|
327
|
+
else entry.reject(new BridgeRequestError(envelope.error));
|
|
328
|
+
});
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (envelope.kind === "event") {
|
|
332
|
+
const listener = listeners.get(envelope.type);
|
|
333
|
+
if (!listener) {
|
|
334
|
+
drop("unknown-event");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
listener(envelope.payload);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
void answer(envelope.id, envelope.method, envelope.params);
|
|
341
|
+
}
|
|
342
|
+
function settleInbound(id, response) {
|
|
343
|
+
inbound.set(id, { status: "settled", response });
|
|
344
|
+
if (inbound.size > REPLAY_CACHE_SIZE) {
|
|
345
|
+
for (const [key, value] of inbound) {
|
|
346
|
+
if (key !== id && value.status === "settled") {
|
|
347
|
+
inbound.delete(key);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
send(response);
|
|
353
|
+
}
|
|
354
|
+
async function answer(id, method, params) {
|
|
355
|
+
const seen = inbound.get(id);
|
|
356
|
+
if (seen) {
|
|
357
|
+
drop("duplicate-request");
|
|
358
|
+
if (seen.status === "settled") send(seen.response);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const handler = handlers.get(method);
|
|
362
|
+
if (!handler) {
|
|
363
|
+
drop("unknown-method");
|
|
364
|
+
send({
|
|
365
|
+
kind: "response",
|
|
366
|
+
id,
|
|
367
|
+
ok: false,
|
|
368
|
+
error: { code: 4200, message: `Unsupported method: ${method}` }
|
|
369
|
+
});
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
inbound.set(id, { status: "running" });
|
|
373
|
+
try {
|
|
374
|
+
const result = await handler(params);
|
|
375
|
+
settleInbound(id, { kind: "response", id, ok: true, result: _nullishCoalesce(result, () => ( null)) });
|
|
376
|
+
} catch (error) {
|
|
377
|
+
settleInbound(id, {
|
|
378
|
+
kind: "response",
|
|
379
|
+
id,
|
|
380
|
+
ok: false,
|
|
381
|
+
error: {
|
|
382
|
+
code: -32603,
|
|
383
|
+
message: error instanceof Error ? error.message : "Page error"
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
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(
|
|
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(
|
|
431
|
+
bridgeError(
|
|
432
|
+
BridgeErrorCode.CHANNEL_CLOSED,
|
|
433
|
+
"The connection to the app closed."
|
|
434
|
+
)
|
|
435
|
+
) : error
|
|
436
|
+
);
|
|
437
|
+
}
|
|
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);
|
|
453
|
+
},
|
|
454
|
+
emit(type, payload) {
|
|
455
|
+
if (closed) return;
|
|
456
|
+
try {
|
|
457
|
+
send({ kind: "event", type, payload });
|
|
458
|
+
} catch (e2) {
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
handle(method, handler) {
|
|
462
|
+
handlers.set(method, handler);
|
|
463
|
+
},
|
|
464
|
+
on(type, handler) {
|
|
465
|
+
listeners.set(type, handler);
|
|
466
|
+
},
|
|
467
|
+
close() {
|
|
468
|
+
if (closed) return;
|
|
469
|
+
closed = true;
|
|
470
|
+
unsubscribe();
|
|
471
|
+
const closing = new BridgeRequestError(
|
|
472
|
+
bridgeError(
|
|
473
|
+
BridgeErrorCode.CHANNEL_CLOSED,
|
|
474
|
+
"The connection to the app closed."
|
|
475
|
+
)
|
|
476
|
+
);
|
|
477
|
+
for (const [, entry] of pending) {
|
|
478
|
+
if (entry.timer !== void 0) clearTimeout(entry.timer);
|
|
479
|
+
entry.reject(closing);
|
|
480
|
+
}
|
|
481
|
+
pending.clear();
|
|
482
|
+
notifyPending();
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}
|
|
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
|
+
|
|
587
|
+
// src/core/bridge/validate.ts
|
|
588
|
+
function isRecord2(value) {
|
|
589
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
590
|
+
}
|
|
591
|
+
var TX_HASH = /^0x[0-9a-fA-F]{64}$/;
|
|
592
|
+
var HEX = /^0x[0-9a-fA-F]+$/;
|
|
593
|
+
function isTxHash(value) {
|
|
594
|
+
return typeof value === "string" && TX_HASH.test(value);
|
|
595
|
+
}
|
|
596
|
+
function isHex(value) {
|
|
597
|
+
return typeof value === "string" && HEX.test(value);
|
|
598
|
+
}
|
|
599
|
+
function optionalString(value) {
|
|
600
|
+
return typeof value === "string" ? value : void 0;
|
|
601
|
+
}
|
|
602
|
+
function parseWalletState(value) {
|
|
603
|
+
if (!isRecord2(value)) return void 0;
|
|
604
|
+
if (typeof value.isReady !== "boolean") return void 0;
|
|
605
|
+
if (typeof value.isConnected !== "boolean") return void 0;
|
|
606
|
+
if (!Array.isArray(value.accounts)) return void 0;
|
|
607
|
+
const accounts = [];
|
|
608
|
+
for (const entry of value.accounts) {
|
|
609
|
+
if (isRecord2(entry) && typeof entry.caip10 === "string") {
|
|
610
|
+
accounts.push({ caip10: entry.caip10 });
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
const chainId = typeof value.chainId === "string" ? value.chainId : value.chainId === null ? null : void 0;
|
|
614
|
+
if (chainId === void 0) return void 0;
|
|
615
|
+
return {
|
|
616
|
+
isReady: value.isReady,
|
|
617
|
+
isConnected: value.isConnected,
|
|
618
|
+
accounts,
|
|
619
|
+
chainId,
|
|
620
|
+
icon: optionalString(value.icon),
|
|
621
|
+
name: optionalString(value.name)
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function parseHelloResult(value) {
|
|
625
|
+
if (!isRecord2(value)) return void 0;
|
|
626
|
+
if (typeof value.protocol !== "number" || !Number.isFinite(value.protocol)) {
|
|
627
|
+
return void 0;
|
|
628
|
+
}
|
|
629
|
+
const host = isRecord2(value.host) ? value.host : void 0;
|
|
630
|
+
if (!host) return void 0;
|
|
631
|
+
const platform = host.platform === "ios" || host.platform === "android" ? host.platform : "other";
|
|
632
|
+
const wallet = parseWalletState(value.wallet);
|
|
633
|
+
if (!wallet) return void 0;
|
|
634
|
+
if (!isRecord2(value.config)) return void 0;
|
|
635
|
+
const capabilities = Array.isArray(value.capabilities) ? value.capabilities.filter(
|
|
636
|
+
(entry) => typeof entry === "string"
|
|
637
|
+
) : [];
|
|
638
|
+
return {
|
|
639
|
+
protocol: value.protocol,
|
|
640
|
+
host: {
|
|
641
|
+
platform,
|
|
642
|
+
app: optionalString(host.app),
|
|
643
|
+
version: optionalString(host.version)
|
|
644
|
+
},
|
|
645
|
+
capabilities,
|
|
646
|
+
config: value.config,
|
|
647
|
+
wallet
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/core/bridge/wallet.ts
|
|
652
|
+
|
|
653
|
+
var ALLOWED = new Set(ALLOWED_WALLET_METHODS);
|
|
654
|
+
var SWITCH_CONFIRMATION_TIMEOUT_MS = 15e3;
|
|
655
|
+
var HASH_PATTERN = /^0x[0-9a-fA-F]{64}$/;
|
|
656
|
+
var HEX_PATTERN = /^0x[0-9a-fA-F]*$/;
|
|
657
|
+
function evmAccount(state) {
|
|
658
|
+
return _optionalChain([state, 'access', _13 => _13.accounts, 'access', _14 => _14.find, 'call', _15 => _15((account) => account.caip10.startsWith("eip155:")), 'optionalAccess', _16 => _16.caip10]);
|
|
659
|
+
}
|
|
660
|
+
function evmAddressFrom(state) {
|
|
661
|
+
const caip10 = evmAccount(state);
|
|
662
|
+
if (!caip10) return void 0;
|
|
663
|
+
const parts = caip10.split(":");
|
|
664
|
+
return parts.length === 3 ? parts[2] : void 0;
|
|
665
|
+
}
|
|
666
|
+
function evmChainIdFrom(caip2) {
|
|
667
|
+
if (!caip2) return void 0;
|
|
668
|
+
const parts = caip2.split(":");
|
|
669
|
+
if (parts.length !== 2 || parts[0] !== "eip155") return void 0;
|
|
670
|
+
const id = Number(parts[1]);
|
|
671
|
+
return Number.isInteger(id) && id > 0 ? id : void 0;
|
|
672
|
+
}
|
|
673
|
+
function switchTargetChainId(params) {
|
|
674
|
+
const first = Array.isArray(params) ? params[0] : void 0;
|
|
675
|
+
if (typeof first !== "object" || first === null) return void 0;
|
|
676
|
+
const hex = first.chainId;
|
|
677
|
+
if (typeof hex !== "string") return void 0;
|
|
678
|
+
const id = Number.parseInt(hex, 16);
|
|
679
|
+
return Number.isInteger(id) && id > 0 ? id : void 0;
|
|
680
|
+
}
|
|
681
|
+
function syntheticChain(chainId) {
|
|
682
|
+
return {
|
|
683
|
+
id: chainId,
|
|
684
|
+
name: _chunk4KCSH4T3cjs.getChainName.call(void 0, chainId),
|
|
685
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
686
|
+
rpcUrls: { default: { http: [] } }
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
function assertResultShape(method, result) {
|
|
690
|
+
const bad = (detail) => {
|
|
691
|
+
const error = new BridgeRequestError(
|
|
692
|
+
bridgeError(
|
|
693
|
+
BridgeErrorCode.MALFORMED_RESULT,
|
|
694
|
+
"The app returned something unexpected. Check your wallet activity before trying again.",
|
|
695
|
+
`${method}: ${detail}`
|
|
696
|
+
)
|
|
697
|
+
);
|
|
698
|
+
throw SUBMITTING_WALLET_METHODS.includes(method) ? _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0, error) : error;
|
|
699
|
+
};
|
|
700
|
+
switch (method) {
|
|
701
|
+
case "eth_sendTransaction":
|
|
702
|
+
case "wallet_sendTransaction":
|
|
703
|
+
if (typeof result !== "string" || !HASH_PATTERN.test(result)) {
|
|
704
|
+
bad("expected a 32-byte transaction hash");
|
|
705
|
+
}
|
|
706
|
+
return;
|
|
707
|
+
case "eth_signTypedData_v4":
|
|
708
|
+
if (typeof result !== "string" || !HEX_PATTERN.test(result)) {
|
|
709
|
+
bad("expected a hex signature");
|
|
710
|
+
}
|
|
711
|
+
return;
|
|
712
|
+
case "eth_chainId":
|
|
713
|
+
if (typeof result !== "string" || !HEX_PATTERN.test(result)) {
|
|
714
|
+
bad("expected a hex quantity");
|
|
715
|
+
}
|
|
716
|
+
return;
|
|
717
|
+
case "eth_accounts":
|
|
718
|
+
if (!Array.isArray(result)) bad("expected an array of addresses");
|
|
719
|
+
return;
|
|
720
|
+
default:
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
function createBridgedWalletSession(options) {
|
|
725
|
+
let state = options.state;
|
|
726
|
+
const { transport, resolveChain } = options;
|
|
727
|
+
let cachedClient;
|
|
728
|
+
let cachedKey;
|
|
729
|
+
const stateWaiters = /* @__PURE__ */ new Set();
|
|
730
|
+
async function walletRequest(method, params) {
|
|
731
|
+
if (!ALLOWED.has(method)) {
|
|
732
|
+
throw new Error(`Method not supported over the bridge: ${method}`);
|
|
733
|
+
}
|
|
734
|
+
const target = switchTargetChainId(params);
|
|
735
|
+
const chainId = target !== void 0 ? `eip155:${target}` : _nullishCoalesce(state.chainId, () => ( void 0));
|
|
736
|
+
if (!chainId) {
|
|
737
|
+
throw new Error("No chain selected for this wallet request");
|
|
738
|
+
}
|
|
739
|
+
const submitting = SUBMITTING_WALLET_METHODS.includes(method);
|
|
740
|
+
const caip27 = { chainId, request: { method, params } };
|
|
741
|
+
let result;
|
|
742
|
+
try {
|
|
743
|
+
result = await transport.request(
|
|
744
|
+
BRIDGE_METHOD.WALLET_REQUEST,
|
|
745
|
+
caip27,
|
|
746
|
+
{ timeoutMs: USER_APPROVAL_TIMEOUT_MS, uncertainOnTimeout: submitting }
|
|
747
|
+
);
|
|
748
|
+
} catch (error) {
|
|
749
|
+
if (submitting && isBridgeRequestError(error) && error.code === -32603) {
|
|
750
|
+
throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0,
|
|
751
|
+
new BridgeRequestError(
|
|
752
|
+
bridgeError(
|
|
753
|
+
BridgeErrorCode.SUBMISSION_UNCERTAIN,
|
|
754
|
+
"The app could not confirm whether the transaction was sent. Check your wallet activity before trying again.",
|
|
755
|
+
error.data
|
|
756
|
+
)
|
|
757
|
+
)
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
if (submitting && isBridgeCode(error, BridgeErrorCode.SUBMISSION_UNCERTAIN)) {
|
|
761
|
+
throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0, error);
|
|
762
|
+
}
|
|
763
|
+
throw error;
|
|
764
|
+
}
|
|
765
|
+
assertResultShape(method, result);
|
|
766
|
+
return result;
|
|
767
|
+
}
|
|
768
|
+
const evmTransport = _viem.custom.call(void 0, {
|
|
769
|
+
async request({ method, params }) {
|
|
770
|
+
return walletRequest(method, params);
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
function currentClient() {
|
|
774
|
+
const address = evmAddressFrom(state);
|
|
775
|
+
const chainId = evmChainIdFrom(state.chainId);
|
|
776
|
+
if (!address || chainId === void 0) return void 0;
|
|
777
|
+
const chain = _nullishCoalesce(resolveChain(chainId), () => ( syntheticChain(chainId)));
|
|
778
|
+
const key = `${address}:${chainId}`;
|
|
779
|
+
if (cachedClient && cachedKey === key) return cachedClient;
|
|
780
|
+
cachedClient = _viem.createWalletClient.call(void 0, {
|
|
781
|
+
account: address,
|
|
782
|
+
chain,
|
|
783
|
+
transport: evmTransport
|
|
784
|
+
});
|
|
785
|
+
cachedKey = key;
|
|
786
|
+
return cachedClient;
|
|
787
|
+
}
|
|
788
|
+
function awaitChain(chainId) {
|
|
789
|
+
if (evmChainIdFrom(state.chainId) === chainId) return Promise.resolve();
|
|
790
|
+
return new Promise((resolve, reject) => {
|
|
791
|
+
let timer;
|
|
792
|
+
const waiter = (next) => {
|
|
793
|
+
if (evmChainIdFrom(next.chainId) !== chainId) return;
|
|
794
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
795
|
+
stateWaiters.delete(waiter);
|
|
796
|
+
resolve();
|
|
797
|
+
};
|
|
798
|
+
timer = setTimeout(() => {
|
|
799
|
+
stateWaiters.delete(waiter);
|
|
800
|
+
reject(
|
|
801
|
+
new Error(
|
|
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`
|
|
803
|
+
)
|
|
804
|
+
);
|
|
805
|
+
}, SWITCH_CONFIRMATION_TIMEOUT_MS);
|
|
806
|
+
stateWaiters.add(waiter);
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
const session = {
|
|
810
|
+
get walletClient() {
|
|
811
|
+
return currentClient();
|
|
812
|
+
},
|
|
813
|
+
get canSignEvm() {
|
|
814
|
+
return state.isConnected && currentClient() !== void 0;
|
|
815
|
+
},
|
|
816
|
+
// Reads fall back to `getPublicClient`; a bridged host has no
|
|
817
|
+
// wallet-backed client to offer.
|
|
818
|
+
publicClient: void 0,
|
|
819
|
+
get address() {
|
|
820
|
+
return evmAddressFrom(state);
|
|
821
|
+
},
|
|
822
|
+
get caipAddress() {
|
|
823
|
+
return evmAccount(state);
|
|
824
|
+
},
|
|
825
|
+
get isConnected() {
|
|
826
|
+
return state.isConnected;
|
|
827
|
+
},
|
|
828
|
+
get isReady() {
|
|
829
|
+
return state.isReady;
|
|
830
|
+
},
|
|
831
|
+
get icon() {
|
|
832
|
+
return state.icon;
|
|
833
|
+
},
|
|
834
|
+
isSolana: false,
|
|
835
|
+
solanaAddress: void 0,
|
|
836
|
+
solanaProvider: void 0,
|
|
837
|
+
solanaConnection: void 0,
|
|
838
|
+
openConnect: () => transport.emit("wallet.connectRequested"),
|
|
839
|
+
disconnect: () => transport.emit("wallet.disconnectRequested"),
|
|
840
|
+
switchChain: async (chainId) => {
|
|
841
|
+
try {
|
|
842
|
+
await walletRequest("wallet_switchEthereumChain", [
|
|
843
|
+
{ chainId: `0x${chainId.toString(16)}` }
|
|
844
|
+
]);
|
|
845
|
+
} catch (error) {
|
|
846
|
+
if (isBridgeRequestError(error)) throw new Error(error.message);
|
|
847
|
+
throw error;
|
|
848
|
+
}
|
|
849
|
+
await awaitChain(chainId);
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
return {
|
|
853
|
+
session,
|
|
854
|
+
applyWalletState(next) {
|
|
855
|
+
state = next;
|
|
856
|
+
for (const waiter of [...stateWaiters]) waiter(next);
|
|
857
|
+
_optionalChain([options, 'access', _19 => _19.onStateChange, 'optionalCall', _20 => _20(next)]);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// src/core/bridge/connect.ts
|
|
863
|
+
var BridgeHandshakeError = class extends Error {
|
|
864
|
+
constructor(message) {
|
|
865
|
+
super(message);
|
|
866
|
+
this.name = "BridgeHandshakeError";
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
async function connectToHost(options) {
|
|
870
|
+
let invalidFrames = 0;
|
|
871
|
+
const channel = createWindowChannel(options.target, () => {
|
|
872
|
+
invalidFrames += 1;
|
|
873
|
+
});
|
|
874
|
+
const transport = createBridgeTransport({
|
|
875
|
+
channel,
|
|
876
|
+
onPendingChange: options.onPendingChange
|
|
877
|
+
});
|
|
878
|
+
const params = {
|
|
879
|
+
protocol: PROTOCOL_VERSION,
|
|
880
|
+
modalVersion: _chunk6KG642KHcjs.MODAL_VERSION
|
|
881
|
+
};
|
|
882
|
+
let raw;
|
|
883
|
+
try {
|
|
884
|
+
raw = await transport.request(BRIDGE_METHOD.HELLO, params, {
|
|
885
|
+
timeoutMs: options.helloTimeoutMs
|
|
886
|
+
});
|
|
887
|
+
} catch (error) {
|
|
888
|
+
transport.close();
|
|
889
|
+
throw error;
|
|
890
|
+
}
|
|
891
|
+
const hello = parseHelloResult(raw);
|
|
892
|
+
if (!hello) {
|
|
893
|
+
transport.close();
|
|
894
|
+
throw new BridgeHandshakeError(
|
|
895
|
+
invalidFrames > 0 ? "The app answered the handshake with something that was not a string frame." : "The app answered the handshake with an unusable payload."
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
let config = hello.config;
|
|
899
|
+
const wallet = createBridgedWalletSession({
|
|
900
|
+
transport,
|
|
901
|
+
state: hello.wallet,
|
|
902
|
+
resolveChain: options.resolveChain,
|
|
903
|
+
onStateChange: options.onWalletState
|
|
904
|
+
});
|
|
905
|
+
transport.on("wallet.state", (payload) => {
|
|
906
|
+
const next = parseWalletState(payload);
|
|
907
|
+
if (next) wallet.applyWalletState(next);
|
|
908
|
+
});
|
|
909
|
+
transport.on("session.configure", (payload) => {
|
|
910
|
+
if (typeof payload !== "object" || payload === null) return;
|
|
911
|
+
config = payload;
|
|
912
|
+
_optionalChain([options, 'access', _21 => _21.onConfig, 'optionalCall', _22 => _22(config)]);
|
|
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
|
+
}
|
|
938
|
+
return {
|
|
939
|
+
transport,
|
|
940
|
+
hello,
|
|
941
|
+
wallet,
|
|
942
|
+
get config() {
|
|
943
|
+
return config;
|
|
944
|
+
},
|
|
945
|
+
get channelScope() {
|
|
946
|
+
return channelScope;
|
|
947
|
+
},
|
|
948
|
+
channelScopeSettled,
|
|
949
|
+
close() {
|
|
950
|
+
transport.close();
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// src/core/bridge/capabilities.ts
|
|
956
|
+
async function requestHostTransfer(transport, params) {
|
|
957
|
+
let result;
|
|
958
|
+
try {
|
|
959
|
+
result = await transport.request(
|
|
960
|
+
BRIDGE_METHOD.SEND_TRANSACTION,
|
|
961
|
+
params,
|
|
962
|
+
{ timeoutMs: USER_APPROVAL_TIMEOUT_MS, uncertainOnTimeout: true }
|
|
963
|
+
);
|
|
964
|
+
} catch (error) {
|
|
965
|
+
if (error instanceof Error && isBridgeCode(error, BridgeErrorCode.SUBMISSION_UNCERTAIN)) {
|
|
966
|
+
throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0, error);
|
|
967
|
+
}
|
|
968
|
+
throw error;
|
|
969
|
+
}
|
|
970
|
+
if (!isTxHash(_optionalChain([result, 'optionalAccess', _25 => _25.txHash]))) {
|
|
971
|
+
throw _chunk7ICSHJFEcjs.markSubmissionUncertain.call(void 0,
|
|
972
|
+
new Error(
|
|
973
|
+
"The app did not return a transaction hash. Check your activity before trying again."
|
|
974
|
+
)
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
return result.txHash;
|
|
978
|
+
}
|
|
979
|
+
async function requestHostRecoverySignature(transport, params) {
|
|
980
|
+
const result = await transport.request(
|
|
981
|
+
BRIDGE_METHOD.SIGN_RECOVERY,
|
|
982
|
+
params,
|
|
983
|
+
{ timeoutMs: USER_APPROVAL_TIMEOUT_MS }
|
|
984
|
+
);
|
|
985
|
+
if (!isHex(_optionalChain([result, 'optionalAccess', _26 => _26.signature]))) {
|
|
986
|
+
throw new Error("The app did not return a signature.");
|
|
987
|
+
}
|
|
988
|
+
return result.signature;
|
|
989
|
+
}
|
|
990
|
+
async function requestHostBrowser(transport, url) {
|
|
991
|
+
let parsed;
|
|
992
|
+
try {
|
|
993
|
+
parsed = new URL(url);
|
|
994
|
+
} catch (e6) {
|
|
995
|
+
throw new Error("The payment page address could not be read.");
|
|
996
|
+
}
|
|
997
|
+
if (parsed.protocol !== "https:") {
|
|
998
|
+
throw new Error("The payment page address is not a secure link.");
|
|
999
|
+
}
|
|
1000
|
+
await transport.request(BRIDGE_METHOD.OPEN_URL, {
|
|
1001
|
+
url
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/core/bridge/ui-state.ts
|
|
1006
|
+
var SETTLING_SCREENS = /* @__PURE__ */ new Set(["processing"]);
|
|
1007
|
+
var HOME_SCREENS = /* @__PURE__ */ new Set(["connect", "form", "lookup"]);
|
|
1008
|
+
function isHomeScreen(screen) {
|
|
1009
|
+
return HOME_SCREENS.has(screen);
|
|
1010
|
+
}
|
|
1011
|
+
function dismissalFor(input) {
|
|
1012
|
+
if (input.walletRequestPending) {
|
|
1013
|
+
return {
|
|
1014
|
+
state: "blocked",
|
|
1015
|
+
reason: "wallet-request-pending",
|
|
1016
|
+
message: "Waiting for your wallet."
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
if (input.submitting) {
|
|
1020
|
+
return {
|
|
1021
|
+
state: "blocked",
|
|
1022
|
+
reason: "submission-in-flight",
|
|
1023
|
+
message: "Confirming your deposit."
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
if (SETTLING_SCREENS.has(input.screen)) {
|
|
1027
|
+
return {
|
|
1028
|
+
state: "blocked",
|
|
1029
|
+
reason: "settlement-in-progress",
|
|
1030
|
+
message: "Your deposit is on its way."
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
return { state: "allowed" };
|
|
1034
|
+
}
|
|
1035
|
+
function canGoBackNow(input) {
|
|
1036
|
+
return dismissalFor(input).state !== "blocked";
|
|
1037
|
+
}
|
|
1038
|
+
function uiStateFor(input) {
|
|
1039
|
+
return { screen: input.screen, dismissal: dismissalFor(input) };
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// src/core/bridge/viewport.ts
|
|
1043
|
+
var VIEWPORT_HEIGHT_PROPERTY = "--rs-embed-viewport-height";
|
|
1044
|
+
function trackVisualViewport(win) {
|
|
1045
|
+
const target = win;
|
|
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]);
|
|
1048
|
+
if (!viewport || !style) return () => {
|
|
1049
|
+
};
|
|
1050
|
+
const apply = () => {
|
|
1051
|
+
style.setProperty(VIEWPORT_HEIGHT_PROPERTY, `${viewport.height}px`);
|
|
1052
|
+
};
|
|
1053
|
+
apply();
|
|
1054
|
+
viewport.addEventListener("resize", apply);
|
|
1055
|
+
viewport.addEventListener("scroll", apply);
|
|
1056
|
+
return () => {
|
|
1057
|
+
viewport.removeEventListener("resize", apply);
|
|
1058
|
+
viewport.removeEventListener("scroll", apply);
|
|
1059
|
+
style.removeProperty(VIEWPORT_HEIGHT_PROPERTY);
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// src/core/modal-ui-state.ts
|
|
1064
|
+
var UNKNOWN_SCREEN = "unknown";
|
|
1065
|
+
|
|
1066
|
+
// src/embed.tsx
|
|
1067
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
1068
|
+
var WithdrawModal = _react.lazy.call(void 0,
|
|
1069
|
+
() => Promise.resolve().then(() => _interopRequireWildcard(require("./WithdrawModal-VP6PMIRO.cjs"))).then((m) => ({ default: m.WithdrawModal }))
|
|
1070
|
+
);
|
|
1071
|
+
var ClaimModal = _react.lazy.call(void 0,
|
|
1072
|
+
() => Promise.resolve().then(() => _interopRequireWildcard(require("./ClaimModal-IKTJU43Y.cjs"))).then((m) => ({ default: m.ClaimModal }))
|
|
1073
|
+
);
|
|
1074
|
+
function missingField(config, keys) {
|
|
1075
|
+
const missing = keys.find(
|
|
1076
|
+
(key) => typeof config[key] !== "string" || config[key] === ""
|
|
1077
|
+
);
|
|
1078
|
+
return missing ? {
|
|
1079
|
+
code: "EMBED_CONFIG_INVALID",
|
|
1080
|
+
message: `The app did not supply ${String(missing)}.`
|
|
1081
|
+
} : null;
|
|
1082
|
+
}
|
|
1083
|
+
var EVM_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
1084
|
+
function isEvmAddress(value) {
|
|
1085
|
+
return typeof value === "string" && EVM_ADDRESS.test(value);
|
|
1086
|
+
}
|
|
1087
|
+
function isEvmChainId(value) {
|
|
1088
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
1089
|
+
}
|
|
1090
|
+
function missingCapability(capabilities, needed, mode) {
|
|
1091
|
+
return capabilities.includes(needed) ? null : {
|
|
1092
|
+
code: "EMBED_CAPABILITY_MISSING",
|
|
1093
|
+
message: `This app cannot run ${mode}: it does not implement ${needed}.`
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
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
|
+
}
|
|
1109
|
+
switch (config.mode) {
|
|
1110
|
+
case "deposit": {
|
|
1111
|
+
const missing = missingField(config, [
|
|
1112
|
+
"backendUrl",
|
|
1113
|
+
"recipient",
|
|
1114
|
+
"targetToken"
|
|
1115
|
+
]);
|
|
1116
|
+
if (missing) return missing;
|
|
1117
|
+
const { targetChain } = config;
|
|
1118
|
+
const validTarget = typeof targetChain === "number" && Number.isInteger(targetChain) && targetChain > 0 || targetChain === "solana" || targetChain === _chunk4KCSH4T3cjs.HYPERCORE_SPOT_CAIP2;
|
|
1119
|
+
return validTarget ? null : {
|
|
1120
|
+
code: "EMBED_CONFIG_INVALID",
|
|
1121
|
+
message: `The app supplied a targetChain this page cannot resolve: ${JSON.stringify(targetChain)}.`
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
case "withdraw": {
|
|
1125
|
+
const capability = missingCapability(
|
|
1126
|
+
capabilities,
|
|
1127
|
+
CAPABILITY.SEND_TRANSACTION,
|
|
1128
|
+
"a withdrawal"
|
|
1129
|
+
);
|
|
1130
|
+
if (capability) return capability;
|
|
1131
|
+
const missing = missingField(config, ["backendUrl", "accountAddress"]);
|
|
1132
|
+
if (missing) return missing;
|
|
1133
|
+
const badWithdrawField = !isEvmAddress(config.accountAddress) && "accountAddress" || !isEvmChainId(config.sourceChain) && "sourceChain" || !isEvmAddress(config.sourceToken) && "sourceToken";
|
|
1134
|
+
return badWithdrawField ? {
|
|
1135
|
+
code: "EMBED_CONFIG_INVALID",
|
|
1136
|
+
message: `The app supplied a ${badWithdrawField} this page cannot use.`
|
|
1137
|
+
} : null;
|
|
1138
|
+
}
|
|
1139
|
+
case "claim": {
|
|
1140
|
+
const capability = missingCapability(
|
|
1141
|
+
capabilities,
|
|
1142
|
+
CAPABILITY.SIGN_RECOVERY,
|
|
1143
|
+
"a claim"
|
|
1144
|
+
);
|
|
1145
|
+
if (capability) return capability;
|
|
1146
|
+
return missingField(config, ["backendUrl"]);
|
|
1147
|
+
}
|
|
1148
|
+
default:
|
|
1149
|
+
return {
|
|
1150
|
+
code: "EMBED_MODE_UNSUPPORTED",
|
|
1151
|
+
message: `This page cannot run in ${String(_nullishCoalesce(config.mode, () => ( "an unnamed")))} mode.`
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
function sanitizeConfig(config) {
|
|
1156
|
+
const str = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
1157
|
+
const num = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1158
|
+
const bool = (value) => typeof value === "boolean" ? value : void 0;
|
|
1159
|
+
const arr = (value) => Array.isArray(value) ? value : void 0;
|
|
1160
|
+
const obj = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1161
|
+
const target = (value) => {
|
|
1162
|
+
if (typeof value === "number" && Number.isInteger(value) && value > 0) {
|
|
1163
|
+
return value;
|
|
1164
|
+
}
|
|
1165
|
+
return value === "solana" || value === _chunk4KCSH4T3cjs.HYPERCORE_SPOT_CAIP2 ? value : void 0;
|
|
1166
|
+
};
|
|
1167
|
+
return {
|
|
1168
|
+
// Raw, because it is the discriminant `refusal` switches on — anything
|
|
1169
|
+
// else has to reach it to be named in the error.
|
|
1170
|
+
mode: config.mode,
|
|
1171
|
+
// Typed like everything else, even though `refusal` also checks them.
|
|
1172
|
+
// Required is a property of the MODE, not of the field: `targetToken` and
|
|
1173
|
+
// `recipient` are required for a deposit and optional seeds for a
|
|
1174
|
+
// withdrawal, so passing them through raw let a withdraw config carry a
|
|
1175
|
+
// non-string into `targetToken.toLowerCase()` and take the page down.
|
|
1176
|
+
// Dropping first means `refusal` still fails the modes that need them, and
|
|
1177
|
+
// the modes that do not simply see an absent seed.
|
|
1178
|
+
backendUrl: str(config.backendUrl),
|
|
1179
|
+
recipient: str(config.recipient),
|
|
1180
|
+
targetChain: target(config.targetChain),
|
|
1181
|
+
targetToken: str(config.targetToken),
|
|
1182
|
+
sourceChain: num(config.sourceChain),
|
|
1183
|
+
sourceToken: str(config.sourceToken),
|
|
1184
|
+
defaultAmount: str(config.defaultAmount),
|
|
1185
|
+
appBalanceUsd: num(config.appBalanceUsd),
|
|
1186
|
+
outputTokenRules: arr(config.outputTokenRules),
|
|
1187
|
+
rejectUnmapped: bool(config.rejectUnmapped),
|
|
1188
|
+
forceRegister: bool(config.forceRegister),
|
|
1189
|
+
enableWallet: bool(config.enableWallet),
|
|
1190
|
+
enableFiatOnramp: bool(config.enableFiatOnramp),
|
|
1191
|
+
enableQrTransfer: bool(config.enableQrTransfer),
|
|
1192
|
+
enableGaslessDeposit: bool(config.enableGaslessDeposit),
|
|
1193
|
+
enableExchangeConnect: bool(config.enableExchangeConnect),
|
|
1194
|
+
enableAnalyticsIngest: bool(config.enableAnalyticsIngest),
|
|
1195
|
+
fiatMethods: obj(config.fiatMethods),
|
|
1196
|
+
assetMigrations: obj(config.assetMigrations),
|
|
1197
|
+
initialAssetMigration: str(
|
|
1198
|
+
config.initialAssetMigration
|
|
1199
|
+
),
|
|
1200
|
+
theme: obj(config.theme),
|
|
1201
|
+
uiConfig: obj(config.uiConfig),
|
|
1202
|
+
debug: bool(config.debug),
|
|
1203
|
+
accountAddress: str(config.accountAddress),
|
|
1204
|
+
defaultTxHash: str(config.defaultTxHash),
|
|
1205
|
+
defaultDestination: str(config.defaultDestination)
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
function onrampUnavailable(config, capabilities) {
|
|
1209
|
+
if (config.mode !== "deposit") return null;
|
|
1210
|
+
if (capabilities.includes(CAPABILITY.OPEN_URL)) return null;
|
|
1211
|
+
if (!config.enableFiatOnramp && !config.enableExchangeConnect) return null;
|
|
1212
|
+
return {
|
|
1213
|
+
code: "EMBED_CAPABILITY_MISSING",
|
|
1214
|
+
message: `Fiat and exchange funding are hidden: this app does not implement ${CAPABILITY.OPEN_URL}.`
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
function toModalProps(config, canOpenExternally, walletWithheld) {
|
|
1218
|
+
return {
|
|
1219
|
+
isOpen: true,
|
|
1220
|
+
// Native draws the sheet. Inline is what stops the page drawing a scrim
|
|
1221
|
+
// and a second one inside it; the class carries back what an inline mount
|
|
1222
|
+
// otherwise loses — safe-area clearance and the input sizing that stops
|
|
1223
|
+
// iOS zooming on focus, both of which the stylesheet scopes to the overlay.
|
|
1224
|
+
inline: true,
|
|
1225
|
+
className: "rs-embed",
|
|
1226
|
+
onClose: () => {
|
|
1227
|
+
},
|
|
1228
|
+
targetChain: config.targetChain,
|
|
1229
|
+
targetToken: config.targetToken,
|
|
1230
|
+
recipient: config.recipient,
|
|
1231
|
+
backendUrl: config.backendUrl,
|
|
1232
|
+
sourceChain: config.sourceChain,
|
|
1233
|
+
sourceToken: config.sourceToken,
|
|
1234
|
+
defaultAmount: config.defaultAmount,
|
|
1235
|
+
appBalanceUsd: config.appBalanceUsd,
|
|
1236
|
+
outputTokenRules: config.outputTokenRules,
|
|
1237
|
+
rejectUnmapped: config.rejectUnmapped,
|
|
1238
|
+
forceRegister: config.forceRegister,
|
|
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,
|
|
1243
|
+
enableFiatOnramp: canOpenExternally && config.enableFiatOnramp,
|
|
1244
|
+
enableQrTransfer: config.enableQrTransfer,
|
|
1245
|
+
enableGaslessDeposit: config.enableGaslessDeposit,
|
|
1246
|
+
enableExchangeConnect: canOpenExternally && config.enableExchangeConnect,
|
|
1247
|
+
enableAnalyticsIngest: config.enableAnalyticsIngest,
|
|
1248
|
+
fiatMethods: config.fiatMethods,
|
|
1249
|
+
assetMigrations: config.assetMigrations,
|
|
1250
|
+
initialAssetMigration: config.initialAssetMigration,
|
|
1251
|
+
theme: config.theme,
|
|
1252
|
+
uiConfig: config.uiConfig,
|
|
1253
|
+
debug: config.debug
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
function DepositEmbed({ target, onFatal }) {
|
|
1257
|
+
const [session, setSession] = _react.useState.call(void 0, null);
|
|
1258
|
+
const [config, setConfig] = _react.useState.call(void 0, null);
|
|
1259
|
+
const [walletPending, setWalletPending] = _react.useState.call(void 0, false);
|
|
1260
|
+
const [channelScope, setChannelScope] = _react.useState.call(void 0, "unknown");
|
|
1261
|
+
const pendingRef = _react.useRef.call(void 0, false);
|
|
1262
|
+
const completedRef = _react.useRef.call(void 0, false);
|
|
1263
|
+
const uiRef = _react.useRef.call(void 0, {
|
|
1264
|
+
screen: UNKNOWN_SCREEN,
|
|
1265
|
+
submitting: false
|
|
1266
|
+
});
|
|
1267
|
+
const onFatalRef = _react.useRef.call(void 0, onFatal);
|
|
1268
|
+
onFatalRef.current = onFatal;
|
|
1269
|
+
_react.useEffect.call(void 0,
|
|
1270
|
+
() => trackVisualViewport(_nullishCoalesce(target, () => ( globalThis.window))),
|
|
1271
|
+
[target]
|
|
1272
|
+
);
|
|
1273
|
+
_react.useEffect.call(void 0, () => {
|
|
1274
|
+
let live = true;
|
|
1275
|
+
let opened = null;
|
|
1276
|
+
let chains = [];
|
|
1277
|
+
void (async () => {
|
|
1278
|
+
try {
|
|
1279
|
+
const next = await connectToHost({
|
|
1280
|
+
target: _nullishCoalesce(target, () => ( globalThis.window)),
|
|
1281
|
+
resolveChain: (chainId) => chains.find((chain) => chain.id === chainId),
|
|
1282
|
+
onConfig: (updated) => {
|
|
1283
|
+
if (live) setConfig(sanitizeConfig(updated));
|
|
1284
|
+
},
|
|
1285
|
+
onPendingChange: (pending) => {
|
|
1286
|
+
pendingRef.current = pending > 0;
|
|
1287
|
+
if (live) setWalletPending(pending > 0);
|
|
1288
|
+
},
|
|
1289
|
+
onChannelScope: (scope) => {
|
|
1290
|
+
if (live) setChannelScope(scope);
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
if (!live) {
|
|
1294
|
+
next.close();
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
opened = next;
|
|
1298
|
+
next.transport.handle(HOST_METHOD.BACK, () => {
|
|
1299
|
+
if (!canGoBackNow({
|
|
1300
|
+
...uiRef.current,
|
|
1301
|
+
walletRequestPending: pendingRef.current
|
|
1302
|
+
})) {
|
|
1303
|
+
return { handled: true };
|
|
1304
|
+
}
|
|
1305
|
+
const back = uiRef.current.back;
|
|
1306
|
+
_optionalChain([back, 'optionalCall', _31 => _31()]);
|
|
1307
|
+
return { handled: Boolean(back) };
|
|
1308
|
+
});
|
|
1309
|
+
_chunk6KG642KHcjs.setEmbedHost.call(void 0, next.hello.host);
|
|
1310
|
+
setSession(next);
|
|
1311
|
+
setChannelScope(next.channelScope);
|
|
1312
|
+
setConfig(sanitizeConfig(next.hello.config));
|
|
1313
|
+
void _chunkV2OBGLJDcjs.primeRuntimeChains.call(void 0, next.hello.config.backendUrl).then((result) => {
|
|
1314
|
+
chains = result;
|
|
1315
|
+
});
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
if (live) _optionalChain([onFatalRef, 'access', _32 => _32.current, 'optionalCall', _33 => _33(error)]);
|
|
1318
|
+
}
|
|
1319
|
+
})();
|
|
1320
|
+
return () => {
|
|
1321
|
+
live = false;
|
|
1322
|
+
_optionalChain([opened, 'optionalAccess', _34 => _34.close, 'call', _35 => _35()]);
|
|
1323
|
+
_chunk6KG642KHcjs.setEmbedHost.call(void 0, null);
|
|
1324
|
+
};
|
|
1325
|
+
}, [target]);
|
|
1326
|
+
const handleUiState = _react.useCallback.call(void 0,
|
|
1327
|
+
(state) => {
|
|
1328
|
+
if (isHomeScreen(state.screen)) completedRef.current = false;
|
|
1329
|
+
uiRef.current = state;
|
|
1330
|
+
_optionalChain([session, 'optionalAccess', _36 => _36.transport, 'access', _37 => _37.emit, 'call', _38 => _38(
|
|
1331
|
+
"ui.state",
|
|
1332
|
+
uiStateFor({ ...state, walletRequestPending: walletPending })
|
|
1333
|
+
)]);
|
|
1334
|
+
},
|
|
1335
|
+
[session, walletPending]
|
|
1336
|
+
);
|
|
1337
|
+
const openExternally = _react.useCallback.call(void 0,
|
|
1338
|
+
async (url) => {
|
|
1339
|
+
if (!session) throw new Error("The app is not connected.");
|
|
1340
|
+
await requestHostBrowser(session.transport, url);
|
|
1341
|
+
},
|
|
1342
|
+
[session]
|
|
1343
|
+
);
|
|
1344
|
+
_react.useEffect.call(void 0, () => {
|
|
1345
|
+
if (!session) return;
|
|
1346
|
+
session.transport.emit(
|
|
1347
|
+
"ui.state",
|
|
1348
|
+
uiStateFor({ ...uiRef.current, walletRequestPending: walletPending })
|
|
1349
|
+
);
|
|
1350
|
+
}, [session, walletPending]);
|
|
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]);
|
|
1358
|
+
_react.useEffect.call(void 0, () => {
|
|
1359
|
+
if (!session || !refused) return;
|
|
1360
|
+
session.transport.emit("error", refused);
|
|
1361
|
+
}, [session, _optionalChain([refused, 'optionalAccess', _39 => _39.code]), _optionalChain([refused, 'optionalAccess', _40 => _40.message])]);
|
|
1362
|
+
const onrampHidden = config && session && !refused ? onrampUnavailable(config, session.hello.capabilities) : null;
|
|
1363
|
+
_react.useEffect.call(void 0, () => {
|
|
1364
|
+
if (!session || !onrampHidden) return;
|
|
1365
|
+
session.transport.emit("error", onrampHidden);
|
|
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])]);
|
|
1375
|
+
if (!session || !config || refused) return null;
|
|
1376
|
+
const ready = config;
|
|
1377
|
+
const { transport } = session;
|
|
1378
|
+
const canOpenExternally = session.hello.capabilities.includes(CAPABILITY.OPEN_URL);
|
|
1379
|
+
const shared = {
|
|
1380
|
+
isOpen: true,
|
|
1381
|
+
inline: true,
|
|
1382
|
+
className: "rs-embed",
|
|
1383
|
+
backendUrl: ready.backendUrl,
|
|
1384
|
+
enableAnalyticsIngest: ready.enableAnalyticsIngest,
|
|
1385
|
+
theme: config.theme,
|
|
1386
|
+
uiConfig: config.uiConfig,
|
|
1387
|
+
debug: config.debug,
|
|
1388
|
+
onReady: () => transport.emit("ready"),
|
|
1389
|
+
onEvent: (event) => transport.emit("analytics", event),
|
|
1390
|
+
onError: (data) => transport.emit("error", data),
|
|
1391
|
+
onClose: () => transport.emit("dismissRequested", {
|
|
1392
|
+
source: completedRef.current ? "flow-complete" : "close-button"
|
|
1393
|
+
})
|
|
1394
|
+
};
|
|
1395
|
+
if (ready.mode === "withdraw") {
|
|
1396
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Suspense, { fallback: null, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1397
|
+
WithdrawModal,
|
|
1398
|
+
{
|
|
1399
|
+
...shared,
|
|
1400
|
+
accountAddress: ready.accountAddress,
|
|
1401
|
+
sourceChain: ready.sourceChain,
|
|
1402
|
+
sourceToken: ready.sourceToken,
|
|
1403
|
+
targetChain: typeof ready.targetChain === "number" ? ready.targetChain : void 0,
|
|
1404
|
+
targetToken: ready.targetToken,
|
|
1405
|
+
recipient: ready.recipient,
|
|
1406
|
+
defaultAmount: ready.defaultAmount,
|
|
1407
|
+
forceRegister: ready.forceRegister,
|
|
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
|
+
},
|
|
1420
|
+
onUiState: handleUiState,
|
|
1421
|
+
onLifecycle: (event) => {
|
|
1422
|
+
if (event.type === "complete") completedRef.current = true;
|
|
1423
|
+
transport.emit("lifecycle", event);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
) });
|
|
1427
|
+
}
|
|
1428
|
+
if (ready.mode === "claim") {
|
|
1429
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react.Suspense, { fallback: null, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1430
|
+
ClaimModal,
|
|
1431
|
+
{
|
|
1432
|
+
...shared,
|
|
1433
|
+
defaultTxHash: ready.defaultTxHash,
|
|
1434
|
+
defaultRefundDestination: ready.defaultDestination,
|
|
1435
|
+
signRecovery: async ({ chainId, signer, depositId, destination }) => {
|
|
1436
|
+
await refuseIfUnscoped();
|
|
1437
|
+
return await requestHostRecoverySignature(transport, {
|
|
1438
|
+
chainId,
|
|
1439
|
+
signer,
|
|
1440
|
+
depositId,
|
|
1441
|
+
destination
|
|
1442
|
+
});
|
|
1443
|
+
},
|
|
1444
|
+
onUiState: handleUiState,
|
|
1445
|
+
onLifecycle: (event) => {
|
|
1446
|
+
if (event.type === "complete") completedRef.current = true;
|
|
1447
|
+
transport.emit("lifecycle", event);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
) });
|
|
1451
|
+
}
|
|
1452
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1453
|
+
_chunkYCQZJQO6cjs.DepositModalInner,
|
|
1454
|
+
{
|
|
1455
|
+
...toModalProps(ready, canOpenExternally, walletWithheld),
|
|
1456
|
+
openExternally: canOpenExternally ? openExternally : void 0,
|
|
1457
|
+
walletSession: walletWithheld ? void 0 : session.wallet.session,
|
|
1458
|
+
walletIntegration: "host_supplied",
|
|
1459
|
+
hasWalletClientProp: false,
|
|
1460
|
+
onUiState: handleUiState,
|
|
1461
|
+
onReady: () => session.transport.emit("ready"),
|
|
1462
|
+
onLifecycle: (event) => {
|
|
1463
|
+
if (event.type === "complete") completedRef.current = true;
|
|
1464
|
+
session.transport.emit("lifecycle", event);
|
|
1465
|
+
},
|
|
1466
|
+
onEvent: (event) => session.transport.emit("analytics", event),
|
|
1467
|
+
onError: (data) => session.transport.emit("error", data),
|
|
1468
|
+
onClose: () => session.transport.emit("dismissRequested", {
|
|
1469
|
+
source: completedRef.current ? "flow-complete" : "close-button"
|
|
1470
|
+
})
|
|
1471
|
+
}
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
|
|
1476
|
+
exports.DepositEmbed = DepositEmbed;
|