@orangecheck/auth-client 2.30.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3187,6 +3187,7 @@ function Hint({ children }) {
3187
3187
  }
3188
3188
  var DEFAULT_AUTH_ORIGIN2 = "https://ochk.io";
3189
3189
  var MIN_CONFIRMATIONS = 6;
3190
+ var MIN_SATS = 1e3;
3190
3191
  var n = (v) => v.toLocaleString("en-US");
3191
3192
  function bondFloorsText(f) {
3192
3193
  const sats = f.sats_floor > 0 ? `at least ${n(f.sats_floor)} sats` : "under 1,000 sats";
@@ -3197,23 +3198,56 @@ var short = (outpoint) => {
3197
3198
  const [txid = "", vout = ""] = outpoint.split(":");
3198
3199
  return `${txid.slice(0, 8)}\u2026${txid.slice(-4)}:${vout}`;
3199
3200
  };
3201
+ var usable = (c) => c.sats >= MIN_SATS && c.age_blocks >= MIN_CONFIRMATIONS;
3202
+ var dustText = (count) => `${n(count)} ${count === 1 ? "coin" : "coins"} under ${n(MIN_SATS)} sats, too small to back an account`;
3200
3203
  var REFUSAL = {
3201
3204
  invalid_address: "that isn't a Bitcoin address we can read",
3202
3205
  chain_unavailable: "couldn't read the chain just now \xB7 nothing changed, try again in a minute",
3203
3206
  sig_invalid: "that signature isn't from this coin's address \xB7 sign with the wallet that holds it",
3204
3207
  bond_expired: "the message expired \xB7 start again",
3205
- bond_not_yet_valid: "your device's clock looks wrong",
3208
+ bond_not_yet_valid: "your device's clock looks wrong \xB7 check it and start again",
3206
3209
  bond_subject_mismatch: "that message was for another account \xB7 start again",
3207
3210
  bond_malformed: "the signed message changed on the way \xB7 start again",
3211
+ bond_window_too_long: "that message's signing window is too long \xB7 start again",
3208
3212
  coin_not_found: "that coin doesn't exist on-chain",
3209
3213
  coin_address_mismatch: "that coin isn't at this address",
3210
3214
  coin_unconfirmed: "that coin isn't confirmed yet",
3211
3215
  coin_too_recent: "that coin needs six confirmations first, about an hour",
3212
3216
  coin_spent: "that coin has been spent \xB7 pick one still in your wallet",
3217
+ coin_too_small: `that coin is under ${n(MIN_SATS)} sats, too small to back an account`,
3213
3218
  coin_backs_another_account: "that coin already backs another orangecheck account",
3214
- not_authenticated: "your session ended \xB7 sign in again"
3219
+ coin_backed_another_recently: "that coin backed another account until recently \xB7 it can back this one 30 days after it was released",
3220
+ not_authenticated: "your session ended \xB7 sign in again",
3221
+ rate_limited: "too many tries \xB7 wait a minute, then try again"
3215
3222
  };
3216
- var refusal = (reason) => reason && REFUSAL[reason] || "your backing didn't save \xB7 nothing changed, try again";
3223
+ var bondRefusal = (reason) => reason && REFUSAL[reason] || "your backing didn't save \xB7 nothing changed, try again";
3224
+ var smallStyle = { ...bodyStyle, fontSize: 12, margin: 0 };
3225
+ var explainerStyle = {
3226
+ ...hintStyle,
3227
+ fontSize: 12,
3228
+ lineHeight: 1.55,
3229
+ opacity: 1,
3230
+ margin: 0
3231
+ };
3232
+ var fieldLabelStyle = {
3233
+ display: "block",
3234
+ color: V.foreground,
3235
+ fontSize: 13,
3236
+ fontWeight: 500,
3237
+ margin: "0 0 4px"
3238
+ };
3239
+ var addressStyle = { wordBreak: "break-all", color: V.foreground };
3240
+ function coinStyle(picked, young) {
3241
+ return {
3242
+ background: V.card,
3243
+ border: `1px ${young ? "dashed" : "solid"} ${picked ? V.primary : V.border}`,
3244
+ padding: "0.75rem",
3245
+ display: "flex",
3246
+ gap: 10,
3247
+ alignItems: "flex-start",
3248
+ cursor: young ? "not-allowed" : "pointer"
3249
+ };
3250
+ }
3217
3251
  async function fetchOcBond(opts) {
3218
3252
  const r = await fetch(`${opts?.authOrigin ?? DEFAULT_AUTH_ORIGIN2}/api/auth/bond`, {
3219
3253
  credentials: "include"
@@ -3231,6 +3265,7 @@ function OcBond({
3231
3265
  const [loadErr, setLoadErr] = React4.useState(false);
3232
3266
  const [nonce, setNonce] = React4.useState(0);
3233
3267
  const [adding, setAdding] = React4.useState(false);
3268
+ const [confirming, setConfirming] = React4.useState(false);
3234
3269
  const [busy, setBusy] = React4.useState(false);
3235
3270
  const [err, setErr] = React4.useState(null);
3236
3271
  React4.useEffect(() => {
@@ -3252,6 +3287,10 @@ function OcBond({
3252
3287
  body: body ? JSON.stringify(body) : void 0
3253
3288
  });
3254
3289
  const j = await r.json().catch(() => ({}));
3290
+ const pin = readTabSession();
3291
+ if (pin && r.ok && typeof j.token === "string") {
3292
+ writeTabSession({ token: j.token, didOc: pin.didOc });
3293
+ }
3255
3294
  return { ok: r.ok && j.ok === true, ...j };
3256
3295
  },
3257
3296
  [authOrigin]
@@ -3261,7 +3300,8 @@ function OcBond({
3261
3300
  setErr(null);
3262
3301
  const j = await call("DELETE").catch(() => ({ ok: false, reason: "network" }));
3263
3302
  setBusy(false);
3264
- if (!j.ok) return setErr(refusal(j.reason));
3303
+ if (!j.ok) return setErr(bondRefusal(j.reason));
3304
+ setConfirming(false);
3265
3305
  setBond(null);
3266
3306
  onChange?.(null);
3267
3307
  }
@@ -3305,16 +3345,71 @@ function OcBond({
3305
3345
  n(bond.checked_height),
3306
3346
  " \xB7 only you and orangecheck see this line"
3307
3347
  ] }),
3308
- /* @__PURE__ */ jsxs(FormButtons, { children: [
3309
- /* @__PURE__ */ jsx("button", { type: "button", style: ghostBtnStyle(busy), disabled: busy, onClick: () => setAdding(true), children: "use another coin" }),
3310
- /* @__PURE__ */ jsx("button", { type: "button", style: dangerBtnStyle(busy), disabled: busy, onClick: () => void release(), children: "stop backing" })
3348
+ confirming ? /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": "stop backing", "data-oc-bond-confirm": "", children: [
3349
+ /* @__PURE__ */ jsx("p", { style: { ...bodyStyle, color: V.foreground, margin: 0 }, children: "stop backing? apps that ask for a backed account may stop letting you in." }),
3350
+ /* @__PURE__ */ jsxs(FormButtons, { children: [
3351
+ /* @__PURE__ */ jsx(
3352
+ "button",
3353
+ {
3354
+ type: "button",
3355
+ style: dangerBtnStyle(busy),
3356
+ disabled: busy,
3357
+ onClick: () => void release(),
3358
+ children: "stop backing"
3359
+ }
3360
+ ),
3361
+ /* @__PURE__ */ jsx(
3362
+ "button",
3363
+ {
3364
+ type: "button",
3365
+ style: ghostBtnStyle(busy),
3366
+ disabled: busy,
3367
+ autoFocus: true,
3368
+ onClick: () => {
3369
+ setErr(null);
3370
+ setConfirming(false);
3371
+ },
3372
+ children: "keep"
3373
+ }
3374
+ )
3375
+ ] })
3376
+ ] }) : /* @__PURE__ */ jsxs(FormButtons, { children: [
3377
+ /* @__PURE__ */ jsx(
3378
+ "button",
3379
+ {
3380
+ type: "button",
3381
+ style: ghostBtnStyle(false),
3382
+ onClick: () => {
3383
+ setErr(null);
3384
+ setAdding(true);
3385
+ },
3386
+ children: "use another coin"
3387
+ }
3388
+ ),
3389
+ /* @__PURE__ */ jsx(
3390
+ "button",
3391
+ {
3392
+ type: "button",
3393
+ style: dangerBtnStyle(false),
3394
+ onClick: () => setConfirming(true),
3395
+ children: "stop backing"
3396
+ }
3397
+ )
3311
3398
  ] }),
3312
3399
  err ? /* @__PURE__ */ jsx(ErrorLine, { children: err }) : null
3313
3400
  ] }) : null,
3314
3401
  !bond && !adding ? /* @__PURE__ */ jsxs("div", { style: panelStyle(), children: [
3315
3402
  /* @__PURE__ */ jsx(SectionLabel, { children: "\xA7 not backed" }),
3316
- /* @__PURE__ */ jsx("p", { style: bodyStyle, children: "your account works everywhere as it is. apps that want to keep out bots can ask for a backed account: one coin you hold, that never moves and that they never see." }),
3317
- /* @__PURE__ */ jsx("button", { type: "button", style: primaryBtnStyle(false), onClick: () => setAdding(true), children: "back it with a coin" })
3403
+ /* @__PURE__ */ jsx("p", { style: bodyStyle, children: "your account works everywhere as it is. some apps let in only accounts backed by a coin you hold. it stays in your wallet, and apps never see which coin." }),
3404
+ /* @__PURE__ */ jsx(
3405
+ "button",
3406
+ {
3407
+ type: "button",
3408
+ style: primaryBtnStyle(false),
3409
+ onClick: () => setAdding(true),
3410
+ children: "back your account"
3411
+ }
3412
+ )
3318
3413
  ] }) : null,
3319
3414
  adding ? /* @__PURE__ */ jsx(
3320
3415
  BondForm,
@@ -3328,9 +3423,9 @@ function OcBond({
3328
3423
  }
3329
3424
  }
3330
3425
  ) : null,
3331
- /* @__PURE__ */ jsxs("p", { style: hintStyle, children: [
3426
+ /* @__PURE__ */ jsxs("p", { style: explainerStyle, children: [
3332
3427
  "> ",
3333
- "apps see that a coin backs you, in rough steps, and a number unique to each app, so they can't compare notes. an app can block that number; getting past it means moving the coin, and a moved coin starts its age again."
3428
+ "apps see only rough floors, like \u201Cat least 100,000 sats, held 30 days or more\u201D, and a number unique to that app. never the coin, your address or your balance. an app can block that number; only moving the coin gets past it, and a moved coin starts its age again."
3334
3429
  ] })
3335
3430
  ] });
3336
3431
  }
@@ -3345,135 +3440,212 @@ function BondForm({
3345
3440
  const [message, setMessage] = React4.useState(null);
3346
3441
  const [busy, setBusy] = React4.useState(false);
3347
3442
  const [err, setErr] = React4.useState(null);
3443
+ const id = React4.useId();
3444
+ const addr = address.trim();
3445
+ const canFind = addr.length >= 14;
3348
3446
  async function run(fn) {
3349
3447
  setBusy(true);
3350
3448
  setErr(null);
3351
3449
  try {
3352
3450
  await fn();
3353
3451
  } catch {
3354
- setErr(refusal("chain_unavailable"));
3452
+ setErr(bondRefusal("chain_unavailable"));
3355
3453
  } finally {
3356
3454
  setBusy(false);
3357
3455
  }
3358
3456
  }
3359
3457
  const findCoins = () => run(async () => {
3360
- const j = await call("POST", { action: "coins", address: address.trim() });
3361
- if (!j.ok) return setErr(refusal(j.reason));
3458
+ const j = await call("POST", { action: "coins", address: addr });
3459
+ if (!j.ok) return setErr(bondRefusal(j.reason));
3362
3460
  const list = j.coins ?? [];
3363
3461
  setCoins(list);
3364
- setChosen(list.find((c) => c.age_blocks >= MIN_CONFIRMATIONS)?.outpoint ?? "");
3462
+ setChosen(list.find(usable)?.outpoint ?? "");
3365
3463
  });
3366
3464
  const getMessage = () => run(async () => {
3367
- const j = await call("POST", { action: "message", address: address.trim(), outpoint: chosen });
3368
- if (!j.ok || typeof j.message !== "string") return setErr(refusal(j.reason));
3465
+ const j = await call("POST", { action: "message", address: addr, outpoint: chosen });
3466
+ if (!j.ok || typeof j.message !== "string") return setErr(bondRefusal(j.reason));
3369
3467
  setMessage(j.message);
3370
3468
  });
3371
3469
  const submit = (signature) => run(async () => {
3372
3470
  const j = await call("POST", { action: "bond", message, signature });
3373
- if (!j.ok || !j.bond) return setErr(refusal(j.reason));
3471
+ if (!j.ok || !j.bond) return setErr(bondRefusal(j.reason));
3374
3472
  onDone(j.bond);
3375
3473
  });
3376
- return /* @__PURE__ */ jsxs("div", { style: panelStyle("accent"), "data-oc-bond-form": "", children: [
3377
- /* @__PURE__ */ jsx(SectionLabel, { children: "\xA7 back your account with a coin" }),
3378
- message ? /* @__PURE__ */ jsxs(Fragment, { children: [
3474
+ function back() {
3475
+ setErr(null);
3476
+ if (message) setMessage(null);
3477
+ else setCoins(null);
3478
+ }
3479
+ const error = err ? /* @__PURE__ */ jsx(ErrorLine, { children: err }) : null;
3480
+ const backButton = /* @__PURE__ */ jsx("button", { type: "button", style: ghostBtnStyle(busy), disabled: busy, onClick: back, children: "back" });
3481
+ const cancelButton = /* @__PURE__ */ jsx("button", { type: "button", style: ghostBtnStyle(busy), disabled: busy, onClick: onCancel, children: "cancel" });
3482
+ let step;
3483
+ if (message) {
3484
+ step = /* @__PURE__ */ jsxs(Fragment, { children: [
3379
3485
  /* @__PURE__ */ jsxs("p", { style: bodyStyle, children: [
3380
- "sign with the wallet that holds",
3381
- " ",
3382
- /* @__PURE__ */ jsx("span", { style: { wordBreak: "break-all", color: V.foreground }, children: address.trim() }),
3383
- ". the coin doesn't move and nothing is spent."
3486
+ "sign with the wallet that holds ",
3487
+ /* @__PURE__ */ jsx("span", { style: addressStyle, children: addr }),
3488
+ ". signing spends nothing, and the coin stays in your wallet."
3384
3489
  ] }),
3385
3490
  /* @__PURE__ */ jsx(
3386
3491
  LazyWalletButton,
3387
3492
  {
3388
- address: address.trim(),
3493
+ address: addr,
3389
3494
  message,
3390
3495
  showManual: true,
3391
3496
  onSigned: (sig) => void submit(sig),
3392
3497
  onError: (e) => setErr(e.message ?? "the wallet refused to sign")
3393
3498
  }
3394
- )
3395
- ] }) : coins ? coins.length === 0 ? /* @__PURE__ */ jsx("p", { style: bodyStyle, children: "no confirmed coins at that address \xB7 send some sats there and wait for six confirmations, about an hour. the longer a coin sits, the more it says." }) : /* @__PURE__ */ jsxs("div", { role: "radiogroup", "aria-label": "pick one coin", style: { display: "grid", gap: 8 }, children: [
3396
- /* @__PURE__ */ jsx("p", { style: bodyStyle, children: "pick one coin \xB7 value spread over several coins doesn't add up" }),
3397
- coins.map((c) => {
3398
- const young = c.age_blocks < MIN_CONFIRMATIONS;
3399
- return /* @__PURE__ */ jsxs(
3400
- "label",
3499
+ ),
3500
+ error,
3501
+ /* @__PURE__ */ jsxs(FormButtons, { children: [
3502
+ backButton,
3503
+ cancelButton
3504
+ ] })
3505
+ ] });
3506
+ } else if (coins) {
3507
+ const eligible = coins.filter((c) => c.sats >= MIN_SATS);
3508
+ const dust = coins.length - eligible.length;
3509
+ step = /* @__PURE__ */ jsxs(Fragment, { children: [
3510
+ coins.length === 0 ? /* @__PURE__ */ jsxs("p", { style: bodyStyle, children: [
3511
+ "no confirmed coins at that address \xB7 send at least ",
3512
+ n(MIN_SATS),
3513
+ " sats there and wait for six confirmations, about an hour. the longer a coin sits, the more it says."
3514
+ ] }) : eligible.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
3515
+ /* @__PURE__ */ jsx("p", { style: { ...bodyStyle, color: V.foreground }, children: dustText(dust) }),
3516
+ /* @__PURE__ */ jsxs("p", { style: bodyStyle, children: [
3517
+ "send at least ",
3518
+ n(MIN_SATS),
3519
+ " sats there in one payment and wait for six confirmations, about an hour. coins aren't added together."
3520
+ ] })
3521
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3522
+ /* @__PURE__ */ jsx("p", { id: `${id}-pick`, style: bodyStyle, children: "pick one coin \xB7 coins aren't added together" }),
3523
+ /* @__PURE__ */ jsx(
3524
+ "div",
3401
3525
  {
3402
- style: {
3403
- ...panelStyle(chosen === c.outpoint ? "accent" : "default"),
3404
- padding: "0.75rem",
3405
- display: "flex",
3406
- gap: 10,
3407
- alignItems: "flex-start",
3408
- cursor: young ? "not-allowed" : "pointer",
3409
- opacity: young ? 0.6 : 1
3410
- },
3411
- children: [
3412
- /* @__PURE__ */ jsx(
3413
- "input",
3526
+ role: "radiogroup",
3527
+ "aria-labelledby": `${id}-pick`,
3528
+ style: { display: "grid", gap: 8 },
3529
+ children: eligible.map((c) => {
3530
+ const young = c.age_blocks < MIN_CONFIRMATIONS;
3531
+ return /* @__PURE__ */ jsxs(
3532
+ "label",
3414
3533
  {
3415
- type: "radio",
3416
- name: "oc-bond-coin",
3417
- value: c.outpoint,
3418
- checked: chosen === c.outpoint,
3419
- disabled: young,
3420
- onChange: () => setChosen(c.outpoint)
3421
- }
3422
- ),
3423
- /* @__PURE__ */ jsxs("span", { style: { display: "grid", gap: 2, minWidth: 0 }, children: [
3424
- /* @__PURE__ */ jsxs("span", { style: { color: V.foreground, fontSize: 13 }, children: [
3425
- n(c.sats),
3426
- " sats, held ",
3427
- Math.floor(c.age_blocks / 144),
3428
- " days"
3429
- ] }),
3430
- /* @__PURE__ */ jsx("span", { style: hintStyle, children: young ? "too recent: needs six confirmations" : `apps would see ${bondFloorsText(c)}` }),
3431
- /* @__PURE__ */ jsx("span", { style: { ...hintStyle, wordBreak: "break-all" }, children: short(c.outpoint) })
3432
- ] })
3433
- ]
3434
- },
3435
- c.outpoint
3436
- );
3437
- })
3438
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3439
- /* @__PURE__ */ jsx("p", { style: bodyStyle, children: "which address holds the coin? use one that holds nothing else of yours: orangecheck learns its address and amount. apps never do." }),
3440
- /* @__PURE__ */ jsx(
3441
- "input",
3442
- {
3443
- style: inputStyle,
3444
- value: address,
3445
- onChange: (e) => setAddress(e.target.value),
3446
- placeholder: "bc1q\u2026",
3447
- spellCheck: false,
3448
- autoComplete: "off",
3449
- "aria-label": "Bitcoin address"
3450
- }
3451
- )
3452
- ] }),
3453
- err ? /* @__PURE__ */ jsx(ErrorLine, { children: err }) : null,
3454
- /* @__PURE__ */ jsxs(FormButtons, { children: [
3455
- !coins && !message ? /* @__PURE__ */ jsx(
3456
- "button",
3457
- {
3458
- type: "button",
3459
- style: primaryBtnStyle(busy || address.trim().length < 14),
3460
- disabled: busy || address.trim().length < 14,
3461
- onClick: () => void findCoins(),
3462
- children: "find its coins"
3463
- }
3464
- ) : null,
3465
- coins && coins.length > 0 && !message ? /* @__PURE__ */ jsx(
3466
- "button",
3467
- {
3468
- type: "button",
3469
- style: primaryBtnStyle(busy || !chosen),
3470
- disabled: busy || !chosen,
3471
- onClick: () => void getMessage(),
3472
- children: "continue"
3473
- }
3474
- ) : null,
3475
- /* @__PURE__ */ jsx("button", { type: "button", style: ghostBtnStyle(busy), disabled: busy, onClick: onCancel, children: "cancel" })
3476
- ] })
3534
+ style: coinStyle(chosen === c.outpoint, young),
3535
+ children: [
3536
+ /* @__PURE__ */ jsx(
3537
+ "input",
3538
+ {
3539
+ type: "radio",
3540
+ name: "oc-bond-coin",
3541
+ value: c.outpoint,
3542
+ checked: chosen === c.outpoint,
3543
+ disabled: young,
3544
+ onChange: () => setChosen(c.outpoint),
3545
+ style: { accentColor: V.primary, margin: "2px 0 0" }
3546
+ }
3547
+ ),
3548
+ /* @__PURE__ */ jsxs("span", { style: { display: "grid", gap: 2, minWidth: 0 }, children: [
3549
+ /* @__PURE__ */ jsxs(
3550
+ "span",
3551
+ {
3552
+ style: {
3553
+ color: young ? V.muted : V.foreground,
3554
+ fontSize: 13
3555
+ },
3556
+ children: [
3557
+ n(c.sats),
3558
+ " sats, held",
3559
+ " ",
3560
+ Math.floor(c.age_blocks / 144),
3561
+ " days"
3562
+ ]
3563
+ }
3564
+ ),
3565
+ /* @__PURE__ */ jsx("span", { style: smallStyle, children: young ? "too recent: needs six confirmations" : `apps would see ${bondFloorsText(c)}` }),
3566
+ /* @__PURE__ */ jsx(
3567
+ "span",
3568
+ {
3569
+ style: {
3570
+ ...smallStyle,
3571
+ fontFamily: SIGNIN_FONT,
3572
+ wordBreak: "break-all"
3573
+ },
3574
+ children: short(c.outpoint)
3575
+ }
3576
+ )
3577
+ ] })
3578
+ ]
3579
+ },
3580
+ c.outpoint
3581
+ );
3582
+ })
3583
+ }
3584
+ ),
3585
+ dust > 0 ? /* @__PURE__ */ jsx("p", { style: { ...smallStyle, marginTop: 8 }, children: dustText(dust) }) : null
3586
+ ] }),
3587
+ error,
3588
+ /* @__PURE__ */ jsxs(FormButtons, { children: [
3589
+ eligible.length > 0 ? /* @__PURE__ */ jsx(
3590
+ "button",
3591
+ {
3592
+ type: "button",
3593
+ style: primaryBtnStyle(busy || !chosen),
3594
+ disabled: busy || !chosen,
3595
+ onClick: () => void getMessage(),
3596
+ children: "continue"
3597
+ }
3598
+ ) : null,
3599
+ backButton,
3600
+ cancelButton
3601
+ ] })
3602
+ ] });
3603
+ } else {
3604
+ step = /* @__PURE__ */ jsxs(
3605
+ "form",
3606
+ {
3607
+ style: { margin: 0 },
3608
+ onSubmit: (e) => {
3609
+ e.preventDefault();
3610
+ if (canFind && !busy) void findCoins();
3611
+ },
3612
+ children: [
3613
+ /* @__PURE__ */ jsx("label", { htmlFor: `${id}-address`, style: fieldLabelStyle, children: "bitcoin address that holds the coin" }),
3614
+ /* @__PURE__ */ jsx("p", { id: `${id}-advice`, style: { ...bodyStyle, margin: "0 0 8px" }, children: "use one that holds nothing else of yours: orangecheck learns its address and amount. apps never do." }),
3615
+ /* @__PURE__ */ jsx(
3616
+ "input",
3617
+ {
3618
+ id: `${id}-address`,
3619
+ "aria-describedby": `${id}-advice`,
3620
+ style: inputStyle,
3621
+ value: address,
3622
+ onChange: (e) => setAddress(e.target.value),
3623
+ placeholder: "bc1q\u2026",
3624
+ spellCheck: false,
3625
+ autoComplete: "off",
3626
+ autoCapitalize: "off"
3627
+ }
3628
+ ),
3629
+ error,
3630
+ /* @__PURE__ */ jsxs(FormButtons, { children: [
3631
+ /* @__PURE__ */ jsx(
3632
+ "button",
3633
+ {
3634
+ type: "submit",
3635
+ style: primaryBtnStyle(busy || !canFind),
3636
+ disabled: busy || !canFind,
3637
+ children: "find its coins"
3638
+ }
3639
+ ),
3640
+ cancelButton
3641
+ ] })
3642
+ ]
3643
+ }
3644
+ );
3645
+ }
3646
+ return /* @__PURE__ */ jsxs("div", { style: panelStyle("accent"), "data-oc-bond-form": "", children: [
3647
+ /* @__PURE__ */ jsx(SectionLabel, { children: "\xA7 back your account" }),
3648
+ step
3477
3649
  ] });
3478
3650
  }
3479
3651
  function resolveAuthOrigin(opts) {