@lukso/transaction-view-headless 0.4.3-dev.661418d → 0.4.3-dev.a07a66f

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.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +31 -29
  2. package/ARG_ACCESS_PATTERN.md +265 -0
  3. package/CONTEXT_VARIANT_GUIDE.md +4 -4
  4. package/EVENT_SYSTEM_SUMMARY.md +601 -0
  5. package/HEADER_EVENTS_GUIDE.md +291 -0
  6. package/RECOMPOSITION_REFERENCE.md +303 -0
  7. package/TRANSACTION_MODIFICATION_GUIDE.md +927 -0
  8. package/dist/composables/index.cjs +1 -1
  9. package/dist/composables/index.cjs.map +1 -1
  10. package/dist/composables/index.d.cts +3 -3
  11. package/dist/composables/index.d.ts +3 -3
  12. package/dist/composables/index.js +1 -1
  13. package/dist/composables/index.js.map +1 -1
  14. package/dist/{index-CSDjhiKV.d.cts → index-BqL7xdDl.d.cts} +2 -2
  15. package/dist/{index-CMLU1hKL.d.ts → index-CNUHqRdk.d.ts} +2 -2
  16. package/dist/index.cjs +60 -1
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +5 -4
  19. package/dist/index.d.ts +5 -4
  20. package/dist/index.js +55 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/registry/index.d.cts +2 -2
  23. package/dist/registry/index.d.ts +2 -2
  24. package/dist/types/index.cjs +68 -0
  25. package/dist/types/index.cjs.map +1 -1
  26. package/dist/types/index.d.cts +229 -169
  27. package/dist/types/index.d.ts +229 -169
  28. package/dist/types/index.js +55 -0
  29. package/dist/types/index.js.map +1 -1
  30. package/dist/utils/index.d.cts +1 -1
  31. package/dist/utils/index.d.ts +1 -1
  32. package/dist/{view-loader-dD86QAlQ.d.cts → view-loader--mEEI8YY.d.ts} +1 -1
  33. package/dist/{view-loader-ii8AxiQR.d.ts → view-loader-D7ApWfdN.d.cts} +1 -1
  34. package/dist/view-matching-C9G3z8lQ.d.cts +203 -0
  35. package/dist/view-matching-C9G3z8lQ.d.ts +203 -0
  36. package/package.json +3 -3
  37. package/src/composables/use-transaction-playback.ts +8 -5
  38. package/src/types/index.ts +14 -0
  39. package/src/types/view-events.ts +322 -0
