diff --git a/crates/ghostkey-server/src/scheduler.rs b/crates/ghostkey-server/src/scheduler.rs index dbe6468..c1482c0 100644 --- a/crates/ghostkey-server/src/scheduler.rs +++ b/crates/ghostkey-server/src/scheduler.rs @@ -435,25 +435,28 @@ async fn enqueue_alarm_escalation( let amount_sat = crate::lightning::heartbeat_amount_sat(); let one_tap_block = match mint_or_reuse_one_tap_token(state, vault_id, now_iso).await? { Some(token) => format!( - "Tap this link and pay the tiny {amount_sat}-sat Lightning \ - invoice to check in:\n\n\ + "Tap this link and pay {amount_sat} sats from any Lightning \ + wallet to check in:\n\n\ {base}/#/checkin-link/{vault_id}/{token}\n\n" ), None => String::new(), }; + // "1 days" reads like a robot wrote it, at the exact moment the + // email most needs to be taken seriously. + let days_word = if days_left == 1 { "day" } else { "days" }; let (subject, lead) = match count_so_far { 0 => ( - format!("You missed a check-in. {days_left} days until your heir is notified"), + format!("You missed a check-in. {days_left} {days_word} until your heir is notified"), "This is the first daily reminder.".to_string(), ), n if n < 7 => ( - format!("{days_left} days left to check in before your heir is contacted"), + format!("{days_left} {days_word} left to check in before your heir is contacted"), format!("You've now missed {} daily reminders.", n + 1), ), _ => ( format!( - "Last few days: {days_left} days until your heir is notified about {display_label}" + "Last few days: {days_left} {days_word} until your heir is notified about {display_label}" ), "This is one of the final reminders.".to_string(), ), @@ -465,7 +468,7 @@ async fn enqueue_alarm_escalation( {one_tap_block}\ You can also open the dashboard on any device:\n\n\ {base}/#/checkin\n\n\ - If we don't hear from you within {days_left} day(s), your heir \ + If we don't hear from you within {days_left} {days_word}, your heir \ will receive a claim link for this vault. You can stop that \ instantly by checking in.\n\n\ From GhostKey\n" @@ -756,17 +759,16 @@ async fn enqueue_pre_deadline_reminder( "Hello,\n\n\ A quick reminder that {display_label} needs a check-in by \ {deadline_friendly}. That's about 24 hours from now.\n\n\ - Tap this link and pay the tiny {amount_sat}-sat Lightning \ - invoice. The payment is your proof you're still here, and it \ + Tap this link and pay {amount_sat} sats from any Lightning \ + wallet. The payment is your proof you're still here, and it \ resets the countdown.\n\n\ {one_tap_url}\n\n\ - You can pay from any Lightning wallet. If you'd rather not from \ - this email, open the dashboard on any device and check in \ - there:\n\n\ + If you'd rather not pay from this email, open the dashboard \ + on any device and check in there:\n\n\ {base}/#/checkin\n\n\ - If we don't hear from you by the deadline, you'll get one more \ - email, and then your heir will be contacted after the \ - grace period.\n\n\ + If we don't hear from you by the deadline, we'll keep \ + reminding you every day through the grace period. Only after \ + that would your heir be contacted.\n\n\ If this email reached you by mistake, you can ignore it.\n\n\ From GhostKey\n" ); @@ -789,7 +791,7 @@ async fn enqueue_pre_deadline_reminder( "title": title, "body": format!( "{display_label} needs a check-in by {deadline_friendly}. \ - Pay a tiny {amount_sat}-sat Lightning invoice to check in." + Pay {amount_sat} sats from any Lightning wallet to check in." ), "url": one_tap_url, }) @@ -1092,8 +1094,8 @@ async fn enqueue_alarm_owner( let amount_sat = crate::lightning::heartbeat_amount_sat(); let one_tap_block = match &one_tap_url { Some(url) => format!( - "Tap this link and pay the tiny {amount_sat}-sat Lightning \ - invoice to check in. The payment is your proof you're still \ + "Tap this link and pay {amount_sat} sats from any Lightning \ + wallet to check in. The payment is your proof you're still \ here and resets the clock.\n\n\ {url}\n\n" ), diff --git a/ghostkey-web/src/CheckinPortal.tsx b/ghostkey-web/src/CheckinPortal.tsx index f2e6d9f..023c23e 100644 --- a/ghostkey-web/src/CheckinPortal.tsx +++ b/ghostkey-web/src/CheckinPortal.tsx @@ -198,20 +198,19 @@ export function CheckinPortal({ initialId }: { initialId?: string }) { {state.kind === "no-credentials" && (
Open any Bitcoin wallet and tap Receive. A
- Lightning wallet works too. Apps like Wallet of Satoshi, Bitnob,
- Cash App, or Phoenix each give you a Bitcoin address that adds the
- money to your balance. Copy the long address that starts with{" "}
+ Lightning wallet works too. Apps like Blink, Bitnob, or Wallet of
+ Satoshi each give you a Bitcoin address that adds the money to
+ your balance. Copy the long address that starts with{" "}
{bech32PrefixFor(sealed.network)}{" "}
and paste it below.
Paste any Bitcoin address you control on the {networkLabel(params.network)}.{" "} - A Lightning wallet works too. Apps like Wallet of Satoshi, Bitnob, - Cash App, or Phoenix each give you a Bitcoin address that adds the - money to your balance. {walletExamplesInline(params.network)}. + A Lightning wallet works too. Apps like Blink, Bitnob, or Wallet of + Satoshi each give you a Bitcoin address that adds the money to your + balance. {walletExamplesInline(params.network)}.
✓ - Verified. Recorded by the owner of this vault, and untampered. + Verified. Recorded by the owner of this vault, and it hasn't been + changed since.
) : (Minting invoice…
+Getting your check-in ready…
)} {state.kind === "error" && ( diff --git a/ghostkey-web/src/RecoveryGuide.tsx b/ghostkey-web/src/RecoveryGuide.tsx index 64c5f43..b50cc89 100644 --- a/ghostkey-web/src/RecoveryGuide.tsx +++ b/ghostkey-web/src/RecoveryGuide.tsx @@ -50,9 +50,10 @@ export function RecoveryGuide({ onNavigate }: Props) {Your heir can still claim. The rules that release your Bitcoin live on the Bitcoin network, not on our servers. At setup you - download one recovery file that holds everything needed to claim - without us. Keep it with your important papers and tell your heir - where it is. + save two files: your own spare key, and a file made for your + heir with its own short unlock code. Keep the heir's file and + its code together with your important papers, and tell your + heir where they are.
- At setup you download a single file, named something like{" "}
+ Your spare key is a file named something like{" "}
ghostkey-recovery-yourvault.html
- . It contains the vault's rules and your own encrypted key. It
- does not need GhostKey, an account, or an internet connection to
- do its job.
+ . It opens with the same password you sign in with, and it's for
+ you: if you ever lose access to GhostKey, it reaches your money.
+ Your heir cannot open this one, and that's on purpose. You never
+ have to write your password down.
- Treat it like a key to a safe. Store a copy somewhere safe and
- lasting, and make sure the people who would need it know where to
- find it. If you ever misplace it, you can sign in and download a
- fresh copy from the{" "}
+ Your heir's file is named something like{" "}
+
+ ghostkey-for-ada.html
+
+ . It opens with a short code of five simple words, shown to you
+ once at setup. Keep the file and its code together, somewhere
+ your heir will look when the time comes: with your will, your
+ important papers, or someone you both trust. Keeping the code
+ beside the file is safe, because Bitcoin's own timer keeps the
+ file powerless while you're alive and checking in.
+
+ Neither file needs GhostKey, an account, or an internet + connection to do its job. If you misplace your own spare key, + sign in and download a fresh copy from the{" "}