@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.
- package/README.md +260 -220
- 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
|
-
- [
|
|
20
|
-
- [
|
|
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
|
-
|
|
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
|
|
82
|
-
|
|
|
83
|
-
| `dev`
|
|
84
|
-
| `staging`
|
|
85
|
-
| `prelive`
|
|
86
|
-
| `production`
|
|
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
|
|
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
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
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
|
-
|
|
893
|
-
|
|
894
|
-
|
|
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
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1098
|
-
|
|
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
|
```
|