@1sat/permission-module-ui 0.0.45 → 0.0.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OneSatPermissionPrompt.d.ts +5 -14
- package/dist/OneSatPermissionPrompt.d.ts.map +1 -1
- package/dist/index.js +576 -727
- package/dist/styles.d.ts +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/package.json +40 -40
package/dist/index.js
CHANGED
|
@@ -2,68 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/OneSatPermissionPrompt.tsx
|
|
4
4
|
import {
|
|
5
|
+
isTransactionPrompt,
|
|
5
6
|
verifyIntent
|
|
6
7
|
} from "@1sat/permission-module";
|
|
7
|
-
|
|
8
|
-
// ../types/dist/constants.js
|
|
9
|
-
var ORDINALS_BASKET = "p 1sat ordinals";
|
|
10
|
-
var BSV21_BASKET = "p 1sat bsv21";
|
|
11
|
-
var OPNS_BASKET = "p 1sat opns";
|
|
12
|
-
var LOCK_BASKET = "p 1sat lock";
|
|
13
|
-
var P1SAT_INTENTS = {
|
|
14
|
-
OPNS_REGISTER: "opns.register",
|
|
15
|
-
OPNS_DEREGISTER: "opns.deregister",
|
|
16
|
-
OPNS_LIST: "opns.list",
|
|
17
|
-
OPNS_TRANSFER: "opns.transfer",
|
|
18
|
-
OPNS_CANCEL_LISTING: "opns.cancel-listing",
|
|
19
|
-
OPNS_PURCHASE: "opns.purchase",
|
|
20
|
-
ORDINAL_TRANSFER: "ordinal.transfer",
|
|
21
|
-
ORDINAL_LIST: "ordinal.list",
|
|
22
|
-
ORDINAL_CANCEL_LISTING: "ordinal.cancel-listing",
|
|
23
|
-
ORDINAL_PURCHASE: "ordinal.purchase",
|
|
24
|
-
ORDINAL_BURN: "ordinal.burn",
|
|
25
|
-
ORDINAL_INSCRIBE: "ordinal.inscribe",
|
|
26
|
-
ORDINAL_INSCRIBE_SIGMA: "ordinal.inscribe-sigma",
|
|
27
|
-
ORDINAL_MINT_COLLECTION: "ordinal.mint-collection",
|
|
28
|
-
ORDINAL_MINT_ITEM: "ordinal.mint-item",
|
|
29
|
-
LOCK_LOCK: "lock.lock",
|
|
30
|
-
LOCK_UNLOCK: "lock.unlock",
|
|
31
|
-
BSV21_TRANSFER: "bsv21.transfer",
|
|
32
|
-
BSV21_PURCHASE: "bsv21.purchase",
|
|
33
|
-
BSV21_MINT: "bsv21.mint",
|
|
34
|
-
BSV21_DEPLOY: "bsv21.deploy"
|
|
35
|
-
};
|
|
36
|
-
var P1SAT_INTENT_IDS = new Set(Object.values(P1SAT_INTENTS));
|
|
37
|
-
var MAX_INSCRIPTION_BYTES = 50 * 1024 * 1024;
|
|
38
|
-
var EXCHANGE_RATE_CACHE_TTL = 5 * 60 * 1000;
|
|
39
|
-
var DEFAULT_STREAM_CHUNK_SIZE = 1024 * 1024;
|
|
40
|
-
|
|
41
|
-
// ../types/dist/index.js
|
|
42
|
-
var TokenType;
|
|
43
|
-
(function(TokenType2) {
|
|
44
|
-
TokenType2["BSV20"] = "bsv20";
|
|
45
|
-
TokenType2["BSV21"] = "bsv21";
|
|
46
|
-
})(TokenType || (TokenType = {}));
|
|
47
|
-
var TokenSelectionStrategy;
|
|
48
|
-
(function(TokenSelectionStrategy2) {
|
|
49
|
-
TokenSelectionStrategy2["SmallestFirst"] = "smallest";
|
|
50
|
-
TokenSelectionStrategy2["LargestFirst"] = "largest";
|
|
51
|
-
TokenSelectionStrategy2["RetainOrder"] = "retain";
|
|
52
|
-
TokenSelectionStrategy2["Random"] = "random";
|
|
53
|
-
})(TokenSelectionStrategy || (TokenSelectionStrategy = {}));
|
|
54
|
-
var TokenInputMode;
|
|
55
|
-
(function(TokenInputMode2) {
|
|
56
|
-
TokenInputMode2["All"] = "all";
|
|
57
|
-
TokenInputMode2["Needed"] = "needed";
|
|
58
|
-
})(TokenInputMode || (TokenInputMode = {}));
|
|
59
|
-
var RoytaltyType;
|
|
60
|
-
(function(RoytaltyType2) {
|
|
61
|
-
RoytaltyType2["Paymail"] = "paymail";
|
|
62
|
-
RoytaltyType2["Address"] = "address";
|
|
63
|
-
RoytaltyType2["Script"] = "script";
|
|
64
|
-
})(RoytaltyType || (RoytaltyType = {}));
|
|
65
|
-
|
|
66
|
-
// src/OneSatPermissionPrompt.tsx
|
|
67
8
|
import { useEffect, useState } from "react";
|
|
68
9
|
|
|
69
10
|
// src/styles.ts
|
|
@@ -190,6 +131,28 @@ var promptStyles = `
|
|
|
190
131
|
padding: 16px;
|
|
191
132
|
}
|
|
192
133
|
|
|
134
|
+
/* Subtle danger chrome for burn / destructive token ops */
|
|
135
|
+
.opp-featured-danger {
|
|
136
|
+
border-color: rgba(220, 38, 38, 0.45);
|
|
137
|
+
background: color-mix(in srgb, var(--opp-card-bg) 88%, #7f1d1d 12%);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.opp-featured-danger .opp-featured-title {
|
|
141
|
+
color: #f87171;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.opp-featured-danger .opp-featured-image,
|
|
145
|
+
.opp-featured-danger .opp-featured-placeholder {
|
|
146
|
+
border: 1px solid rgba(220, 38, 38, 0.35);
|
|
147
|
+
background: rgba(127, 29, 29, 0.25);
|
|
148
|
+
color: #fca5a5;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.opp-dark .opp-featured-danger {
|
|
152
|
+
border-color: rgba(248, 113, 113, 0.4);
|
|
153
|
+
background: color-mix(in srgb, var(--opp-card-bg) 85%, #450a0a 15%);
|
|
154
|
+
}
|
|
155
|
+
|
|
193
156
|
.opp-featured-image {
|
|
194
157
|
width: 80px;
|
|
195
158
|
height: 80px;
|
|
@@ -213,6 +176,89 @@ var promptStyles = `
|
|
|
213
176
|
font-size: 18px;
|
|
214
177
|
}
|
|
215
178
|
|
|
179
|
+
.opp-preview-opns {
|
|
180
|
+
display: flex;
|
|
181
|
+
flex-direction: column;
|
|
182
|
+
align-items: center;
|
|
183
|
+
justify-content: center;
|
|
184
|
+
gap: 4px;
|
|
185
|
+
padding: 6px;
|
|
186
|
+
box-sizing: border-box;
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.opp-preview-opns-avatar {
|
|
191
|
+
width: 36px;
|
|
192
|
+
height: 36px;
|
|
193
|
+
border-radius: 999px;
|
|
194
|
+
object-fit: cover;
|
|
195
|
+
background: rgba(0, 0, 0, 0.08);
|
|
196
|
+
flex-shrink: 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.opp-preview-opns-name {
|
|
200
|
+
font-size: 11px;
|
|
201
|
+
font-weight: 600;
|
|
202
|
+
max-width: 100%;
|
|
203
|
+
overflow: hidden;
|
|
204
|
+
text-overflow: ellipsis;
|
|
205
|
+
white-space: nowrap;
|
|
206
|
+
text-align: center;
|
|
207
|
+
color: var(--opp-fg, inherit);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.opp-preview-text {
|
|
211
|
+
margin: 0;
|
|
212
|
+
padding: 6px;
|
|
213
|
+
box-sizing: border-box;
|
|
214
|
+
overflow: hidden;
|
|
215
|
+
font-size: 9px;
|
|
216
|
+
line-height: 1.25;
|
|
217
|
+
white-space: pre-wrap;
|
|
218
|
+
word-break: break-word;
|
|
219
|
+
font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
|
|
220
|
+
color: var(--opp-muted);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.opp-preview-json {
|
|
224
|
+
white-space: pre;
|
|
225
|
+
overflow: auto;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.opp-preview-frame {
|
|
229
|
+
border: 0;
|
|
230
|
+
padding: 0;
|
|
231
|
+
overflow: hidden;
|
|
232
|
+
background: #fff;
|
|
233
|
+
pointer-events: none;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.opp-preview-value {
|
|
237
|
+
display: flex;
|
|
238
|
+
align-items: center;
|
|
239
|
+
justify-content: center;
|
|
240
|
+
box-sizing: border-box;
|
|
241
|
+
background: rgba(229, 169, 32, 0.12);
|
|
242
|
+
border: 1px solid rgba(229, 169, 32, 0.35);
|
|
243
|
+
color: var(--opp-fg, inherit);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.opp-preview-value-icon {
|
|
247
|
+
width: 32px;
|
|
248
|
+
height: 32px;
|
|
249
|
+
color: #E5A920;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Amount subtitles must never ellipsis — full sat counts are the point. */
|
|
253
|
+
.opp-featured-subtitle-text.opp-amount {
|
|
254
|
+
font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
|
|
255
|
+
font-variant-numeric: tabular-nums;
|
|
256
|
+
white-space: normal;
|
|
257
|
+
overflow: visible;
|
|
258
|
+
text-overflow: unset;
|
|
259
|
+
word-break: keep-all;
|
|
260
|
+
}
|
|
261
|
+
|
|
216
262
|
.opp-featured-meta {
|
|
217
263
|
display: flex;
|
|
218
264
|
flex-direction: column;
|
|
@@ -246,6 +292,38 @@ var promptStyles = `
|
|
|
246
292
|
font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
|
|
247
293
|
}
|
|
248
294
|
|
|
295
|
+
.opp-featured-meta-line {
|
|
296
|
+
display: flex;
|
|
297
|
+
align-items: center;
|
|
298
|
+
gap: 6px;
|
|
299
|
+
min-width: 0;
|
|
300
|
+
font-size: 12px;
|
|
301
|
+
color: var(--opp-muted);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.opp-featured-meta-line-bare {
|
|
305
|
+
align-items: center;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.opp-featured-meta-key {
|
|
309
|
+
flex-shrink: 0;
|
|
310
|
+
opacity: 0.75;
|
|
311
|
+
min-width: 2.5em;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.opp-featured-meta-value {
|
|
315
|
+
white-space: nowrap;
|
|
316
|
+
overflow: hidden;
|
|
317
|
+
text-overflow: ellipsis;
|
|
318
|
+
min-width: 0;
|
|
319
|
+
flex: 1;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.opp-featured-meta-value-mono {
|
|
323
|
+
font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
|
|
324
|
+
font-size: 11px;
|
|
325
|
+
}
|
|
326
|
+
|
|
249
327
|
.opp-trust-wrap {
|
|
250
328
|
display: flex;
|
|
251
329
|
flex-direction: column;
|
|
@@ -405,26 +483,25 @@ var promptStyles = `
|
|
|
405
483
|
`;
|
|
406
484
|
|
|
407
485
|
// src/OneSatPermissionPrompt.tsx
|
|
408
|
-
import { jsx, jsxs
|
|
486
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
409
487
|
function OneSatPermissionPrompt({
|
|
410
488
|
request,
|
|
411
489
|
onApprove,
|
|
412
490
|
onReject,
|
|
413
491
|
theme = "auto",
|
|
414
|
-
services
|
|
492
|
+
services
|
|
415
493
|
}) {
|
|
416
494
|
const resolvedTheme = useResolvedTheme(theme);
|
|
417
|
-
const base =
|
|
495
|
+
const base = viewFromRequest(request);
|
|
418
496
|
const [busy, setBusy] = useState(false);
|
|
419
|
-
const [verified, setVerified] = useState(
|
|
420
|
-
const
|
|
421
|
-
const trustState = intent?.trust?.state;
|
|
422
|
-
const p1satIntent = intent?.p1satIntent;
|
|
497
|
+
const [verified, setVerified] = useState();
|
|
498
|
+
const txPrompt = request.kind === "transaction" && isTransactionPrompt(request.payload) ? request.payload : undefined;
|
|
423
499
|
useEffect(() => {
|
|
424
|
-
if (!
|
|
500
|
+
if (!services || !txPrompt?.trust || !txPrompt.verify)
|
|
425
501
|
return;
|
|
426
502
|
let live = true;
|
|
427
|
-
|
|
503
|
+
const getContentUrl = services.ordfs?.getContentUrl?.bind(services.ordfs);
|
|
504
|
+
verifyIntent(services, txPrompt.verify.kind, txPrompt.verify.inputs, txPrompt.verify.outputs, getContentUrl).then((res) => {
|
|
428
505
|
if (live && res)
|
|
429
506
|
setVerified(res);
|
|
430
507
|
}).catch(() => {
|
|
@@ -433,8 +510,8 @@ function OneSatPermissionPrompt({
|
|
|
433
510
|
return () => {
|
|
434
511
|
live = false;
|
|
435
512
|
};
|
|
436
|
-
}, [
|
|
437
|
-
const
|
|
513
|
+
}, [services, txPrompt]);
|
|
514
|
+
const view = verified ? applyVerification(base, verified) : base;
|
|
438
515
|
const handle = (action) => () => {
|
|
439
516
|
if (busy)
|
|
440
517
|
return;
|
|
@@ -461,7 +538,6 @@ function OneSatPermissionPrompt({
|
|
|
461
538
|
return () => window.removeEventListener("keydown", onKey);
|
|
462
539
|
}, [onApprove, onReject, busy]);
|
|
463
540
|
const className = `opp-root${resolvedTheme === "dark" ? " opp-dark" : ""}`;
|
|
464
|
-
const featuredVariant = summary.featured?.variant ?? "ordinal";
|
|
465
541
|
return /* @__PURE__ */ jsxs("div", {
|
|
466
542
|
className,
|
|
467
543
|
children: [
|
|
@@ -506,11 +582,11 @@ function OneSatPermissionPrompt({
|
|
|
506
582
|
}),
|
|
507
583
|
/* @__PURE__ */ jsx("h2", {
|
|
508
584
|
className: "opp-title",
|
|
509
|
-
children:
|
|
585
|
+
children: view.title
|
|
510
586
|
}),
|
|
511
587
|
/* @__PURE__ */ jsx("p", {
|
|
512
588
|
className: "opp-subtitle",
|
|
513
|
-
children:
|
|
589
|
+
children: view.subtitle
|
|
514
590
|
}),
|
|
515
591
|
/* @__PURE__ */ jsx("div", {
|
|
516
592
|
className: "opp-status",
|
|
@@ -518,58 +594,79 @@ function OneSatPermissionPrompt({
|
|
|
518
594
|
})
|
|
519
595
|
]
|
|
520
596
|
}),
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
597
|
+
view.panels.map((panel, i) => {
|
|
598
|
+
const variant = panel.variant ?? "ordinal";
|
|
599
|
+
const classes = ["opp-featured"];
|
|
600
|
+
if (variant === "token")
|
|
601
|
+
classes.push("opp-featured-token");
|
|
602
|
+
if (variant === "value")
|
|
603
|
+
classes.push("opp-featured-value");
|
|
604
|
+
if (panel.tone === "danger")
|
|
605
|
+
classes.push("opp-featured-danger");
|
|
606
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
607
|
+
className: classes.join(" "),
|
|
608
|
+
children: [
|
|
609
|
+
/* @__PURE__ */ jsx(PanelPreview, {
|
|
610
|
+
panel
|
|
611
|
+
}),
|
|
612
|
+
/* @__PURE__ */ jsxs("div", {
|
|
613
|
+
className: "opp-featured-meta",
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ jsx("div", {
|
|
616
|
+
className: "opp-featured-title",
|
|
617
|
+
children: panel.title
|
|
618
|
+
}),
|
|
619
|
+
panel.subtitle && /* @__PURE__ */ jsxs("div", {
|
|
620
|
+
className: "opp-featured-subtitle",
|
|
621
|
+
children: [
|
|
622
|
+
/* @__PURE__ */ jsx("span", {
|
|
623
|
+
className: panel.amountSats != null ? "opp-featured-subtitle-text opp-amount" : "opp-featured-subtitle-text",
|
|
624
|
+
children: panel.subtitle
|
|
625
|
+
}),
|
|
626
|
+
panel.subtitleCopy && /* @__PURE__ */ jsx(CopyButton, {
|
|
627
|
+
text: panel.subtitleCopy
|
|
628
|
+
})
|
|
629
|
+
]
|
|
630
|
+
}),
|
|
631
|
+
(panel.meta ?? []).map((m) => /* @__PURE__ */ jsxs("div", {
|
|
632
|
+
className: `opp-featured-meta-line${m.key ? "" : " opp-featured-meta-line-bare"}`,
|
|
633
|
+
children: [
|
|
634
|
+
m.key ? /* @__PURE__ */ jsx("span", {
|
|
635
|
+
className: "opp-featured-meta-key",
|
|
636
|
+
children: m.key
|
|
637
|
+
}) : null,
|
|
638
|
+
/* @__PURE__ */ jsx("span", {
|
|
639
|
+
className: `opp-featured-meta-value${m.key ? "" : " opp-featured-meta-value-mono"}`,
|
|
640
|
+
title: m.copyValue ?? m.value,
|
|
641
|
+
children: m.value
|
|
642
|
+
}),
|
|
643
|
+
m.copyValue && /* @__PURE__ */ jsx(CopyButton, {
|
|
644
|
+
text: m.copyValue
|
|
645
|
+
})
|
|
646
|
+
]
|
|
647
|
+
}, `${m.key}:${m.value}`))
|
|
648
|
+
]
|
|
649
|
+
})
|
|
650
|
+
]
|
|
651
|
+
}, `panel-${i}-${panel.title}`);
|
|
555
652
|
}),
|
|
556
|
-
|
|
653
|
+
view.trust && /* @__PURE__ */ jsxs("div", {
|
|
557
654
|
className: "opp-trust-wrap",
|
|
558
655
|
children: [
|
|
559
656
|
/* @__PURE__ */ jsx("span", {
|
|
560
|
-
className: `opp-trust opp-trust-${
|
|
561
|
-
children: trustLabel(
|
|
657
|
+
className: `opp-trust opp-trust-${view.trust.state}`,
|
|
658
|
+
children: trustLabel(view.trust.state)
|
|
562
659
|
}),
|
|
563
|
-
|
|
564
|
-
className: `opp-trust-note opp-trust-note-${
|
|
565
|
-
children:
|
|
660
|
+
view.trust.note && /* @__PURE__ */ jsx("div", {
|
|
661
|
+
className: `opp-trust-note opp-trust-note-${view.trust.state}`,
|
|
662
|
+
children: view.trust.note
|
|
566
663
|
})
|
|
567
664
|
]
|
|
568
665
|
}),
|
|
569
|
-
(
|
|
666
|
+
(view.rows.length > 0 || view.indexerFee || view.funding) && /* @__PURE__ */ jsxs("div", {
|
|
570
667
|
className: "opp-card",
|
|
571
668
|
children: [
|
|
572
|
-
|
|
669
|
+
view.rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
573
670
|
className: "opp-row",
|
|
574
671
|
children: [
|
|
575
672
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -591,29 +688,41 @@ function OneSatPermissionPrompt({
|
|
|
591
688
|
})
|
|
592
689
|
]
|
|
593
690
|
}, `${row.key}:${row.value}`)),
|
|
594
|
-
|
|
691
|
+
view.indexerFee && /* @__PURE__ */ jsxs("div", {
|
|
692
|
+
className: "opp-row",
|
|
595
693
|
children: [
|
|
596
|
-
/* @__PURE__ */
|
|
597
|
-
className: "opp-row",
|
|
694
|
+
/* @__PURE__ */ jsx("span", {
|
|
695
|
+
className: "opp-row-key",
|
|
696
|
+
children: "1Sat Overlay Fee"
|
|
697
|
+
}),
|
|
698
|
+
/* @__PURE__ */ jsxs("span", {
|
|
699
|
+
className: "opp-row-value opp-amount",
|
|
598
700
|
children: [
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
children: "Indexer fee"
|
|
602
|
-
}),
|
|
603
|
-
/* @__PURE__ */ jsxs("span", {
|
|
604
|
-
className: "opp-row-value",
|
|
605
|
-
children: [
|
|
606
|
-
formatSats(summary.indexerFee.sats),
|
|
607
|
-
" sats"
|
|
608
|
-
]
|
|
609
|
-
})
|
|
701
|
+
formatSats(view.indexerFee.sats),
|
|
702
|
+
" sats"
|
|
610
703
|
]
|
|
704
|
+
})
|
|
705
|
+
]
|
|
706
|
+
}),
|
|
707
|
+
view.funding?.networkFeeSats != null && /* @__PURE__ */ jsxs("div", {
|
|
708
|
+
className: "opp-row",
|
|
709
|
+
children: [
|
|
710
|
+
/* @__PURE__ */ jsx("span", {
|
|
711
|
+
className: "opp-row-key",
|
|
712
|
+
children: "Network fee"
|
|
611
713
|
}),
|
|
612
|
-
|
|
613
|
-
className: "opp-
|
|
614
|
-
children:
|
|
714
|
+
/* @__PURE__ */ jsxs("span", {
|
|
715
|
+
className: "opp-row-value opp-amount",
|
|
716
|
+
children: [
|
|
717
|
+
formatSats(view.funding.networkFeeSats),
|
|
718
|
+
" sats"
|
|
719
|
+
]
|
|
615
720
|
})
|
|
616
721
|
]
|
|
722
|
+
}),
|
|
723
|
+
view.funding?.note && /* @__PURE__ */ jsx("div", {
|
|
724
|
+
className: "opp-fee-note",
|
|
725
|
+
children: view.funding.note
|
|
617
726
|
})
|
|
618
727
|
]
|
|
619
728
|
}),
|
|
@@ -650,6 +759,120 @@ function OneSatPermissionPrompt({
|
|
|
650
759
|
]
|
|
651
760
|
});
|
|
652
761
|
}
|
|
762
|
+
function viewFromRequest(req) {
|
|
763
|
+
if (req.kind === "transaction" && isTransactionPrompt(req.payload)) {
|
|
764
|
+
return {
|
|
765
|
+
title: req.payload.title,
|
|
766
|
+
subtitle: req.payload.subtitle,
|
|
767
|
+
panels: req.payload.panels,
|
|
768
|
+
rows: req.payload.rows,
|
|
769
|
+
trust: req.payload.trust,
|
|
770
|
+
indexerFee: req.payload.indexerFee,
|
|
771
|
+
funding: req.payload.funding
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
if (req.kind === "basketAccess") {
|
|
775
|
+
const baskets = req.payload.baskets ?? [];
|
|
776
|
+
const isView = baskets.length > 0 && baskets.every((b) => b.scope || b.basket.startsWith("p "));
|
|
777
|
+
const panels = baskets.filter((b) => b.imageUrl || b.name || b.value).map((b) => ({
|
|
778
|
+
title: b.scope === "collection" ? b.name ? `Collection · ${b.name}` : "Collection" : b.scope ? b.scope : "Basket",
|
|
779
|
+
subtitle: b.value ? b.value.length > 24 ? `${b.value.slice(0, 10)}…${b.value.slice(-10)}` : b.value : b.basket,
|
|
780
|
+
subtitleCopy: b.value,
|
|
781
|
+
...b.imageUrl && {
|
|
782
|
+
previewKind: "image",
|
|
783
|
+
contentUrl: b.imageUrl,
|
|
784
|
+
imageUrl: b.imageUrl
|
|
785
|
+
},
|
|
786
|
+
tone: "default"
|
|
787
|
+
}));
|
|
788
|
+
const rows = baskets.flatMap((b) => {
|
|
789
|
+
if (b.scope === "collection") {
|
|
790
|
+
return b.description ? [{ key: "Access", value: b.description }] : [];
|
|
791
|
+
}
|
|
792
|
+
return [
|
|
793
|
+
{
|
|
794
|
+
key: b.basket,
|
|
795
|
+
value: b.description ?? "List, insert, and remove outputs"
|
|
796
|
+
}
|
|
797
|
+
];
|
|
798
|
+
});
|
|
799
|
+
return {
|
|
800
|
+
title: isView ? baskets.length === 1 ? baskets[0].scope === "collection" ? "Grant Collection View" : "Grant Item View" : `Grant View (${baskets.length})` : baskets.length === 1 ? "Grant Basket Access" : `Grant Access to ${baskets.length} Baskets`,
|
|
801
|
+
subtitle: isView ? `${shortenOriginator(req.originator)} wants to view items in your wallet` : `${shortenOriginator(req.originator)} wants to read and write 1Sat baskets`,
|
|
802
|
+
panels,
|
|
803
|
+
rows
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
if (req.kind === "protocol") {
|
|
807
|
+
return {
|
|
808
|
+
title: "Protocol Access",
|
|
809
|
+
subtitle: `${shortenOriginator(req.originator)} wants protocol access`,
|
|
810
|
+
panels: [],
|
|
811
|
+
rows: [{ key: "Detail", value: req.summary || "Protocol request" }]
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
return {
|
|
815
|
+
title: "Signature Request",
|
|
816
|
+
subtitle: `${shortenOriginator(req.originator)} wants a signature`,
|
|
817
|
+
panels: [],
|
|
818
|
+
rows: [{ key: "Detail", value: req.summary || "Signature request" }]
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
function applyVerification(base, res) {
|
|
822
|
+
const panels = base.panels.map((p, i) => {
|
|
823
|
+
if (i !== 0)
|
|
824
|
+
return p;
|
|
825
|
+
const keepOpns = p.previewKind === "opns";
|
|
826
|
+
const kindFromVerify = res.contentType ? previewKindFromContentType(res.contentType) : undefined;
|
|
827
|
+
const nextKind = keepOpns ? "opns" : kindFromVerify && kindFromVerify !== "none" ? kindFromVerify : p.previewKind;
|
|
828
|
+
const mediaUrl = res.contentUrl ?? p.contentUrl ?? p.imageUrl;
|
|
829
|
+
let subtitle = p.subtitle;
|
|
830
|
+
if (res.name && !keepOpns) {
|
|
831
|
+
if (!subtitle) {
|
|
832
|
+
subtitle = res.name;
|
|
833
|
+
} else {
|
|
834
|
+
const parts = subtitle.trim().split(/\s+/);
|
|
835
|
+
if (parts.length >= 2) {
|
|
836
|
+
parts[parts.length - 1] = res.name;
|
|
837
|
+
subtitle = parts.join(" ");
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return {
|
|
842
|
+
...p,
|
|
843
|
+
previewKind: nextKind,
|
|
844
|
+
...subtitle ? { subtitle } : {},
|
|
845
|
+
...keepOpns ? {
|
|
846
|
+
...res.contentUrl && !p.imageUrl ? { imageUrl: res.contentUrl } : p.imageUrl ? { imageUrl: p.imageUrl } : {}
|
|
847
|
+
} : nextKind === "image" ? { imageUrl: mediaUrl, contentUrl: mediaUrl } : mediaUrl ? { contentUrl: mediaUrl, imageUrl: undefined } : {}
|
|
848
|
+
};
|
|
849
|
+
});
|
|
850
|
+
return {
|
|
851
|
+
...base,
|
|
852
|
+
panels,
|
|
853
|
+
trust: { state: res.state, note: res.note }
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function previewKindFromContentType(ct) {
|
|
857
|
+
const c = ct.toLowerCase();
|
|
858
|
+
if (c === "image/svg+xml" || c === "svg" || c.endsWith("+svg"))
|
|
859
|
+
return "svg";
|
|
860
|
+
if (c.startsWith("image/"))
|
|
861
|
+
return "image";
|
|
862
|
+
if (c.includes("json"))
|
|
863
|
+
return "json";
|
|
864
|
+
if (c.includes("html") || c === "application/xhtml+xml")
|
|
865
|
+
return "html";
|
|
866
|
+
if (c.startsWith("text/"))
|
|
867
|
+
return "text";
|
|
868
|
+
return "none";
|
|
869
|
+
}
|
|
870
|
+
function formatSatsFull(n) {
|
|
871
|
+
return `${n.toLocaleString("en-US")} sats`;
|
|
872
|
+
}
|
|
873
|
+
function formatSats(n) {
|
|
874
|
+
return n.toLocaleString("en-US");
|
|
875
|
+
}
|
|
653
876
|
function trustLabel(state) {
|
|
654
877
|
if (state === "verified")
|
|
655
878
|
return "Verified";
|
|
@@ -657,8 +880,218 @@ function trustLabel(state) {
|
|
|
657
880
|
return "Mismatch";
|
|
658
881
|
return "Unverified";
|
|
659
882
|
}
|
|
660
|
-
function
|
|
661
|
-
|
|
883
|
+
function PanelPreview({ panel }) {
|
|
884
|
+
const variant = panel.variant ?? "ordinal";
|
|
885
|
+
const baseClass = variant === "token" ? "opp-featured-image opp-featured-image-token" : variant === "value" ? "opp-featured-image opp-preview-value" : "opp-featured-image";
|
|
886
|
+
const kind = panel.previewKind ?? (panel.imageUrl ? "image" : "none");
|
|
887
|
+
const mediaUrl = panel.contentUrl ?? panel.imageUrl;
|
|
888
|
+
const [imgBroken, setImgBroken] = useState(false);
|
|
889
|
+
if (variant === "value") {
|
|
890
|
+
const icon = panel.valueIcon ?? "pay";
|
|
891
|
+
return /* @__PURE__ */ jsx("div", {
|
|
892
|
+
className: baseClass,
|
|
893
|
+
title: panel.amountSats != null ? formatSatsFull(panel.amountSats) : undefined,
|
|
894
|
+
"aria-hidden": true,
|
|
895
|
+
children: /* @__PURE__ */ jsx(ValueGlyph, {
|
|
896
|
+
kind: icon
|
|
897
|
+
})
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
if (kind === "opns") {
|
|
901
|
+
const showAvatar = Boolean(panel.imageUrl) && !imgBroken;
|
|
902
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
903
|
+
className: `${baseClass} opp-preview-opns`,
|
|
904
|
+
"aria-hidden": !panel.opnsHero,
|
|
905
|
+
children: [
|
|
906
|
+
showAvatar ? /* @__PURE__ */ jsx("img", {
|
|
907
|
+
className: "opp-preview-opns-avatar",
|
|
908
|
+
src: panel.imageUrl,
|
|
909
|
+
alt: "",
|
|
910
|
+
onError: () => setImgBroken(true)
|
|
911
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
912
|
+
className: "opp-preview-opns-avatar opp-featured-placeholder",
|
|
913
|
+
children: "◈"
|
|
914
|
+
}),
|
|
915
|
+
/* @__PURE__ */ jsx("span", {
|
|
916
|
+
className: "opp-preview-opns-name",
|
|
917
|
+
title: panel.opnsHero,
|
|
918
|
+
children: panel.opnsHero ?? "OpNS"
|
|
919
|
+
})
|
|
920
|
+
]
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
if (kind === "image" && panel.imageUrl && !imgBroken) {
|
|
924
|
+
return /* @__PURE__ */ jsx("img", {
|
|
925
|
+
className: baseClass,
|
|
926
|
+
src: panel.imageUrl,
|
|
927
|
+
alt: panel.title,
|
|
928
|
+
onError: () => setImgBroken(true)
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
if (kind === "image" && imgBroken) {
|
|
932
|
+
return /* @__PURE__ */ jsx("div", {
|
|
933
|
+
className: `${baseClass} opp-featured-placeholder`,
|
|
934
|
+
"aria-hidden": true,
|
|
935
|
+
children: "▭"
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
if ((kind === "text" || kind === "json" || kind === "html") && panel.previewText) {
|
|
939
|
+
return /* @__PURE__ */ jsx("pre", {
|
|
940
|
+
className: `${baseClass} opp-preview-text${kind === "json" ? " opp-preview-json" : ""}`,
|
|
941
|
+
children: panel.previewText
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
if ((kind === "text" || kind === "json") && mediaUrl) {
|
|
945
|
+
return /* @__PURE__ */ jsx(FetchedTextPreview, {
|
|
946
|
+
url: mediaUrl,
|
|
947
|
+
kind,
|
|
948
|
+
className: baseClass
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
if ((kind === "html" || kind === "svg") && mediaUrl) {
|
|
952
|
+
return /* @__PURE__ */ jsx("iframe", {
|
|
953
|
+
className: `${baseClass} opp-preview-frame`,
|
|
954
|
+
src: mediaUrl,
|
|
955
|
+
title: `${panel.title} preview`,
|
|
956
|
+
sandbox: "",
|
|
957
|
+
referrerPolicy: "no-referrer"
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
return /* @__PURE__ */ jsx("div", {
|
|
961
|
+
className: `${baseClass} opp-featured-placeholder`,
|
|
962
|
+
"aria-hidden": true,
|
|
963
|
+
children: variant === "token" ? "◎" : previewGlyph(kind)
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
function previewGlyph(kind) {
|
|
967
|
+
if (kind === "text" || kind === "json")
|
|
968
|
+
return "¶";
|
|
969
|
+
if (kind === "html" || kind === "svg")
|
|
970
|
+
return "⌂";
|
|
971
|
+
return "▭";
|
|
972
|
+
}
|
|
973
|
+
function ValueGlyph({ kind }) {
|
|
974
|
+
if (kind === "lock") {
|
|
975
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
976
|
+
className: "opp-preview-value-icon",
|
|
977
|
+
viewBox: "0 0 24 24",
|
|
978
|
+
fill: "none",
|
|
979
|
+
"aria-hidden": true,
|
|
980
|
+
children: [
|
|
981
|
+
/* @__PURE__ */ jsx("rect", {
|
|
982
|
+
x: "5",
|
|
983
|
+
y: "11",
|
|
984
|
+
width: "14",
|
|
985
|
+
height: "10",
|
|
986
|
+
rx: "2",
|
|
987
|
+
stroke: "currentColor",
|
|
988
|
+
strokeWidth: "2"
|
|
989
|
+
}),
|
|
990
|
+
/* @__PURE__ */ jsx("path", {
|
|
991
|
+
d: "M8 11V8a4 4 0 018 0v3",
|
|
992
|
+
stroke: "currentColor",
|
|
993
|
+
strokeWidth: "2",
|
|
994
|
+
strokeLinecap: "round"
|
|
995
|
+
})
|
|
996
|
+
]
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
if (kind === "unlock") {
|
|
1000
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
1001
|
+
className: "opp-preview-value-icon",
|
|
1002
|
+
viewBox: "0 0 24 24",
|
|
1003
|
+
fill: "none",
|
|
1004
|
+
"aria-hidden": true,
|
|
1005
|
+
children: [
|
|
1006
|
+
/* @__PURE__ */ jsx("rect", {
|
|
1007
|
+
x: "5",
|
|
1008
|
+
y: "11",
|
|
1009
|
+
width: "14",
|
|
1010
|
+
height: "10",
|
|
1011
|
+
rx: "2",
|
|
1012
|
+
stroke: "currentColor",
|
|
1013
|
+
strokeWidth: "2"
|
|
1014
|
+
}),
|
|
1015
|
+
/* @__PURE__ */ jsx("path", {
|
|
1016
|
+
d: "M8 11V7.5A4 4 0 0116 7",
|
|
1017
|
+
stroke: "currentColor",
|
|
1018
|
+
strokeWidth: "2",
|
|
1019
|
+
strokeLinecap: "round"
|
|
1020
|
+
}),
|
|
1021
|
+
/* @__PURE__ */ jsx("path", {
|
|
1022
|
+
d: "M16 4.5v3",
|
|
1023
|
+
stroke: "currentColor",
|
|
1024
|
+
strokeWidth: "2",
|
|
1025
|
+
strokeLinecap: "round"
|
|
1026
|
+
})
|
|
1027
|
+
]
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
1031
|
+
className: "opp-preview-value-icon",
|
|
1032
|
+
viewBox: "0 0 24 24",
|
|
1033
|
+
fill: "none",
|
|
1034
|
+
"aria-hidden": true,
|
|
1035
|
+
children: [
|
|
1036
|
+
/* @__PURE__ */ jsx("circle", {
|
|
1037
|
+
cx: "12",
|
|
1038
|
+
cy: "12",
|
|
1039
|
+
r: "9",
|
|
1040
|
+
stroke: "currentColor",
|
|
1041
|
+
strokeWidth: "2"
|
|
1042
|
+
}),
|
|
1043
|
+
/* @__PURE__ */ jsx("path", {
|
|
1044
|
+
d: "M12 7v10M9 10.5c0-1.4 1.3-2.5 3-2.5s3 1.1 3 2.5-1.3 2.5-3 2.5-3 1.1-3 2.5 1.3 2.5 3 2.5 3-1.1 3-2.5",
|
|
1045
|
+
stroke: "currentColor",
|
|
1046
|
+
strokeWidth: "2",
|
|
1047
|
+
strokeLinecap: "round"
|
|
1048
|
+
})
|
|
1049
|
+
]
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
function FetchedTextPreview({
|
|
1053
|
+
url,
|
|
1054
|
+
kind,
|
|
1055
|
+
className
|
|
1056
|
+
}) {
|
|
1057
|
+
const [body, setBody] = useState(null);
|
|
1058
|
+
const [failed, setFailed] = useState(false);
|
|
1059
|
+
useEffect(() => {
|
|
1060
|
+
let cancelled = false;
|
|
1061
|
+
setBody(null);
|
|
1062
|
+
setFailed(false);
|
|
1063
|
+
fetch(url).then(async (res) => {
|
|
1064
|
+
if (!res.ok)
|
|
1065
|
+
throw new Error(String(res.status));
|
|
1066
|
+
const text = await res.text();
|
|
1067
|
+
if (cancelled)
|
|
1068
|
+
return;
|
|
1069
|
+
if (kind === "json") {
|
|
1070
|
+
try {
|
|
1071
|
+
setBody(JSON.stringify(JSON.parse(text), null, 2));
|
|
1072
|
+
return;
|
|
1073
|
+
} catch {}
|
|
1074
|
+
}
|
|
1075
|
+
setBody(text.slice(0, 800));
|
|
1076
|
+
}).catch(() => {
|
|
1077
|
+
if (!cancelled)
|
|
1078
|
+
setFailed(true);
|
|
1079
|
+
});
|
|
1080
|
+
return () => {
|
|
1081
|
+
cancelled = true;
|
|
1082
|
+
};
|
|
1083
|
+
}, [url, kind]);
|
|
1084
|
+
if (failed) {
|
|
1085
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1086
|
+
className: `${className} opp-featured-placeholder`,
|
|
1087
|
+
"aria-hidden": true,
|
|
1088
|
+
children: "¶"
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
return /* @__PURE__ */ jsx("pre", {
|
|
1092
|
+
className: `${className} opp-preview-text${kind === "json" ? " opp-preview-json" : ""}`,
|
|
1093
|
+
children: body ?? "…"
|
|
1094
|
+
});
|
|
662
1095
|
}
|
|
663
1096
|
function CopyButton({ text }) {
|
|
664
1097
|
const [copied, setCopied] = useState(false);
|
|
@@ -713,9 +1146,6 @@ function CopyButton({ text }) {
|
|
|
713
1146
|
})
|
|
714
1147
|
});
|
|
715
1148
|
}
|
|
716
|
-
function copyable(key, full) {
|
|
717
|
-
return { key, value: shortenValue(full), copyValue: full };
|
|
718
|
-
}
|
|
719
1149
|
function useResolvedTheme(theme) {
|
|
720
1150
|
const [resolved, setResolved] = useState(() => theme === "auto" ? readSystemTheme() : theme);
|
|
721
1151
|
useEffect(() => {
|
|
@@ -736,596 +1166,15 @@ function readSystemTheme() {
|
|
|
736
1166
|
return "light";
|
|
737
1167
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
738
1168
|
}
|
|
739
|
-
function applyVerification(base, res) {
|
|
740
|
-
const rows = base.rows.map((row) => {
|
|
741
|
-
if (row.key === "Origin" && res.origin)
|
|
742
|
-
return copyable("Origin", res.origin);
|
|
743
|
-
if (row.key === "Type" && res.contentType) {
|
|
744
|
-
return { key: "Type", value: res.contentType };
|
|
745
|
-
}
|
|
746
|
-
return row;
|
|
747
|
-
});
|
|
748
|
-
if (res.contentLength !== undefined && !rows.some((r) => r.key === "Size")) {
|
|
749
|
-
rows.push({
|
|
750
|
-
key: "Size",
|
|
751
|
-
value: `${res.contentLength.toLocaleString("en-US")} bytes`
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
|
-
return {
|
|
755
|
-
...base,
|
|
756
|
-
rows,
|
|
757
|
-
trust: { state: res.state, note: res.note },
|
|
758
|
-
featured: base.featured ? {
|
|
759
|
-
...base.featured,
|
|
760
|
-
title: res.name ?? base.featured.title,
|
|
761
|
-
imageUrl: res.contentUrl ?? base.featured.imageUrl
|
|
762
|
-
} : undefined
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
function summarizeRequest(req) {
|
|
766
|
-
if (req.kind === "transaction") {
|
|
767
|
-
const intent = req.intent;
|
|
768
|
-
const byIntent = summarizeByP1SatIntent(req, intent);
|
|
769
|
-
if (byIntent)
|
|
770
|
-
return byIntent;
|
|
771
|
-
switch (intent.kind) {
|
|
772
|
-
case "ordinal-transfer":
|
|
773
|
-
return summarizeOrdinalTransfer(req, intent);
|
|
774
|
-
case "token-transfer":
|
|
775
|
-
return summarizeTokenTransfer(req, intent);
|
|
776
|
-
case "lock":
|
|
777
|
-
return summarizeLock(req, intent);
|
|
778
|
-
case "unlock":
|
|
779
|
-
return summarizeUnlock(req, intent);
|
|
780
|
-
case "inscription":
|
|
781
|
-
return summarizeInscription(req, intent);
|
|
782
|
-
case "listing":
|
|
783
|
-
return summarizeListing(req, intent);
|
|
784
|
-
case "cancel-listing":
|
|
785
|
-
return summarizeCancelListing(req, intent);
|
|
786
|
-
case "purchase":
|
|
787
|
-
return summarizePurchase(req, intent);
|
|
788
|
-
case "social-post":
|
|
789
|
-
return summarizeSocialPost(req, intent);
|
|
790
|
-
case "opns":
|
|
791
|
-
return summarizeOpns(req, intent);
|
|
792
|
-
default:
|
|
793
|
-
return summarizeUnknownTx(req, intent);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
if (req.kind === "protocol") {
|
|
797
|
-
return summarizeProtocol(req);
|
|
798
|
-
}
|
|
799
|
-
if (req.kind === "basketAccess") {
|
|
800
|
-
return summarizeBasketAccess(req);
|
|
801
|
-
}
|
|
802
|
-
return summarizeSignature(req);
|
|
803
|
-
}
|
|
804
|
-
function summarizeBasketAccess(req) {
|
|
805
|
-
const intent = req.intent;
|
|
806
|
-
const baskets = intent.baskets ?? [];
|
|
807
|
-
return {
|
|
808
|
-
title: baskets.length === 1 ? "Grant Basket Access" : `Grant Access to ${baskets.length} Baskets`,
|
|
809
|
-
subtitle: `${shortenOriginator(req.originator)} wants to read and write 1Sat baskets`,
|
|
810
|
-
rows: baskets.map((b) => ({
|
|
811
|
-
key: b.basket,
|
|
812
|
-
value: b.description ?? "List, insert, and remove outputs"
|
|
813
|
-
}))
|
|
814
|
-
};
|
|
815
|
-
}
|
|
816
|
-
var INTENT_TITLES = {
|
|
817
|
-
"opns.register": "Publish name",
|
|
818
|
-
"opns.deregister": "Unpublish name",
|
|
819
|
-
"opns.list": "List name for sale",
|
|
820
|
-
"opns.transfer": "Transfer name",
|
|
821
|
-
"opns.cancel-listing": "Cancel listing",
|
|
822
|
-
"opns.purchase": "Buy name",
|
|
823
|
-
"ordinal.transfer": "Send ordinal",
|
|
824
|
-
"ordinal.list": "List for sale",
|
|
825
|
-
"ordinal.cancel-listing": "Cancel listing",
|
|
826
|
-
"ordinal.purchase": "Buy ordinal",
|
|
827
|
-
"ordinal.burn": "Burn ordinal",
|
|
828
|
-
"ordinal.inscribe": "Create inscription",
|
|
829
|
-
"ordinal.inscribe-sigma": "Create inscription",
|
|
830
|
-
"ordinal.mint-collection": "Mint collection",
|
|
831
|
-
"ordinal.mint-item": "Mint collection item",
|
|
832
|
-
"lock.lock": "Lock BSV",
|
|
833
|
-
"lock.unlock": "Unlock BSV",
|
|
834
|
-
"bsv21.transfer": "Send tokens",
|
|
835
|
-
"bsv21.purchase": "Buy tokens",
|
|
836
|
-
"bsv21.mint": "Mint tokens",
|
|
837
|
-
"bsv21.deploy": "Deploy token"
|
|
838
|
-
};
|
|
839
|
-
function summarizeByP1SatIntent(req, intent) {
|
|
840
|
-
const id = intent.p1satIntent;
|
|
841
|
-
if (!id || !INTENT_TITLES[id])
|
|
842
|
-
return;
|
|
843
|
-
let base;
|
|
844
|
-
switch (intent.kind) {
|
|
845
|
-
case "ordinal-transfer":
|
|
846
|
-
base = summarizeOrdinalTransfer(req, intent);
|
|
847
|
-
break;
|
|
848
|
-
case "token-transfer":
|
|
849
|
-
base = summarizeTokenTransfer(req, intent);
|
|
850
|
-
break;
|
|
851
|
-
case "lock":
|
|
852
|
-
base = summarizeLock(req, intent);
|
|
853
|
-
break;
|
|
854
|
-
case "unlock":
|
|
855
|
-
base = summarizeUnlock(req, intent);
|
|
856
|
-
break;
|
|
857
|
-
case "inscription":
|
|
858
|
-
base = summarizeInscription(req, intent);
|
|
859
|
-
break;
|
|
860
|
-
case "listing":
|
|
861
|
-
base = summarizeListing(req, intent);
|
|
862
|
-
break;
|
|
863
|
-
case "cancel-listing":
|
|
864
|
-
base = summarizeCancelListing(req, intent);
|
|
865
|
-
break;
|
|
866
|
-
case "purchase":
|
|
867
|
-
base = summarizePurchase(req, intent);
|
|
868
|
-
break;
|
|
869
|
-
case "opns":
|
|
870
|
-
base = summarizeOpns(req, intent);
|
|
871
|
-
break;
|
|
872
|
-
default:
|
|
873
|
-
base = summarizeUnknownTx(req, intent);
|
|
874
|
-
}
|
|
875
|
-
return {
|
|
876
|
-
...base,
|
|
877
|
-
title: INTENT_TITLES[id],
|
|
878
|
-
subtitle: intentSubtitle(req, id, intent),
|
|
879
|
-
feeSats: undefined,
|
|
880
|
-
network: undefined,
|
|
881
|
-
trust: intent.trust ?? base.trust,
|
|
882
|
-
indexerFee: intent.indexerFeeSats != null && intent.indexerFeeSats > 0 ? {
|
|
883
|
-
sats: intent.indexerFeeSats,
|
|
884
|
-
note: intent.indexerFeeNote
|
|
885
|
-
} : base.indexerFee
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
function intentSubtitle(req, id, intent) {
|
|
889
|
-
const o = shortenOriginator(req.originator);
|
|
890
|
-
const name = tagValue(intent.inputs[0]?.tags, "name") ?? tagValue(intent.outputs.find((out) => out.tags.some((t) => t.startsWith("name:")))?.tags, "name");
|
|
891
|
-
const quoted = name ? `“${name}”` : undefined;
|
|
892
|
-
switch (id) {
|
|
893
|
-
case "opns.register":
|
|
894
|
-
return `${o} wants to publish ${quoted ?? "an OpNS name"}`;
|
|
895
|
-
case "opns.deregister":
|
|
896
|
-
return `${o} wants to unpublish ${quoted ?? "an OpNS name"}`;
|
|
897
|
-
case "opns.list":
|
|
898
|
-
return `${o} wants to list ${quoted ?? "an OpNS name"} for sale`;
|
|
899
|
-
case "opns.transfer":
|
|
900
|
-
return `${o} wants to transfer ${quoted ?? "an OpNS name"}`;
|
|
901
|
-
case "opns.cancel-listing":
|
|
902
|
-
return `${o} wants to cancel ${quoted ? `the listing of ${quoted}` : "an OpNS listing"}`;
|
|
903
|
-
case "opns.purchase":
|
|
904
|
-
return `${o} wants to buy ${quoted ?? "an OpNS name"}`;
|
|
905
|
-
case "ordinal.transfer":
|
|
906
|
-
return `${o} wants to transfer an ordinal`;
|
|
907
|
-
case "ordinal.list":
|
|
908
|
-
return `${o} wants to list ${quoted ?? "an ordinal"} for sale`;
|
|
909
|
-
case "ordinal.cancel-listing":
|
|
910
|
-
return `${o} wants to cancel ${quoted ? `the listing of ${quoted}` : "an ordinal listing"}`;
|
|
911
|
-
case "ordinal.purchase":
|
|
912
|
-
return `${o} wants to purchase an ordinal into your wallet`;
|
|
913
|
-
case "ordinal.burn":
|
|
914
|
-
return `${o} wants to burn an ordinal`;
|
|
915
|
-
case "ordinal.inscribe":
|
|
916
|
-
case "ordinal.inscribe-sigma":
|
|
917
|
-
return `${o} wants to inscribe content into your wallet`;
|
|
918
|
-
case "ordinal.mint-collection":
|
|
919
|
-
return `${o} wants to mint a collection`;
|
|
920
|
-
case "ordinal.mint-item":
|
|
921
|
-
return `${o} wants to mint a collection item`;
|
|
922
|
-
case "lock.lock":
|
|
923
|
-
return `${o} wants to time-lock funds`;
|
|
924
|
-
case "lock.unlock":
|
|
925
|
-
return `${o} wants to unlock matured locks`;
|
|
926
|
-
case "bsv21.transfer":
|
|
927
|
-
return `${o} wants to send tokens`;
|
|
928
|
-
case "bsv21.purchase":
|
|
929
|
-
return `${o} wants to purchase tokens into your wallet`;
|
|
930
|
-
case "bsv21.mint":
|
|
931
|
-
return `${o} wants to mint tokens`;
|
|
932
|
-
case "bsv21.deploy":
|
|
933
|
-
return `${o} wants to deploy a BSV21 token`;
|
|
934
|
-
default:
|
|
935
|
-
return `${o} wants to ${req.summary.toLowerCase()}`;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
function tagValue(tags, key) {
|
|
939
|
-
if (!tags)
|
|
940
|
-
return;
|
|
941
|
-
const prefix = `${key}:`;
|
|
942
|
-
for (const t of tags) {
|
|
943
|
-
if (t.startsWith(prefix))
|
|
944
|
-
return t.slice(prefix.length);
|
|
945
|
-
}
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
function summarizeOrdinalTransfer(req, intent) {
|
|
949
|
-
const ordinal = intent.inputs[0];
|
|
950
|
-
const origin = tagValue(ordinal?.tags, "origin");
|
|
951
|
-
const name = tagValue(ordinal?.tags, "name");
|
|
952
|
-
const contentType = tagValue(ordinal?.tags, "type");
|
|
953
|
-
const collectionId = tagValue(ordinal?.tags, "collectionId");
|
|
954
|
-
const recipient = intent.outputs.find((o) => o.recipient)?.recipient;
|
|
955
|
-
const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
|
|
956
|
-
const rows = [];
|
|
957
|
-
if (recipient)
|
|
958
|
-
rows.push(copyable("Recipient", recipient));
|
|
959
|
-
if (origin)
|
|
960
|
-
rows.push(copyable("Origin", origin));
|
|
961
|
-
if (contentType)
|
|
962
|
-
rows.push({ key: "Type", value: contentType });
|
|
963
|
-
return {
|
|
964
|
-
title: "Send ordinal",
|
|
965
|
-
subtitle: `${shortenOriginator(req.originator)} wants to transfer an ordinal`,
|
|
966
|
-
rows,
|
|
967
|
-
featured: imageUrl ? {
|
|
968
|
-
imageUrl,
|
|
969
|
-
title: name ?? "Untitled ordinal",
|
|
970
|
-
subtitle: collectionId ?? contentType
|
|
971
|
-
} : undefined
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
function summarizeTokenTransfer(req, intent) {
|
|
975
|
-
const totals = new Map;
|
|
976
|
-
for (const input of intent.inputs) {
|
|
977
|
-
const tokenId = tagValue(input.tags, "bsv21");
|
|
978
|
-
if (!tokenId)
|
|
979
|
-
continue;
|
|
980
|
-
const sym2 = tagValue(input.tags, "sym");
|
|
981
|
-
const amt = BigInt(tagValue(input.tags, "amt") ?? "0");
|
|
982
|
-
const cur = totals.get(tokenId) ?? { sym: sym2, inAmt: 0n, changeAmt: 0n };
|
|
983
|
-
cur.inAmt += amt;
|
|
984
|
-
if (!cur.sym && sym2)
|
|
985
|
-
cur.sym = sym2;
|
|
986
|
-
totals.set(tokenId, cur);
|
|
987
|
-
}
|
|
988
|
-
for (const output of intent.outputs) {
|
|
989
|
-
if (output.basket !== BSV21_BASKET)
|
|
990
|
-
continue;
|
|
991
|
-
const tokenId = tagValue(output.tags, "bsv21");
|
|
992
|
-
if (!tokenId)
|
|
993
|
-
continue;
|
|
994
|
-
const amt = BigInt(tagValue(output.tags, "amt") ?? "0");
|
|
995
|
-
const cur = totals.get(tokenId);
|
|
996
|
-
if (cur)
|
|
997
|
-
cur.changeAmt += amt;
|
|
998
|
-
}
|
|
999
|
-
const rows = [];
|
|
1000
|
-
let featured;
|
|
1001
|
-
let primaryTokenId;
|
|
1002
|
-
for (const [tokenId, info] of totals) {
|
|
1003
|
-
if (!primaryTokenId)
|
|
1004
|
-
primaryTokenId = tokenId;
|
|
1005
|
-
const sent = info.inAmt - info.changeAmt;
|
|
1006
|
-
rows.push({ key: "Amount", value: sent.toLocaleString("en-US") });
|
|
1007
|
-
}
|
|
1008
|
-
const to = intent.outputs.find((o) => o.recipient && o.satoshis === 1)?.recipient;
|
|
1009
|
-
if (to)
|
|
1010
|
-
rows.push(copyable("Recipient", to));
|
|
1011
|
-
const firstIn = intent.inputs.find((i) => tagValue(i.tags, "bsv21"));
|
|
1012
|
-
const sym = (primaryTokenId ? totals.get(primaryTokenId)?.sym : undefined) ?? tagValue(firstIn?.tags, "sym");
|
|
1013
|
-
const iconRef = tagValue(firstIn?.tags, "icon");
|
|
1014
|
-
const iconUrl = iconRef && intent.contentUrls?.[iconRef] || primaryTokenId && intent.contentUrls?.[primaryTokenId] || undefined;
|
|
1015
|
-
if (primaryTokenId) {
|
|
1016
|
-
featured = {
|
|
1017
|
-
variant: "token",
|
|
1018
|
-
imageUrl: iconUrl,
|
|
1019
|
-
title: sym ?? "Token",
|
|
1020
|
-
subtitle: shortenId(primaryTokenId),
|
|
1021
|
-
subtitleCopy: primaryTokenId
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
const indexerFee = resolveIndexerFee(intent);
|
|
1025
|
-
return {
|
|
1026
|
-
title: "Send tokens",
|
|
1027
|
-
subtitle: `${shortenOriginator(req.originator)} wants to send tokens`,
|
|
1028
|
-
rows,
|
|
1029
|
-
featured,
|
|
1030
|
-
indexerFee
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
function resolveIndexerFee(intent) {
|
|
1034
|
-
if (intent.indexerFeeSats != null && intent.indexerFeeSats > 0) {
|
|
1035
|
-
return {
|
|
1036
|
-
sats: intent.indexerFeeSats,
|
|
1037
|
-
note: intent.indexerFeeNote
|
|
1038
|
-
};
|
|
1039
|
-
}
|
|
1040
|
-
const tokenOutCount = intent.outputs.filter((o) => o.basket === BSV21_BASKET || tagValue(o.tags, "bsv21")).length;
|
|
1041
|
-
const feeLike = intent.outputs.filter((o) => !o.basket && o.recipient && o.satoshis > 1);
|
|
1042
|
-
const isPurchase = intent.p1satIntent?.endsWith(".purchase") || intent.kind === "purchase";
|
|
1043
|
-
if (isPurchase || feeLike.length !== 1)
|
|
1044
|
-
return;
|
|
1045
|
-
const fee = feeLike[0];
|
|
1046
|
-
if (!fee || fee.satoshis <= 0)
|
|
1047
|
-
return;
|
|
1048
|
-
const note = tokenOutCount > 0 ? `Overlay processing · ${formatSats(Math.round(fee.satoshis / tokenOutCount))} sats × ${tokenOutCount} token outs` : "Overlay processing fee";
|
|
1049
|
-
return { sats: fee.satoshis, note };
|
|
1050
|
-
}
|
|
1051
|
-
function summarizeLock(req, intent) {
|
|
1052
|
-
const decoded = intent.outputs.filter((o) => o.lockUntilHeight !== undefined);
|
|
1053
|
-
const lockOutputs = decoded.length > 0 ? decoded : intent.outputs.filter((o) => o.basket === LOCK_BASKET);
|
|
1054
|
-
const sats = (lockOutputs.length > 0 ? lockOutputs : intent.outputs).reduce((s, o) => s + o.satoshis, 0);
|
|
1055
|
-
const until = decoded[0]?.lockUntilHeight;
|
|
1056
|
-
const rows = [
|
|
1057
|
-
{ key: "Amount", value: `${sats.toLocaleString("en-US")} sats` }
|
|
1058
|
-
];
|
|
1059
|
-
if (until !== undefined) {
|
|
1060
|
-
rows.push({
|
|
1061
|
-
key: "Lock until block",
|
|
1062
|
-
value: until.toLocaleString("en-US")
|
|
1063
|
-
});
|
|
1064
|
-
}
|
|
1065
|
-
return {
|
|
1066
|
-
title: "Lock BSV",
|
|
1067
|
-
subtitle: `${shortenOriginator(req.originator)} wants to time-lock funds`,
|
|
1068
|
-
rows
|
|
1069
|
-
};
|
|
1070
|
-
}
|
|
1071
|
-
function summarizeUnlock(req, intent) {
|
|
1072
|
-
const sats = intent.inputs.reduce((s, i) => s + i.satoshis, 0);
|
|
1073
|
-
return {
|
|
1074
|
-
title: "Unlock Matured",
|
|
1075
|
-
subtitle: `${shortenOriginator(req.originator)} wants to unlock matured locks`,
|
|
1076
|
-
rows: [{ key: "Amount", value: `${sats} sats` }]
|
|
1077
|
-
};
|
|
1078
|
-
}
|
|
1079
|
-
function summarizeInscription(req, intent) {
|
|
1080
|
-
const inscriptionOutput = intent.outputs.find((o) => o.tags.some((t) => t.startsWith("type:"))) ?? intent.outputs[0];
|
|
1081
|
-
const contentType = tagValue(inscriptionOutput?.tags, "type");
|
|
1082
|
-
const name = tagValue(inscriptionOutput?.tags, "name");
|
|
1083
|
-
const recipient = inscriptionOutput?.recipient;
|
|
1084
|
-
const rows = [];
|
|
1085
|
-
if (contentType)
|
|
1086
|
-
rows.push({ key: "Type", value: contentType });
|
|
1087
|
-
if (name)
|
|
1088
|
-
rows.push({ key: "Name", value: name });
|
|
1089
|
-
if (recipient)
|
|
1090
|
-
rows.push(copyable("Recipient", recipient));
|
|
1091
|
-
return {
|
|
1092
|
-
title: "Create Inscription",
|
|
1093
|
-
subtitle: `${shortenOriginator(req.originator)} wants to inscribe content into your wallet`,
|
|
1094
|
-
rows
|
|
1095
|
-
};
|
|
1096
|
-
}
|
|
1097
|
-
function summarizeListing(req, intent) {
|
|
1098
|
-
const listingOutput = intent.outputs.find((o) => o.listingPriceSats !== undefined) ?? intent.outputs.find((o) => o.tags.some((t) => t.startsWith("price:")));
|
|
1099
|
-
const ordinal = intent.inputs[0];
|
|
1100
|
-
const origin = tagValue(ordinal?.tags, "origin") ?? tagValue(listingOutput?.tags, "origin");
|
|
1101
|
-
const name = tagValue(ordinal?.tags, "name") ?? tagValue(listingOutput?.tags, "name");
|
|
1102
|
-
const contentType = tagValue(ordinal?.tags, "type") ?? tagValue(listingOutput?.tags, "type");
|
|
1103
|
-
const collectionId = tagValue(ordinal?.tags, "collectionId");
|
|
1104
|
-
const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
|
|
1105
|
-
const price = listingOutput?.listingPriceSats;
|
|
1106
|
-
const rows = [];
|
|
1107
|
-
if (name)
|
|
1108
|
-
rows.push({ key: "Name", value: name });
|
|
1109
|
-
if (price !== undefined) {
|
|
1110
|
-
rows.push({ key: "Price", value: `${price.toLocaleString("en-US")} sats` });
|
|
1111
|
-
}
|
|
1112
|
-
if (origin)
|
|
1113
|
-
rows.push(copyable("Origin", origin));
|
|
1114
|
-
if (contentType)
|
|
1115
|
-
rows.push({ key: "Type", value: contentType });
|
|
1116
|
-
return {
|
|
1117
|
-
title: "List Ordinal for Sale",
|
|
1118
|
-
subtitle: `${shortenOriginator(req.originator)} wants to list ${name ? `“${name}”` : "an ordinal"} for sale`,
|
|
1119
|
-
rows,
|
|
1120
|
-
featured: imageUrl ? {
|
|
1121
|
-
imageUrl,
|
|
1122
|
-
title: name ?? "Untitled ordinal",
|
|
1123
|
-
subtitle: collectionId ?? contentType
|
|
1124
|
-
} : undefined
|
|
1125
|
-
};
|
|
1126
|
-
}
|
|
1127
|
-
function summarizeCancelListing(req, intent) {
|
|
1128
|
-
const listing = intent.inputs[0];
|
|
1129
|
-
const reclaimed = intent.outputs[0];
|
|
1130
|
-
const origin = tagValue(listing?.tags, "origin") ?? tagValue(reclaimed?.tags, "origin");
|
|
1131
|
-
const name = tagValue(listing?.tags, "name") ?? tagValue(reclaimed?.tags, "name");
|
|
1132
|
-
const contentType = tagValue(listing?.tags, "type") ?? tagValue(reclaimed?.tags, "type");
|
|
1133
|
-
const collectionId = tagValue(listing?.tags, "collectionId");
|
|
1134
|
-
const price = tagValue(listing?.tags, "price");
|
|
1135
|
-
const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
|
|
1136
|
-
const rows = [];
|
|
1137
|
-
if (name)
|
|
1138
|
-
rows.push({ key: "Name", value: name });
|
|
1139
|
-
if (price)
|
|
1140
|
-
rows.push({ key: "Original price", value: `${price} sats` });
|
|
1141
|
-
if (origin)
|
|
1142
|
-
rows.push(copyable("Origin", origin));
|
|
1143
|
-
if (contentType)
|
|
1144
|
-
rows.push({ key: "Type", value: contentType });
|
|
1145
|
-
return {
|
|
1146
|
-
title: "Cancel Listing",
|
|
1147
|
-
subtitle: `${shortenOriginator(req.originator)} wants to cancel ${name ? `the listing of “${name}”` : "an ordinal listing"}`,
|
|
1148
|
-
rows,
|
|
1149
|
-
featured: imageUrl ? {
|
|
1150
|
-
imageUrl,
|
|
1151
|
-
title: name ?? "Untitled ordinal",
|
|
1152
|
-
subtitle: collectionId ?? contentType
|
|
1153
|
-
} : undefined
|
|
1154
|
-
};
|
|
1155
|
-
}
|
|
1156
|
-
function summarizePurchase(req, intent) {
|
|
1157
|
-
const incoming = intent.outputs.find((o) => o.basket === ORDINALS_BASKET || o.basket === BSV21_BASKET);
|
|
1158
|
-
const isToken = incoming?.basket === BSV21_BASKET;
|
|
1159
|
-
const origin = tagValue(incoming?.tags, "origin");
|
|
1160
|
-
const name = tagValue(incoming?.tags, "name");
|
|
1161
|
-
const contentType = tagValue(incoming?.tags, "type");
|
|
1162
|
-
const collectionId = tagValue(incoming?.tags, "collectionId");
|
|
1163
|
-
const sym = tagValue(incoming?.tags, "sym");
|
|
1164
|
-
const amt = tagValue(incoming?.tags, "amt");
|
|
1165
|
-
const tokenId = tagValue(incoming?.tags, "bsv21");
|
|
1166
|
-
const sellerOutput = intent.outputs.find((o) => !o.basket && o.recipient && o.satoshis > 1);
|
|
1167
|
-
const price = sellerOutput?.satoshis;
|
|
1168
|
-
const rows = [];
|
|
1169
|
-
if (price !== undefined)
|
|
1170
|
-
rows.push({ key: "Price", value: `${price.toLocaleString("en-US")} sats` });
|
|
1171
|
-
if (isToken) {
|
|
1172
|
-
if (amt)
|
|
1173
|
-
rows.push({ key: "Amount", value: amt });
|
|
1174
|
-
} else {
|
|
1175
|
-
if (origin)
|
|
1176
|
-
rows.push(copyable("Origin", origin));
|
|
1177
|
-
if (contentType)
|
|
1178
|
-
rows.push({ key: "Type", value: contentType });
|
|
1179
|
-
}
|
|
1180
|
-
const featuredImage = !isToken && origin ? intent.contentUrls?.[origin] : undefined;
|
|
1181
|
-
const iconRef = tagValue(incoming?.tags, "icon");
|
|
1182
|
-
const iconUrl = iconRef && intent.contentUrls?.[iconRef] || tokenId && intent.contentUrls?.[tokenId] || undefined;
|
|
1183
|
-
let featured;
|
|
1184
|
-
if (isToken && (sym || tokenId)) {
|
|
1185
|
-
featured = {
|
|
1186
|
-
variant: "token",
|
|
1187
|
-
imageUrl: iconUrl,
|
|
1188
|
-
title: sym ?? "Token",
|
|
1189
|
-
subtitle: tokenId ? shortenId(tokenId) : undefined,
|
|
1190
|
-
subtitleCopy: tokenId
|
|
1191
|
-
};
|
|
1192
|
-
} else if (featuredImage) {
|
|
1193
|
-
featured = {
|
|
1194
|
-
imageUrl: featuredImage,
|
|
1195
|
-
title: name ?? "Untitled ordinal",
|
|
1196
|
-
subtitle: collectionId ?? contentType
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
return {
|
|
1200
|
-
title: isToken ? "Buy tokens" : "Buy ordinal",
|
|
1201
|
-
subtitle: isToken ? `${shortenOriginator(req.originator)} wants to purchase tokens into your wallet` : `${shortenOriginator(req.originator)} wants to purchase an ordinal into your wallet`,
|
|
1202
|
-
rows,
|
|
1203
|
-
featured,
|
|
1204
|
-
trust: intent.trust,
|
|
1205
|
-
indexerFee: resolveIndexerFee(intent)
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
function summarizeSocialPost(req, intent) {
|
|
1209
|
-
return {
|
|
1210
|
-
title: "Social Post",
|
|
1211
|
-
subtitle: `${shortenOriginator(req.originator)} wants to publish a post`,
|
|
1212
|
-
rows: []
|
|
1213
|
-
};
|
|
1214
|
-
}
|
|
1215
|
-
function summarizeOpns(req, intent) {
|
|
1216
|
-
const input = intent.inputs[0];
|
|
1217
|
-
const opnsOutput = intent.outputs.find((o) => o.basket === OPNS_BASKET);
|
|
1218
|
-
const recipient = intent.outputs.find((o) => !o.basket && o.recipient)?.recipient;
|
|
1219
|
-
const name = tagValue(input?.tags, "name") ?? tagValue(opnsOutput?.tags, "name");
|
|
1220
|
-
const origin = tagValue(input?.tags, "origin") ?? tagValue(opnsOutput?.tags, "origin");
|
|
1221
|
-
const priceTag = intent.outputs.flatMap((o) => o.tags).find((t) => t.startsWith("price:"));
|
|
1222
|
-
const price = priceTag?.slice("price:".length);
|
|
1223
|
-
const rows = [];
|
|
1224
|
-
if (name)
|
|
1225
|
-
rows.push({ key: "Name", value: name });
|
|
1226
|
-
if (opnsOutput?.opnsProfileName) {
|
|
1227
|
-
rows.push({ key: "Display name", value: opnsOutput.opnsProfileName });
|
|
1228
|
-
}
|
|
1229
|
-
if (recipient)
|
|
1230
|
-
rows.push(copyable("Recipient", recipient));
|
|
1231
|
-
if (price)
|
|
1232
|
-
rows.push({ key: "Price", value: `${price} sats` });
|
|
1233
|
-
if (origin)
|
|
1234
|
-
rows.push(copyable("Origin", origin));
|
|
1235
|
-
const copy = opnsCopy(intent.p1satIntent, Boolean(recipient));
|
|
1236
|
-
const nameBit = name ? `“${name}”` : "an OpNS name";
|
|
1237
|
-
const avatarOrigin = opnsOutput?.opnsAvatarOrigin;
|
|
1238
|
-
const avatarUrl = avatarOrigin ? intent.contentUrls?.[avatarOrigin] : undefined;
|
|
1239
|
-
return {
|
|
1240
|
-
title: copy.title,
|
|
1241
|
-
subtitle: `${shortenOriginator(req.originator)} wants to ${copy.verb} ${nameBit}`,
|
|
1242
|
-
rows,
|
|
1243
|
-
...avatarUrl && {
|
|
1244
|
-
featured: {
|
|
1245
|
-
variant: "token",
|
|
1246
|
-
imageUrl: avatarUrl,
|
|
1247
|
-
title: opnsOutput?.opnsProfileName ?? name ?? "Avatar",
|
|
1248
|
-
...name && { subtitle: name }
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
function opnsCopy(p1satIntent, isTransferHeuristic) {
|
|
1254
|
-
switch (p1satIntent) {
|
|
1255
|
-
case "opns.register":
|
|
1256
|
-
return { title: "Publish name", verb: "publish" };
|
|
1257
|
-
case "opns.deregister":
|
|
1258
|
-
return { title: "Unpublish name", verb: "unpublish" };
|
|
1259
|
-
case "opns.list":
|
|
1260
|
-
return { title: "List name for sale", verb: "list" };
|
|
1261
|
-
case "opns.transfer":
|
|
1262
|
-
return { title: "Transfer name", verb: "transfer" };
|
|
1263
|
-
case "opns.cancel-listing":
|
|
1264
|
-
return { title: "Cancel listing", verb: "cancel the listing of" };
|
|
1265
|
-
case "opns.purchase":
|
|
1266
|
-
return { title: "Buy name", verb: "buy" };
|
|
1267
|
-
default:
|
|
1268
|
-
return isTransferHeuristic ? { title: "Transfer OpNS Name", verb: "transfer" } : { title: "Update OpNS Name", verb: "update" };
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
function summarizeUnknownTx(req, intent) {
|
|
1272
|
-
const ins = intent.inputs.length;
|
|
1273
|
-
const outs = intent.outputs.length;
|
|
1274
|
-
return {
|
|
1275
|
-
title: "Transaction Request",
|
|
1276
|
-
subtitle: `${shortenOriginator(req.originator)} wants to ${req.summary.toLowerCase()}`,
|
|
1277
|
-
rows: [{ key: "Inputs / Outputs", value: `${ins} / ${outs}` }]
|
|
1278
|
-
};
|
|
1279
|
-
}
|
|
1280
|
-
function shortenId(id, max = 24) {
|
|
1281
|
-
if (id.length <= max)
|
|
1282
|
-
return id;
|
|
1283
|
-
return `${id.slice(0, 8)}…${id.slice(-6)}`;
|
|
1284
|
-
}
|
|
1285
|
-
function shortenValue(value, head = 12, tail = 10) {
|
|
1286
|
-
if (value.length <= head + tail + 1)
|
|
1287
|
-
return value;
|
|
1288
|
-
return `${value.slice(0, head)}…${value.slice(-tail)}`;
|
|
1289
|
-
}
|
|
1290
|
-
function summarizeProtocol(req) {
|
|
1291
|
-
const intent = req.intent;
|
|
1292
|
-
const rows = [
|
|
1293
|
-
{ key: "Protocol", value: "1Sat (p 1sat)" },
|
|
1294
|
-
{ key: "Access", value: intent.access ?? "read-only" }
|
|
1295
|
-
];
|
|
1296
|
-
return {
|
|
1297
|
-
title: "Protocol Access",
|
|
1298
|
-
subtitle: intent.notes ?? `${shortenOriginator(req.originator)} requests read-only access to derive your 1Sat addresses. Signing remains per-transaction.`,
|
|
1299
|
-
rows
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
function summarizeSignature(req) {
|
|
1303
|
-
const intent = req.intent;
|
|
1304
|
-
const rows = [];
|
|
1305
|
-
if (intent.protocolID) {
|
|
1306
|
-
rows.push({ key: "Protocol", value: JSON.stringify(intent.protocolID) });
|
|
1307
|
-
}
|
|
1308
|
-
if (intent.keyID)
|
|
1309
|
-
rows.push({ key: "Key ID", value: intent.keyID });
|
|
1310
|
-
if (intent.counterparty) {
|
|
1311
|
-
rows.push({
|
|
1312
|
-
key: "Counterparty",
|
|
1313
|
-
value: shortenOriginator(intent.counterparty)
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1316
|
-
if (typeof intent.dataLength === "number") {
|
|
1317
|
-
rows.push({ key: "Payload", value: `${intent.dataLength} bytes` });
|
|
1318
|
-
}
|
|
1319
|
-
return {
|
|
1320
|
-
title: "Signature Request",
|
|
1321
|
-
subtitle: `${shortenOriginator(req.originator)} requests a signature`,
|
|
1322
|
-
rows
|
|
1323
|
-
};
|
|
1324
|
-
}
|
|
1325
1169
|
function shortenOriginator(origin) {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1170
|
+
try {
|
|
1171
|
+
const u = new URL(origin.includes("://") ? origin : `https://${origin}`);
|
|
1172
|
+
return u.host || origin;
|
|
1173
|
+
} catch {
|
|
1174
|
+
if (origin.length <= 32)
|
|
1175
|
+
return origin;
|
|
1176
|
+
return `${origin.slice(0, 14)}…${origin.slice(-12)}`;
|
|
1177
|
+
}
|
|
1329
1178
|
}
|
|
1330
1179
|
export {
|
|
1331
1180
|
OneSatPermissionPrompt
|