@rougechain/sdk 0.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/dist/index.cjs ADDED
@@ -0,0 +1,664 @@
1
+ 'use strict';
2
+
3
+ var mlDsa_js = require('@noble/post-quantum/ml-dsa.js');
4
+
5
+ // src/signer.ts
6
+
7
+ // src/utils.ts
8
+ function hexToBytes(hex) {
9
+ const bytes = new Uint8Array(hex.length / 2);
10
+ for (let i = 0; i < hex.length; i += 2) {
11
+ bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
12
+ }
13
+ return bytes;
14
+ }
15
+ function bytesToHex(bytes) {
16
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
17
+ }
18
+ function generateNonce() {
19
+ const bytes = crypto.getRandomValues(new Uint8Array(16));
20
+ return bytesToHex(bytes);
21
+ }
22
+
23
+ // src/signer.ts
24
+ var BURN_ADDRESS = "XRGE_BURN_0x000000000000000000000000000000000000000000000000000000000000DEAD";
25
+ function serializePayload(payload) {
26
+ const json = JSON.stringify(payload, Object.keys(payload).sort());
27
+ return new TextEncoder().encode(json);
28
+ }
29
+ function signTransaction(payload, privateKey, publicKey) {
30
+ const payloadBytes = serializePayload(payload);
31
+ const signature = mlDsa_js.ml_dsa65.sign(payloadBytes, hexToBytes(privateKey));
32
+ return {
33
+ payload,
34
+ signature: bytesToHex(signature),
35
+ public_key: publicKey
36
+ };
37
+ }
38
+ function verifyTransaction(signedTx) {
39
+ try {
40
+ const payloadBytes = serializePayload(signedTx.payload);
41
+ return mlDsa_js.ml_dsa65.verify(
42
+ hexToBytes(signedTx.signature),
43
+ payloadBytes,
44
+ hexToBytes(signedTx.public_key)
45
+ );
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+ function isBurnAddress(address) {
51
+ return address === BURN_ADDRESS;
52
+ }
53
+ function buildAndSign(wallet, payload) {
54
+ const full = {
55
+ ...payload,
56
+ from: wallet.publicKey,
57
+ timestamp: Date.now(),
58
+ nonce: generateNonce()
59
+ };
60
+ return signTransaction(full, wallet.privateKey, wallet.publicKey);
61
+ }
62
+ function createSignedTransfer(wallet, to, amount, fee = 1, token = "XRGE") {
63
+ return buildAndSign(wallet, { type: "transfer", to, amount, fee, token });
64
+ }
65
+ function createSignedTokenCreation(wallet, tokenName, tokenSymbol, initialSupply, fee = 10) {
66
+ return buildAndSign(wallet, {
67
+ type: "create_token",
68
+ token_name: tokenName,
69
+ token_symbol: tokenSymbol,
70
+ initial_supply: initialSupply,
71
+ fee
72
+ });
73
+ }
74
+ function createSignedSwap(wallet, tokenIn, tokenOut, amountIn, minAmountOut) {
75
+ return buildAndSign(wallet, {
76
+ type: "swap",
77
+ token_in: tokenIn,
78
+ token_out: tokenOut,
79
+ amount_in: amountIn,
80
+ min_amount_out: minAmountOut
81
+ });
82
+ }
83
+ function createSignedPoolCreation(wallet, tokenA, tokenB, amountA, amountB) {
84
+ return buildAndSign(wallet, {
85
+ type: "create_pool",
86
+ token_a: tokenA,
87
+ token_b: tokenB,
88
+ amount_a: amountA,
89
+ amount_b: amountB
90
+ });
91
+ }
92
+ function createSignedAddLiquidity(wallet, poolId, amountA, amountB) {
93
+ return buildAndSign(wallet, {
94
+ type: "add_liquidity",
95
+ pool_id: poolId,
96
+ amount_a: amountA,
97
+ amount_b: amountB
98
+ });
99
+ }
100
+ function createSignedRemoveLiquidity(wallet, poolId, lpAmount) {
101
+ return buildAndSign(wallet, {
102
+ type: "remove_liquidity",
103
+ pool_id: poolId,
104
+ lp_amount: lpAmount
105
+ });
106
+ }
107
+ function createSignedStake(wallet, amount, fee = 1) {
108
+ return buildAndSign(wallet, { type: "stake", amount, fee });
109
+ }
110
+ function createSignedUnstake(wallet, amount, fee = 1) {
111
+ return buildAndSign(wallet, { type: "unstake", amount, fee });
112
+ }
113
+ function createSignedFaucetRequest(wallet) {
114
+ return buildAndSign(wallet, { type: "faucet" });
115
+ }
116
+ function createSignedBurn(wallet, amount, fee = 1, token = "XRGE") {
117
+ return buildAndSign(wallet, {
118
+ type: "transfer",
119
+ to: BURN_ADDRESS,
120
+ amount,
121
+ fee,
122
+ token
123
+ });
124
+ }
125
+ function createSignedNftCreateCollection(wallet, symbol, name, opts = {}) {
126
+ return buildAndSign(wallet, {
127
+ type: "nft_create_collection",
128
+ symbol,
129
+ name,
130
+ fee: 50,
131
+ maxSupply: opts.maxSupply,
132
+ royaltyBps: opts.royaltyBps,
133
+ image: opts.image,
134
+ description: opts.description
135
+ });
136
+ }
137
+ function createSignedNftMint(wallet, collectionId, name, opts = {}) {
138
+ return buildAndSign(wallet, {
139
+ type: "nft_mint",
140
+ collectionId,
141
+ name,
142
+ fee: 5,
143
+ metadataUri: opts.metadataUri,
144
+ attributes: opts.attributes
145
+ });
146
+ }
147
+ function createSignedNftBatchMint(wallet, collectionId, names, opts = {}) {
148
+ return buildAndSign(wallet, {
149
+ type: "nft_batch_mint",
150
+ collectionId,
151
+ names,
152
+ fee: 5 * names.length,
153
+ uris: opts.uris,
154
+ batchAttributes: opts.batchAttributes
155
+ });
156
+ }
157
+ function createSignedNftTransfer(wallet, collectionId, tokenId, to, salePrice) {
158
+ return buildAndSign(wallet, {
159
+ type: "nft_transfer",
160
+ collectionId,
161
+ tokenId,
162
+ to,
163
+ fee: 1,
164
+ salePrice
165
+ });
166
+ }
167
+ function createSignedNftBurn(wallet, collectionId, tokenId) {
168
+ return buildAndSign(wallet, {
169
+ type: "nft_burn",
170
+ collectionId,
171
+ tokenId,
172
+ fee: 0.1
173
+ });
174
+ }
175
+ function createSignedNftLock(wallet, collectionId, tokenId, locked) {
176
+ return buildAndSign(wallet, {
177
+ type: "nft_lock",
178
+ collectionId,
179
+ tokenId,
180
+ locked,
181
+ fee: 0.1
182
+ });
183
+ }
184
+ function createSignedNftFreezeCollection(wallet, collectionId, frozen) {
185
+ return buildAndSign(wallet, {
186
+ type: "nft_freeze_collection",
187
+ collectionId,
188
+ frozen,
189
+ fee: 0.1
190
+ });
191
+ }
192
+
193
+ // src/client.ts
194
+ var RougeChain = class {
195
+ constructor(baseUrl, options = {}) {
196
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
197
+ this.fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
198
+ this.headers = { "Content-Type": "application/json" };
199
+ if (options.apiKey) {
200
+ this.headers["X-API-Key"] = options.apiKey;
201
+ }
202
+ this.nft = new NftClient(this);
203
+ this.dex = new DexClient(this);
204
+ this.bridge = new BridgeClient(this);
205
+ }
206
+ // ===== Internal helpers =====
207
+ /** @internal */
208
+ async get(path) {
209
+ const res = await this.fetchFn(`${this.baseUrl}${path}`, {
210
+ headers: this.headers
211
+ });
212
+ if (!res.ok) {
213
+ throw new Error(`GET ${path} failed: ${res.status} ${res.statusText}`);
214
+ }
215
+ return res.json();
216
+ }
217
+ /** @internal */
218
+ async post(path, body) {
219
+ const res = await this.fetchFn(`${this.baseUrl}${path}`, {
220
+ method: "POST",
221
+ headers: this.headers,
222
+ body: JSON.stringify(body)
223
+ });
224
+ if (!res.ok) {
225
+ const text = await res.text().catch(() => "");
226
+ throw new Error(
227
+ `POST ${path} failed: ${res.status} ${res.statusText} ${text}`
228
+ );
229
+ }
230
+ return res.json();
231
+ }
232
+ /** @internal */
233
+ async submitTx(endpoint, signedTx) {
234
+ try {
235
+ const raw = await this.post(endpoint, signedTx);
236
+ const { success, error, ...rest } = raw;
237
+ return {
238
+ success,
239
+ error,
240
+ data: Object.keys(rest).length > 0 ? rest : void 0
241
+ };
242
+ } catch (e) {
243
+ return {
244
+ success: false,
245
+ error: e instanceof Error ? e.message : String(e)
246
+ };
247
+ }
248
+ }
249
+ // ===== Stats & Health =====
250
+ async getStats() {
251
+ return this.get("/stats");
252
+ }
253
+ async getHealth() {
254
+ return this.get("/health");
255
+ }
256
+ // ===== Blocks =====
257
+ async getBlocks(opts = {}) {
258
+ const q = opts.limit ? `?limit=${opts.limit}` : "";
259
+ const data = await this.get(`/blocks${q}`);
260
+ return data.blocks;
261
+ }
262
+ async getBlocksSummary(range = "24h") {
263
+ return this.get(`/blocks/summary?range=${range}`);
264
+ }
265
+ // ===== Balance =====
266
+ async getBalance(publicKey) {
267
+ return this.get(`/balance/${publicKey}`);
268
+ }
269
+ async getTokenBalance(publicKey, token) {
270
+ const data = await this.get(
271
+ `/balance/${publicKey}/${token}`
272
+ );
273
+ return data.balance;
274
+ }
275
+ // ===== Transactions =====
276
+ async getTransactions(opts = {}) {
277
+ const params = new URLSearchParams();
278
+ if (opts.limit) params.set("limit", String(opts.limit));
279
+ if (opts.offset) params.set("offset", String(opts.offset));
280
+ const q = params.toString();
281
+ return this.get(`/txs${q ? `?${q}` : ""}`);
282
+ }
283
+ // ===== Tokens =====
284
+ async getTokens() {
285
+ const data = await this.get(
286
+ "/tokens"
287
+ );
288
+ return data.tokens;
289
+ }
290
+ async getTokenMetadata(symbol) {
291
+ return this.get(`/token/${symbol}/metadata`);
292
+ }
293
+ async getTokenHolders(symbol) {
294
+ const data = await this.get(
295
+ `/token/${symbol}/holders`
296
+ );
297
+ return data.holders;
298
+ }
299
+ async getTokenTransactions(symbol) {
300
+ return this.get(`/token/${symbol}/transactions`);
301
+ }
302
+ // ===== Validators =====
303
+ async getValidators() {
304
+ const data = await this.get("/validators");
305
+ return data.validators;
306
+ }
307
+ async getValidatorStats() {
308
+ return this.get("/validators/stats");
309
+ }
310
+ async getFinality() {
311
+ return this.get("/finality");
312
+ }
313
+ // ===== Peers =====
314
+ async getPeers() {
315
+ const data = await this.get("/peers");
316
+ return data.peers;
317
+ }
318
+ // ===== Burned =====
319
+ async getBurnedTokens() {
320
+ return this.get("/burned");
321
+ }
322
+ // ===== Write operations =====
323
+ async transfer(wallet, params) {
324
+ const tx = createSignedTransfer(
325
+ wallet,
326
+ params.to,
327
+ params.amount,
328
+ params.fee,
329
+ params.token
330
+ );
331
+ return this.submitTx("/v2/transfer", tx);
332
+ }
333
+ async createToken(wallet, params) {
334
+ const tx = createSignedTokenCreation(
335
+ wallet,
336
+ params.name,
337
+ params.symbol,
338
+ params.totalSupply,
339
+ params.fee
340
+ );
341
+ return this.submitTx("/v2/token/create", tx);
342
+ }
343
+ async stake(wallet, params) {
344
+ const tx = createSignedStake(wallet, params.amount, params.fee);
345
+ return this.submitTx("/v2/stake", tx);
346
+ }
347
+ async unstake(wallet, params) {
348
+ const tx = createSignedUnstake(wallet, params.amount, params.fee);
349
+ return this.submitTx("/v2/unstake", tx);
350
+ }
351
+ async faucet(wallet) {
352
+ const tx = createSignedFaucetRequest(wallet);
353
+ return this.submitTx("/v2/faucet", tx);
354
+ }
355
+ async burn(wallet, amount, fee = 1, token = "XRGE") {
356
+ const tx = createSignedBurn(wallet, amount, fee, token);
357
+ return this.submitTx("/v2/transfer", tx);
358
+ }
359
+ async updateTokenMetadata(wallet, params) {
360
+ try {
361
+ const data = await this.post("/token/metadata/update", {
362
+ token_symbol: params.symbol,
363
+ from_public_key: wallet.publicKey,
364
+ from_private_key: wallet.privateKey,
365
+ image: params.image,
366
+ description: params.description,
367
+ website: params.website,
368
+ twitter: params.twitter,
369
+ discord: params.discord
370
+ });
371
+ return data;
372
+ } catch (e) {
373
+ return {
374
+ success: false,
375
+ error: e instanceof Error ? e.message : String(e)
376
+ };
377
+ }
378
+ }
379
+ };
380
+ var NftClient = class {
381
+ constructor(rc) {
382
+ this.rc = rc;
383
+ }
384
+ // Queries
385
+ async getCollections() {
386
+ const data = await this.rc.get(
387
+ "/nft/collections"
388
+ );
389
+ return data.collections;
390
+ }
391
+ async getCollection(collectionId) {
392
+ return this.rc.get(
393
+ `/nft/collection/${encodeURIComponent(collectionId)}`
394
+ );
395
+ }
396
+ async getTokens(collectionId, opts = {}) {
397
+ const params = new URLSearchParams();
398
+ if (opts.limit !== void 0) params.set("limit", String(opts.limit));
399
+ if (opts.offset !== void 0) params.set("offset", String(opts.offset));
400
+ const q = params.toString();
401
+ return this.rc.get(
402
+ `/nft/collection/${encodeURIComponent(collectionId)}/tokens${q ? `?${q}` : ""}`
403
+ );
404
+ }
405
+ async getToken(collectionId, tokenId) {
406
+ return this.rc.get(
407
+ `/nft/token/${encodeURIComponent(collectionId)}/${tokenId}`
408
+ );
409
+ }
410
+ async getByOwner(pubkey) {
411
+ const data = await this.rc.get(
412
+ `/nft/owner/${encodeURIComponent(pubkey)}`
413
+ );
414
+ return data.nfts;
415
+ }
416
+ // Write operations
417
+ async createCollection(wallet, params) {
418
+ const tx = createSignedNftCreateCollection(wallet, params.symbol, params.name, {
419
+ maxSupply: params.maxSupply,
420
+ royaltyBps: params.royaltyBps,
421
+ image: params.image,
422
+ description: params.description
423
+ });
424
+ return this.rc.submitTx("/v2/nft/collection/create", tx);
425
+ }
426
+ async mint(wallet, params) {
427
+ const tx = createSignedNftMint(wallet, params.collectionId, params.name, {
428
+ metadataUri: params.metadataUri,
429
+ attributes: params.attributes
430
+ });
431
+ return this.rc.submitTx("/v2/nft/mint", tx);
432
+ }
433
+ async batchMint(wallet, params) {
434
+ const tx = createSignedNftBatchMint(
435
+ wallet,
436
+ params.collectionId,
437
+ params.names,
438
+ { uris: params.uris, batchAttributes: params.batchAttributes }
439
+ );
440
+ return this.rc.submitTx("/v2/nft/batch-mint", tx);
441
+ }
442
+ async transfer(wallet, params) {
443
+ const tx = createSignedNftTransfer(
444
+ wallet,
445
+ params.collectionId,
446
+ params.tokenId,
447
+ params.to,
448
+ params.salePrice
449
+ );
450
+ return this.rc.submitTx("/v2/nft/transfer", tx);
451
+ }
452
+ async burn(wallet, params) {
453
+ const tx = createSignedNftBurn(wallet, params.collectionId, params.tokenId);
454
+ return this.rc.submitTx("/v2/nft/burn", tx);
455
+ }
456
+ async lock(wallet, params) {
457
+ const tx = createSignedNftLock(
458
+ wallet,
459
+ params.collectionId,
460
+ params.tokenId,
461
+ params.locked
462
+ );
463
+ return this.rc.submitTx("/v2/nft/lock", tx);
464
+ }
465
+ async freezeCollection(wallet, params) {
466
+ const tx = createSignedNftFreezeCollection(
467
+ wallet,
468
+ params.collectionId,
469
+ params.frozen
470
+ );
471
+ return this.rc.submitTx("/v2/nft/freeze-collection", tx);
472
+ }
473
+ };
474
+ var DexClient = class {
475
+ constructor(rc) {
476
+ this.rc = rc;
477
+ }
478
+ // Queries
479
+ async getPools() {
480
+ const data = await this.rc.get("/pools");
481
+ return data.pools;
482
+ }
483
+ async getPool(poolId) {
484
+ return this.rc.get(`/pool/${poolId}`);
485
+ }
486
+ async getPoolEvents(poolId) {
487
+ const data = await this.rc.get(
488
+ `/pool/${poolId}/events`
489
+ );
490
+ return data.events;
491
+ }
492
+ async getPoolPrices(poolId) {
493
+ return this.rc.get(`/pool/${poolId}/prices`);
494
+ }
495
+ async getPoolStats(poolId) {
496
+ return this.rc.get(`/pool/${poolId}/stats`);
497
+ }
498
+ async quote(params) {
499
+ return this.rc.post("/swap/quote", {
500
+ pool_id: params.poolId,
501
+ token_in: params.tokenIn,
502
+ amount_in: params.amountIn
503
+ });
504
+ }
505
+ // Write operations
506
+ async swap(wallet, params) {
507
+ const tx = createSignedSwap(
508
+ wallet,
509
+ params.tokenIn,
510
+ params.tokenOut,
511
+ params.amountIn,
512
+ params.minAmountOut
513
+ );
514
+ return this.rc.submitTx("/v2/swap/execute", tx);
515
+ }
516
+ async createPool(wallet, params) {
517
+ const tx = createSignedPoolCreation(
518
+ wallet,
519
+ params.tokenA,
520
+ params.tokenB,
521
+ params.amountA,
522
+ params.amountB
523
+ );
524
+ return this.rc.submitTx("/v2/pool/create", tx);
525
+ }
526
+ async addLiquidity(wallet, params) {
527
+ const tx = createSignedAddLiquidity(
528
+ wallet,
529
+ params.poolId,
530
+ params.amountA,
531
+ params.amountB
532
+ );
533
+ return this.rc.submitTx("/v2/pool/add-liquidity", tx);
534
+ }
535
+ async removeLiquidity(wallet, params) {
536
+ const tx = createSignedRemoveLiquidity(wallet, params.poolId, params.lpAmount);
537
+ return this.rc.submitTx("/v2/pool/remove-liquidity", tx);
538
+ }
539
+ };
540
+ var BridgeClient = class {
541
+ constructor(rc) {
542
+ this.rc = rc;
543
+ }
544
+ async getConfig() {
545
+ try {
546
+ const data = await this.rc.get("/bridge/config");
547
+ return {
548
+ enabled: data.enabled === true,
549
+ custodyAddress: data.custodyAddress,
550
+ chainId: data.chainId ?? 84532
551
+ };
552
+ } catch {
553
+ return { enabled: false, chainId: 84532 };
554
+ }
555
+ }
556
+ async getWithdrawals() {
557
+ const data = await this.rc.get(
558
+ "/bridge/withdrawals"
559
+ );
560
+ return data.withdrawals;
561
+ }
562
+ async withdraw(wallet, params) {
563
+ try {
564
+ const evm = params.evmAddress.startsWith("0x") ? params.evmAddress : `0x${params.evmAddress}`;
565
+ const data = await this.rc.post(
566
+ "/bridge/withdraw",
567
+ {
568
+ fromPrivateKey: wallet.privateKey,
569
+ fromPublicKey: wallet.publicKey,
570
+ amountUnits: params.amount,
571
+ evmAddress: evm,
572
+ fee: params.fee
573
+ }
574
+ );
575
+ return {
576
+ success: data.success === true,
577
+ error: data.error,
578
+ data
579
+ };
580
+ } catch (e) {
581
+ return {
582
+ success: false,
583
+ error: e instanceof Error ? e.message : String(e)
584
+ };
585
+ }
586
+ }
587
+ async claim(params) {
588
+ try {
589
+ const data = await this.rc.post(
590
+ "/bridge/claim",
591
+ {
592
+ evmTxHash: params.evmTxHash.startsWith("0x") ? params.evmTxHash : `0x${params.evmTxHash}`,
593
+ evmAddress: params.evmAddress.startsWith("0x") ? params.evmAddress : `0x${params.evmAddress}`,
594
+ evmSignature: params.evmSignature,
595
+ recipientRougechainPubkey: params.recipientPubkey
596
+ }
597
+ );
598
+ return {
599
+ success: data.success === true,
600
+ error: data.error,
601
+ data
602
+ };
603
+ } catch (e) {
604
+ return {
605
+ success: false,
606
+ error: e instanceof Error ? e.message : String(e)
607
+ };
608
+ }
609
+ }
610
+ };
611
+ var Wallet = class _Wallet {
612
+ constructor(publicKey, privateKey) {
613
+ this.publicKey = publicKey;
614
+ this.privateKey = privateKey;
615
+ }
616
+ /**
617
+ * Generate a new ML-DSA-65 keypair.
618
+ * Uses crypto.getRandomValues for secure randomness.
619
+ */
620
+ static generate() {
621
+ const keypair = mlDsa_js.ml_dsa65.keygen();
622
+ return new _Wallet(
623
+ bytesToHex(keypair.publicKey),
624
+ bytesToHex(keypair.secretKey)
625
+ );
626
+ }
627
+ /**
628
+ * Restore a wallet from existing hex-encoded keys.
629
+ */
630
+ static fromKeys(publicKey, privateKey) {
631
+ return new _Wallet(publicKey, privateKey);
632
+ }
633
+ /**
634
+ * Export keys as a plain object (for serialization/storage).
635
+ */
636
+ toJSON() {
637
+ return { publicKey: this.publicKey, privateKey: this.privateKey };
638
+ }
639
+ /**
640
+ * Verify that the keypair is valid by signing and verifying a test message.
641
+ */
642
+ verify() {
643
+ try {
644
+ const msg = new TextEncoder().encode("rougechain-verify");
645
+ const sig = mlDsa_js.ml_dsa65.sign(msg, hexToBytes(this.privateKey));
646
+ return mlDsa_js.ml_dsa65.verify(sig, msg, hexToBytes(this.publicKey));
647
+ } catch {
648
+ return false;
649
+ }
650
+ }
651
+ };
652
+
653
+ exports.BURN_ADDRESS = BURN_ADDRESS;
654
+ exports.RougeChain = RougeChain;
655
+ exports.Wallet = Wallet;
656
+ exports.bytesToHex = bytesToHex;
657
+ exports.generateNonce = generateNonce;
658
+ exports.hexToBytes = hexToBytes;
659
+ exports.isBurnAddress = isBurnAddress;
660
+ exports.serializePayload = serializePayload;
661
+ exports.signTransaction = signTransaction;
662
+ exports.verifyTransaction = verifyTransaction;
663
+ //# sourceMappingURL=index.cjs.map
664
+ //# sourceMappingURL=index.cjs.map