@@ -0,0 +1,601 @@
1
+ # Transaction View Event System - Complete Summary
2
+
3
+ This document provides a comprehensive overview of the event-based communication system for transaction views.
4
+
5
+ ## Overview
6
+
7
+ Transaction views use a custom event system to communicate with their parent containers. This enables:
8
+
9
+ 1. **Header Information** - Views tell parents what addresses to display
10
+ 2. **Transaction Modifications** - Views modify transaction parameters (e.g., force transfers, slippage)
11
+ 3. **Context-Aware Rendering** - Views adapt UI based on WHERE they're displayed
12
+
13
+ ## Architecture
14
+
15
+ ```
16
+ ┌──────────────────────────────────────────────────────────┐
17
+ │ View Component │
18
+ │ (e.g., LSP7TransferView, SwapView, SetDataView) │
19
+ │ │
20
+ │ Emits: │
21
+ │ - header-info (visual: from/to/title) │
22
+ │ - transaction-modification (data changes) │
23
+ └────────────────────┬─────────────────────────────────────┘
24
+ │ bubbles: true, composed: true
25
+
26
+ ┌──────────────────────────────────────────────────────────┐
27
+ │ <transaction-playback index="1"> │
28
+ │ │
29
+ │ - Receives events from child view │
30
+ │ - Validates (index match, re-decode) │
31
+ │ - Adds context (transaction path) │
32
+ │ - Re-emits for parent │
33
+ └────────────────────┬─────────────────────────────────────┘
34
+ │ bubbles: true, composed: true
35
+
36
+ ┌──────────────────────────────────────────────────────────┐
37
+ │ Top-Level Container │
38
+ │ (Wallet, App, Approval Screen) │
39
+ │ │
40
+ │ - Updates header display (from/to) │
41
+ │ - Applies transaction modifications │
42
+ │ - Re-wraps modified data (Execute/Batch) │
43
+ │ - Re-decodes and updates UI │
44
+ │ - Shows modification summary to user │
45
+ └──────────────────────────────────────────────────────────┘
46
+ ```
47
+
48
+ ## Event Types
49
+
50
+ ### 1. Header Info Event
51
+
52
+ **Purpose:** Tell parent containers what addresses/title to display in the header.
53
+
54
+ **Event Name:** `header-info`
55
+
56
+ **Use Case:**
57
+ - Transfer view shows transfer's from/to (not Execute's from/to)
58
+ - Swap view shows token pair info
59
+ - SetData view shows profile being modified
60
+
61
+ **Type:**
62
+ ```typescript
63
+ interface TransactionHeaderInfo {
64
+ from?: string // Override "from" address
65
+ to?: string // Override "to" address
66
+ title?: string // Transaction title
67
+ subtitle?: string // Additional description
68
+ icon?: string // Icon identifier
69
+ metadata?: Record<string, any> // Custom data
70
+ }
71
+ ```
72
+
73
+ **Usage:**
74
+ ```typescript
75
+ import { dispatchHeaderInfo, getArgByName } from '@lukso/transaction-view-headless'
76
+
77
+ connectedCallback() {
78
+ super.connectedCallback()
79
+
80
+ dispatchHeaderInfo(this, {
81
+ from: getArgByName(this.transaction.args, 'from') as string,
82
+ to: getArgByName(this.transaction.args, 'to') as string,
83
+ title: 'LSP7 Token Transfer'
84
+ })
85
+ }
86
+ ```
87
+
88
+ **Documentation:** [HEADER_EVENTS_GUIDE.md](./HEADER_EVENTS_GUIDE.md)
89
+
90
+ ---
91
+
92
+ ### 2. Transaction Modification Event
93
+
94
+ **Purpose:** Modify transaction data before submission (e.g., enable force transfer, adjust slippage).
95
+
96
+ **Event Name:** `transaction-modification`
97
+
98
+ **Use Case:**
99
+ - Force transfer checkbox (modify `force` arg)
100
+ - Slippage tolerance slider (modify `minOutput` arg)
101
+ - Gas limit adjustment
102
+ - Allowance amount changes
103
+
104
+ **Type:**
105
+ ```typescript
106
+ interface TransactionModification {
107
+ data: `0x${string}` // Modified LOCAL transaction data
108
+ transactionIndex: number // Playback index (matches <transaction-playback index>)
109
+ reason: string // Human-readable explanation
110
+ userInitiated: boolean // User action vs automatic
111
+ summary?: { // Optional quick summary
112
+ field: string
113
+ oldValue: string
114
+ newValue: string
115
+ }
116
+ validation?: { // Optional validation
117
+ isValid: boolean
118
+ error?: string
119
+ warnings?: string[]
120
+ }
121
+ }
122
+ ```
123
+
124
+ **Extended Type (after transaction-playback adds context):**
125
+ ```typescript
126
+ interface TransactionModificationWithContext extends TransactionModification {
127
+ transactionPath: number[] // Path from root: [0, 2] = batch[0].children[2]
128
+ localTransaction: DecoderResult
129
+ decodedResult: DecoderResult // Re-decoded for verification
130
+ }
131
+ ```
132
+
133
+ **Usage:**
134
+ ```typescript
135
+ import { dispatchTransactionModification } from '@lukso/transaction-view-headless'
136
+ import { encodeFunctionData } from 'viem'
137
+
138
+ private handleForceCheckbox(checked: boolean) {
139
+ const newData = encodeFunctionData({
140
+ abi: LSP7_ABI,
141
+ functionName: 'transfer',
142
+ args: [from, to, amount, checked, data] // force = checked
143
+ })
144
+
145
+ dispatchTransactionModification(this, {
146
+ data: newData,
147
+ transactionIndex: this.index,
148
+ reason: 'User enabled force transfer to EOA',
149
+ userInitiated: true,
150
+ summary: {
151
+ field: 'force',
152
+ oldValue: 'false',
153
+ newValue: 'true'
154
+ }
155
+ })
156
+ }
157
+ ```
158
+
159
+ **Documentation:** [TRANSACTION_MODIFICATION_GUIDE.md](./TRANSACTION_MODIFICATION_GUIDE.md)
160
+
161
+ ---
162
+
163
+ ## Props Passed to Views
164
+
165
+ Views receive these props from `<transaction-playback>`:
166
+
167
+ ```typescript
168
+ interface ViewProps {
169
+ transaction: DecoderResult // Required: Full decoded transaction
170
+ context?: ViewContext // Optional: WHERE displayed (approval, feed, detail, etc.)
171
+ variant?: ViewVariant // Optional: HOW to render (implementation-specific)
172
+ }
173
+ ```
174
+
175
+ **Context Values:**
176
+ - `approval` - Transaction approval flow (security-focused, interactive)
177
+ - `feed` - Activity feed (compact, read-only)
178
+ - `list` - Transaction lists (scannable)
179
+ - `detail` - Full transaction detail (comprehensive)
180
+ - `review` - Pre-submission review
181
+ - `notification` - Push notifications (minimal)
182
+ - `embed` - Embedded in other interfaces
183
+ - `batch-summary` - Inside a batch summary
184
+
185
+ **Context-Aware Rendering Example:**
186
+ ```typescript
187
+ render() {
188
+ if (this.context === 'approval') {
189
+ // Show interactive checkbox
190
+ return html`
191
+ <label>
192
+ <input type="checkbox" @change=${this.handleForceChange} />
193
+ Force transfer
194
+ </label>
195
+ `
196
+ } else if (this.context === 'feed') {
197
+ // Show read-only status
198
+ return html`
199
+ ${this.force ? html`<div>⚠️ Forced transfer</div>` : ''}
200
+ `
201
+ } else {
202
+ // Detail view - full info
203
+ return html`<div>Force: ${this.force ? 'Yes' : 'No'}</div>`
204
+ }
205
+ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Helper Functions
211
+
212
+ ### Header Events
213
+
214
+ ```typescript
215
+ // Dispatch header info
216
+ dispatchHeaderInfo(element: HTMLElement, info: TransactionHeaderInfo): void
217
+
218
+ // Type guard
219
+ isHeaderInfoEvent(event: Event): event is HeaderInfoEvent
220
+ ```
221
+
222
+ ### Transaction Modifications
223
+
224
+ ```typescript
225
+ // Dispatch modification
226
+ dispatchTransactionModification(element: HTMLElement, mod: TransactionModification): void
227
+
228
+ // Type guard
229
+ isTransactionModificationEvent(event: Event): event is TransactionModificationEvent
230
+ ```
231
+
232
+ ### Event Constants
233
+
234
+ ```typescript
235
+ import { TransactionViewEvents } from '@lukso/transaction-view-headless'
236
+
237
+ TransactionViewEvents.HEADER_INFO // 'header-info'
238
+ TransactionViewEvents.TRANSACTION_MODIFICATION // 'transaction-modification'
239
+ TransactionViewEvents.STATE_CHANGE // 'view-state-change' (future)
240
+ TransactionViewEvents.ACTION // 'view-action' (future)
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Complete Example: Force Transfer
246
+
247
+ ### 1. View Component
248
+
249
+ ```typescript
250
+ import { dispatchHeaderInfo, dispatchTransactionModification, getArgByName } from '@lukso/transaction-view-headless'
251
+ import { encodeFunctionData } from 'viem'
252
+
253
+ @customElement('lsp7-transfer-view')
254
+ export class LSP7TransferView extends CoreLitElement {
255
+ @property({ type: Object }) transaction!: DecoderResult
256
+ @property({ type: String }) context?: ViewContext
257
+ @property({ type: Number }) index!: number
258
+
259
+ @state()
260
+ private force = false
261
+
262
+ connectedCallback() {
263
+ super.connectedCallback()
264
+
265
+ // Emit header info
266
+ dispatchHeaderInfo(this, {
267
+ from: getArgByName(this.transaction.args, 'from') as string,
268
+ to: getArgByName(this.transaction.args, 'to') as string,
269
+ title: 'LSP7 Transfer'
270
+ })
271
+
272
+ // Initialize force from transaction
273
+ this.force = (getArgByName(this.transaction.args, 'force') as boolean) ?? false
274
+ }
275
+
276
+ private handleForceChange(checked: boolean) {
277
+ this.force = checked
278
+
279
+ // Re-encode with new force value
280
+ const newData = encodeFunctionData({
281
+ abi: LSP7_ABI,
282
+ functionName: 'transfer',
283
+ args: [
284
+ getArgByName(this.transaction.args, 'from'),
285
+ getArgByName(this.transaction.args, 'to'),
286
+ getArgByName(this.transaction.args, 'amount'),
287
+ checked,
288
+ getArgByName(this.transaction.args, 'data')
289
+ ]
290
+ })
291
+
292
+ // Emit modification
293
+ dispatchTransactionModification(this, {
294
+ data: newData,
295
+ transactionIndex: this.index,
296
+ reason: checked
297
+ ? 'User enabled force transfer to EOA'
298
+ : 'User disabled force transfer',
299
+ userInitiated: true,
300
+ summary: {
301
+ field: 'force',
302
+ oldValue: String(!checked),
303
+ newValue: String(checked)
304
+ }
305
+ })
306
+ }
307
+
308
+ render() {
309
+ // Context-aware rendering
310
+ if (this.context === 'approval') {
311
+ return html`
312
+ <div>
313
+ <h3>Transfer ${this.formatAmount()} tokens</h3>
314
+ <label>
315
+ <input
316
+ type="checkbox"
317
+ .checked=${this.force}
318
+ @change=${(e) => this.handleForceChange(e.target.checked)}
319
+ />
320
+ Force transfer (required for EOA recipients)
321
+ </label>
322
+ </div>
323
+ `
324
+ } else {
325
+ return html`
326
+ <div>
327
+ Transfer ${this.formatAmount()} tokens
328
+ ${this.force ? html`<span>⚠️ Forced</span>` : ''}
329
+ </div>
330
+ `
331
+ }
332
+ }
333
+ }
334
+ ```
335
+
336
+ ### 2. Transaction Playback (handles automatically)
337
+
338
+ ```typescript
339
+ // Already implemented in transaction-playback.ts
340
+ // - Listens for header-info and transaction-modification events
341
+ // - Validates modifications
342
+ // - Re-decodes modified data
343
+ // - Adds transaction path context
344
+ // - Re-emits for top-level container
345
+ ```
346
+
347
+ ### 3. Top-Level Container
348
+
349
+ ```typescript
350
+ class ApprovalScreen extends LitElement {
351
+ @state() originalTx: DecoderResult
352
+ @state() modifiedTx?: DecoderResult
353
+ @state() modifications: TransactionModificationWithContext[] = []
354
+ @state() headerInfo?: TransactionHeaderInfo
355
+
356
+ render() {
357
+ return html`
358
+ <div class="approval">
359
+ <!-- Header with from/to from header-info event -->
360
+ <div class="header">
361
+ <h2>${this.headerInfo?.title ?? 'Transaction'}</h2>
362
+ <div>From: ${this.headerInfo?.from ?? this.originalTx.from}</div>
363
+ <div>To: ${this.headerInfo?.to ?? this.originalTx.to}</div>
364
+ </div>
365
+
366
+ <!-- Show modifications -->
367
+ ${this.modifications.length > 0 ? html`
368
+ <div class="modifications">
369
+ <h3>User Modifications:</h3>
370
+ ${this.modifications.map(mod => html`
371
+ <div>
372
+ ${mod.reason}
373
+ ${mod.summary ? html`
374
+ <span>(${mod.summary.field}: ${mod.summary.oldValue} → ${mod.summary.newValue})</span>
375
+ ` : ''}
376
+ </div>
377
+ `)}
378
+ </div>
379
+ ` : ''}
380
+
381
+ <!-- Transaction view -->
382
+ <transaction-playback
383
+ .transaction=${this.modifiedTx ?? this.originalTx}
384
+ index="1"
385
+ context="approval"
386
+ @header-info=${this.handleHeaderInfo}
387
+ @transaction-modification=${this.handleModification}
388
+ ></transaction-playback>
389
+
390
+ <button @click=${this.approve}>Approve</button>
391
+ </div>
392
+ `
393
+ }
394
+
395
+ private handleHeaderInfo(e: CustomEvent) {
396
+ this.headerInfo = e.detail
397
+ }
398
+
399
+ private async handleModification(e: CustomEvent) {
400
+ const mod: TransactionModificationWithContext = e.detail
401
+
402
+ // Store modification
403
+ this.modifications.push(mod)
404
+
405
+ // Apply to transaction tree
406
+ this.modifiedTx = await this.applyModification(this.originalTx, mod)
407
+ }
408
+
409
+ private async applyModification(
410
+ rootTx: DecoderResult,
411
+ mod: TransactionModificationWithContext
412
+ ): Promise<DecoderResult> {
413
+ // Navigate transaction tree using mod.transactionPath
414
+ // Apply mod.data at the correct level
415
+ // Re-encode wrappers (Execute/Batch)
416
+ // Re-decode entire tree
417
+ // Return modified transaction
418
+ // (See TRANSACTION_MODIFICATION_GUIDE.md for full implementation)
419
+ }
420
+
421
+ private async approve() {
422
+ const finalTx = this.modifiedTx ?? this.originalTx
423
+ await this.wallet.sendTransaction(finalTx)
424
+ }
425
+ }
426
+ ```
427
+
428
+ ---
429
+
430
+ ## Key Concepts
431
+
432
+ ### 1. **Separation of Concerns**
433
+
434
+ - **Header Info** = Visual display (from/to/title)
435
+ - **Transaction Modification** = Data changes (args, value, gas)
436
+
437
+ These are separate events because they serve different purposes.
438
+
439
+ ### 2. **Local Transaction Data**
440
+
441
+ Views emit their **local** transaction data (not wrapped in Execute/Batch).
442
+ Parents handle re-wrapping.
443
+
444
+ ```
445
+ View emits: transfer(from, to, amount, force, data)
446
+ Parent re-wraps: execute(target, 0, transferData)
447
+ ```
448
+
449
+ ### 3. **Re-decoding for Security**
450
+
451
+ Parents **must** re-decode modified data to verify it's valid:
452
+
453
+ ```typescript
454
+ const reDecoded = await decoder.decode({ ...tx, data: mod.data })
455
+ if (!reDecoded) throw new Error('Invalid modification')
456
+ ```
457
+
458
+ ### 4. **Context-Aware Rendering**
459
+
460
+ Views adapt UI based on `context` prop:
461
+
462
+ ```typescript
463
+ approval → Interactive controls (checkboxes, sliders)
464
+ feed → Read-only status indicators
465
+ detail → Full information display
466
+ ```
467
+
468
+ ### 5. **Transaction Paths**
469
+
470
+ Path notation for nested transactions:
471
+
472
+ ```
473
+ [1] → Simple transaction
474
+ [0, 2] → Batch[0].children[2]
475
+ [0, 1, 0] → Batch[0].children[1].children[0]
476
+ ```
477
+
478
+ ---
479
+
480
+ ## Best Practices
481
+
482
+ ### For View Developers
483
+
484
+ 1. ✅ Emit header info in `connectedCallback()` (early)
485
+ 2. ✅ Include correct `transactionIndex` (from props)
486
+ 3. ✅ Provide clear, human-readable `reason` strings
487
+ 4. ✅ Use context prop to adapt UI
488
+ 5. ✅ Validate user input before emitting modifications
489
+ 6. ✅ Use helper functions (`dispatchHeaderInfo`, `dispatchTransactionModification`)
490
+
491
+ ### For Container Developers
492
+
493
+ 1. ✅ Always re-decode modified data
494
+ 2. ✅ Show modifications to user before submission
495
+ 3. ✅ Validate modifications (check `validation` field)
496
+ 4. ✅ Keep audit trail of modifications
497
+ 5. ✅ Handle re-wrapping for Execute/Batch transactions
498
+
499
+ ### Security
500
+
501
+ 1. ✅ Re-decode all modifications
502
+ 2. ✅ Display what changed to user
503
+ 3. ✅ Validate before applying
504
+ 4. ✅ Log modifications for audit
505
+ 5. ✅ Never skip verification
506
+
507
+ ---
508
+
509
+ ## Debugging
510
+
511
+ ### Enable Debug Mode
512
+
513
+ ```html
514
+ <transaction-playback
515
+ .transaction="${tx}"
516
+ debug
517
+ ></transaction-playback>
518
+ ```
519
+
520
+ Shows:
521
+ - Playback info (index, batch status)
522
+ - Matched view ID
523
+ - **Header info received** (from/to/title)
524
+ - Transaction path
525
+
526
+ ### Console Logging
527
+
528
+ ```typescript
529
+ // In view
530
+ console.log('Emitting modification:', modification)
531
+
532
+ // In parent
533
+ console.log('Received modification:', event.detail)
534
+ console.log('Transaction path:', event.detail.transactionPath)
535
+ ```
536
+
537
+ ---
538
+
539
+ ## Type Imports
540
+
541
+ ```typescript
542
+ // Header events
543
+ import type {
544
+ TransactionHeaderInfo,
545
+ HeaderInfoEvent
546
+ } from '@lukso/transaction-view-headless'
547
+
548
+ // Transaction modifications
549
+ import type {
550
+ TransactionModification,
551
+ TransactionModificationWithContext,
552
+ TransactionModificationEvent
553
+ } from '@lukso/transaction-view-headless'
554
+
555
+ // Helpers and constants
556
+ import {
557
+ TransactionViewEvents,
558
+ dispatchHeaderInfo,
559
+ dispatchTransactionModification,
560
+ isHeaderInfoEvent,
561
+ isTransactionModificationEvent
562
+ } from '@lukso/transaction-view-headless'
563
+
564
+ // View props
565
+ import type {
566
+ ViewContext,
567
+ ViewVariant
568
+ } from '@lukso/transaction-view-headless'
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Related Documentation
574
+
575
+ - [HEADER_EVENTS_GUIDE.md](./HEADER_EVENTS_GUIDE.md) - Complete header events documentation
576
+ - [TRANSACTION_MODIFICATION_GUIDE.md](./TRANSACTION_MODIFICATION_GUIDE.md) - Complete modification guide
577
+ - [CONTEXT_VARIANT_GUIDE.md](./CONTEXT_VARIANT_GUIDE.md) - Context and variant system
578
+ - [PLAYBACK_GUIDE.md](./PLAYBACK_GUIDE.md) - Transaction playback system
579
+
580
+ ---
581
+
582
+ ## Quick Reference
583
+
584
+ | Need to... | Use... | Event | Documentation |
585
+ |------------|--------|-------|---------------|
586
+ | Change header from/to | `dispatchHeaderInfo` | `header-info` | HEADER_EVENTS_GUIDE.md |
587
+ | Modify transaction data | `dispatchTransactionModification` | `transaction-modification` | TRANSACTION_MODIFICATION_GUIDE.md |
588
+ | Adapt UI by context | Check `this.context` prop | - | CONTEXT_VARIANT_GUIDE.md |
589
+ | Listen in parent | `@header-info`, `@transaction-modification` | Both | This doc |
590
+ | Debug events | Set `debug` prop on playback | - | This doc |
591
+
592
+ ---
593
+
594
+ ## Future Events
595
+
596
+ These events are planned but not yet implemented:
597
+
598
+ - **`view-state-change`** - For loading, error, interactive state changes
599
+ - **`view-action`** - For user actions like "Approve", "Reject", "Sign"
600
+
601
+ The event system is designed to be extensible for future needs.