@yallet/rwa-sdk 0.2.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.
Files changed (58) hide show
  1. package/README.md +365 -0
  2. package/dist/credential-nft-server.d.ts +75 -0
  3. package/dist/credential-nft-server.d.ts.map +1 -0
  4. package/dist/credential-nft-server.js +122 -0
  5. package/dist/credential-nft-server.js.map +1 -0
  6. package/dist/credential-nft.d.ts +31 -0
  7. package/dist/credential-nft.d.ts.map +1 -0
  8. package/dist/credential-nft.js +38 -0
  9. package/dist/credential-nft.js.map +1 -0
  10. package/dist/encryption.d.ts +107 -0
  11. package/dist/encryption.d.ts.map +1 -0
  12. package/dist/encryption.js +176 -0
  13. package/dist/encryption.js.map +1 -0
  14. package/dist/index.d.ts +56 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +66 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/metadata.d.ts +161 -0
  19. package/dist/metadata.d.ts.map +1 -0
  20. package/dist/metadata.js +180 -0
  21. package/dist/metadata.js.map +1 -0
  22. package/dist/minting.d.ts +63 -0
  23. package/dist/minting.d.ts.map +1 -0
  24. package/dist/minting.js +194 -0
  25. package/dist/minting.js.map +1 -0
  26. package/dist/payloads.d.ts +120 -0
  27. package/dist/payloads.d.ts.map +1 -0
  28. package/dist/payloads.js +118 -0
  29. package/dist/payloads.js.map +1 -0
  30. package/dist/registry.d.ts +77 -0
  31. package/dist/registry.d.ts.map +1 -0
  32. package/dist/registry.js +173 -0
  33. package/dist/registry.js.map +1 -0
  34. package/dist/sdk.d.ts +158 -0
  35. package/dist/sdk.d.ts.map +1 -0
  36. package/dist/sdk.js +346 -0
  37. package/dist/sdk.js.map +1 -0
  38. package/dist/storage.d.ts +80 -0
  39. package/dist/storage.d.ts.map +1 -0
  40. package/dist/storage.js +284 -0
  41. package/dist/storage.js.map +1 -0
  42. package/dist/types.d.ts +278 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +19 -0
  45. package/dist/types.js.map +1 -0
  46. package/package.json +64 -0
  47. package/src/credential-nft-server.ts +201 -0
  48. package/src/credential-nft.ts +64 -0
  49. package/src/encryption.ts +308 -0
  50. package/src/index.ts +151 -0
  51. package/src/metadata.ts +336 -0
  52. package/src/minting.ts +266 -0
  53. package/src/payloads.ts +238 -0
  54. package/src/registry.ts +236 -0
  55. package/src/sdk.ts +507 -0
  56. package/src/storage.ts +364 -0
  57. package/src/types.ts +318 -0
  58. package/wasm/README.md +33 -0
