@optimex-xyz/market-maker-sdk 0.8.1 → 0.8.5

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 (2) hide show
  1. package/README.md +260 -220
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # PMM API Integration Documentation
2
2
 
3
- > **CHANGELOG (v0.8.0)**:
3
+ > **CHANGELOG (v0.8.0)**:
4
+ >
4
5
  > - **Breaking Changes:**
5
6
  > - Update to get router contract from protocol fetcher
6
7
  > - Use consistent trade_id across all protocol
@@ -15,25 +16,64 @@ A comprehensive guide for implementing Private Market Makers (PMMs) in the cross
15
16
 
16
17
  ## Table of Contents
17
18
 
18
- - [PMM API Integration Documentation](#pmm-api-integration-documentation)
19
- - [1. Overview](#1-overview)
20
- - [2. Quick Start](#2-quick-start)
19
+ - [PMM API Integration Documentation](#pmm-api-integration-documentation)
20
+ - [Table of Contents](#table-of-contents)
21
+ - [1. Overview](#1-overview)
22
+ - [1.1. Integration Flow](#11-integration-flow)
23
+ - [2. Quick Start](#2-quick-start)
24
+ - [2.1. API Environments](#21-api-environments)
21
25
  - [3. PMM Backend APIs](#3-pmm-backend-apis)
22
26
  - [3.1. Endpoint: `/indicative-quote`](#31-endpoint-indicative-quote)
27
+ - [Description](#description)
28
+ - [Request Parameters](#request-parameters)
29
+ - [Example Request](#example-request)
30
+ - [Expected Response](#expected-response)
23
31
  - [3.2. Endpoint: `/commitment-quote`](#32-endpoint-commitment-quote)
32
+ - [Description](#description-1)
33
+ - [Request Parameters](#request-parameters-1)
34
+ - [Example Request](#example-request-1)
35
+ - [Expected Response](#expected-response-1)
24
36
  - [3.3. Endpoint: `/liquidation-quote`](#33-endpoint-liquidation-quote)
37
+ - [Description](#description-2)
38
+ - [Request Parameters](#request-parameters-2)
39
+ - [Example Request](#example-request-2)
40
+ - [Expected Response](#expected-response-2)
25
41
  - [3.4. Endpoint: `/settlement-signature`](#34-endpoint-settlement-signature)
42
+ - [Description](#description-3)
43
+ - [Request Parameters](#request-parameters-3)
44
+ - [Example Request](#example-request-3)
45
+ - [Expected Response](#expected-response-3)
26
46
  - [3.5. Endpoint: `/ack-settlement`](#35-endpoint-ack-settlement)
27
- - [3.6. Endpoint: `/signal-payment`](#36-endpoint-signal-payment)
47
+ - [Description](#description-4)
48
+ - [Request Parameters](#request-parameters-4)
49
+ - [Example Request](#example-request-4)
50
+ - [Expected Response](#expected-response-4)
51
+ - [3.6. Endpoint: `/signal-payment`](#36-endpoint-signal-payment)
52
+ - [Description](#description-5)
53
+ - [Request Parameters](#request-parameters-5)
54
+ - [Example Request](#example-request-5)
55
+ - [Expected Response](#expected-response-5)
28
56
  - [4. Solver API Endpoints for PMMs](#4-solver-api-endpoints-for-pmms)
29
57
  - [4.1. Endpoint: `/v1/market-maker/tokens`](#41-endpoint-v1market-makertokens)
58
+ - [Description](#description-6)
59
+ - [Request Parameters](#request-parameters-6)
60
+ - [Example Request](#example-request-6)
61
+ - [Expected Response](#expected-response-6)
30
62
  - [4.2. Endpoint: `/v1/market-maker/submit-settlement-tx`](#42-endpoint-v1market-makersubmit-settlement-tx)
63
+ - [Description](#description-7)
64
+ - [Request Parameters](#request-parameters-7)
65
+ - [Example Request](#example-request-7)
66
+ - [Expected Response](#expected-response-7)
67
+ - [Notes](#notes)
31
68
  - [4.3. Endpoint: `/v1/market-maker/trades/:tradeId`](#43-endpoint-v1market-makertradestradeid)
69
+ - [Description](#description-8)
70
+ - [Request Parameters](#request-parameters-8)
71
+ - [Example Request](#example-request-8)
72
+ - [Expected Response](#expected-response-8)
32
73
  - [5. PMM Making Payment](#5-pmm-making-payment)
33
74
  - [5.1. EVM](#51-evm)
34
75
  - [5.2. Bitcoin](#52-bitcoin)
35
76
 
36
-
37
77
  ## 1. Overview
38
78
 
39
79
  The PMM integration with Optimex involves bidirectional API communication:
@@ -43,7 +83,6 @@ The PMM integration with Optimex involves bidirectional API communication:
43
83
 
44
84
  ### 1.1. Integration Flow
45
85
 
46
-
47
86
  ```mermaid
48
87
  sequenceDiagram
49
88
  participant User
@@ -78,22 +117,24 @@ sequenceDiagram
78
117
 
79
118
  ### 2.1. API Environments
80
119
 
81
- | Environment | Description |
82
- | ---------------- | -------------------------------------------------------------------- |
83
- | `dev` | internal environment with test networks and development services |
84
- | `staging` | Staging environment with test networks and staging services |
85
- | `prelive` | Pre production environment with mainnet networks for testing before release |
86
- | `production` | Production environment with mainnet networks and production services |
120
+ | Environment | Description |
121
+ | ------------ | --------------------------------------------------------------------------- |
122
+ | `dev` | internal environment with test networks and development services |
123
+ | `staging` | Staging environment with test networks and staging services |
124
+ | `prelive` | Pre production environment with mainnet networks for testing before release |
125
+ | `production` | Production environment with mainnet networks and production services |
87
126
 
88
127
  <details>
89
128
  <summary><strong>Staging Contracts</strong></summary>
90
129
 
91
130
  **Optimex L2 Testnet**
131
+
92
132
  - **Signer**: [0xA89F5060B810F3b6027D7663880c43ee77A865C7](https://scan-testnet.optimex.xyz/address/0xA89F5060B810F3b6027D7663880c43ee77A865C7)
93
133
  - **Router**: [0x31C88ebd9E430455487b6a5c8971e8eF63e97ED4](https://scan-testnet.optimex.xyz/address/0x31C88ebd9E430455487b6a5c8971e8eF63e97ED4)
94
134
  - **ProtocolFetcherProxy**: [0x7c07151ca4DFd93F352Ab9B132A95866697c38c2](https://scan-testnet.optimex.xyz/address/0x7c07151ca4DFd93F352Ab9B132A95866697c38c2)
95
135
 
96
136
  **Ethereum Sepolia**
137
+
97
138
  - **Payment**: [0x7387DcCfE2f1D5F80b4ECDF91eF58541517e90D2](https://sepolia.etherscan.io/address/0x7387DcCfE2f1D5F80b4ECDF91eF58541517e90D2)
98
139
  - **ETHVault**: [0x17aD543010fc8E8065b85E203839C0CBEcdfC851](https://sepolia.etherscan.io/address/0x17aD543010fc8E8065b85E203839C0CBEcdfC851)
99
140
  - **WETHVault**: [0x673Ac1489457F43F04403940cE425ae19a9D639B](https://sepolia.etherscan.io/address/0x673Ac1489457F43F04403940cE425ae19a9D639B)
@@ -105,13 +146,14 @@ sequenceDiagram
105
146
  <details>
106
147
  <summary><strong>Production/Prelive Contracts</strong></summary>
107
148
 
108
-
109
149
  **Optimex L2 Mainnet**
150
+
110
151
  - **Signer**: [0xCF9786F123F1071023dB8049808C223e94c384be](https://scan.optimex.xyz/address/0xCF9786F123F1071023dB8049808C223e94c384be)
111
152
  - **Router**: [0x1e878cCa765a8aAFEBecCa672c767441b4859634](https://scan.optimex.xyz/address/0x1e878cCa765a8aAFEBecCa672c767441b4859634)
112
153
  - **ProtocolFetcherProxy**: [0xFDEd4CEf9aE1E03D0BeF161262a266c1c157a32b](https://scan.optimex.xyz/address/0xFDEd4CEf9aE1E03D0BeF161262a266c1c157a32b)
113
154
 
114
155
  **Ethereum Mainnet**
156
+
115
157
  - **Payment**: [0x0A497AC4261E37FA4062762C23Cf3cB642C839b8](https://etherscan.io/address/0x0A497AC4261E37FA4062762C23Cf3cB642C839b8)
116
158
  - **ETHVault**: [0xF7fedF4A250157010807E6eA60258E3B768149Ff](https://etherscan.io/address/0xF7fedF4A250157010807E6eA60258E3B768149Ff)
117
159
  - **WETHVault**: [0xaD3f379AaED8Eca895209Af446F2e34f07145dbC](https://etherscan.io/address/0xaD3f379AaED8Eca895209Af446F2e34f07145dbC)
@@ -178,52 +220,53 @@ GET /indicative-quote?from_token_id=ETH&to_token_id=BTC&amount=10000000000000000
178
220
  ```js
179
221
  async function getIndicativeQuote(req, res) {
180
222
  try {
181
- const { from_token_id, to_token_id, amount, session_id } = req.query;
223
+ const { from_token_id, to_token_id, amount, session_id } = req.query
182
224
 
183
225
  // Generate a session ID if not provided
184
- const sessionId = session_id || generateSessionId();
226
+ const sessionId = session_id || generateSessionId()
185
227
 
186
228
  // Fetch token information from Solver API
187
- const tokensResponse = await fetch('https://api.solver.example/v1/market-maker/tokens');
188
- const tokensData = await tokensResponse.json();
229
+ const tokensResponse = await fetch('https://api.solver.example/v1/market-maker/tokens')
230
+ const tokensData = await tokensResponse.json()
189
231
 
190
232
  // Find the from token and to token
191
- const fromToken = tokensData.data.tokens.find(token => token.token_id === from_token_id);
192
- const toToken = tokensData.data.tokens.find(token => token.token_id === to_token_id);
233
+ const fromToken = tokensData.data.tokens.find((token) => token.token_id === from_token_id)
234
+ const toToken = tokensData.data.tokens.find((token) => token.token_id === to_token_id)
193
235
 
194
236
  if (!fromToken || !toToken) {
195
237
  return res.status(400).json({
196
238
  session_id: sessionId,
197
239
  pmm_receiving_address: '',
198
240
  indicative_quote: '0',
199
- error: 'Token not found'
200
- });
241
+ error: 'Token not found',
242
+ })
201
243
  }
202
244
 
203
245
  // Calculate the quote (implementation specific to your PMM)
204
246
  // Note: Treat amount as BigInt
205
- const amountBigInt = BigInt(amount);
206
- const quote = calculateQuote(fromToken, toToken, amountBigInt);
247
+ const amountBigInt = BigInt(amount)
248
+ const quote = calculateQuote(fromToken, toToken, amountBigInt)
207
249
 
208
250
  // Get the receiving address for this token pair
209
- const pmmReceivingAddress = getPMMReceivingAddress(fromToken.network_id);
251
+ const pmmReceivingAddress = getPMMReceivingAddress(fromToken.network_id)
210
252
 
211
253
  return res.status(200).json({
212
254
  session_id: sessionId,
213
255
  pmm_receiving_address: pmmReceivingAddress,
214
256
  indicative_quote: quote.toString(),
215
- error: ''
216
- });
257
+ error: '',
258
+ })
217
259
  } catch (error) {
218
260
  return res.status(500).json({
219
261
  session_id: req.query.session_id || '',
220
262
  pmm_receiving_address: '',
221
263
  indicative_quote: '0',
222
- error: error.message
223
- });
264
+ error: error.message,
265
+ })
224
266
  }
225
267
  }
226
268
  ```
269
+
227
270
  </details>
228
271
 
229
272
  ### 3.2. Endpoint: `/commitment-quote`
@@ -288,39 +331,39 @@ async function getCommitmentQuote(req, res) {
288
331
  user_deposit_tx,
289
332
  user_deposit_vault,
290
333
  trade_deadline,
291
- script_deadline
292
- } = req.query;
334
+ script_deadline,
335
+ } = req.query
293
336
 
294
337
  // Validate the session exists
295
- const session = await sessionRepository.findById(session_id);
338
+ const session = await sessionRepository.findById(session_id)
296
339
  if (!session) {
297
340
  return res.status(400).json({
298
341
  trade_id,
299
342
  commitment_quote: '0',
300
- error: 'Session not found'
301
- });
343
+ error: 'Session not found',
344
+ })
302
345
  }
303
346
 
304
347
  // Fetch token information from Solver API
305
- const tokensResponse = await fetch('https://api.solver.example/v1/market-maker/tokens');
306
- const tokensData = await tokensResponse.json();
348
+ const tokensResponse = await fetch('https://api.solver.example/v1/market-maker/tokens')
349
+ const tokensData = await tokensResponse.json()
307
350
 
308
351
  // Find the from token and to token
309
- const fromToken = tokensData.data.tokens.find(token => token.token_id === from_token_id);
310
- const toToken = tokensData.data.tokens.find(token => token.token_id === to_token_id);
352
+ const fromToken = tokensData.data.tokens.find((token) => token.token_id === from_token_id)
353
+ const toToken = tokensData.data.tokens.find((token) => token.token_id === to_token_id)
311
354
 
312
355
  if (!fromToken || !toToken) {
313
356
  return res.status(400).json({
314
357
  trade_id,
315
358
  commitment_quote: '0',
316
- error: 'Token not found'
317
- });
359
+ error: 'Token not found',
360
+ })
318
361
  }
319
362
 
320
363
  // Calculate the final quote (implementation specific to your PMM)
321
364
  // Note: Treat numeric values as BigInt
322
- const amountBigInt = BigInt(amount);
323
- const quote = calculateFinalQuote(fromToken, toToken, amountBigInt, trade_deadline);
365
+ const amountBigInt = BigInt(amount)
366
+ const quote = calculateFinalQuote(fromToken, toToken, amountBigInt, trade_deadline)
324
367
 
325
368
  // Store the trade in the database
326
369
  await tradeRepository.create({
@@ -335,23 +378,24 @@ async function getCommitmentQuote(req, res) {
335
378
  userDepositVault: user_deposit_vault,
336
379
  tradeDeadline: trade_deadline,
337
380
  scriptDeadline: script_deadline,
338
- commitmentQuote: quote.toString()
339
- });
381
+ commitmentQuote: quote.toString(),
382
+ })
340
383
 
341
384
  return res.status(200).json({
342
385
  trade_id,
343
386
  commitment_quote: quote.toString(),
344
- error: ''
345
- });
387
+ error: '',
388
+ })
346
389
  } catch (error) {
347
390
  return res.status(500).json({
348
391
  trade_id: req.query.trade_id || '',
349
392
  commitment_quote: '0',
350
- error: error.message
351
- });
393
+ error: error.message,
394
+ })
352
395
  }
353
396
  }
354
397
  ```
398
+
355
399
  </details>
356
400
 
357
401
  ### 3.3. Endpoint: `/liquidation-quote`
@@ -417,39 +461,39 @@ async function getLiquidationQuote(req, res) {
417
461
  user_deposit_tx,
418
462
  user_deposit_vault,
419
463
  trade_deadline,
420
- script_deadline
421
- } = req.query;
464
+ script_deadline,
465
+ } = req.query
422
466
 
423
467
  // Validate the session exists
424
- const session = await sessionRepository.findById(session_id);
468
+ const session = await sessionRepository.findById(session_id)
425
469
  if (!session) {
426
470
  return res.status(400).json({
427
471
  trade_id,
428
472
  liquidation_quote: '0',
429
- error: 'Session not found'
430
- });
473
+ error: 'Session not found',
474
+ })
431
475
  }
432
476
 
433
477
  // Fetch token information from Solver API
434
- const tokensResponse = await fetch('https://api.solver.example/v1/market-maker/tokens');
435
- const tokensData = await tokensResponse.json();
478
+ const tokensResponse = await fetch('https://api.solver.example/v1/market-maker/tokens')
479
+ const tokensData = await tokensResponse.json()
436
480
 
437
481
  // Find the from token and to token
438
- const fromToken = tokensData.data.tokens.find(token => token.token_id === from_token_id);
439
- const toToken = tokensData.data.tokens.find(token => token.token_id === to_token_id);
482
+ const fromToken = tokensData.data.tokens.find((token) => token.token_id === from_token_id)
483
+ const toToken = tokensData.data.tokens.find((token) => token.token_id === to_token_id)
440
484
 
441
485
  if (!fromToken || !toToken) {
442
486
  return res.status(400).json({
443
487
  trade_id,
444
488
  liquidation_quote: '0',
445
- error: 'Token not found'
446
- });
489
+ error: 'Token not found',
490
+ })
447
491
  }
448
492
 
449
493
  // Calculate the firm liquidation quote (implementation specific to your PMM)
450
494
  // Note: Treat numeric values as BigInt
451
- const amountBigInt = BigInt(amount);
452
- const quote = calculateLiquidationQuote(fromToken, toToken, amountBigInt, trade_deadline);
495
+ const amountBigInt = BigInt(amount)
496
+ const quote = calculateLiquidationQuote(fromToken, toToken, amountBigInt, trade_deadline)
453
497
 
454
498
  // Store the trade in the database
455
499
  await tradeRepository.create({
@@ -464,23 +508,24 @@ async function getLiquidationQuote(req, res) {
464
508
  userDepositVault: user_deposit_vault,
465
509
  tradeDeadline: trade_deadline,
466
510
  scriptDeadline: script_deadline,
467
- liquidationQuote: quote.toString()
468
- });
511
+ liquidationQuote: quote.toString(),
512
+ })
469
513
 
470
514
  return res.status(200).json({
471
515
  trade_id,
472
516
  liquidation_quote: quote.toString(),
473
- error: ''
474
- });
517
+ error: '',
518
+ })
475
519
  } catch (error) {
476
520
  return res.status(500).json({
477
521
  trade_id: req.query.trade_id || '',
478
522
  liquidation_quote: '0',
479
- error: error.message
480
- });
523
+ error: error.message,
524
+ })
481
525
  }
482
526
  }
483
527
  ```
528
+
484
529
  </details>
485
530
 
486
531
  ### 3.4. Endpoint: `/settlement-signature`
@@ -529,35 +574,35 @@ GET /settlement-signature?trade_id=0x3d09b8eb94466bffa126aeda68c8c0f330633a7d005
529
574
  ```js
530
575
  async function getSettlementSignature(req, res) {
531
576
  try {
532
- const { trade_id, committed_quote, trade_deadline, script_deadline } = req.query;
577
+ const { trade_id, committed_quote, trade_deadline, script_deadline } = req.query
533
578
 
534
579
  // Fetch the trade from the database
535
- const trade = await tradeRepository.findById(trade_id);
580
+ const trade = await tradeRepository.findById(trade_id)
536
581
  if (!trade) {
537
582
  return res.status(400).json({
538
583
  trade_id,
539
584
  signature: '',
540
585
  deadline: 0,
541
- error: 'Trade not found'
542
- });
586
+ error: 'Trade not found',
587
+ })
543
588
  }
544
589
 
545
590
  // Fetch trade details from Solver API
546
- const tradeDetailsResponse = await fetch(`https://api.solver.example/v1/market-maker/trades/${trade_id}`);
547
- const tradeDetails = await tradeDetailsResponse.json();
591
+ const tradeDetailsResponse = await fetch(`https://api.solver.example/v1/market-maker/trades/${trade_id}`)
592
+ const tradeDetails = await tradeDetailsResponse.json()
548
593
 
549
594
  // Calculate a deadline (30 minutes from now)
550
- const deadline = Math.floor(Date.now() / 1000) + 1800;
595
+ const deadline = Math.floor(Date.now() / 1000) + 1800
551
596
 
552
597
  // Get PMM data
553
- const pmmId = process.env.PMM_ID; // Your PMM ID
598
+ const pmmId = process.env.PMM_ID // Your PMM ID
554
599
 
555
600
  // Get the presigns and trade data from tradeDetails
556
- const { from_token, to_token } = tradeDetails.data;
601
+ const { from_token, to_token } = tradeDetails.data
557
602
 
558
603
  // Create a commitment info hash
559
604
  // Note: Treat numeric values as BigInt
560
- const committedQuoteBigInt = BigInt(committed_quote);
605
+ const committedQuoteBigInt = BigInt(committed_quote)
561
606
  const commitInfoHash = createCommitInfoHash(
562
607
  pmmId,
563
608
  trade.pmmReceivingAddress,
@@ -565,28 +610,29 @@ async function getSettlementSignature(req, res) {
565
610
  to_token.address,
566
611
  committedQuoteBigInt,
567
612
  deadline
568
- );
613
+ )
569
614
 
570
615
  // Sign the commitment with your private key
571
- const privateKey = process.env.PMM_PRIVATE_KEY;
572
- const signature = signMessage(privateKey, trade_id, commitInfoHash);
616
+ const privateKey = process.env.PMM_PRIVATE_KEY
617
+ const signature = signMessage(privateKey, trade_id, commitInfoHash)
573
618
 
574
619
  return res.status(200).json({
575
620
  trade_id,
576
621
  signature,
577
622
  deadline,
578
- error: ''
579
- });
623
+ error: '',
624
+ })
580
625
  } catch (error) {
581
626
  return res.status(500).json({
582
627
  trade_id: req.query.trade_id || '',
583
628
  signature: '',
584
629
  deadline: 0,
585
- error: error.message
586
- });
630
+ error: error.message,
631
+ })
587
632
  }
588
633
  }
589
634
  ```
635
+
590
636
  </details>
591
637
 
592
638
  ### 3.5. Endpoint: `/ack-settlement`
@@ -636,39 +682,40 @@ trade_id=0x024be4dae899989e0c3d9b4459e5811613bcd04016dc56529f16a19d2a7724c0&trad
636
682
  ```js
637
683
  async function ackSettlement(req, res) {
638
684
  try {
639
- const { trade_id, trade_deadline, script_deadline, chosen } = req.body;
685
+ const { trade_id, trade_deadline, script_deadline, chosen } = req.body
640
686
 
641
687
  // Fetch the trade from the database
642
- const trade = await tradeRepository.findById(trade_id);
688
+ const trade = await tradeRepository.findById(trade_id)
643
689
  if (!trade) {
644
690
  return res.status(400).json({
645
691
  trade_id,
646
692
  status: 'error',
647
- error: 'Trade not found'
648
- });
693
+ error: 'Trade not found',
694
+ })
649
695
  }
650
696
 
651
697
  // Update trade status based on whether it was chosen
652
698
  await tradeRepository.update(trade_id, {
653
699
  chosen: chosen === 'true',
654
700
  tradeDeadline: trade_deadline,
655
- scriptDeadline: script_deadline
656
- });
701
+ scriptDeadline: script_deadline,
702
+ })
657
703
 
658
704
  return res.status(200).json({
659
705
  trade_id,
660
706
  status: 'acknowledged',
661
- error: ''
662
- });
707
+ error: '',
708
+ })
663
709
  } catch (error) {
664
710
  return res.status(500).json({
665
711
  trade_id: req.body.trade_id || '',
666
712
  status: 'error',
667
- error: error.message
668
- });
713
+ error: error.message,
714
+ })
669
715
  }
670
716
  }
671
717
  ```
718
+
672
719
  </details>
673
720
 
674
721
  ### 3.6. Endpoint: `/signal-payment`
@@ -718,45 +765,46 @@ trade_id=0x3bfe2fc4889a98a39b31b348e7b212ea3f2bea63fd1ea2e0c8ba326433677328&tota
718
765
  ```js
719
766
  async function signalPayment(req, res) {
720
767
  try {
721
- const { trade_id, total_fee_amount, trade_deadline, script_deadline } = req.body;
768
+ const { trade_id, total_fee_amount, trade_deadline, script_deadline } = req.body
722
769
 
723
770
  // Fetch the trade from the database
724
- const trade = await tradeRepository.findById(trade_id);
771
+ const trade = await tradeRepository.findById(trade_id)
725
772
  if (!trade) {
726
773
  return res.status(400).json({
727
774
  trade_id,
728
775
  status: 'error',
729
- error: 'Trade not found'
730
- });
776
+ error: 'Trade not found',
777
+ })
731
778
  }
732
779
 
733
780
  // Update trade with fee amount
734
781
  await tradeRepository.update(trade_id, {
735
782
  totalFeeAmount: total_fee_amount,
736
783
  tradeDeadline: trade_deadline,
737
- scriptDeadline: script_deadline
738
- });
784
+ scriptDeadline: script_deadline,
785
+ })
739
786
 
740
787
  // Queue the payment task
741
788
  await paymentQueue.add({
742
789
  tradeId: trade_id,
743
- totalFeeAmount: total_fee_amount
744
- });
790
+ totalFeeAmount: total_fee_amount,
791
+ })
745
792
 
746
793
  return res.status(200).json({
747
794
  trade_id,
748
795
  status: 'acknowledged',
749
- error: ''
750
- });
796
+ error: '',
797
+ })
751
798
  } catch (error) {
752
799
  return res.status(500).json({
753
800
  trade_id: req.body.trade_id || '',
754
801
  status: 'error',
755
- error: error.message
756
- });
802
+ error: error.message,
803
+ })
757
804
  }
758
805
  }
759
806
  ```
807
+
760
808
  </details>
761
809
 
762
810
  ## 4. Solver API Endpoints for PMMs
@@ -791,79 +839,81 @@ GET /v1/market-maker/tokens
791
839
 
792
840
  ```json
793
841
  {
794
- "data": {
795
- "supported_networks": [
796
- {
797
- "network_id": "bitcoin_testnet",
798
- "name": "Bitcoin Testnet",
799
- "symbol": "tBTC",
800
- "type": "BTC",
801
- "logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/btc_network.svg"
802
- },
803
- {
804
- "network_id": "ethereum_sepolia",
805
- "name": "Ethereum Sepolia",
806
- "symbol": "ETH",
807
- "type": "EVM",
808
- "logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/eth_network.svg"
809
- }
810
- ],
811
- "tokens": [
812
- {
813
- "id": 2,
814
- "network_id": "bitcoin_testnet",
815
- "token_id": "tBTC",
816
- "network_name": "Bitcoin Testnet",
817
- "network_symbol": "tBTC",
818
- "network_type": "BTC",
819
- "token_name": "Bitcoin Testnet",
820
- "token_symbol": "tBTC",
821
- "token_address": "native",
822
- "token_decimals": 8,
823
- "token_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/tbtc.svg",
824
- "network_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/btc_network.svg",
825
- "active": true,
826
- "created_at": "2024-10-28T07:24:33.179Z",
827
- "updated_at": "2024-11-07T04:40:46.454Z"
828
- },
829
- {
830
- "id": 11,
831
- "network_id": "ethereum_sepolia",
832
- "token_id": "ETH",
833
- "network_name": "Ethereum Sepolia",
834
- "network_symbol": "ETH",
835
- "network_type": "EVM",
836
- "token_name": "Ethereum Sepolia",
837
- "token_symbol": "ETH",
838
- "token_address": "native",
839
- "token_decimals": 18,
840
- "token_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/eth.svg",
841
- "network_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/eth_network.svg",
842
- "active": true,
843
- "created_at": "2024-11-22T08:36:59.175Z",
844
- "updated_at": "2024-11-22T08:36:59.175Z"
845
- }
846
- ],
847
- "pairs": [
848
- {
849
- "from_token_id": "ETH",
850
- "to_token_id": "tBTC",
851
- "is_active": true
852
- },
853
- {
854
- "from_token_id": "tBTC",
855
- "to_token_id": "ETH",
856
- "is_active": true
857
- }
858
- ]
859
- }
842
+ "data": {
843
+ "supported_networks": [
844
+ {
845
+ "network_id": "bitcoin_testnet",
846
+ "name": "Bitcoin Testnet",
847
+ "symbol": "tBTC",
848
+ "type": "BTC",
849
+ "logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/btc_network.svg"
850
+ },
851
+ {
852
+ "network_id": "ethereum_sepolia",
853
+ "name": "Ethereum Sepolia",
854
+ "symbol": "ETH",
855
+ "type": "EVM",
856
+ "logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/eth_network.svg"
857
+ }
858
+ ],
859
+ "tokens": [
860
+ {
861
+ "id": 2,
862
+ "network_id": "bitcoin_testnet",
863
+ "token_id": "tBTC",
864
+ "network_name": "Bitcoin Testnet",
865
+ "network_symbol": "tBTC",
866
+ "network_type": "BTC",
867
+ "token_name": "Bitcoin Testnet",
868
+ "token_symbol": "tBTC",
869
+ "token_address": "native",
870
+ "token_decimals": 8,
871
+ "token_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/tbtc.svg",
872
+ "network_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/btc_network.svg",
873
+ "active": true,
874
+ "created_at": "2024-10-28T07:24:33.179Z",
875
+ "updated_at": "2024-11-07T04:40:46.454Z"
876
+ },
877
+ {
878
+ "id": 11,
879
+ "network_id": "ethereum_sepolia",
880
+ "token_id": "ETH",
881
+ "network_name": "Ethereum Sepolia",
882
+ "network_symbol": "ETH",
883
+ "network_type": "EVM",
884
+ "token_name": "Ethereum Sepolia",
885
+ "token_symbol": "ETH",
886
+ "token_address": "native",
887
+ "token_decimals": 18,
888
+ "token_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/eth.svg",
889
+ "network_logo_uri": "https://storage.googleapis.com/Optimex-static-35291d79/images/tokens/eth_network.svg",
890
+ "active": true,
891
+ "created_at": "2024-11-22T08:36:59.175Z",
892
+ "updated_at": "2024-11-22T08:36:59.175Z"
893
+ }
894
+ ],
895
+ "pairs": [
896
+ {
897
+ "from_token_id": "ETH",
898
+ "to_token_id": "tBTC",
899
+ "is_active": true
900
+ },
901
+ {
902
+ "from_token_id": "tBTC",
903
+ "to_token_id": "ETH",
904
+ "is_active": true
905
+ }
906
+ ]
907
+ }
860
908
  }
861
909
  ```
910
+
862
911
  </details>
863
912
 
864
913
  ### 4.2. Endpoint: `/v1/market-maker/submit-settlement-tx`
865
914
 
866
915
  #### Description
916
+
867
917
  Allows the PMM to submit settlement transaction hashes for trades. This endpoint is essential for completing the trade settlement process and must be called after making payments.
868
918
 
869
919
  #### Request Parameters
@@ -889,17 +939,18 @@ Allows the PMM to submit settlement transaction hashes for trades. This endpoint
889
939
  - `signed_at` (integer): UNIX timestamp (seconds) when you signed this submission.
890
940
  - `settlement_tx` (string): Should be hex format with a `0x` prefix
891
941
 
892
- - **For EVM Chains:**
893
- - Use the transaction hash directly without additional encoding
894
- - Example: `settlement_tx`: [0x7a87d2c423e13533b5ae0ecc5af900a7b697048103f4f6e32d19edde5e707355](https://etherscan.io/tx/0x7a87d2c423e13533b5ae0ecc5af900a7b697048103f4f6e32d19edde5e707355)
942
+ - **For EVM Chains:**
943
+
944
+ - Use the transaction hash directly without additional encoding
945
+ - Example: `settlement_tx`: [0x7a87d2c423e13533b5ae0ecc5af900a7b697048103f4f6e32d19edde5e707355](https://etherscan.io/tx/0x7a87d2c423e13533b5ae0ecc5af900a7b697048103f4f6e32d19edde5e707355)
895
946
 
896
- - **For Bitcoin or Solana:**
897
- - Must encode raw_tx string using the `l2Encode` function
898
- - Example raw_tx string: `3d83c7846d6e5b04279175a9592705a15373f3029b866d5224cc0744489fe403`
899
- - After encoding
900
- ```
901
- "settlement_tx": "0x33643833633738343664366535623034323739313735613935393237303561313533373366333032396238363664353232346363303734343438396665343033"
902
- ```
947
+ - **For Bitcoin or Solana:**
948
+ - Must encode raw_tx string using the `l2Encode` function
949
+ - Example raw_tx string: `3d83c7846d6e5b04279175a9592705a15373f3029b866d5224cc0744489fe403`
950
+ - After encoding
951
+ ```
952
+ "settlement_tx": "0x33643833633738343664366535623034323739313735613935393237303561313533373366333032396238363664353232346363303734343438396665343033"
953
+ ```
903
954
 
904
955
  <details>
905
956
  <summary><strong>Bitcoin l2Encode</strong></summary>
@@ -919,6 +970,7 @@ export const l2Encode = (info: string) => {
919
970
  return ensureHexPrefix(ethers.hexlify(toUtf8Bytes(info)))
920
971
  }
921
972
  ```
973
+
922
974
  </details>
923
975
 
924
976
  #### Example Request
@@ -1035,9 +1087,7 @@ GET /v1/market-maker/trades/0xfc24b9bc1299b50896027cb4c85d041c911e062147ffaf7ae9
1035
1087
  "user_deposit_tx": "0x202186375a3b8d55de4d8d1afb7f6a5bec8978cef3b705e6cb379729d03b16c7",
1036
1088
  "deposit_vault": "0xf7fedf4a250157010807e6ea60258e3b768149ff",
1037
1089
  "payment_bundle": {
1038
- "trade_ids": [
1039
- "0xfc24b9bc1299b50896027cb4c85d041c911e062147ffaf7ae9c7e51b670086c2"
1040
- ],
1090
+ "trade_ids": ["0xfc24b9bc1299b50896027cb4c85d041c911e062147ffaf7ae9c7e51b670086c2"],
1041
1091
  "settlement_tx": "3d83c7846d6e5b04279175a9592705a15373f3029b866d5224cc0744489fe403",
1042
1092
  "signature": "0x479a5a89e7a871026b60307351ea650fc667890b25d3d02df7ed2e93f94db90d7c3f8dbd823220896b8ad49b13a90851199236e82a644ffbe99e53503929fe151b",
1043
1093
  "start_index": 0,
@@ -1054,6 +1104,7 @@ GET /v1/market-maker/trades/0xfc24b9bc1299b50896027cb4c85d041c911e062147ffaf7ae9
1054
1104
  }
1055
1105
  }
1056
1106
  ```
1107
+
1057
1108
  </details>
1058
1109
 
1059
1110
  ## 5. PMM Making Payment
@@ -1063,53 +1114,47 @@ GET /v1/market-maker/trades/0xfc24b9bc1299b50896027cb4c85d041c911e062147ffaf7ae9
1063
1114
  In case the target chain is EVM-based, the transaction should emit the event from the `l1 payment contract` with the correct values for pmmAmountOut and protocolFee.
1064
1115
 
1065
1116
  ```js
1066
- const { ethers } = require('ethers');
1117
+ const { ethers } = require('ethers')
1067
1118
 
1068
1119
  async function makeEVMPayment(tradeId, toAddress, amount, token, protocolFeeAmount) {
1069
1120
  try {
1070
1121
  // Get the private key from your secure storage
1071
- const privateKey = process.env.PMM_EVM_PRIVATE_KEY;
1122
+ const privateKey = process.env.PMM_EVM_PRIVATE_KEY
1072
1123
 
1073
1124
  // Set up the provider and signer
1074
- const rpcUrl = getRpcUrlForNetwork(token.networkId);
1075
- const provider = new ethers.JsonRpcProvider(rpcUrl);
1076
- const signer = new ethers.Wallet(privateKey, provider);
1125
+ const rpcUrl = getRpcUrlForNetwork(token.networkId)
1126
+ const provider = new ethers.JsonRpcProvider(rpcUrl)
1127
+ const signer = new ethers.Wallet(privateKey, provider)
1077
1128
 
1078
1129
  // Get the payment contract address
1079
- const paymentAddress = getPaymentAddressForNetwork(token.networkId);
1130
+ const paymentAddress = getPaymentAddressForNetwork(token.networkId)
1080
1131
 
1081
1132
  // Create the contract instance
1082
1133
  const paymentAbi = [
1083
1134
  // ABI for the payment contract
1084
- "function payment(bytes32 tradeId, address token, address recipient, uint256 amount, uint256 feeAmount, uint256 deadline) payable returns (bool)"
1085
- ];
1086
- const paymentContract = new ethers.Contract(paymentAddress, paymentAbi, signer);
1135
+ 'function payment(bytes32 tradeId, address token, address recipient, uint256 amount, uint256 feeAmount, uint256 deadline) payable returns (bool)',
1136
+ ]
1137
+ const paymentContract = new ethers.Contract(paymentAddress, paymentAbi, signer)
1087
1138
 
1088
1139
  // Calculate the deadline (30 minutes from now)
1089
- const deadline = Math.floor(Date.now() / 1000) + 30 * 60;
1140
+ const deadline = Math.floor(Date.now() / 1000) + 30 * 60
1090
1141
 
1091
1142
  // If the token is native, we need to set the value
1092
- const value = token.tokenAddress === 'native' ? amount : 0;
1093
- const tokenAddress = token.tokenAddress === 'native' ? ethers.ZeroAddress : token.tokenAddress;
1143
+ const value = token.tokenAddress === 'native' ? amount : 0
1144
+ const tokenAddress = token.tokenAddress === 'native' ? ethers.ZeroAddress : token.tokenAddress
1094
1145
 
1095
1146
  // Submit the transaction
1096
- const tx = await paymentContract.payment(
1097
- tradeId,
1098
- tokenAddress,
1099
- toAddress,
1100
- amount,
1101
- protocolFeeAmount,
1102
- deadline,
1103
- { value }
1104
- );
1147
+ const tx = await paymentContract.payment(tradeId, tokenAddress, toAddress, amount, protocolFeeAmount, deadline, {
1148
+ value,
1149
+ })
1105
1150
 
1106
- console.log(`Transfer transaction sent: ${tx.hash}`);
1151
+ console.log(`Transfer transaction sent: ${tx.hash}`)
1107
1152
 
1108
1153
  // Return the transaction hash with the 0x prefix
1109
- return `0x${tx.hash.replace(/^0x/, '')}`;
1154
+ return `0x${tx.hash.replace(/^0x/, '')}`
1110
1155
  } catch (error) {
1111
- console.error('EVM payment error:', error);
1112
- throw error;
1156
+ console.error('EVM payment error:', error)
1157
+ throw error
1113
1158
  }
1114
1159
  }
1115
1160
  ```
@@ -1119,11 +1164,12 @@ async function makeEVMPayment(tradeId, toAddress, amount, token, protocolFeeAmou
1119
1164
  In case the target chain is Bitcoin, the transaction should have at least N + 1 outputs, with the first N outputs being the settlement UTXOs for trades, and one of them being the change UTXO for the user with the correct amount. The output N + 1 is the OP_RETURN output with the hash of tradeIds.
1120
1165
 
1121
1166
  ```js
1167
+ import { getTradeIdsHash } from '@optimex-xyz/market-maker-sdk'
1168
+
1169
+ import axios from 'axios'
1122
1170
  import * as bitcoin from 'bitcoinjs-lib'
1123
1171
  import { ECPairFactory } from 'ecpair'
1124
1172
  import * as ecc from 'tiny-secp256k1'
1125
- import axios from 'axios'
1126
- import { getTradeIdsHash } from '@optimex-xyz/market-maker-sdk'
1127
1173
 
1128
1174
  async function makeBitcoinPayment(params) {
1129
1175
  const { toAddress, amount, token, tradeId } = params
@@ -1180,9 +1226,7 @@ async function makeBitcoinPayment(params) {
1180
1226
 
1181
1227
  // Check if we have enough balance
1182
1228
  if (totalInput < amount) {
1183
- throw new Error(
1184
- `Insufficient balance. Need ${amount} satoshis, but only have ${totalInput} satoshis`
1185
- )
1229
+ throw new Error(`Insufficient balance. Need ${amount} satoshis, but only have ${totalInput} satoshis`)
1186
1230
  }
1187
1231
 
1188
1232
  // Get fee rate
@@ -1207,10 +1251,7 @@ async function makeBitcoinPayment(params) {
1207
1251
  // Add OP_RETURN output with trade ID hash
1208
1252
  const tradeIdsHash = getTradeIdsHash([tradeId])
1209
1253
  psbt.addOutput({
1210
- script: bitcoin.script.compile([
1211
- bitcoin.opcodes.OP_RETURN,
1212
- Buffer.from(tradeIdsHash.slice(2), 'hex')
1213
- ]),
1254
+ script: bitcoin.script.compile([bitcoin.opcodes.OP_RETURN, Buffer.from(tradeIdsHash.slice(2), 'hex')]),
1214
1255
  value: 0n,
1215
1256
  })
1216
1257
 
@@ -1237,5 +1278,4 @@ async function makeBitcoinPayment(params) {
1237
1278
 
1238
1279
  return response.data // Transaction ID
1239
1280
  }
1240
-
1241
1281
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optimex-xyz/market-maker-sdk",
3
- "version": "0.8.1",
3
+ "version": "0.8.5",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"