|
| 1 | +# Public Contact Payments — Manual QA Charter |
| 2 | + |
| 3 | +Manual test plan for public Paykit payments to Pubky contacts. |
| 4 | + |
| 5 | +PR context: |
| 6 | + |
| 7 | +- Android: synonymdev/bitkit-android#924 |
| 8 | +- iOS: synonymdev/bitkit-ios#531 |
| 9 | + |
| 10 | +## Scope |
| 11 | + |
| 12 | +Verify that Bitkit can discover public payment endpoints from a Pubky profile/contact and route payments through the existing send flow. |
| 13 | + |
| 14 | +Covered surfaces: |
| 15 | + |
| 16 | +- Pay Contacts endpoint publishing. |
| 17 | +- Payment from saved contact and non-saved Pubky. |
| 18 | +- Payment via Add Contact, Contact Detail, QR scanner, paste/manual send flow. |
| 19 | +- On-chain, Lightning/Bolt11, and combined public payment requests. |
| 20 | +- Contact-tagged activity and contact activity screen. |
| 21 | +- On-chain boosts (RBF/CPFP) preserving expected activity behavior. |
| 22 | + |
| 23 | +## Preconditions |
| 24 | + |
| 25 | +Run on both Android and iOS where possible. |
| 26 | + |
| 27 | +Use staging/regtest builds unless explicitly testing mainnet. Mainnet Pubky profile creation may depend on current Pubky stack rollout status. |
| 28 | + |
| 29 | +Recommended accounts/devices: |
| 30 | + |
| 31 | +- **Wallet A / Sender**: funded wallet used to pay. |
| 32 | +- **Wallet B / Recipient**: wallet with Pubky profile and Pay Contacts enabled. |
| 33 | +- Optional **Wallet C / Non-contact recipient**: useful for testing payment to a Pubky that is not yet in Wallet A's contact list. |
| 34 | + |
| 35 | +Funding recommendations: |
| 36 | + |
| 37 | +- Sender has enough on-chain funds for on-chain sends and RBF/CPFP scenarios. |
| 38 | +- Sender has an active Lightning channel and spending balance for Bolt11/contact Lightning payments. |
| 39 | +- Recipient has completed Pubky profile creation. |
| 40 | + |
| 41 | +## Setup Checks |
| 42 | + |
| 43 | +### S1. Publish public endpoints |
| 44 | + |
| 45 | +1. On Wallet B, create or restore a Pubky profile. |
| 46 | +2. On first-time **Pay Contacts** screen, keep public payments enabled and continue. |
| 47 | +3. If settings expose the Pay Contacts toggle, turn it off and on again. |
| 48 | +4. Confirm no error toast appears. |
| 49 | +5. If available, verify public endpoints on `payky.app` or equivalent tooling. |
| 50 | + |
| 51 | +Expected: |
| 52 | + |
| 53 | +- With Pay Contacts enabled, Wallet B publishes public payment endpoints. |
| 54 | +- With Pay Contacts disabled, Wallet B does not publish endpoints or removes previously published endpoints. |
| 55 | +- Toggling the setting is resilient if Lightning is not immediately ready, as long as on-chain endpoint publishing is possible. |
| 56 | + |
| 57 | +### S2. Disabled recipient |
| 58 | + |
| 59 | +1. On another recipient wallet/profile, disable Pay Contacts. |
| 60 | +2. Try to pay that Pubky from Wallet A. |
| 61 | + |
| 62 | +Expected: |
| 63 | + |
| 64 | +- App does not offer a broken send flow. |
| 65 | +- User sees clear unavailable/no payment methods messaging. |
| 66 | + |
| 67 | +## Core Payment Matrix |
| 68 | + |
| 69 | +Run the following combinations at minimum once on Android and once on iOS. |
| 70 | + |
| 71 | +| Case | Contact state | Entry point | Payment method | Expected | |
| 72 | +| --- | --- | --- | --- | --- | |
| 73 | +| P1 | Saved contact | Contact Detail → Send | On-chain | Payment succeeds; activity is tagged to contact. | |
| 74 | +| P2 | Saved contact | Contact Detail → Send | Bolt11/Lightning | Payment succeeds; activity is tagged to contact. | |
| 75 | +| P3 | Saved contact | Contact Detail → Send | Combined/BIP21 | App chooses valid route or lets user choose; activity is tagged to contact. | |
| 76 | +| P4 | Not in contacts | Add Contact flow | On-chain | User can pay public endpoint if supported by product; contact creation state stays correct. | |
| 77 | +| P5 | Not in contacts | Add Contact flow | Bolt11/Lightning | User can pay public endpoint if supported; no contact is silently created unless explicitly saved. | |
| 78 | +| P6 | Not in contacts | QR scanner with Pubky | Any available | Routes to Add Contact / Contact Detail as appropriate, then payment succeeds. | |
| 79 | +| P7 | Not in contacts | Send → manual/paste Pubky | Any available | Routes to Pubky/contact payment flow, not invalid-address error. | |
| 80 | +| P8 | Existing contact | Send → manual/paste Pubky | Any available | Routes to existing contact rather than Add Contact. | |
| 81 | + |
| 82 | +For each successful payment, verify: |
| 83 | + |
| 84 | +- Review screen shows contact name/pubky context. |
| 85 | +- Amount and asset selection are correct. |
| 86 | +- Swipe/confirm sends successfully. |
| 87 | +- Main activity shows a sent payment with the expected amount. |
| 88 | +- Contact activity screen shows the sent payment under the contact. |
| 89 | +- Contact context is not leaked to the next unrelated payment. |
| 90 | + |
| 91 | +## Detailed Test Cases |
| 92 | + |
| 93 | +### T1. Saved contact, on-chain payment |
| 94 | + |
| 95 | +1. Wallet A adds Wallet B as a contact. |
| 96 | +2. Open Wallet B contact detail. |
| 97 | +3. Tap Send/Pay. |
| 98 | +4. Choose or confirm on-chain route. |
| 99 | +5. Enter a small amount. |
| 100 | +6. Send. |
| 101 | +7. Mine/confirm if needed. |
| 102 | + |
| 103 | +Expected: |
| 104 | + |
| 105 | +- Payment succeeds. |
| 106 | +- Wallet A main activity shows `Sent to {contact name}` or equivalent contact title where supported. |
| 107 | +- Contact Activity for Wallet B includes the sent on-chain payment. |
| 108 | +- Wallet B receives the on-chain payment. |
| 109 | + |
| 110 | +### T2. Saved contact, Lightning payment |
| 111 | + |
| 112 | +1. Ensure Wallet A has spending balance and Wallet B has public Lightning endpoint. |
| 113 | +2. Open Wallet B contact detail. |
| 114 | +3. Tap Send/Pay. |
| 115 | +4. Choose or confirm Lightning route. |
| 116 | +5. Send a small amount. |
| 117 | + |
| 118 | +Expected: |
| 119 | + |
| 120 | +- Payment succeeds. |
| 121 | +- Activity is tagged to Wallet B. |
| 122 | +- If payment goes pending, pending screen and later success/failure keep the correct contact context. |
| 123 | +- Retrying or sending a later unrelated payment does not reuse stale Wallet B contact context. |
| 124 | + |
| 125 | +### T3. Saved contact, combined public request |
| 126 | + |
| 127 | +1. Use a recipient with both on-chain and Lightning endpoints available. |
| 128 | +2. Start payment from contact detail. |
| 129 | +3. Check default method and asset switch behavior. |
| 130 | +4. Send via default route. |
| 131 | +5. Repeat and switch to the other available route if UI allows. |
| 132 | + |
| 133 | +Expected: |
| 134 | + |
| 135 | +- Route priority matches product expectations. |
| 136 | +- Asset switching does not lose contact context. |
| 137 | +- Activity is tagged correctly for both routes. |
| 138 | + |
| 139 | +### T4. Add Contact screen, Pubky not saved |
| 140 | + |
| 141 | +1. On Wallet A, open Contacts → Add Contact. |
| 142 | +2. Enter/paste Wallet C pubky. |
| 143 | +3. Let the profile/payment details load. |
| 144 | +4. If the Send/Pay button is present by design, tap it. |
| 145 | +5. Complete on-chain and Lightning payment variants where endpoints exist. |
| 146 | +6. Return to Contacts. |
| 147 | + |
| 148 | +Expected: |
| 149 | + |
| 150 | +- Payment can be made to public endpoints if product accepts paying non-contacts. |
| 151 | +- User is not forced to save contact unless required by design. |
| 152 | +- If contact is not saved, Contacts list remains unchanged after payment. |
| 153 | +- Add Contact copy matches design, especially wording around public vs private payments. |
| 154 | + |
| 155 | +### T5. QR scanner Pubky route |
| 156 | + |
| 157 | +1. Display or generate Wallet B Pubky QR. |
| 158 | +2. On Wallet A, open scanner from Send or global scan. |
| 159 | +3. Scan Wallet B pubky. |
| 160 | + |
| 161 | +Expected: |
| 162 | + |
| 163 | +- If Wallet B is saved, app opens Wallet B contact detail. |
| 164 | +- If Wallet B is not saved, app opens Add Contact / payment-capable Pubky flow. |
| 165 | +- Payment from the routed screen succeeds and is tagged only when a contact relationship exists or when product intentionally tags public Pubky payments. |
| 166 | + |
| 167 | +### T6. Send flow manual/paste Pubky route |
| 168 | + |
| 169 | +1. On Wallet A, open Send. |
| 170 | +2. Choose manual recipient entry. |
| 171 | +3. Paste Wallet B pubky. |
| 172 | +4. Continue. |
| 173 | + |
| 174 | +Expected: |
| 175 | + |
| 176 | +- Saved contact routes to Contact Detail/payment flow. |
| 177 | +- Non-saved pubky routes to Add Contact/payment flow. |
| 178 | +- Own pubky routes to own profile or shows self-add/self-pay guard, according to product decision. |
| 179 | +- Invalid pubky remains blocked with clear validation. |
| 180 | + |
| 181 | +### T7. Recipient without public endpoints |
| 182 | + |
| 183 | +1. Use a Pubky profile with Pay Contacts disabled or no endpoints. |
| 184 | +2. Try payment from Contact Detail, Add Contact, QR scanner, and Send/manual. |
| 185 | + |
| 186 | +Expected: |
| 187 | + |
| 188 | +- No crash or stuck loading. |
| 189 | +- Clear message that payment methods are unavailable. |
| 190 | +- Contact can still be added/viewed if profile exists. |
| 191 | + |
| 192 | +### T8. Endpoint lifecycle |
| 193 | + |
| 194 | +1. Wallet B enables Pay Contacts. |
| 195 | +2. Wallet A confirms payment methods are available for Wallet B. |
| 196 | +3. Wallet B disables Pay Contacts. |
| 197 | +4. Wallet A refreshes contact/profile or restarts app. |
| 198 | +5. Try payment again. |
| 199 | + |
| 200 | +Expected: |
| 201 | + |
| 202 | +- Disabled endpoints stop being offered after refresh/reload. |
| 203 | +- Re-enabling endpoints makes payment available again. |
| 204 | +- No stale invoice/address is used after disable. |
| 205 | + |
| 206 | +### T9. Existing wallet upgrade path |
| 207 | + |
| 208 | +1. Use an existing wallet/profile created before public Paykit endpoints existed. |
| 209 | +2. Enable Pay Contacts. |
| 210 | +3. Try receiving public contact payments. |
| 211 | +4. Add Lightning channel after profile already exists. |
| 212 | +5. Refresh/restart. |
| 213 | +6. Try Lightning contact payment. |
| 214 | + |
| 215 | +Expected: |
| 216 | + |
| 217 | +- Existing profile can publish endpoints after upgrade. |
| 218 | +- On-chain works before Lightning is ready. |
| 219 | +- Lightning endpoint appears after channel/spending balance is available. |
| 220 | + |
| 221 | +## Activity Checks |
| 222 | + |
| 223 | +For each successful payment type: |
| 224 | + |
| 225 | +1. Check Home activity row. |
| 226 | +2. Open full Activity list. |
| 227 | +3. Open Contact Activity from contact detail. |
| 228 | +4. Open payment detail. |
| 229 | + |
| 230 | +Expected: |
| 231 | + |
| 232 | +- Sent public contact payments show contact-aware title where supported. |
| 233 | +- Contact Activity contains the matching sent payment. |
| 234 | +- Received public payments may not show `Received from {name}` if sender identity is not known for public payments; confirm copy/product expectation. |
| 235 | +- Replaced/boosted transactions do not appear as duplicate stale entries in Contact Activity. |
| 236 | +- Pending → success, pending → failure, and retry flows keep or clear contact context correctly. |
| 237 | + |
| 238 | +## Boost / Replacement Checks |
| 239 | + |
| 240 | +### B1. RBF on contact on-chain send |
| 241 | + |
| 242 | +1. Create a low-fee on-chain payment to a contact. |
| 243 | +2. Before confirmation, open activity details. |
| 244 | +3. Use RBF boost. |
| 245 | +4. Confirm boosted transaction. |
| 246 | + |
| 247 | +Expected: |
| 248 | + |
| 249 | +- Boost succeeds. |
| 250 | +- Main Activity shows boosted/replaced state correctly. |
| 251 | +- Contact Activity shows the final/relevant payment only. |
| 252 | +- Contact context remains attached after replacement. |
| 253 | + |
| 254 | +### B2. CPFP involving contact payment |
| 255 | + |
| 256 | +1. Create an unconfirmed incoming or outgoing transaction that allows CPFP. |
| 257 | +2. Use CPFP boost from activity details. |
| 258 | +3. Confirm boosted transaction. |
| 259 | + |
| 260 | +Expected: |
| 261 | + |
| 262 | +- Boost succeeds. |
| 263 | +- Contact-related activity does not duplicate or lose context. |
| 264 | +- Parent/child transaction details remain understandable. |
| 265 | + |
| 266 | +### B3. Failed/pending contact payment context |
| 267 | + |
| 268 | +1. Start a contact payment likely to go pending or fail. |
| 269 | +2. Without closing the send sheet, retry or start a different payment to a normal address/invoice. |
| 270 | + |
| 271 | +Expected: |
| 272 | + |
| 273 | +- Stale contact context is cleared or moved correctly. |
| 274 | +- The unrelated payment is not tagged to the previous contact. |
| 275 | + |
| 276 | +## Negative / Edge Cases |
| 277 | + |
| 278 | +- Recipient pubky has malformed endpoint document. |
| 279 | +- Endpoint document has only on-chain endpoint. |
| 280 | +- Endpoint document has only Lightning endpoint. |
| 281 | +- Lightning invoice generation fails. |
| 282 | +- On-chain address is unavailable. |
| 283 | +- Endpoint fetch times out or is offline. |
| 284 | +- Wallet has no on-chain balance. |
| 285 | +- Wallet has no spending balance. |
| 286 | +- User disables Pay Contacts while another wallet has the contact detail screen open. |
| 287 | +- Contact is deleted after a payment; historical activity remains readable. |
| 288 | +- Contact is renamed locally after payment; activity title uses the expected current or historical name per product decision. |
| 289 | +- Wallet reset/sign-out removes published endpoints best-effort and never blocks local wipe. |
| 290 | + |
| 291 | +## Suggested Future E2E Coverage |
| 292 | + |
| 293 | +Start small and keep these behind a Pubky/contact-payments tag until stable. |
| 294 | + |
| 295 | +1. **Public contact on-chain payment happy path** |
| 296 | + - Wallet A funded, Wallet B profile with Pay Contacts enabled. |
| 297 | + - Add Wallet B as contact. |
| 298 | + - Pay Wallet B on-chain from Contact Detail. |
| 299 | + - Verify send success and contact activity row. |
| 300 | + |
| 301 | +2. **Public contact Lightning payment happy path** |
| 302 | + - Same setup, with Wallet A spending balance. |
| 303 | + - Pay Wallet B via Lightning from Contact Detail. |
| 304 | + - Verify send success and contact activity row. |
| 305 | + |
| 306 | +3. **Pubky routing from Send/manual** |
| 307 | + - Paste saved contact pubky → opens existing contact payment route. |
| 308 | + - Paste unknown pubky → opens Add Contact/payment route. |
| 309 | + - Invalid/self pubky remains blocked. |
| 310 | + |
| 311 | +4. **Endpoint disabled** |
| 312 | + - Recipient disables Pay Contacts. |
| 313 | + - Sender refreshes and sees payment unavailable. |
| 314 | + |
| 315 | +5. **RBF contact payment** |
| 316 | + - Create on-chain contact payment. |
| 317 | + - Boost with RBF. |
| 318 | + - Verify final activity state and contact activity do not show stale duplicate replacement rows. |
| 319 | + |
| 320 | +6. **Contact context isolation** |
| 321 | + - Start contact payment, force pending/failure if possible. |
| 322 | + - Send unrelated payment. |
| 323 | + - Verify unrelated activity is not tagged to the contact. |
| 324 | + |
| 325 | +## Notes / Known Product Questions |
| 326 | + |
| 327 | +- Public contact payments are not private payments. If copy says both users must add each other to pay privately, verify whether public-payment behavior needs separate copy. |
| 328 | +- If Send/Pay is shown on Add Contact before saving, confirm design/product acceptance. |
| 329 | +- For public incoming payments, sender identity may not be knowable; do not expect `Received from {name}` unless private payment metadata exists. |
| 330 | +- Mainnet demo testing should wait until mainnet Pubky profile creation and Paykit endpoint publishing are available and stable. |
0 commit comments