package/src/storage.ts ADDED
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Yallet RWA SDK - Storage Module
3
+ *
4
+ * Handles uploading encrypted data to Arweave via ArDrive Turbo
5
+ */
6
+
7
+ import type { EncryptedPayload, AssetType } from './types.js';
8
+
9
+ // ======================================
10
+ // Configuration
11
+ // ======================================
12
+
13
+ const ARWEAVE_GATEWAY = 'https://arweave.net';
14
+ const ARWEAVE_FALLBACK_GATEWAYS = ['https://arweave.net', 'https://ar-io.net', 'https://turbo-gateway.com'];
15
+ const ARWEAVE_TX_ID_RE = /^[A-Za-z0-9_-]{43}$/;
16
+ const ARWEAVE_TXISH_RE = /^[A-Za-z0-9_-]{3,128}$/;
17
+
18
+ /** Yallet backend upload API (proxy-api forwards to backend-api/ArDrive Turbo) */
19
+ const YALLET_ARWEAVE_UPLOAD_URL = 'https://api.yallet.xyz/api/v1/storage/arweave/upload';
20
+
21
+ const ARWEAVE_ENDPOINTS = {
22
+ mainnet: 'https://turbo.irys.xyz',
23
+ devnet: 'https://devnet.irys.xyz',
24
+ };
25
+
26
+ /** Uint8Array to base64 (chunked for large payloads) */
27
+ function toBase64(bytes: Uint8Array): string {
28
+ const chunkSize = 32768;
29
+ let binary = '';
30
+ for (let i = 0; i < bytes.length; i += chunkSize) {
31
+ const chunk = bytes.subarray(i, Math.min(i + chunkSize, bytes.length));
32
+ binary += String.fromCharCode.apply(null, chunk as unknown as number[]);
33
+ }
34
+ return btoa(binary);
35
+ }
36
+
37
+ function extractArweaveTxId(input: string | null | undefined): string | null {
38
+ const raw = String(input || '').trim();
39
+ if (!raw) return null;
40
+
41
+ if (raw.startsWith('ar://')) {
42
+ const tx = raw.substring(5).split('/')[0] || '';
43
+ if (ARWEAVE_TX_ID_RE.test(tx)) return tx;
44
+ return ARWEAVE_TXISH_RE.test(tx) ? tx : null;
45
+ }
46
+ if (ARWEAVE_TX_ID_RE.test(raw)) {
47
+ return raw;
48
+ }
49
+ if (ARWEAVE_TXISH_RE.test(raw) && !raw.includes('/')) {
50
+ return raw;
51
+ }
52
+
53
+ try {
54
+ const u = new URL(raw);
55
+ const host = u.hostname.toLowerCase();
56
+ const [pathFirst = '', pathSecond = ''] = u.pathname.replace(/^\/+/, '').split('/');
57
+
58
+ if (ARWEAVE_TX_ID_RE.test(pathFirst)) return pathFirst;
59
+ if (ARWEAVE_TX_ID_RE.test(pathSecond)) return pathSecond;
60
+ if (ARWEAVE_TXISH_RE.test(pathFirst)) return pathFirst;
61
+ if (ARWEAVE_TXISH_RE.test(pathSecond)) return pathSecond;
62
+
63
+ const subdomainMatch = host.match(/^([a-z0-9_-]{43})\.arweave\.net$/i);
64
+ if (subdomainMatch && ARWEAVE_TX_ID_RE.test(subdomainMatch[1])) {
65
+ return subdomainMatch[1];
66
+ }
67
+ } catch (_) {
68
+ return null;
69
+ }
70
+
71
+ return null;
72
+ }
73
+
74
+ function buildArweaveFetchUrls(input: string): string[] {
75
+ const out: string[] = [];
76
+ const push = (u: string | null | undefined): void => {
77
+ if (!u) return;
78
+ const v = String(u).trim();
79
+ if (!v) return;
80
+ if (!out.includes(v)) out.push(v);
81
+ };
82
+
83
+ const raw = String(input || '').trim();
84
+ if (!raw) return out;
85
+
86
+ // Keep original URL first when caller passes full URL.
87
+ if (raw.startsWith('http://') || raw.startsWith('https://')) {
88
+ push(raw);
89
+ }
90
+
91
+ const txId = extractArweaveTxId(raw);
92
+ if (txId) {
93
+ for (const gw of ARWEAVE_FALLBACK_GATEWAYS) {
94
+ push(`${gw}/${txId}`);
95
+ }
96
+ }
97
+
98
+ return out;
99
+ }
100
+
101
+ // ======================================
102
+ // Arweave Upload
103
+ // ======================================
104
+
105
+ export interface UploadOptions {
106
+ /** Arweave API key (for ArDrive Turbo uploads) */
107
+ apiKey?: string;
108
+ /** Network: mainnet or devnet */
109
+ network?: 'mainnet' | 'devnet';
110
+ /** Custom endpoint */
111
+ endpoint?: string;
112
+ /** Content type */
113
+ contentType?: string;
114
+ /** Custom tags */
115
+ tags?: Record<string, string>;
116
+ }
117
+
118
+ export interface UploadResult {
119
+ /** Arweave transaction ID */
120
+ id: string;
121
+ /** Full Arweave URL */
122
+ url: string;
123
+ /** ar:// URI */
124
+ arweaveUri: string;
125
+ /** Upload timestamp */
126
+ timestamp: number;
127
+ }
128
+
129
+ /**
130
+ * Upload data to Arweave.
131
+ * Default: POST to Yallet backend (api.yallet.xyz → backend ArDrive Turbo).
132
+ * If options.endpoint is set to an Irys URL (e.g. turbo.irys.xyz), uses direct Irys /tx instead.
133
+ *
134
+ * @param data - Data to upload (string or Uint8Array)
135
+ * @param options - Upload options
136
+ * @returns Upload result with transaction ID
137
+ */
138
+ export async function uploadToArweave(
139
+ data: string | Uint8Array,
140
+ options: UploadOptions = {}
141
+ ): Promise<UploadResult> {
142
+ const {
143
+ apiKey,
144
+ network = 'mainnet',
145
+ endpoint = YALLET_ARWEAVE_UPLOAD_URL,
146
+ contentType = 'application/octet-stream',
147
+ tags = {},
148
+ } = options;
149
+
150
+ const dataBytes = typeof data === 'string'
151
+ ? new TextEncoder().encode(data)
152
+ : data;
153
+
154
+ const allTags = {
155
+ 'Content-Type': contentType,
156
+ 'App-Name': 'Yallet-RWA-SDK',
157
+ 'App-Version': '0.1.0',
158
+ ...tags,
159
+ };
160
+
161
+ const useYalletApi =
162
+ !endpoint ||
163
+ endpoint === YALLET_ARWEAVE_UPLOAD_URL ||
164
+ endpoint.includes('api.yallet.xyz');
165
+
166
+ if (useYalletApi) {
167
+ const response = await fetch(endpoint, {
168
+ method: 'POST',
169
+ headers: { 'Content-Type': 'application/json' },
170
+ body: JSON.stringify({
171
+ data: toBase64(dataBytes),
172
+ contentType,
173
+ tags: allTags,
174
+ }),
175
+ });
176
+
177
+ const result = await response.json().catch(() => ({} as Record<string, unknown>));
178
+ if (!response.ok) {
179
+ const msg = (result as { message?: string }).message ?? response.statusText;
180
+ throw new Error(`Upload failed: ${response.status} - ${msg}`);
181
+ }
182
+ if ((result as { success?: boolean }).success !== true) {
183
+ const msg = (result as { message?: string }).message ?? 'Upload failed';
184
+ throw new Error(msg);
185
+ }
186
+
187
+ const rawId = (result as { id?: string }).id;
188
+ const rawUrl = (result as { url?: string }).url;
189
+ const id = extractArweaveTxId(rawId) || extractArweaveTxId(rawUrl);
190
+ if (!id) throw new Error('Upload response missing valid Arweave tx id');
191
+ const url = `${ARWEAVE_GATEWAY}/${id}`;
192
+
193
+ return {
194
+ id,
195
+ url,
196
+ arweaveUri: `ar://${id}`,
197
+ timestamp: Date.now(),
198
+ };
199
+ }
200
+
201
+ // Legacy: direct Irys/Turbo
202
+ const headers: Record<string, string> = { 'Content-Type': contentType };
203
+ if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
204
+ const irysEndpoint = endpoint || ARWEAVE_ENDPOINTS[network];
205
+ const response = await fetch(`${irysEndpoint}/tx`, {
206
+ method: 'POST',
207
+ headers,
208
+ body: dataBytes as BodyInit,
209
+ });
210
+
211
+ if (!response.ok) {
212
+ const errorText = await response.text();
213
+ throw new Error(`Upload failed: ${response.status} - ${errorText}`);
214
+ }
215
+
216
+ const result = await response.json() as { id?: string; url?: string };
217
+ const txId = extractArweaveTxId(result.id) || extractArweaveTxId(result.url);
218
+ if (!txId) throw new Error('Upload response missing valid Arweave tx id');
219
+
220
+ return {
221
+ id: txId,
222
+ url: `${ARWEAVE_GATEWAY}/${txId}`,
223
+ arweaveUri: `ar://${txId}`,
224
+ timestamp: Date.now(),
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Upload encrypted asset to Arweave
230
+ *
231
+ * @param encryptedPayload - Encrypted asset data (with extended fields)
232
+ * @param metadata - Additional metadata
233
+ * @param options - Upload options
234
+ * @returns Upload result
235
+ */
236
+ export async function uploadEncryptedAsset(
237
+ encryptedPayload: EncryptedPayload & {
238
+ assetType: AssetType;
239
+ version: number;
240
+ uuid?: string;
241
+ timestamp?: number;
242
+ dataSize?: number;
243
+ },
244
+ metadata: {
245
+ assetType: AssetType;
246
+ direction?: 'owned' | 'sent' | 'received';
247
+ network?: 'mainnet' | 'devnet';
248
+ },
249
+ options: UploadOptions = {}
250
+ ): Promise<UploadResult> {
251
+ const payload = {
252
+ encrypted: {
253
+ ephemeral_pub: encryptedPayload.ephemeral_pub,
254
+ encrypted_aes_key: encryptedPayload.encrypted_aes_key,
255
+ iv: encryptedPayload.iv,
256
+ encrypted_data: encryptedPayload.encrypted_data,
257
+ },
258
+ metadata: {
259
+ ...metadata,
260
+ version: encryptedPayload.version,
261
+ uuid: encryptedPayload.uuid,
262
+ timestamp: encryptedPayload.timestamp,
263
+ dataSize: encryptedPayload.dataSize,
264
+ uploadedAt: Date.now(),
265
+ },
266
+ };
267
+
268
+ const jsonString = JSON.stringify(payload);
269
+
270
+ return uploadToArweave(jsonString, {
271
+ ...options,
272
+ contentType: 'application/json',
273
+ tags: {
274
+ 'Yallet-Type': 'encrypted-asset',
275
+ 'Asset-Type': metadata.assetType,
276
+ 'Direction': metadata.direction || 'sent',
277
+ 'Network': metadata.network || options.network || 'mainnet',
278
+ ...(encryptedPayload.uuid ? { 'UUID': encryptedPayload.uuid } : {}),
279
+ ...options.tags,
280
+ },
281
+ });
282
+ }
283
+
284
+ /**
285
+ * Upload NFT metadata to Arweave
286
+ *
287
+ * @param metadata - NFT metadata object
288
+ * @param options - Upload options
289
+ * @returns Upload result
290
+ */
291
+ export async function uploadMetadata(
292
+ metadata: Record<string, unknown>,
293
+ options: UploadOptions = {}
294
+ ): Promise<UploadResult> {
295
+ const jsonString = JSON.stringify(metadata);
296
+
297
+ return uploadToArweave(jsonString, {
298
+ ...options,
299
+ contentType: 'application/json',
300
+ tags: {
301
+ 'Content-Type': 'application/json',
302
+ 'Type': 'nft-metadata',
303
+ ...options.tags,
304
+ },
305
+ });
306
+ }
307
+
308
+ /**
309
+ * Download data from Arweave
310
+ *
311
+ * @param txIdOrUri - Transaction ID or ar:// URI
312
+ * @returns Fetched data
313
+ */
314
+ export async function downloadFromArweave(txIdOrUri: string): Promise<Response> {
315
+ const urls = buildArweaveFetchUrls(txIdOrUri);
316
+ if (urls.length === 0) {
317
+ throw new Error('Invalid Arweave tx id or URI');
318
+ }
319
+
320
+ let lastError: Error | null = null;
321
+
322
+ for (const url of urls) {
323
+ const controller = new AbortController();
324
+ const timeoutId = setTimeout(() => controller.abort(), 30000);
325
+
326
+ try {
327
+ const response = await fetch(url, { signal: controller.signal });
328
+ if (!response) {
329
+ if (!lastError) {
330
+ lastError = new Error('Download failed: empty response');
331
+ }
332
+ continue;
333
+ }
334
+ if (!response.ok) {
335
+ lastError = new Error(`Download failed: ${response.status}`);
336
+ continue;
337
+ }
338
+ return response;
339
+ } catch (err) {
340
+ if (err instanceof Error && err.name === 'AbortError') {
341
+ lastError = new Error('Download timeout');
342
+ } else {
343
+ lastError = err instanceof Error ? err : new Error(String(err));
344
+ }
345
+ } finally {
346
+ clearTimeout(timeoutId);
347
+ }
348
+ }
349
+
350
+ throw lastError || new Error('Download failed');
351
+ }
352
+
353
+ /**
354
+ * Download and parse JSON from Arweave
355
+ *
356
+ * @param txIdOrUri - Transaction ID or ar:// URI
357
+ * @returns Parsed JSON
358
+ */
359
+ export async function downloadJsonFromArweave<T = unknown>(
360
+ txIdOrUri: string
361
+ ): Promise<T> {
362
+ const response = await downloadFromArweave(txIdOrUri);
363
+ return response.json() as Promise<T>;
364
+ }
package/src/types.ts ADDED
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Yallet RWA SDK - Type Definitions
3
+ */
4
+
5
+ // ======================================
6
+ // Asset Types
7
+ // ======================================
8
+
9
+ /**
10
+ * Supported RWA asset types
11
+ * Matches chrome-extension RWA_ASSET_TYPES for compatibility (no statement/receipt in extension).
12
+ */
13
+ export enum AssetType {
14
+ NOTE = 'note',
15
+ INVOICE = 'invoice',
16
+ PHOTO = 'photo',
17
+ FILE = 'file',
18
+ CONTACT = 'contact',
19
+ }
20
+
21
+ /**
22
+ * Invoice data structure
23
+ * Aligns with chrome-extension invoice format for decrypt compatibility.
24
+ */
25
+ export interface InvoiceData {
26
+ /** Unique invoice ID/number (extension: invoiceNo) */
27
+ invoiceId: string;
28
+ /** Invoice amount / total */
29
+ amount: number;
30
+ /** Currency code (e.g., 'USD', 'EUR') */
31
+ currency: string;
32
+ /** Invoice date (ISO string) */
33
+ date: string;
34
+ /** Due date (ISO string) (extension: dueDate) */
35
+ dueDate?: string;
36
+ /** Invoice description */
37
+ description?: string;
38
+ /** Line items (extension: lineItems with name, price, qty, unit, total) */
39
+ items?: InvoiceItem[];
40
+ /** Additional notes (extension: notePayee) */
41
+ notes?: string;
42
+ /** Custom metadata */
43
+ metadata?: Record<string, unknown>;
44
+ /** Extension-compat: billTo contact id */
45
+ billTo?: string;
46
+ /** Extension-compat: PO number */
47
+ poNo?: string;
48
+ /** Extension-compat: discount rate 0-100 */
49
+ discountRate?: number;
50
+ /** Extension-compat: discount amount */
51
+ discountAmount?: number;
52
+ /** Extension-compat: tax rate 0-100 */
53
+ taxRate?: number;
54
+ /** Extension-compat: subtotal */
55
+ subtotal?: number;
56
+ /** Extension-compat: tax amount */
57
+ taxAmount?: number;
58
+ /** Extension-compat: total (same as amount) */
59
+ total?: number;
60
+ /** Extension-compat: payment method 'bank' | 'crypto' */
61
+ paymentMethod?: string;
62
+ /** Extension-compat: payment terms */
63
+ paymentTerms?: string;
64
+ /** Extension-compat: note to payee */
65
+ notePayee?: string;
66
+ }
67
+
68
+ export interface InvoiceItem {
69
+ description: string;
70
+ quantity: number;
71
+ unitPrice: number;
72
+ amount: number;
73
+ /** Extension-compat: line item name (same as description) */
74
+ name?: string;
75
+ /** Extension-compat: unit e.g. 'units' | 'hours' */
76
+ unit?: string;
77
+ /** Extension-compat: qty (same as quantity) */
78
+ qty?: number;
79
+ /** Extension-compat: total (same as amount) */
80
+ total?: number;
81
+ }
82
+
83
+ /**
84
+ * Note data structure
85
+ */
86
+ export interface NoteData {
87
+ title: string;
88
+ content: string;
89
+ tags?: string[];
90
+ metadata?: Record<string, unknown>;
91
+ }
92
+
93
+ /**
94
+ * Contact data structure
95
+ */
96
+ export interface ContactData {
97
+ name: string;
98
+ email?: string;
99
+ phone?: string;
100
+ company?: string;
101
+ address?: string;
102
+ notes?: string;
103
+ metadata?: Record<string, unknown>;
104
+ }
105
+
106
+ /**
107
+ * File data structure
108
+ */
109
+ export interface FileData {
110
+ filename: string;
111
+ mimeType: string;
112
+ /** Base64 encoded file content */
113
+ content: string;
114
+ size: number;
115
+ metadata?: Record<string, unknown>;
116
+ }
117
+
118
+ /**
119
+ * Photo data structure
120
+ */
121
+ export interface PhotoData {
122
+ filename: string;
123
+ mimeType: string;
124
+ /** Base64 encoded image content */
125
+ content: string;
126
+ width?: number;
127
+ height?: number;
128
+ metadata?: Record<string, unknown>;
129
+ }
130
+
131
+ // ======================================
132
+ // Encryption Types
133
+ // ======================================
134
+
135
+ /**
136
+ * Encrypted payload structure (ECIES)
137
+ */
138
+ export interface EncryptedPayload {
139
+ /** Ephemeral public key (base64) */
140
+ ephemeral_pub: string;
141
+ /** Encrypted AES key (base64) */
142
+ encrypted_aes_key: string;
143
+ /** Initialization vector (base64) */
144
+ iv: string;
145
+ /** Encrypted data (base64) */
146
+ encrypted_data: string;
147
+ }
148
+
149
+ /**
150
+ * Asset envelope for encryption
151
+ */
152
+ export interface AssetEnvelope {
153
+ version: number;
154
+ type: AssetType;
155
+ timestamp: number;
156
+ uuid: string;
157
+ schema?: string;
158
+ previousToken?: string;
159
+ data: unknown;
160
+ }
161
+
162
+ /**
163
+ * Encrypt function signature (compatible with WASM)
164
+ */
165
+ export type EncryptFunction = (
166
+ recipientXidentityB64: string,
167
+ plaintext: Uint8Array
168
+ ) => string; // Returns JSON string or "error:..."
169
+
170
+ // ======================================
171
+ // User Registry Types
172
+ // ======================================
173
+
174
+ /**
175
+ * Registered user with xidentity
176
+ */
177
+ export interface RegisteredUser {
178
+ /** User's Solana wallet address */
179
+ solanaAddress: string;
180
+ /** User's xidentity public key (base64) */
181
+ xidentity: string;
182
+ /** Optional display name */
183
+ name?: string;
184
+ /** Optional email */
185
+ email?: string;
186
+ /** Registration timestamp */
187
+ registeredAt: number;
188
+ /** Additional metadata */
189
+ metadata?: Record<string, unknown>;
190
+ }
191
+
192
+ /**
193
+ * User registry interface
194
+ */
195
+ export interface UserRegistry {
196
+ /** Get user by Solana address */
197
+ getUser(solanaAddress: string): Promise<RegisteredUser | null>;
198
+ /** Register a new user */
199
+ registerUser(user: RegisteredUser): Promise<void>;
200
+ /** Update user */
201
+ updateUser(solanaAddress: string, updates: Partial<RegisteredUser>): Promise<void>;
202
+ /** Delete user */
203
+ deleteUser(solanaAddress: string): Promise<void>;
204
+ /** List all users */
205
+ listUsers(): Promise<RegisteredUser[]>;
206
+ }
207
+
208
+ // ======================================
209
+ // Minting Types
210
+ // ======================================
211
+
212
+ /**
213
+ * Mint request parameters
214
+ */
215
+ export interface MintRequest {
216
+ /** Asset type */
217
+ assetType: AssetType;
218
+ /** Asset data (InvoiceData, NoteData, ContactData, FileData, PhotoData) */
219
+ assetData: InvoiceData | NoteData | ContactData | FileData | PhotoData;
220
+ /** Recipient's Solana address */
221
+ recipientAddress: string;
222
+ /** NFT name */
223
+ name: string;
224
+ /** NFT description */
225
+ description?: string;
226
+ /** Additional NFT attributes */
227
+ attributes?: Array<{ trait_type: string; value: string }>;
228
+ /** Unique identifier for tracking (auto-generated if not provided) */
229
+ uuid?: string;
230
+ /** Previous token address for version chain (null for first version) */
231
+ previousToken?: string;
232
+ /** Schema identifier for data format validation */
233
+ schema?: string;
234
+ /** MIME type of the asset content */
235
+ mimeType?: string;
236
+ /** Size of the encrypted data in bytes */
237
+ dataSize?: number;
238
+ }
239
+
240
+ /**
241
+ * Mint result
242
+ */
243
+ export interface MintResult {
244
+ /** Whether minting was successful */
245
+ success: boolean;
246
+ /** Asset ID (Solana address of the NFT) */
247
+ assetId?: string;
248
+ /** Transaction signature */
249
+ signature?: string;
250
+ /** Arweave transaction ID for encrypted data */
251
+ arweaveTxId?: string;
252
+ /** Arweave transaction ID for metadata */
253
+ metadataArweaveTxId?: string;
254
+ /** UUID used for this mint */
255
+ uuid?: string;
256
+ /** Error message if failed */
257
+ error?: string;
258
+ }
259
+
260
+ // ======================================
261
+ // Tree Management Types
262
+ // ======================================
263
+
264
+ /**
265
+ * Merkle tree configuration
266
+ */
267
+ export interface TreeConfig {
268
+ /** Tree address (Solana pubkey) */
269
+ treeAddress: string;
270
+ /** Tree authority address */
271
+ treeAuthority: string;
272
+ /** Maximum depth */
273
+ maxDepth: number;
274
+ /** Total capacity */
275
+ capacity: number;
276
+ /** Current usage */
277
+ used: number;
278
+ /** Remaining slots */
279
+ remaining: number;
280
+ /** Usage percentage */
281
+ usagePercent: number;
282
+ }
283
+
284
+ // ======================================
285
+ // SDK Configuration Types
286
+ // ======================================
287
+
288
+ /**
289
+ * SDK configuration options
290
+ */
291
+ export interface SDKConfig {
292
+ /** Solana RPC endpoint */
293
+ rpcEndpoint: string;
294
+ /** Network: 'mainnet' or 'devnet' */
295
+ network: 'mainnet' | 'devnet';
296
+ /** Merkle tree address (optional, will use backend if not provided) */
297
+ merkleTreeAddress?: string;
298
+ /** Merkle tree authority */
299
+ merkleTreeAuthority?: string;
300
+ /** Arweave upload endpoint */
301
+ arweaveEndpoint?: string;
302
+ /** Arweave API key for uploads (ArDrive Turbo) */
303
+ arweaveApiKey?: string;
304
+ /** Backend API URL for tree management */
305
+ backendApiUrl?: string;
306
+ }
307
+
308
+ /**
309
+ * Signer interface for transaction signing
310
+ */
311
+ export interface Signer {
312
+ /** Solana public key (base58) */
313
+ publicKey: string;
314
+ /** Sign transaction */
315
+ signTransaction(tx: Uint8Array): Promise<Uint8Array>;
316
+ /** Sign message */
317
+ signMessage(message: Uint8Array): Promise<Uint8Array>;
318
+ }
package/wasm/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # ACEGF WASM directory
2
+
3
+ This directory holds the WASM build artifacts from [acegf-wallet](https://github.com/phaykhe/yallet-chrome), used by the RWA SDK at runtime for end-to-end encryption compatible with the Yallet extension.
4
+
5
+ ## How to build and place WASM
6
+
7
+ 1. In the **acegf-wallet** repo root, run:
8
+ ```bash
9
+ wasm-pack build --target web
10
+ ```
11
+ 2. Copy the generated artifacts into this SDK's `wasm/` directory:
12
+ ```bash
13
+ cp /path/to/acegf-wallet/pkg/acegf_bg.wasm /path/to/dev.yallet.rwa-sdk/wasm/
14
+ cp /path/to/acegf-wallet/pkg/acegf.js /path/to/dev.yallet.rwa-sdk/wasm/
15
+ cp /path/to/acegf-wallet/pkg/acegf.d.ts /path/to/dev.yallet.rwa-sdk/wasm/
16
+ ```
17
+ 3. When publishing or packing the SDK, the `wasm/` directory is included via the `files` field in `package.json`.
18
+
19
+ ## Initializing WASM in your app
20
+
21
+ The SDK does not load WASM automatically; the caller must initialize acegf and pass the encrypt function:
22
+
23
+ ```ts
24
+ import init from '@yallet/rwa-sdk/wasm/acegf.js'; // or your copy path
25
+ import { createRWASDK, createWasmEncryptor } from '@yallet/rwa-sdk';
26
+
27
+ const acegf = await init(); // optional wasm path: init('/path/to/acegf_bg.wasm')
28
+ const encryptFn = createWasmEncryptor(acegf.acegf_encrypt_for_xidentity);
29
+
30
+ const sdk = createRWASDK(config, { wasmEncryptFn: encryptFn });
31
+ ```
32
+
33
+ If you do not pass `wasmEncryptFn`, the SDK uses its built-in pure JS ECIES implementation (decryption in the Yallet extension may not match exactly; prefer WASM in production).