@mania-labs/mania-sdk 1.0.0 → 1.0.1

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.
@@ -0,0 +1,328 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { parseEther } from 'viem';
3
+ import {
4
+ formatEthValue,
5
+ formatTokenAmount,
6
+ parseEthValue,
7
+ calculateWithSlippage,
8
+ calculateMigrationProgress,
9
+ formatPrice,
10
+ formatMarketCap,
11
+ isValidAddress,
12
+ truncateAddress,
13
+ bpsToPercent,
14
+ percentToBps,
15
+ calculatePriceImpact,
16
+ sleep,
17
+ withRetry,
18
+ } from '../../utils.js';
19
+
20
+ describe('formatEthValue', () => {
21
+ it('should format ETH value with default 4 decimals', () => {
22
+ const wei = parseEther('1.23456789');
23
+ expect(formatEthValue(wei)).toBe('1.2346');
24
+ });
25
+
26
+ it('should format ETH value with custom decimals', () => {
27
+ const wei = parseEther('1.23456789');
28
+ expect(formatEthValue(wei, 2)).toBe('1.23');
29
+ });
30
+
31
+ it('should handle zero value', () => {
32
+ expect(formatEthValue(0n)).toBe('0.0000');
33
+ });
34
+
35
+ it('should handle small amounts', () => {
36
+ const wei = parseEther('0.0001');
37
+ expect(formatEthValue(wei, 4)).toBe('0.0001');
38
+ });
39
+
40
+ it('should handle large amounts', () => {
41
+ const wei = parseEther('1000000');
42
+ expect(formatEthValue(wei)).toBe('1000000.0000');
43
+ });
44
+ });
45
+
46
+ describe('formatTokenAmount', () => {
47
+ it('should format billions with B suffix', () => {
48
+ const amount = parseEther('1500000000'); // 1.5B
49
+ expect(formatTokenAmount(amount)).toBe('1.50B');
50
+ });
51
+
52
+ it('should format millions with M suffix', () => {
53
+ const amount = parseEther('1500000'); // 1.5M
54
+ expect(formatTokenAmount(amount)).toBe('1.50M');
55
+ });
56
+
57
+ it('should format thousands with K suffix', () => {
58
+ const amount = parseEther('1500'); // 1.5K
59
+ expect(formatTokenAmount(amount)).toBe('1.50K');
60
+ });
61
+
62
+ it('should format small amounts without suffix', () => {
63
+ const amount = parseEther('500');
64
+ expect(formatTokenAmount(amount)).toBe('500.00');
65
+ });
66
+
67
+ it('should use custom decimals', () => {
68
+ const amount = parseEther('1234567890');
69
+ expect(formatTokenAmount(amount, 3)).toBe('1.235B');
70
+ });
71
+ });
72
+
73
+ describe('parseEthValue', () => {
74
+ it('should parse decimal string to wei', () => {
75
+ expect(parseEthValue('1.5')).toBe(parseEther('1.5'));
76
+ });
77
+
78
+ it('should parse integer string to wei', () => {
79
+ expect(parseEthValue('10')).toBe(parseEther('10'));
80
+ });
81
+
82
+ it('should parse zero', () => {
83
+ expect(parseEthValue('0')).toBe(0n);
84
+ });
85
+ });
86
+
87
+ describe('calculateWithSlippage', () => {
88
+ it('should apply 1% slippage (100 bps)', () => {
89
+ const amount = parseEther('1');
90
+ const result = calculateWithSlippage(amount, 100);
91
+ expect(result).toBe(parseEther('0.99'));
92
+ });
93
+
94
+ it('should apply 5% slippage (500 bps)', () => {
95
+ const amount = parseEther('1');
96
+ const result = calculateWithSlippage(amount, 500);
97
+ expect(result).toBe(parseEther('0.95'));
98
+ });
99
+
100
+ it('should handle 0% slippage', () => {
101
+ const amount = parseEther('1');
102
+ const result = calculateWithSlippage(amount, 0);
103
+ expect(result).toBe(amount);
104
+ });
105
+
106
+ it('should handle 10% slippage (1000 bps)', () => {
107
+ const amount = parseEther('1');
108
+ const result = calculateWithSlippage(amount, 1000);
109
+ expect(result).toBe(parseEther('0.9'));
110
+ });
111
+ });
112
+
113
+ describe('calculateMigrationProgress', () => {
114
+ it('should return 0 for zero reserves', () => {
115
+ expect(calculateMigrationProgress(0n)).toBe(0);
116
+ });
117
+
118
+ it('should return 50 for half-filled (2 ETH)', () => {
119
+ const twoEth = parseEther('2');
120
+ expect(calculateMigrationProgress(twoEth)).toBe(50);
121
+ });
122
+
123
+ it('should return 100 for threshold reached (4 ETH)', () => {
124
+ const fourEth = parseEther('4');
125
+ expect(calculateMigrationProgress(fourEth)).toBe(100);
126
+ });
127
+
128
+ it('should return 100 for over threshold', () => {
129
+ const fiveEth = parseEther('5');
130
+ expect(calculateMigrationProgress(fiveEth)).toBe(100);
131
+ });
132
+
133
+ it('should return 25 for 1 ETH', () => {
134
+ const oneEth = parseEther('1');
135
+ expect(calculateMigrationProgress(oneEth)).toBe(25);
136
+ });
137
+ });
138
+
139
+ describe('formatPrice', () => {
140
+ it('should format very small prices with exponential notation', () => {
141
+ const price = 100000000000n; // 0.0000001 ETH
142
+ const result = formatPrice(price);
143
+ expect(result).toMatch(/e-/);
144
+ });
145
+
146
+ it('should format small prices with 8 decimals', () => {
147
+ const price = 50000000000000n; // 0.00005 ETH
148
+ const result = formatPrice(price);
149
+ expect(result).toBe('0.00005000');
150
+ });
151
+
152
+ it('should format medium prices with 6 decimals', () => {
153
+ const price = 5000000000000000n; // 0.005 ETH
154
+ const result = formatPrice(price);
155
+ expect(result).toBe('0.005000');
156
+ });
157
+
158
+ it('should format normal prices with 4 decimals', () => {
159
+ const price = 50000000000000000n; // 0.05 ETH
160
+ const result = formatPrice(price);
161
+ expect(result).toBe('0.0500');
162
+ });
163
+ });
164
+
165
+ describe('formatMarketCap', () => {
166
+ it('should format large market caps with K suffix', () => {
167
+ const marketCap = parseEther('1500');
168
+ expect(formatMarketCap(marketCap)).toBe('1.50K ETH');
169
+ });
170
+
171
+ it('should format small market caps without suffix', () => {
172
+ const marketCap = parseEther('500');
173
+ expect(formatMarketCap(marketCap)).toBe('500.00 ETH');
174
+ });
175
+
176
+ it('should format zero market cap', () => {
177
+ expect(formatMarketCap(0n)).toBe('0.00 ETH');
178
+ });
179
+ });
180
+
181
+ describe('isValidAddress', () => {
182
+ it('should return true for valid address', () => {
183
+ expect(isValidAddress('0x1234567890abcdef1234567890abcdef12345678')).toBe(true);
184
+ });
185
+
186
+ it('should return true for checksummed address', () => {
187
+ expect(isValidAddress('0xABCDEF1234567890abcdef1234567890ABCDEF12')).toBe(true);
188
+ });
189
+
190
+ it('should return false for invalid hex', () => {
191
+ expect(isValidAddress('0xGHIJ567890abcdef1234567890abcdef12345678')).toBe(false);
192
+ });
193
+
194
+ it('should return false for wrong length', () => {
195
+ expect(isValidAddress('0x1234')).toBe(false);
196
+ });
197
+
198
+ it('should return false for missing prefix', () => {
199
+ expect(isValidAddress('1234567890abcdef1234567890abcdef12345678')).toBe(false);
200
+ });
201
+ });
202
+
203
+ describe('truncateAddress', () => {
204
+ const address = '0x1234567890abcdef1234567890abcdef12345678' as `0x${string}`;
205
+
206
+ it('should truncate with default 4 chars', () => {
207
+ expect(truncateAddress(address)).toBe('0x1234...5678');
208
+ });
209
+
210
+ it('should truncate with custom length', () => {
211
+ expect(truncateAddress(address, 6)).toBe('0x123456...345678');
212
+ });
213
+
214
+ it('should handle 2 chars', () => {
215
+ expect(truncateAddress(address, 2)).toBe('0x12...78');
216
+ });
217
+ });
218
+
219
+ describe('bpsToPercent', () => {
220
+ it('should convert 100 bps to 1%', () => {
221
+ expect(bpsToPercent(100)).toBe(1);
222
+ });
223
+
224
+ it('should convert 50 bps to 0.5%', () => {
225
+ expect(bpsToPercent(50)).toBe(0.5);
226
+ });
227
+
228
+ it('should convert 1000 bps to 10%', () => {
229
+ expect(bpsToPercent(1000)).toBe(10);
230
+ });
231
+
232
+ it('should handle bigint input', () => {
233
+ expect(bpsToPercent(100n)).toBe(1);
234
+ });
235
+ });
236
+
237
+ describe('percentToBps', () => {
238
+ it('should convert 1% to 100 bps', () => {
239
+ expect(percentToBps(1)).toBe(100);
240
+ });
241
+
242
+ it('should convert 0.5% to 50 bps', () => {
243
+ expect(percentToBps(0.5)).toBe(50);
244
+ });
245
+
246
+ it('should convert 10% to 1000 bps', () => {
247
+ expect(percentToBps(10)).toBe(1000);
248
+ });
249
+
250
+ it('should round fractional bps', () => {
251
+ expect(percentToBps(1.234)).toBe(123);
252
+ });
253
+ });
254
+
255
+ describe('calculatePriceImpact', () => {
256
+ it('should calculate positive price impact', () => {
257
+ const current = parseEther('0.01');
258
+ const newPrice = parseEther('0.011');
259
+ expect(calculatePriceImpact(current, newPrice)).toBe(10);
260
+ });
261
+
262
+ it('should calculate negative price impact', () => {
263
+ const current = parseEther('0.01');
264
+ const newPrice = parseEther('0.009');
265
+ expect(calculatePriceImpact(current, newPrice)).toBe(-10);
266
+ });
267
+
268
+ it('should return 0 for zero current price', () => {
269
+ expect(calculatePriceImpact(0n, parseEther('0.01'))).toBe(0);
270
+ });
271
+
272
+ it('should return 0 for same price', () => {
273
+ const price = parseEther('0.01');
274
+ expect(calculatePriceImpact(price, price)).toBe(0);
275
+ });
276
+ });
277
+
278
+ describe('sleep', () => {
279
+ it('should delay for specified milliseconds', async () => {
280
+ const start = Date.now();
281
+ await sleep(50);
282
+ const elapsed = Date.now() - start;
283
+ expect(elapsed).toBeGreaterThanOrEqual(45);
284
+ expect(elapsed).toBeLessThan(100);
285
+ });
286
+ });
287
+
288
+ describe('withRetry', () => {
289
+ it('should succeed on first try', async () => {
290
+ const fn = vi.fn().mockResolvedValue('success');
291
+ const result = await withRetry(fn, 3, 10);
292
+ expect(result).toBe('success');
293
+ expect(fn).toHaveBeenCalledTimes(1);
294
+ });
295
+
296
+ it('should retry on failure and eventually succeed', async () => {
297
+ const fn = vi
298
+ .fn()
299
+ .mockRejectedValueOnce(new Error('fail'))
300
+ .mockRejectedValueOnce(new Error('fail'))
301
+ .mockResolvedValue('success');
302
+
303
+ const result = await withRetry(fn, 3, 10);
304
+ expect(result).toBe('success');
305
+ expect(fn).toHaveBeenCalledTimes(3);
306
+ });
307
+
308
+ it('should throw after max retries exhausted', async () => {
309
+ const fn = vi.fn().mockRejectedValue(new Error('always fails'));
310
+
311
+ await expect(withRetry(fn, 3, 10)).rejects.toThrow('always fails');
312
+ expect(fn).toHaveBeenCalledTimes(3);
313
+ });
314
+
315
+ it('should use exponential backoff', async () => {
316
+ const fn = vi
317
+ .fn()
318
+ .mockRejectedValueOnce(new Error('fail'))
319
+ .mockResolvedValue('success');
320
+
321
+ const start = Date.now();
322
+ await withRetry(fn, 3, 50);
323
+ const elapsed = Date.now() - start;
324
+
325
+ // First retry should be at 50ms (base delay)
326
+ expect(elapsed).toBeGreaterThanOrEqual(45);
327
+ });
328
+ });
package/src/constants.ts CHANGED
@@ -52,8 +52,8 @@ export interface ChainConfig {
52
52
  */
53
53
  export const CHAIN_CONFIGS: Record<number, ChainConfig> = {
54
54
  // Mega Eth Testnet
55
- 6543: {
56
- chainId: 6543,
55
+ 6343: {
56
+ chainId: 6343,
57
57
  name: "Mega Eth Testnet",
58
58
  factoryAddress: "0x0d593cE47EBA2d15a77ddbAc41BdE6d03CC9241b" as Address,
59
59
  wethAddress: "0x4200000000000000000000000000000000000006" as Address,
package/src/mania.ts CHANGED
@@ -317,12 +317,13 @@ export class ManiaSDK {
317
317
  const wallet = this.getConnectedWallet();
318
318
 
319
319
  const hash = await wallet.writeContract({
320
- chain: null,
321
- account: null,
320
+ chain: wallet.chain,
321
+ account: wallet.account!,
322
322
  address: this.factoryAddress,
323
323
  abi: MANIA_FACTORY_ABI,
324
324
  functionName: "create",
325
325
  args: [params.name, params.symbol, params.uri, params.creator],
326
+ gas: 300_000_000n,
326
327
  });
327
328
 
328
329
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
@@ -353,13 +354,14 @@ export class ManiaSDK {
353
354
  const wallet = this.getConnectedWallet();
354
355
 
355
356
  const hash = await wallet.writeContract({
356
- chain: null,
357
- account: null,
357
+ chain: wallet.chain,
358
+ account: wallet.account!,
358
359
  address: this.factoryAddress,
359
360
  abi: MANIA_FACTORY_ABI,
360
361
  functionName: "createAndBuy",
361
362
  args: [params.name, params.symbol, params.uri, params.creator, params.minTokensOut],
362
363
  value: params.buyAmountEth,
364
+ gas: 300_000_000n,
363
365
  });
364
366
 
365
367
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
@@ -392,13 +394,14 @@ export class ManiaSDK {
392
394
  const recipient = params.recipient ?? wallet.account!.address;
393
395
 
394
396
  const hash = await wallet.writeContract({
395
- chain: null,
396
- account: null,
397
+ chain: wallet.chain,
398
+ account: wallet.account!,
397
399
  address: this.factoryAddress,
398
400
  abi: MANIA_FACTORY_ABI,
399
401
  functionName: "buy",
400
402
  args: [params.token, params.minTokensOut, recipient],
401
403
  value: params.amountEth,
404
+ gas: 300_000_000n,
402
405
  });
403
406
 
404
407
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
@@ -441,12 +444,13 @@ export class ManiaSDK {
441
444
  const wallet = this.getConnectedWallet();
442
445
 
443
446
  const hash = await wallet.writeContract({
444
- chain: null,
445
- account: null,
447
+ chain: wallet.chain,
448
+ account: wallet.account!,
446
449
  address: this.factoryAddress,
447
450
  abi: MANIA_FACTORY_ABI,
448
451
  functionName: "sell",
449
452
  args: [params.token, params.amountTokens, params.minEthOut],
453
+ gas: 300_000_000n,
450
454
  });
451
455
 
452
456
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
@@ -491,13 +495,14 @@ export class ManiaSDK {
491
495
  const globalState = await this.getGlobalState();
492
496
 
493
497
  const hash = await wallet.writeContract({
494
- chain: null,
495
- account: null,
498
+ chain: wallet.chain,
499
+ account: wallet.account!,
496
500
  address: this.factoryAddress,
497
501
  abi: MANIA_FACTORY_ABI,
498
502
  functionName: "migrate",
499
503
  args: [params.token],
500
504
  value: globalState.poolMigrationFee,
505
+ gas: 300_000_000n,
501
506
  });
502
507
 
503
508
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash });