@teleportdao/bitcoin 1.0.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.
Files changed (72) hide show
  1. package/dist/bitcoin-base.d.ts +56 -0
  2. package/dist/bitcoin-base.d.ts.map +1 -0
  3. package/dist/bitcoin-base.js +138 -0
  4. package/dist/bitcoin-base.js.map +1 -0
  5. package/dist/bitcoin-interface-utils.d.ts +18 -0
  6. package/dist/bitcoin-interface-utils.d.ts.map +1 -0
  7. package/dist/bitcoin-interface-utils.js +31 -0
  8. package/dist/bitcoin-interface-utils.js.map +1 -0
  9. package/dist/bitcoin-interface.d.ts +154 -0
  10. package/dist/bitcoin-interface.d.ts.map +1 -0
  11. package/dist/bitcoin-interface.js +248 -0
  12. package/dist/bitcoin-interface.js.map +1 -0
  13. package/dist/bitcoin-utils.d.ts +70 -0
  14. package/dist/bitcoin-utils.d.ts.map +1 -0
  15. package/dist/bitcoin-utils.js +388 -0
  16. package/dist/bitcoin-utils.js.map +1 -0
  17. package/dist/helper/burn-request-helper.d.ts +7 -0
  18. package/dist/helper/burn-request-helper.d.ts.map +1 -0
  19. package/dist/helper/burn-request-helper.js +26 -0
  20. package/dist/helper/burn-request-helper.js.map +1 -0
  21. package/dist/helper/teleport-request-helper.d.ts +45 -0
  22. package/dist/helper/teleport-request-helper.d.ts.map +1 -0
  23. package/dist/helper/teleport-request-helper.js +141 -0
  24. package/dist/helper/teleport-request-helper.js.map +1 -0
  25. package/dist/index.d.ts +7 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +15 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/sign/sign-transaction.d.ts +8 -0
  30. package/dist/sign/sign-transaction.d.ts.map +1 -0
  31. package/dist/sign/sign-transaction.js +41 -0
  32. package/dist/sign/sign-transaction.js.map +1 -0
  33. package/dist/teleport-dao-payments.d.ts +92 -0
  34. package/dist/teleport-dao-payments.d.ts.map +1 -0
  35. package/dist/teleport-dao-payments.js +203 -0
  36. package/dist/teleport-dao-payments.js.map +1 -0
  37. package/dist/transaction-builder/bitcoin-transaction-builder.d.ts +12 -0
  38. package/dist/transaction-builder/bitcoin-transaction-builder.d.ts.map +1 -0
  39. package/dist/transaction-builder/bitcoin-transaction-builder.js +50 -0
  40. package/dist/transaction-builder/bitcoin-transaction-builder.js.map +1 -0
  41. package/dist/transaction-builder/transaction-builder-common.d.ts +80 -0
  42. package/dist/transaction-builder/transaction-builder-common.d.ts.map +1 -0
  43. package/dist/transaction-builder/transaction-builder-common.js +170 -0
  44. package/dist/transaction-builder/transaction-builder-common.js.map +1 -0
  45. package/dist/transaction-builder/transaction-builder.d.ts +19 -0
  46. package/dist/transaction-builder/transaction-builder.d.ts.map +1 -0
  47. package/dist/transaction-builder/transaction-builder.js +130 -0
  48. package/dist/transaction-builder/transaction-builder.js.map +1 -0
  49. package/dist/utils/networks.d.ts +36 -0
  50. package/dist/utils/networks.d.ts.map +1 -0
  51. package/dist/utils/networks.js +30 -0
  52. package/dist/utils/networks.js.map +1 -0
  53. package/dist/utils/tools.d.ts +13 -0
  54. package/dist/utils/tools.d.ts.map +1 -0
  55. package/dist/utils/tools.js +65 -0
  56. package/dist/utils/tools.js.map +1 -0
  57. package/package.json +34 -0
  58. package/src/bitcoin-base.js +174 -0
  59. package/src/bitcoin-interface-utils.js +42 -0
  60. package/src/bitcoin-interface.js +267 -0
  61. package/src/bitcoin-utils.js +443 -0
  62. package/src/helper/burn-request-helper.js +27 -0
  63. package/src/helper/teleport-request-helper.js +162 -0
  64. package/src/index.js +15 -0
  65. package/src/sign/sign-transaction.js +36 -0
  66. package/src/teleport-dao-payments.js +276 -0
  67. package/src/transaction-builder/bitcoin-transaction-builder.js +37 -0
  68. package/src/transaction-builder/transaction-builder-common.js +228 -0
  69. package/src/transaction-builder/transaction-builder.js +135 -0
  70. package/src/utils/networks.js +31 -0
  71. package/src/utils/tools.js +72 -0
  72. package/tsconfig.json +9 -0
