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