@sip-protocol/sdk 0.3.2 → 0.5.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/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +2881 -295
- package/dist/browser.mjs +62 -2
- package/dist/chunk-AOZIY3GU.mjs +12995 -0
- package/dist/chunk-BCLIX5T2.mjs +12940 -0
- package/dist/chunk-DMHBKRWV.mjs +14712 -0
- package/dist/chunk-FKXPHKYD.mjs +12955 -0
- package/dist/chunk-HGU6HZRC.mjs +231 -0
- package/dist/chunk-J4Q4NJ2U.mjs +13544 -0
- package/dist/chunk-OPQ2GQIO.mjs +13013 -0
- package/dist/chunk-W2B7T6WU.mjs +14714 -0
- package/dist/index-5jAdWMA-.d.ts +8973 -0
- package/dist/index-B9Vkpaao.d.mts +8973 -0
- package/dist/index-BcWNakUD.d.ts +7990 -0
- package/dist/index-BsKY3Hr0.d.mts +7990 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2852 -266
- package/dist/index.mjs +62 -2
- package/dist/proofs/noir.mjs +1 -1
- package/package.json +2 -1
- package/src/adapters/near-intents.ts +8 -0
- package/src/bitcoin/index.ts +51 -0
- package/src/bitcoin/silent-payments.ts +865 -0
- package/src/bitcoin/taproot.ts +590 -0
- package/src/compliance/compliance-manager.ts +87 -0
- package/src/compliance/conditional-threshold.ts +379 -0
- package/src/compliance/conditional.ts +382 -0
- package/src/compliance/derivation.ts +489 -0
- package/src/compliance/index.ts +50 -8
- package/src/compliance/pdf.ts +365 -0
- package/src/compliance/reports.ts +644 -0
- package/src/compliance/threshold.ts +529 -0
- package/src/compliance/types.ts +223 -0
- package/src/cosmos/ibc-stealth.ts +825 -0
- package/src/cosmos/index.ts +83 -0
- package/src/cosmos/stealth.ts +487 -0
- package/src/errors.ts +8 -0
- package/src/index.ts +80 -1
- package/src/move/aptos.ts +369 -0
- package/src/move/index.ts +35 -0
- package/src/move/sui.ts +367 -0
- package/src/oracle/types.ts +8 -0
- package/src/settlement/backends/direct-chain.ts +8 -0
- package/src/stealth.ts +3 -3
- package/src/validation.ts +42 -1
- package/src/wallet/aptos/adapter.ts +422 -0
- package/src/wallet/aptos/index.ts +10 -0
- package/src/wallet/aptos/mock.ts +410 -0
- package/src/wallet/aptos/types.ts +278 -0
- package/src/wallet/bitcoin/adapter.ts +470 -0
- package/src/wallet/bitcoin/index.ts +38 -0
- package/src/wallet/bitcoin/mock.ts +516 -0
- package/src/wallet/bitcoin/types.ts +274 -0
- package/src/wallet/cosmos/adapter.ts +484 -0
- package/src/wallet/cosmos/index.ts +63 -0
- package/src/wallet/cosmos/mock.ts +596 -0
- package/src/wallet/cosmos/types.ts +462 -0
- package/src/wallet/index.ts +127 -0
- package/src/wallet/sui/adapter.ts +471 -0
- package/src/wallet/sui/index.ts +10 -0
- package/src/wallet/sui/mock.ts +439 -0
- package/src/wallet/sui/types.ts +245 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PDF Export Utilities
|
|
3
|
+
*
|
|
4
|
+
* Lightweight PDF generation for audit reports without external dependencies.
|
|
5
|
+
* Generates PDF 1.4 format documents with professional formatting.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { AuditReport, PdfExportOptions } from './types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate a PDF document from an audit report
|
|
12
|
+
*
|
|
13
|
+
* Creates a professionally formatted PDF report with:
|
|
14
|
+
* - Header with report metadata
|
|
15
|
+
* - Summary statistics
|
|
16
|
+
* - Optional transaction details table
|
|
17
|
+
* - Footer with generation timestamp
|
|
18
|
+
*
|
|
19
|
+
* This implementation uses PDF 1.4 format and works in both Node.js and browsers.
|
|
20
|
+
*
|
|
21
|
+
* @param report - The audit report to export
|
|
22
|
+
* @param options - PDF export options
|
|
23
|
+
* @returns PDF document as Uint8Array
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const report = await reporter.generateAuditReport({...})
|
|
28
|
+
* const pdfBytes = generatePdfReport(report, {
|
|
29
|
+
* title: 'Q1 2025 Audit Report',
|
|
30
|
+
* organization: 'ACME Corp',
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* // Save to file (Node.js)
|
|
34
|
+
* fs.writeFileSync('audit-report.pdf', pdfBytes)
|
|
35
|
+
*
|
|
36
|
+
* // Download in browser
|
|
37
|
+
* const blob = new Blob([pdfBytes], { type: 'application/pdf' })
|
|
38
|
+
* const url = URL.createObjectURL(blob)
|
|
39
|
+
* const a = document.createElement('a')
|
|
40
|
+
* a.href = url
|
|
41
|
+
* a.download = 'audit-report.pdf'
|
|
42
|
+
* a.click()
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function generatePdfReport(
|
|
46
|
+
report: AuditReport,
|
|
47
|
+
options: PdfExportOptions = {}
|
|
48
|
+
): Uint8Array {
|
|
49
|
+
const {
|
|
50
|
+
title = 'SIP Protocol Audit Report',
|
|
51
|
+
organization = '',
|
|
52
|
+
includeTransactions = true,
|
|
53
|
+
maxTransactions = 100,
|
|
54
|
+
} = options
|
|
55
|
+
|
|
56
|
+
// Build PDF content
|
|
57
|
+
const content = buildPdfContent(report, {
|
|
58
|
+
title,
|
|
59
|
+
organization,
|
|
60
|
+
includeTransactions,
|
|
61
|
+
maxTransactions,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// Generate PDF binary
|
|
65
|
+
return generatePdfBinary(content, title)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Build PDF content structure
|
|
70
|
+
*/
|
|
71
|
+
function buildPdfContent(
|
|
72
|
+
report: AuditReport,
|
|
73
|
+
options: Required<PdfExportOptions>
|
|
74
|
+
): string {
|
|
75
|
+
const lines: string[] = []
|
|
76
|
+
|
|
77
|
+
// Header
|
|
78
|
+
lines.push(options.title)
|
|
79
|
+
if (options.organization && options.organization.trim() !== '') {
|
|
80
|
+
lines.push(`Organization: ${options.organization}`)
|
|
81
|
+
}
|
|
82
|
+
lines.push(`Report ID: ${report.reportId}`)
|
|
83
|
+
lines.push(
|
|
84
|
+
`Generated: ${report.generatedAt.toISOString().replace('T', ' ').slice(0, 19)} UTC`
|
|
85
|
+
)
|
|
86
|
+
lines.push('')
|
|
87
|
+
|
|
88
|
+
// Period
|
|
89
|
+
lines.push('Report Period')
|
|
90
|
+
lines.push(` Start: ${formatDate(report.period.start)}`)
|
|
91
|
+
lines.push(` End: ${formatDate(report.period.end)}`)
|
|
92
|
+
lines.push('')
|
|
93
|
+
|
|
94
|
+
// Summary Statistics
|
|
95
|
+
lines.push('Summary Statistics')
|
|
96
|
+
lines.push(` Total Transactions: ${report.summary.transactionCount}`)
|
|
97
|
+
lines.push(
|
|
98
|
+
` Total Volume: ${formatBigInt(report.summary.totalVolume)}`
|
|
99
|
+
)
|
|
100
|
+
lines.push(
|
|
101
|
+
` Unique Counterparties: ${report.summary.uniqueCounterparties}`
|
|
102
|
+
)
|
|
103
|
+
lines.push('')
|
|
104
|
+
|
|
105
|
+
// Transaction Details
|
|
106
|
+
if (options.includeTransactions && report.transactions.length > 0) {
|
|
107
|
+
lines.push('Transaction Details')
|
|
108
|
+
lines.push('')
|
|
109
|
+
|
|
110
|
+
const txToShow = Math.min(
|
|
111
|
+
report.transactions.length,
|
|
112
|
+
options.maxTransactions
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
for (let i = 0; i < txToShow; i++) {
|
|
116
|
+
const tx = report.transactions[i]
|
|
117
|
+
lines.push(`Transaction ${i + 1}/${report.transactions.length}`)
|
|
118
|
+
lines.push(` ID: ${tx.id}`)
|
|
119
|
+
lines.push(` Sender: ${truncateAddress(tx.sender)}`)
|
|
120
|
+
lines.push(` Recipient: ${truncateAddress(tx.recipient)}`)
|
|
121
|
+
lines.push(` Amount: ${formatAmount(tx.amount)}`)
|
|
122
|
+
lines.push(
|
|
123
|
+
` Timestamp: ${formatTimestamp(tx.timestamp)}`
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if (tx.txHash) {
|
|
127
|
+
lines.push(` Tx Hash: ${truncateHash(tx.txHash)}`)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (tx.metadata && Object.keys(tx.metadata).length > 0) {
|
|
131
|
+
lines.push(` Metadata: ${JSON.stringify(tx.metadata)}`)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
lines.push('')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (report.transactions.length > options.maxTransactions) {
|
|
138
|
+
lines.push(
|
|
139
|
+
`... and ${report.transactions.length - options.maxTransactions} more transactions`
|
|
140
|
+
)
|
|
141
|
+
lines.push('')
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Footer
|
|
146
|
+
lines.push('---')
|
|
147
|
+
lines.push(
|
|
148
|
+
'This report was generated by SIP Protocol compliance tools.'
|
|
149
|
+
)
|
|
150
|
+
lines.push('For verification, please contact your compliance officer.')
|
|
151
|
+
|
|
152
|
+
return lines.join('\n')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate PDF binary from text content
|
|
157
|
+
*
|
|
158
|
+
* Creates a minimal but valid PDF 1.4 document.
|
|
159
|
+
* Uses Courier font for consistent monospace rendering.
|
|
160
|
+
*/
|
|
161
|
+
function generatePdfBinary(content: string, title: string): Uint8Array {
|
|
162
|
+
// PDF object catalog
|
|
163
|
+
const objects: string[] = []
|
|
164
|
+
|
|
165
|
+
// Object 1: Catalog
|
|
166
|
+
objects.push(
|
|
167
|
+
'1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj'
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
// Object 2: Pages
|
|
171
|
+
objects.push(
|
|
172
|
+
'2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj'
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
// Object 3: Page
|
|
176
|
+
objects.push(
|
|
177
|
+
'3 0 obj\n<< /Type /Page /Parent 2 0 R /Resources 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R >>\nendobj'
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
// Object 4: Resources
|
|
181
|
+
objects.push(
|
|
182
|
+
'4 0 obj\n<< /Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Courier >> >> >>\nendobj'
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
// Object 5: Content stream
|
|
186
|
+
const contentStream = buildContentStream(content)
|
|
187
|
+
objects.push(
|
|
188
|
+
`5 0 obj\n<< /Length ${contentStream.length} >>\nstream\n${contentStream}\nendstream\nendobj`
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
// Object 6: Info
|
|
192
|
+
const now = new Date()
|
|
193
|
+
const pdfDate = formatPdfDate(now)
|
|
194
|
+
objects.push(
|
|
195
|
+
`6 0 obj\n<< /Title (${title}) /Author (SIP Protocol) /Creator (SIP SDK) /CreationDate (${pdfDate}) >>\nendobj`
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
// Build PDF structure
|
|
199
|
+
const pdfParts: string[] = []
|
|
200
|
+
|
|
201
|
+
// Header
|
|
202
|
+
pdfParts.push('%PDF-1.4\n%\xE2\xE3\xCF\xD3\n')
|
|
203
|
+
|
|
204
|
+
// Objects
|
|
205
|
+
const xrefOffsets: number[] = [0] // Offset 0 for object 0 (null)
|
|
206
|
+
let currentOffset = pdfParts.join('').length
|
|
207
|
+
|
|
208
|
+
for (const obj of objects) {
|
|
209
|
+
xrefOffsets.push(currentOffset)
|
|
210
|
+
pdfParts.push(obj + '\n')
|
|
211
|
+
currentOffset = pdfParts.join('').length
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Cross-reference table
|
|
215
|
+
const xrefStart = currentOffset
|
|
216
|
+
pdfParts.push('xref\n')
|
|
217
|
+
pdfParts.push(`0 ${xrefOffsets.length}\n`)
|
|
218
|
+
|
|
219
|
+
for (let i = 0; i < xrefOffsets.length; i++) {
|
|
220
|
+
if (i === 0) {
|
|
221
|
+
pdfParts.push('0000000000 65535 f \n')
|
|
222
|
+
} else {
|
|
223
|
+
const offset = String(xrefOffsets[i]).padStart(10, '0')
|
|
224
|
+
pdfParts.push(`${offset} 00000 n \n`)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Trailer
|
|
229
|
+
pdfParts.push('trailer\n')
|
|
230
|
+
pdfParts.push(
|
|
231
|
+
`<< /Size ${xrefOffsets.length} /Root 1 0 R /Info 6 0 R >>\n`
|
|
232
|
+
)
|
|
233
|
+
pdfParts.push('startxref\n')
|
|
234
|
+
pdfParts.push(`${xrefStart}\n`)
|
|
235
|
+
pdfParts.push('%%EOF')
|
|
236
|
+
|
|
237
|
+
// Convert to Uint8Array
|
|
238
|
+
const pdfString = pdfParts.join('')
|
|
239
|
+
const encoder = new TextEncoder()
|
|
240
|
+
return encoder.encode(pdfString)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Build PDF content stream with text positioning
|
|
245
|
+
*/
|
|
246
|
+
function buildContentStream(text: string): string {
|
|
247
|
+
const lines = text.split('\n')
|
|
248
|
+
const commands: string[] = []
|
|
249
|
+
|
|
250
|
+
// Begin text
|
|
251
|
+
commands.push('BT')
|
|
252
|
+
|
|
253
|
+
// Set font and size
|
|
254
|
+
commands.push('/F1 10 Tf')
|
|
255
|
+
|
|
256
|
+
// Set leading (line height)
|
|
257
|
+
commands.push('12 TL')
|
|
258
|
+
|
|
259
|
+
// Start position (left margin: 50, top margin: 50 from bottom)
|
|
260
|
+
let y = 742 // Start from top (792 - 50)
|
|
261
|
+
|
|
262
|
+
for (const line of lines) {
|
|
263
|
+
// Move to position
|
|
264
|
+
commands.push(`50 ${y} Td`)
|
|
265
|
+
|
|
266
|
+
// Escape special characters in line
|
|
267
|
+
const escaped = escapePdfString(line)
|
|
268
|
+
|
|
269
|
+
// Show text
|
|
270
|
+
commands.push(`(${escaped}) Tj`)
|
|
271
|
+
|
|
272
|
+
// Move to next line
|
|
273
|
+
y -= 12
|
|
274
|
+
|
|
275
|
+
// Add new page if needed (simplified - just truncate for now)
|
|
276
|
+
if (y < 50) {
|
|
277
|
+
break
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// End text
|
|
282
|
+
commands.push('ET')
|
|
283
|
+
|
|
284
|
+
return commands.join('\n')
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Escape special characters for PDF strings
|
|
289
|
+
*/
|
|
290
|
+
function escapePdfString(str: string): string {
|
|
291
|
+
return str
|
|
292
|
+
.replace(/\\/g, '\\\\')
|
|
293
|
+
.replace(/\(/g, '\\(')
|
|
294
|
+
.replace(/\)/g, '\\)')
|
|
295
|
+
.replace(/\r/g, '\\r')
|
|
296
|
+
.replace(/\n/g, '\\n')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Format date for PDF metadata (D:YYYYMMDDHHmmSS)
|
|
301
|
+
*/
|
|
302
|
+
function formatPdfDate(date: Date): string {
|
|
303
|
+
const year = date.getUTCFullYear()
|
|
304
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0')
|
|
305
|
+
const day = String(date.getUTCDate()).padStart(2, '0')
|
|
306
|
+
const hour = String(date.getUTCHours()).padStart(2, '0')
|
|
307
|
+
const minute = String(date.getUTCMinutes()).padStart(2, '0')
|
|
308
|
+
const second = String(date.getUTCSeconds()).padStart(2, '0')
|
|
309
|
+
|
|
310
|
+
return `D:${year}${month}${day}${hour}${minute}${second}Z`
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Format date for display (YYYY-MM-DD)
|
|
315
|
+
*/
|
|
316
|
+
function formatDate(date: Date): string {
|
|
317
|
+
return date.toISOString().split('T')[0]
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Format bigint for display with thousands separator
|
|
322
|
+
*/
|
|
323
|
+
function formatBigInt(value: bigint): string {
|
|
324
|
+
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Format amount string with thousands separator
|
|
329
|
+
*/
|
|
330
|
+
function formatAmount(amount: string): string {
|
|
331
|
+
try {
|
|
332
|
+
const num = BigInt(amount)
|
|
333
|
+
return formatBigInt(num)
|
|
334
|
+
} catch {
|
|
335
|
+
return amount
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Format Unix timestamp to readable date
|
|
341
|
+
*/
|
|
342
|
+
function formatTimestamp(timestamp: number): string {
|
|
343
|
+
const date = new Date(timestamp * 1000)
|
|
344
|
+
return date.toISOString().replace('T', ' ').slice(0, 19) + ' UTC'
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Truncate address for display (0x1234...5678)
|
|
349
|
+
*/
|
|
350
|
+
function truncateAddress(address: string): string {
|
|
351
|
+
if (address.length <= 12) {
|
|
352
|
+
return address
|
|
353
|
+
}
|
|
354
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Truncate hash for display
|
|
359
|
+
*/
|
|
360
|
+
function truncateHash(hash: string): string {
|
|
361
|
+
if (hash.length <= 16) {
|
|
362
|
+
return hash
|
|
363
|
+
}
|
|
364
|
+
return `${hash.slice(0, 8)}...${hash.slice(-8)}`
|
|
365
|
+
}
|