@@ -0,0 +1,443 @@
1
+ const bip39 = require("bip39")
2
+ let varUnit = require("varuint-bitcoin")
3
+ const fastRoot = require("merkle-lib/fastRoot")
4
+ const merkle = require("merkle-lib")
5
+ const merkleProof = require("merkle-lib/proof")
6
+ const bitcoin = require("bitcoinjs-lib")
7
+ const networks = require("./utils/networks")
8
+
9
+ function generateMnemonic() {
10
+ const mnemonic = bip39.generateMnemonic(256)
11
+ return mnemonic
12
+ }
13
+
14
+ function parseRawTransaction(rawTransaction) {
15
+ const size = {
16
+ version: 4,
17
+ flag: 2,
18
+ tx: 32,
19
+ index: 4,
20
+ sequence: 4,
21
+ amount: 8,
22
+ }
23
+
24
+ let offset = 0
25
+ let version = rawTransaction.slice(offset, size.version * 2)
26
+ offset += size.version * 2
27
+ let flag = rawTransaction.slice(offset, offset + size.flag * 2)
28
+ offset = flag === "0001" ? offset + size.flag * 2 : offset // * 0x0001 is flag in segwit transactions
29
+
30
+ let inputsStartIndex = offset
31
+
32
+ let numberOfInputs = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
33
+ let noiSize = varUnit.encodingLength(numberOfInputs)
34
+ offset += noiSize * 2
35
+
36
+ for (let i = 0; i < numberOfInputs; i += 1) {
37
+ offset += size.tx * 2
38
+ offset += size.index * 2
39
+ let sigLength = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
40
+ let sigLengthSize = varUnit.encodingLength(sigLength)
41
+ offset += sigLengthSize * 2
42
+ offset += sigLength * 2
43
+ offset += size.sequence * 2
44
+ }
45
+ let inputLastIndex = offset
46
+ let outputStartIndex = offset
47
+
48
+ let numberOfOutputs = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
49
+ let nooSize = varUnit.encodingLength(numberOfOutputs)
50
+ offset += nooSize * 2
51
+
52
+ for (let i = 0; i < numberOfOutputs; i += 1) {
53
+ offset += size.amount * 2
54
+ let unlockSigLength = varUnit.decode(Buffer.from(rawTransaction.slice(offset), "hex"))
55
+ let unlockSigLengthSize = varUnit.encodingLength(unlockSigLength)
56
+ offset += unlockSigLengthSize * 2
57
+ offset += unlockSigLength * 2
58
+ }
59
+ let outputLastIndex = offset
60
+
61
+ version = `0x${version}`
62
+ flag = `0x${flag}`
63
+ const vin = `0x${rawTransaction.slice(inputsStartIndex, inputLastIndex)}`
64
+ const vout = `0x${rawTransaction.slice(outputStartIndex, outputLastIndex)}`
65
+ let witness = `0x${rawTransaction.slice(outputLastIndex, rawTransaction.length - 8)}`
66
+ let locktime = `0x${rawTransaction.slice(rawTransaction.length - 8, rawTransaction.length)}`
67
+ return { version, flag, vin, vout, witness, locktime }
68
+ }
69
+
70
+ function reverseBytes(hexInput) {
71
+ return Buffer.from(hexInput, "hex").reverse().toString("hex")
72
+ }
73
+
74
+ function getAddressType(address, network) {
75
+ if (address.startsWith(network.bech32)) {
76
+ // todo : check length - it could be p2wsh
77
+ return "p2wpkh"
78
+ }
79
+ let base58Data = bitcoin.address.fromBase58Check(address)
80
+ if (base58Data.version === Number(network.scriptHash)) {
81
+ return "p2sh"
82
+ }
83
+ if (base58Data.version === Number(network.pubKeyHash)) {
84
+ return "p2pkh"
85
+ }
86
+
87
+ throw new Error("invalid address")
88
+ }
89
+
90
+ function createAddressObjectByHash({ addressType, hash }, network) {
91
+ let addressObject
92
+ switch (addressType) {
93
+ case "p2pkh":
94
+ addressObject = bitcoin.payments.p2pkh({
95
+ hash,
96
+ network,
97
+ })
98
+ break
99
+ case "p2wpkh":
100
+ addressObject = bitcoin.payments.p2wpkh({
101
+ hash,
102
+ network,
103
+ })
104
+ break
105
+ case "p2sh":
106
+ addressObject = bitcoin.payments.p2sh({
107
+ hash,
108
+ network,
109
+ })
110
+ break
111
+ default:
112
+ throw new Error("address type is incorrect")
113
+ }
114
+ return addressObject
115
+ }
116
+
117
+ function createAddressObjectByScript({ addressType, script }, network) {
118
+ let addressObject
119
+ switch (addressType) {
120
+ case "p2pkh":
121
+ addressObject = bitcoin.payments.p2pkh({
122
+ output: script,
123
+ network,
124
+ })
125
+ break
126
+ case "p2wpkh":
127
+ addressObject = bitcoin.payments.p2wpkh({
128
+ output: script,
129
+ network,
130
+ })
131
+ break
132
+ case "p2sh":
133
+ addressObject = bitcoin.payments.p2sh({
134
+ output: script,
135
+ network,
136
+ })
137
+ break
138
+ default:
139
+ throw new Error("address type is incorrect")
140
+ }
141
+ return addressObject
142
+ }
143
+
144
+ function createAddressObjectByPublicKey({ addressType, publicKey }, network) {
145
+ let addressObject
146
+
147
+ switch (addressType) {
148
+ case "p2pkh":
149
+ addressObject = bitcoin.payments.p2pkh({
150
+ pubkey: publicKey,
151
+ network,
152
+ })
153
+ break
154
+ case "p2wpkh":
155
+ addressObject = bitcoin.payments.p2wpkh({
156
+ pubkey: publicKey,
157
+ network,
158
+ })
159
+ break
160
+ case "p2sh-p2wpkh":
161
+ addressObject = bitcoin.payments.p2sh({
162
+ redeem: bitcoin.payments.p2wpkh({
163
+ pubkey: publicKey,
164
+ network,
165
+ }),
166
+ })
167
+ break
168
+ default:
169
+ throw new Error("address type is incorrect")
170
+ }
171
+ return addressObject
172
+ }
173
+
174
+ function createAddressObjectByAddress(address, network) {
175
+ let addressType = getAddressType(address, network)
176
+ let addressObject
177
+ switch (addressType) {
178
+ case "p2pkh":
179
+ addressObject = bitcoin.payments.p2pkh({
180
+ address,
181
+ network,
182
+ })
183
+ break
184
+ case "p2wpkh":
185
+ addressObject = bitcoin.payments.p2wpkh({
186
+ address,
187
+ network,
188
+ })
189
+ break
190
+ case "p2sh":
191
+ addressObject = bitcoin.payments.p2sh({
192
+ address,
193
+ network,
194
+ })
195
+ break
196
+ default:
197
+ throw new Error("address type is incorrect")
198
+ }
199
+ return { addressObject, addressType }
200
+ }
201
+
202
+ // not used
203
+
204
+ async function deriveAddressFromPubKey(pubKey, network) {
205
+ let { address } = this.bitcoinJS.payments.p2pkh({
206
+ network,
207
+ pubkey: Buffer.from(pubKey, "hex"),
208
+ })
209
+ return address
210
+ }
211
+
212
+ async function deriveAddressFromBufferPubKey(pubKey, network) {
213
+ let { address } = this.bitcoinJS.payments.p2pkh({ network, pubkey: pubKey })
214
+ return address
215
+ }
216
+
217
+ async function getPubKeyFromPrivateKey(privateKey, network) {
218
+ let key = bitcoin.ECPair.fromWIF(privateKey, network)
219
+ return key.publicKey
220
+ }
221
+
222
+ function calculateMerkleProof(blockTransactions, txId, blockMerkleRoot = undefined) {
223
+ let transactionIndex = blockTransactions.findIndex((tx) => tx === txId)
224
+ if (transactionIndex < 0) throw new Error("txId is not in this tree")
225
+ let data = blockTransactions.map((a) => Buffer.from(a, "hex").reverse())
226
+
227
+ if (
228
+ blockMerkleRoot &&
229
+ blockMerkleRoot !== fastRoot(data, bitcoin.crypto.hash256).toString("hex")
230
+ ) {
231
+ throw new Error("calculated anf block merkleRoot not matched")
232
+ }
233
+
234
+ let tree = merkle(data, bitcoin.crypto.hash256)
235
+ let proof = merkleProof(tree, data[transactionIndex])
236
+
237
+ let intermediateNodesArray = proof
238
+ .map((_id) => _id && _id.toString("hex"))
239
+ .filter((_id) => _id != null)
240
+ let intermediateNodes = intermediateNodesArray.reduce(
241
+ (a, value, index) =>
242
+ index !== transactionIndex % 2 && index < intermediateNodesArray.length - 1 ? a + value : a,
243
+ "0x",
244
+ )
245
+ return {
246
+ intermediateNodes,
247
+ transactionIndex,
248
+ }
249
+ }
250
+
251
+ function parseBlockHeader(headerHex) {
252
+ const size = {
253
+ version: 4,
254
+ previousBlockHash: 32,
255
+ merkleRoot: 32,
256
+ timestamp: 4,
257
+ difficulty: 4,
258
+ nonce: 4,
259
+ }
260
+ let offset = 0
261
+ let result = {}
262
+ for (let key in size) {
263
+ result[key] = headerHex.slice(offset, offset + size[key] * 2)
264
+ offset += size[key] * 2
265
+ }
266
+ return result
267
+ }
268
+
269
+ function convertBitcoinScriptToAddress(script, network) {
270
+ try {
271
+ return bitcoin.address?.fromOutputScript(script, network)
272
+ } catch (error) {
273
+ return null
274
+ }
275
+ }
276
+
277
+ function parseRawBlock(rawBlockHex, blockNumber = undefined, network = bitcoin.networks.network) {
278
+ let block = bitcoin.Block.fromBuffer(Buffer.from(rawBlockHex, "hex"))
279
+ let blockHash = block.getHash().toString("hex")
280
+ let merkleRoot = block.merkleRoot.toString("hex")
281
+ let prvBlockHash = block.prevHash.toString("hex")
282
+ return {
283
+ blockNumber,
284
+ merkleRoot,
285
+ prvBlockHash,
286
+ transactions: block.transactions.map((tx) => ({
287
+ txId: tx.getId(),
288
+ version: tx.version,
289
+ locktime: tx.locktime,
290
+ blockNumber,
291
+ blockHash,
292
+ vout: tx.outs.map((vo) => ({
293
+ address: convertBitcoinScriptToAddress(vo.script, network),
294
+ script: vo.script.toString("hex"),
295
+ value: vo.value,
296
+ })),
297
+ vin: tx.ins.map((vi) => ({
298
+ txId: vi.hash.reverse().toString("hex"),
299
+ index: vi.index,
300
+ // // todo optional get from utxo
301
+ // address: null,
302
+ // script: null,
303
+ // value: null,
304
+ })),
305
+ })),
306
+ }
307
+ }
308
+
309
+ function extractTransactionsAndBlockInfoFromRawBlock(
310
+ rawBlockHex,
311
+ blockNumber,
312
+ addresses = [],
313
+ inputs = [],
314
+ network = bitcoin.networks.bitcoin,
315
+ ) {
316
+ let block = bitcoin.Block.fromBuffer(Buffer.from(rawBlockHex, "hex"))
317
+ let blockHash = block.getHash().reverse().toString("hex")
318
+ let merkleRoot = block.merkleRoot.toString("hex")
319
+ let prvBlockHash = block.prevHash.toString("hex")
320
+
321
+ let blockInfo = {
322
+ blockNumber,
323
+ blockHash,
324
+ merkleRoot,
325
+ prvBlockHash,
326
+ }
327
+
328
+ let addressScript = addresses.map((address) =>
329
+ createAddressObjectByAddress(address, network).addressObject.output.toString("hex"),
330
+ )
331
+
332
+ let blockTxIds = block.transactions.map((tx) => tx.getId())
333
+
334
+ let withdrawTxs = []
335
+ let depositTxs = []
336
+ block.transactions.forEach((tx) => {
337
+ let txId = tx.getId()
338
+ let transactionAddressIndex
339
+
340
+ // todo : withdraw txs not working (we cant use utxo here)
341
+ let txVinInput = inputs.find((vin) => vin.txId === txId)
342
+ if (txVinInput) {
343
+ let txMerkleProof = calculateMerkleProof(blockTxIds, txId, merkleRoot)
344
+
345
+ withdrawTxs.push({
346
+ txId: tx.getId(),
347
+ version: tx.version,
348
+ locktime: tx.locktime,
349
+ blockNumber,
350
+ blockHash,
351
+ merkleProof: txMerkleProof,
352
+ vout: tx.outs.map((vo) => ({
353
+ address: convertBitcoinScriptToAddress(vo.script, network),
354
+ script: vo.script.toString("hex"),
355
+ value: vo.value,
356
+ })),
357
+ vin: tx.ins.map((vi) => {
358
+ let viInput = inputs.find((vin) => vin.txId === txId)
359
+ return {
360
+ txId: vi.hash.reverse().toString("hex"),
361
+ index: vi.index,
362
+ address: viInput.address || null,
363
+ script: viInput.script || null,
364
+ value: viInput.value || null,
365
+ }
366
+ }),
367
+ address: txVinInput.address,
368
+ addressScript: createAddressObjectByAddress(
369
+ txVinInput.address,
370
+ network,
371
+ ).addressObject.output.toString("hex"),
372
+ })
373
+ } else if (
374
+ tx.outs.findIndex((blockTxVo) => {
375
+ let sIndex = addressScript.findIndex(
376
+ (addScript) => addScript === blockTxVo.script.toString("hex"),
377
+ )
378
+ if (sIndex >= 0) {
379
+ transactionAddressIndex = sIndex
380
+ return true
381
+ }
382
+ return false
383
+ }) >= 0
384
+ ) {
385
+ // todo we can optimize this calculation (in following function, merkle tree calculate each times but we can do this once for this block)
386
+ let txMerkleProof = calculateMerkleProof(blockTxIds, txId, merkleRoot)
387
+ depositTxs.push({
388
+ txId: tx.getId(),
389
+ version: tx.version,
390
+ locktime: tx.locktime,
391
+ blockNumber,
392
+ blockHash,
393
+ merkleProof: txMerkleProof,
394
+ vout: tx.outs.map((vo) => ({
395
+ address: convertBitcoinScriptToAddress(vo.script, network),
396
+ script: vo.script.toString("hex"),
397
+ value: vo.value,
398
+ })),
399
+ vin: tx.ins.map((vi) => ({
400
+ txId: vi.hash.reverse().toString("hex"),
401
+ index: vi.index,
402
+ // // todo optional get from utxo
403
+ // address: null,
404
+ // script: null,
405
+ // value: null,
406
+ })),
407
+ addressScript: addressScript[transactionAddressIndex],
408
+ address: addresses[transactionAddressIndex],
409
+ })
410
+ }
411
+ })
412
+ return {
413
+ blockInfo,
414
+ withdrawTxs,
415
+ depositTxs,
416
+ }
417
+ }
418
+
419
+ module.exports = {
420
+ parseRawTransaction,
421
+ calculateMerkleProof,
422
+ createAddressObjectByHash,
423
+ createAddressObjectByPublicKey,
424
+ createAddressObjectByAddress,
425
+ createAddressObjectByScript,
426
+
427
+ // ------------------------
428
+ getAddressType,
429
+ deriveAddressFromPubKey,
430
+ deriveAddressFromBufferPubKey,
431
+ getPubKeyFromPrivateKey,
432
+ reverseBytes,
433
+
434
+ parseBlockHeader,
435
+ generateMnemonic,
436
+
437
+ // ---------------------------
438
+ parseRawBlock,
439
+ extractTransactionsAndBlockInfoFromRawBlock,
440
+
441
+ // -----------------------------
442
+ networks,
443
+ }
@@ -0,0 +1,27 @@
1
+ function getBurnTransactionInfo(address, vin = [], vouts = []) {
2
+ let lockerVinIndex = vin.findIndex((vi) => vi.address === address)
3
+ if (lockerVinIndex >= 0) {
4
+ let lockerVin = vin[lockerVinIndex]
5
+ lockerVin.vinIndex = lockerVinIndex
6
+ let totalInputValue = vin.reduce((acc, current) => +acc + +current.value, 0)
7
+ let receivers = []
8
+ let changes = []
9
+ for (let i in vouts) {
10
+ let vout = {
11
+ ...vouts[i],
12
+ index: i,
13
+ }
14
+ if (vout.address === address) {
15
+ changes.push(vout)
16
+ } else {
17
+ receivers.push(vout)
18
+ }
19
+ }
20
+ return { receivers, changes, totalInputValue, lockerVin }
21
+ }
22
+ return null
23
+ }
24
+
25
+ module.exports = {
26
+ getBurnTransactionInfo,
27
+ }
@@ -0,0 +1,162 @@
1
+ const { requestTypes: teleportRequestsType } = require("@teleportdao/configs").teleswap
2
+
3
+ function parseTeleportAndExchangeRequest(data) {
4
+ let parsedData = {}
5
+ parsedData.requestType = "transfer"
6
+
7
+ let offset = 0
8
+ parsedData.chainId = Number(`0x${data.slice(offset, (offset += 2))}`) // 1 bytes
9
+ parsedData.appId = Number(`0x${data.slice(offset, (offset += 4))}`) // 2 bytes
10
+ parsedData.recipientAddress = `0x${data.slice(offset, (offset += 40))}` // 20 bytes
11
+ parsedData.percentageFee = Number(`0x${data.slice(offset, (offset += 4))}`) / 100 // 2 bytes
12
+ parsedData.speed = data.slice(offset, (offset += 2)) === "01" // 1 byte
13
+ if (data.length === offset) {
14
+ return {
15
+ status: true,
16
+ data: parsedData,
17
+ }
18
+ }
19
+
20
+ parsedData.requestType = "exchange"
21
+ parsedData.exchangeTokenAddress = `0x${data.slice(offset, (offset += 40))}` // 20 bytes
22
+ parsedData.outputAmount = Number(`0x${data.slice(offset, (offset += 56))}`) // 28 bytes
23
+ parsedData.deadline = Number(`0x${data.slice(offset, (offset += 8))}`) // 4 bytes
24
+ parsedData.isFixedToken = data.slice(offset, (offset += 2)) === "01" // 1 byte
25
+ if (data.length === offset) {
26
+ return {
27
+ status: true,
28
+ data: parsedData,
29
+ }
30
+ }
31
+
32
+ return {
33
+ status: false,
34
+ message: `invalid OP_RETURN data for requestType: 'transfer or exchange'. invalid data length : ${data.length} - valid length : ${offset}`,
35
+ code: "INVALID_OP_RETURN",
36
+ }
37
+ }
38
+
39
+ function parseLendAndBorrowRequest(data) {
40
+ let parsedData = {}
41
+ parsedData.requestType = "lend"
42
+
43
+ let offset = 0
44
+ parsedData.chainId = Number(`0x${data.slice(offset, (offset += 2))}`) // 1 bytes
45
+ parsedData.appId = Number(`0x${data.slice(offset, (offset += 4))}`) // 2 bytes
46
+ parsedData.recipientAddress = `0x${data.slice(offset, (offset += 40))}` // 20 bytes
47
+ parsedData.percentageFee = Number(`0x${data.slice(offset, (offset += 4))}`) / 100 // 2 bytes
48
+ parsedData.mode = Number(`0x${data.slice(offset, (offset += 2))}`) // 1 byte
49
+ if (data.length === offset) {
50
+ return {
51
+ status: true,
52
+ data: parsedData,
53
+ }
54
+ }
55
+ parsedData.requestType = "borrow"
56
+ parsedData.tokenAddress = `0x${data.slice(offset, (offset += 40))}` // 20 bytes
57
+ parsedData.borrowAmount = Number(`0x${data.slice(offset, (offset += 56))}`) // 28 bytes
58
+ if (data.length === offset) {
59
+ return {
60
+ status: true,
61
+ data: parsedData,
62
+ }
63
+ }
64
+ return {
65
+ status: false,
66
+ message: `invalid OP_RETURN data for requestType: 'lend or borrow'. invalid data length : ${data.length} - valid length : ${offset}`,
67
+ code: "INVALID_OP_RETURN",
68
+ }
69
+ }
70
+
71
+ function parseRawRequest(opReturnData) {
72
+ let data = opReturnData.slice(2, 4) === "4c" ? opReturnData.slice(6) : opReturnData.slice(4)
73
+
74
+ // eslint-disable-next-line no-unused-vars
75
+ let _chainId = Number(`0x${data.slice(0, 2)}`) // 1 bytes
76
+ let appIdHex = data.slice(2, 6) // 2 bytes
77
+ if (!appIdHex) {
78
+ return {
79
+ status: false,
80
+ message: `invalid OP_RETURN data : ${data}`,
81
+ code: "INVALID_APP_ID",
82
+ }
83
+ }
84
+
85
+ let appId = Number(`0x${appIdHex}`) // 2 bytes
86
+
87
+ // get type base on appId
88
+ let requestType = teleportRequestsType.find(
89
+ (rs) => appId >= rs.appIdRange[0] && appId <= rs.appIdRange[1],
90
+ )?.type
91
+
92
+ switch (requestType) {
93
+ case "teleport":
94
+ case "exchange":
95
+ return parseTeleportAndExchangeRequest(data)
96
+ case "lend":
97
+ return parseLendAndBorrowRequest(data)
98
+ default:
99
+ return {
100
+ status: false,
101
+ message: `invalid appId : ${appId}`,
102
+ code: "INVALID_OP_RETURN",
103
+ }
104
+ }
105
+ }
106
+
107
+ function validateRequestAndValue(data, value, { minTeleporterFeeAmount = 0 }) {
108
+ if (!data) {
109
+ return {
110
+ status: false,
111
+ message: "no data to validate. it should not happen",
112
+ code: "NOT_ACCEPTED_BY_TELEPORTER",
113
+ }
114
+ }
115
+
116
+ if (+data.percentageFee > 100) {
117
+ return {
118
+ status: false,
119
+ message: `percentageFee greater than 100 is invalid. percentageFee: ${data.percentageFee}`,
120
+ code: "INVALID_FEE",
121
+ }
122
+ }
123
+
124
+ if ((data.percentageFee / 100) * +value <= minTeleporterFeeAmount) {
125
+ return {
126
+ status: false,
127
+ message: `fee amount is less than or equal minimum teleporter fee amount.percentageFee: ${
128
+ data.percentageFee
129
+ } - value: ${value} - feeAmount ${((data.percentageFee / 100) * +value).toFixed(
130
+ 8,
131
+ )} - minimumFee: ${minTeleporterFeeAmount}`,
132
+ code: "NOT_ACCEPTED_BY_TELEPORTER",
133
+ }
134
+ }
135
+
136
+ return {
137
+ status: true,
138
+ data,
139
+ value,
140
+ }
141
+ }
142
+
143
+ function checkAndParseProtocolRequest(vouts, address, config = { minTeleporterFeeAmount: 0 }) {
144
+ let opReturnData = vouts.find((vout_) => vout_.script.startsWith("6a"))?.script || null
145
+ if (opReturnData) {
146
+ let value = vouts.find((vout_) => vout_.address === address)?.value || 0
147
+ let dataResponse = parseRawRequest(opReturnData)
148
+ if (dataResponse.status) {
149
+ return validateRequestAndValue(dataResponse.data, value, config)
150
+ }
151
+ return dataResponse
152
+ }
153
+ return {
154
+ status: false,
155
+ message: "transaction outputs should contain OP_RETURN",
156
+ code: "NO_OP_RETURN",
157
+ }
158
+ }
159
+
160
+ module.exports = {
161
+ checkAndParseProtocolRequest,
162
+ }
package/src/index.js ADDED
@@ -0,0 +1,15 @@
1
+ // eslint-disable-next-line global-require
2
+ global.Buffer = global.Buffer || require("buffer").Buffer
3
+ const TeleportDaoPayment = require("./teleport-dao-payments")
4
+ const bitcoinUtils = require("./bitcoin-utils")
5
+ const BitcoinInterface = require("./bitcoin-interface")
6
+ const BitcoinInterfaceUtils = require("./bitcoin-interface-utils")
7
+ const BitcoinBase = require("./bitcoin-base")
8
+
9
+ module.exports = {
10
+ TeleportDaoPayment,
11
+ BitcoinInterface,
12
+ BitcoinInterfaceUtils,
13
+ bitcoinUtils,
14
+ BitcoinBase,
15
+ }
@@ -0,0 +1,36 @@
1
+ const bitcoin = require("bitcoinjs-lib")
2
+
3
+ class BitcoinLikeSignTransaction {
4
+ constructor(network) {
5
+ this.network = network
6
+ }
7
+
8
+ async signPsbt(extendedUnsignedTransaction, privateKey) {
9
+ const { network } = this
10
+ const keyPair = bitcoin.ECPair.fromPrivateKey(privateKey, {
11
+ network,
12
+ compressed: true,
13
+ })
14
+ const psbt = bitcoin.Psbt.fromBase64(extendedUnsignedTransaction.unsignedTransaction, {
15
+ network,
16
+ })
17
+ psbt.signAllInputs(keyPair)
18
+
19
+ const partialSigendPsbt = psbt.toBase64()
20
+ return partialSigendPsbt
21
+ }
22
+
23
+ finalizePsbts(psbtsBase64 = []) {
24
+ const finals = psbtsBase64.map((psbtBase64) =>
25
+ bitcoin.Psbt.fromBase64(psbtBase64, { network: this.network }),
26
+ )
27
+ const psbt =
28
+ finals.length === 1
29
+ ? finals[0]
30
+ : new bitcoin.Psbt({ network: this.network }).combine(...finals)
31
+ psbt.finalizeAllInputs()
32
+ return psbt.extractTransaction().toHex()
33
+ }
34
+ }
35
+
36
+ module.exports = BitcoinLikeSignTransaction