@rougechain/sdk 0.9.0 → 1.1.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/README.md +98 -4
- package/dist/index.cjs +118 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +118 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<strong>Build quantum-safe dApps on RougeChain</strong><br />
|
|
11
|
-
Transfers · DEX · NFTs · Shielded Transactions · Bridge · Rollups · Dynamic Fees · Finality Proofs · WebSocket · Mail · Messenger
|
|
11
|
+
Transfers · DEX · NFTs · Social · Shielded Transactions · Bridge · Rollups · Dynamic Fees · Finality Proofs · WebSocket · Mail · Messenger
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
@@ -62,6 +62,7 @@ const { balance } = await rc.getBalance(wallet.publicKey);
|
|
|
62
62
|
| **Shielded** | `rc.shielded` | Private transfers with zk-STARK proofs, shield/unshield XRGE |
|
|
63
63
|
| **Bridge** | `rc.bridge` | ETH ↔ qETH, USDC ↔ qUSDC, XRGE bridge (Base Mainnet/Sepolia) |
|
|
64
64
|
| **Rollup** | `rc` | zk-STARK batch proofs, rollup status, submit transfers |
|
|
65
|
+
| **Social** | `rc.social` | Posts, timeline feed, reposts, likes, follows, comments |
|
|
65
66
|
| **Mail** | `rc.mail` | On-chain encrypted email (`@rouge.quant`) |
|
|
66
67
|
| **Messenger** | `rc.messenger` | E2E encrypted messaging with self-destruct |
|
|
67
68
|
| **Address Resolution** | `rc` | O(1) rouge1↔pubkey resolution via on-chain index |
|
|
@@ -335,6 +336,79 @@ const batch = await rc.getRollupBatch(1);
|
|
|
335
336
|
// { batch_id, transfer_count, proof_size_bytes, proof_time_ms, verified, ... }
|
|
336
337
|
```
|
|
337
338
|
|
|
339
|
+
## Social (`rc.social`)
|
|
340
|
+
|
|
341
|
+
On-chain social layer with posts, threaded replies, reposts, likes, follows, and comments. All write operations require a `wallet` parameter for ML-DSA-65 signed requests.
|
|
342
|
+
|
|
343
|
+
### Posts & Timeline
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
// Create a post (max 4000 chars)
|
|
347
|
+
const { post } = await rc.social.createPost(wallet, "Hello RougeChain!");
|
|
348
|
+
|
|
349
|
+
// Reply to a post (threaded)
|
|
350
|
+
await rc.social.createPost(wallet, "Great point!", post.id);
|
|
351
|
+
|
|
352
|
+
// Delete your own post
|
|
353
|
+
await rc.social.deletePost(wallet, post.id);
|
|
354
|
+
|
|
355
|
+
// Get a single post with stats
|
|
356
|
+
const result = await rc.social.getPost(post.id, wallet.publicKey);
|
|
357
|
+
// result.post, result.stats { likes, reposts, replies, liked, reposted }
|
|
358
|
+
|
|
359
|
+
// Global timeline (all posts, newest first)
|
|
360
|
+
const timeline = await rc.social.getGlobalTimeline(50, 0);
|
|
361
|
+
|
|
362
|
+
// Following feed (posts from people you follow)
|
|
363
|
+
const feed = await rc.social.getFollowingFeed(wallet, 50, 0);
|
|
364
|
+
|
|
365
|
+
// User's posts
|
|
366
|
+
const { posts, total } = await rc.social.getUserPosts(userPubKey);
|
|
367
|
+
|
|
368
|
+
// Get replies to a post
|
|
369
|
+
const replies = await rc.social.getPostReplies(post.id);
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Likes, Reposts & Follows
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
// Like/unlike a post or track (toggle)
|
|
376
|
+
await rc.social.toggleLike(wallet, postOrTrackId);
|
|
377
|
+
|
|
378
|
+
// Repost/unrepost (toggle)
|
|
379
|
+
await rc.social.toggleRepost(wallet, post.id);
|
|
380
|
+
|
|
381
|
+
// Follow/unfollow (toggle)
|
|
382
|
+
await rc.social.toggleFollow(wallet, artistPubKey);
|
|
383
|
+
|
|
384
|
+
// Get stats
|
|
385
|
+
const stats = await rc.social.getPostStats(post.id, wallet.publicKey);
|
|
386
|
+
const artistStats = await rc.social.getArtistStats(pubkey, wallet.publicKey);
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Comments (Track-level)
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
// Comment on a track
|
|
393
|
+
const { comment } = await rc.social.postComment(wallet, trackId, "Fire track!");
|
|
394
|
+
|
|
395
|
+
// Get comments
|
|
396
|
+
const comments = await rc.social.getComments(trackId);
|
|
397
|
+
|
|
398
|
+
// Delete your comment
|
|
399
|
+
await rc.social.deleteComment(wallet, comment.id);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Play Counts
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
// Record a play (debounce client-side, one per session per track)
|
|
406
|
+
await rc.social.recordPlay(wallet, trackId);
|
|
407
|
+
|
|
408
|
+
// Get track stats (plays, likes, comments)
|
|
409
|
+
const trackStats = await rc.social.getTrackStats(trackId, wallet.publicKey);
|
|
410
|
+
```
|
|
411
|
+
|
|
338
412
|
## Mail (`rc.mail`)
|
|
339
413
|
|
|
340
414
|
On-chain encrypted email with `@rouge.quant` / `@qwalla.mail` addresses. All write operations require a `wallet` parameter for ML-DSA-65 request signing — requests are authenticated via `/api/v2/` endpoints with anti-replay nonce protection.
|
|
@@ -364,7 +438,7 @@ const name = await rc.mail.reverseLookup(wallet.publicKey);
|
|
|
364
438
|
// "alice"
|
|
365
439
|
|
|
366
440
|
// Release a name (signed request)
|
|
367
|
-
await rc.mail.releaseName(wallet, "alice"
|
|
441
|
+
await rc.mail.releaseName(wallet, "alice");
|
|
368
442
|
```
|
|
369
443
|
|
|
370
444
|
### Sending & Reading Mail
|
|
@@ -393,6 +467,25 @@ await rc.mail.markRead(wallet, messageId);
|
|
|
393
467
|
await rc.mail.delete(wallet, messageId);
|
|
394
468
|
```
|
|
395
469
|
|
|
470
|
+
### Unread Counts
|
|
471
|
+
|
|
472
|
+
The SDK does not expose a dedicated unread-count endpoint. Derive unread totals client-side from inbox data:
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
// Mail: count unread inbox items
|
|
476
|
+
const inbox = await rc.mail.getInbox(wallet);
|
|
477
|
+
const unreadMail = inbox.filter((m: any) => {
|
|
478
|
+
const label = m.label ?? {};
|
|
479
|
+
return !(label.is_read ?? label.isRead ?? true);
|
|
480
|
+
}).length;
|
|
481
|
+
|
|
482
|
+
// Messenger: sum unread_count across conversations
|
|
483
|
+
const convos = await rc.messenger.getConversations(wallet);
|
|
484
|
+
const unreadChats = convos.reduce((sum: number, c: any) => {
|
|
485
|
+
return sum + (c.unread_count ?? c.unreadCount ?? 0);
|
|
486
|
+
}, 0);
|
|
487
|
+
```
|
|
488
|
+
|
|
396
489
|
## Messenger (`rc.messenger`)
|
|
397
490
|
|
|
398
491
|
End-to-end encrypted messaging with media and self-destruct support. All operations use ML-DSA-65 signed requests via `/api/v2/` endpoints with nonce-based anti-replay protection.
|
|
@@ -425,7 +518,7 @@ await rc.messenger.sendMessage(wallet, conversationId, encryptedContent, {
|
|
|
425
518
|
const messages = await rc.messenger.getMessages(wallet, conversationId);
|
|
426
519
|
|
|
427
520
|
// Delete a message (signed request)
|
|
428
|
-
await rc.messenger.deleteMessage(wallet, messageId);
|
|
521
|
+
await rc.messenger.deleteMessage(wallet, messageId, conversationId);
|
|
429
522
|
|
|
430
523
|
// Delete a conversation (signed request)
|
|
431
524
|
await rc.messenger.deleteConversation(wallet, conversationId);
|
|
@@ -450,7 +543,7 @@ const stats = await rc.shielded.getStats();
|
|
|
450
543
|
// Check if a nullifier has been spent
|
|
451
544
|
const { spent } = await rc.shielded.isNullifierSpent(note.nullifier);
|
|
452
545
|
|
|
453
|
-
// Private transfer (
|
|
546
|
+
// Private transfer (STARK proof generated by WASM prover in browser or Rust prover on node)
|
|
454
547
|
await rc.shielded.transfer(wallet, {
|
|
455
548
|
nullifiers: [note.nullifier],
|
|
456
549
|
outputCommitments: [recipientCommitment],
|
|
@@ -548,6 +641,7 @@ import type {
|
|
|
548
641
|
ShieldedNote,
|
|
549
642
|
RollupStatus, RollupBatchResult, RollupSubmitParams, RollupSubmitResult,
|
|
550
643
|
FeeInfo, FinalityProof, MintTokenParams, VoteMessage, WsSubscribeMessage,
|
|
644
|
+
SocialPost, PostStats, TrackStats, ArtistStats, SocialComment,
|
|
551
645
|
} from "@rougechain/sdk";
|
|
552
646
|
```
|
|
553
647
|
|
package/dist/index.cjs
CHANGED
|
@@ -363,6 +363,7 @@ var RougeChain = class {
|
|
|
363
363
|
this.mail = new MailClient(this);
|
|
364
364
|
this.messenger = new MessengerClient(this);
|
|
365
365
|
this.shielded = new ShieldedClient(this);
|
|
366
|
+
this.social = new SocialClient(this);
|
|
366
367
|
}
|
|
367
368
|
// ===== Internal helpers =====
|
|
368
369
|
/** @internal */
|
|
@@ -994,14 +995,29 @@ var MailClient = class {
|
|
|
994
995
|
}
|
|
995
996
|
// --- Mail (signed) ---
|
|
996
997
|
async send(wallet, params) {
|
|
998
|
+
const sigPayload = params.encrypted_subject + "|" + params.encrypted_body + (params.encrypted_attachment ? "|" + params.encrypted_attachment : "");
|
|
999
|
+
let contentSig = params.content_signature || "";
|
|
1000
|
+
if (!contentSig && wallet.privateKey) {
|
|
1001
|
+
try {
|
|
1002
|
+
const { ml_dsa65: ml_dsa654 } = await import('@noble/post-quantum/ml-dsa.js');
|
|
1003
|
+
const privKey = typeof wallet.privateKey === "string" ? hexToBytes(wallet.privateKey) : wallet.privateKey;
|
|
1004
|
+
const sigBytes = ml_dsa654.sign(
|
|
1005
|
+
new TextEncoder().encode(sigPayload),
|
|
1006
|
+
privKey
|
|
1007
|
+
);
|
|
1008
|
+
contentSig = bytesToHex(sigBytes);
|
|
1009
|
+
} catch {
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
997
1012
|
const signed = signRequest(wallet, {
|
|
998
1013
|
fromWalletId: params.from,
|
|
999
1014
|
toWalletIds: [params.to],
|
|
1000
1015
|
subjectEncrypted: params.encrypted_subject,
|
|
1001
1016
|
bodyEncrypted: params.encrypted_body,
|
|
1002
|
-
|
|
1017
|
+
attachmentEncrypted: params.encrypted_attachment,
|
|
1018
|
+
contentSignature: contentSig,
|
|
1003
1019
|
replyToId: params.reply_to_id,
|
|
1004
|
-
hasAttachment:
|
|
1020
|
+
hasAttachment: !!params.encrypted_attachment
|
|
1005
1021
|
});
|
|
1006
1022
|
return this.rc.submitTx("/v2/mail/send", signed);
|
|
1007
1023
|
}
|
|
@@ -1213,6 +1229,106 @@ var ShieldedClient = class {
|
|
|
1213
1229
|
return this.rc.get("/contracts");
|
|
1214
1230
|
}
|
|
1215
1231
|
};
|
|
1232
|
+
var SocialClient = class {
|
|
1233
|
+
constructor(rc) {
|
|
1234
|
+
this.rc = rc;
|
|
1235
|
+
}
|
|
1236
|
+
async recordPlay(wallet, trackId) {
|
|
1237
|
+
const signed = signRequest(wallet, { trackId });
|
|
1238
|
+
return this.rc.submitTx("/v2/social/play", signed);
|
|
1239
|
+
}
|
|
1240
|
+
async toggleLike(wallet, trackId) {
|
|
1241
|
+
const signed = signRequest(wallet, { trackId });
|
|
1242
|
+
return this.rc.submitTx("/v2/social/like", signed);
|
|
1243
|
+
}
|
|
1244
|
+
async postComment(wallet, trackId, body) {
|
|
1245
|
+
const signed = signRequest(wallet, { trackId, body });
|
|
1246
|
+
return this.rc.submitTx("/v2/social/comment", signed);
|
|
1247
|
+
}
|
|
1248
|
+
async deleteComment(wallet, commentId) {
|
|
1249
|
+
const signed = signRequest(wallet, { commentId });
|
|
1250
|
+
return this.rc.submitTx("/v2/social/comment/delete", signed);
|
|
1251
|
+
}
|
|
1252
|
+
async toggleFollow(wallet, artistPubkey) {
|
|
1253
|
+
const signed = signRequest(wallet, { artistPubkey });
|
|
1254
|
+
return this.rc.submitTx("/v2/social/follow", signed);
|
|
1255
|
+
}
|
|
1256
|
+
async getTrackStats(trackId, viewerPubkey) {
|
|
1257
|
+
const q = viewerPubkey ? `?viewer=${encodeURIComponent(viewerPubkey)}` : "";
|
|
1258
|
+
return this.rc.get(`/social/track/${encodeURIComponent(trackId)}/stats${q}`);
|
|
1259
|
+
}
|
|
1260
|
+
async getComments(trackId, limit = 50, offset = 0) {
|
|
1261
|
+
const data = await this.rc.get(
|
|
1262
|
+
`/social/track/${encodeURIComponent(trackId)}/comments?limit=${limit}&offset=${offset}`
|
|
1263
|
+
);
|
|
1264
|
+
return data.comments ?? [];
|
|
1265
|
+
}
|
|
1266
|
+
async getArtistStats(pubkey, viewerPubkey) {
|
|
1267
|
+
const q = viewerPubkey ? `?viewer=${encodeURIComponent(viewerPubkey)}` : "";
|
|
1268
|
+
return this.rc.get(`/social/artist/${encodeURIComponent(pubkey)}/stats${q}`);
|
|
1269
|
+
}
|
|
1270
|
+
async getUserLikes(pubkey) {
|
|
1271
|
+
const data = await this.rc.get(`/social/user/${encodeURIComponent(pubkey)}/likes`);
|
|
1272
|
+
return data.trackIds ?? [];
|
|
1273
|
+
}
|
|
1274
|
+
async getUserFollowing(pubkey) {
|
|
1275
|
+
const data = await this.rc.get(`/social/user/${encodeURIComponent(pubkey)}/following`);
|
|
1276
|
+
return data.artists ?? [];
|
|
1277
|
+
}
|
|
1278
|
+
// ── Posts ──────────────────────────────────────────────
|
|
1279
|
+
async createPost(wallet, body, replyToId) {
|
|
1280
|
+
const payload = { body };
|
|
1281
|
+
if (replyToId) payload.replyToId = replyToId;
|
|
1282
|
+
const signed = signRequest(wallet, payload);
|
|
1283
|
+
return this.rc.submitTx("/v2/social/post", signed);
|
|
1284
|
+
}
|
|
1285
|
+
async deletePost(wallet, postId) {
|
|
1286
|
+
const signed = signRequest(wallet, { postId });
|
|
1287
|
+
return this.rc.submitTx("/v2/social/post/delete", signed);
|
|
1288
|
+
}
|
|
1289
|
+
async toggleRepost(wallet, postId) {
|
|
1290
|
+
const signed = signRequest(wallet, { postId });
|
|
1291
|
+
return this.rc.submitTx("/v2/social/repost", signed);
|
|
1292
|
+
}
|
|
1293
|
+
async getPost(postId, viewerPubkey) {
|
|
1294
|
+
const q = viewerPubkey ? `?viewer=${encodeURIComponent(viewerPubkey)}` : "";
|
|
1295
|
+
try {
|
|
1296
|
+
return await this.rc.get(`/social/post/${encodeURIComponent(postId)}${q}`);
|
|
1297
|
+
} catch {
|
|
1298
|
+
return null;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
async getPostStats(postId, viewerPubkey) {
|
|
1302
|
+
const q = viewerPubkey ? `?viewer=${encodeURIComponent(viewerPubkey)}` : "";
|
|
1303
|
+
return this.rc.get(`/social/post/${encodeURIComponent(postId)}/stats${q}`);
|
|
1304
|
+
}
|
|
1305
|
+
async getPostReplies(postId, limit = 50, offset = 0) {
|
|
1306
|
+
const data = await this.rc.get(
|
|
1307
|
+
`/social/post/${encodeURIComponent(postId)}/replies?limit=${limit}&offset=${offset}`
|
|
1308
|
+
);
|
|
1309
|
+
return data.replies ?? [];
|
|
1310
|
+
}
|
|
1311
|
+
async getUserPosts(pubkey, limit = 50, offset = 0) {
|
|
1312
|
+
return this.rc.get(
|
|
1313
|
+
`/social/user/${encodeURIComponent(pubkey)}/posts?limit=${limit}&offset=${offset}`
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
async getGlobalTimeline(limit = 50, offset = 0) {
|
|
1317
|
+
const data = await this.rc.get(
|
|
1318
|
+
`/social/timeline?limit=${limit}&offset=${offset}`
|
|
1319
|
+
);
|
|
1320
|
+
return data.posts ?? [];
|
|
1321
|
+
}
|
|
1322
|
+
async getFollowingFeed(wallet, limit = 50, offset = 0) {
|
|
1323
|
+
const signed = signRequest(wallet, { limit, offset });
|
|
1324
|
+
try {
|
|
1325
|
+
const data = await this.rc.submitTx("/v2/social/feed", signed);
|
|
1326
|
+
return data.posts ?? [];
|
|
1327
|
+
} catch {
|
|
1328
|
+
return [];
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1216
1332
|
|
|
1217
1333
|
// src/address.ts
|
|
1218
1334
|
var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|