@teleportdao/bitcoin 1.6.1 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/.tmp/check.ts +101 -0
  2. package/.tmp/psbt/sign-transaction.ts +121 -0
  3. package/.tmp/rbf.ts +45 -0
  4. package/dist/bitcoin-interface-ordinal.d.ts +109 -0
  5. package/dist/bitcoin-interface-ordinal.d.ts.map +1 -0
  6. package/dist/bitcoin-interface-ordinal.js +141 -0
  7. package/dist/bitcoin-interface-ordinal.js.map +1 -0
  8. package/dist/bitcoin-interface-teleswap.d.ts +148 -0
  9. package/dist/bitcoin-interface-teleswap.d.ts.map +1 -0
  10. package/dist/bitcoin-interface-teleswap.js +179 -0
  11. package/dist/bitcoin-interface-teleswap.js.map +1 -0
  12. package/dist/bitcoin-interface-utils.d.ts.map +1 -1
  13. package/dist/bitcoin-interface-utils.js.map +1 -1
  14. package/dist/bitcoin-interface.d.ts +45 -333
  15. package/dist/bitcoin-interface.d.ts.map +1 -1
  16. package/dist/bitcoin-interface.js +68 -202
  17. package/dist/bitcoin-interface.js.map +1 -1
  18. package/dist/bitcoin-utils.d.ts +12 -59
  19. package/dist/bitcoin-utils.d.ts.map +1 -1
  20. package/dist/bitcoin-utils.js +61 -61
  21. package/dist/bitcoin-utils.js.map +1 -1
  22. package/dist/{bitcoin-base.d.ts → bitcoin-wallet-base.d.ts} +9 -9
  23. package/dist/bitcoin-wallet-base.d.ts.map +1 -0
  24. package/dist/{bitcoin-base.js → bitcoin-wallet-base.js} +15 -14
  25. package/dist/bitcoin-wallet-base.js.map +1 -0
  26. package/dist/helper/brc20-helper.d.ts +43 -0
  27. package/dist/helper/brc20-helper.d.ts.map +1 -0
  28. package/dist/helper/brc20-helper.js +129 -0
  29. package/dist/helper/brc20-helper.js.map +1 -0
  30. package/dist/helper/index.d.ts +4 -0
  31. package/dist/helper/index.d.ts.map +1 -0
  32. package/dist/helper/index.js +30 -0
  33. package/dist/helper/index.js.map +1 -0
  34. package/dist/helper/ordinal-helper.d.ts +13 -0
  35. package/dist/helper/ordinal-helper.d.ts.map +1 -0
  36. package/dist/helper/ordinal-helper.js +127 -0
  37. package/dist/helper/ordinal-helper.js.map +1 -0
  38. package/dist/helper/teleswap-helper.d.ts +84 -0
  39. package/dist/helper/teleswap-helper.d.ts.map +1 -0
  40. package/dist/helper/teleswap-helper.js +181 -0
  41. package/dist/helper/teleswap-helper.js.map +1 -0
  42. package/dist/index.d.ts +8 -3
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +8 -3
  45. package/dist/index.js.map +1 -1
  46. package/dist/ordinal-wallet.d.ts +536 -0
  47. package/dist/ordinal-wallet.d.ts.map +1 -0
  48. package/dist/ordinal-wallet.js +448 -0
  49. package/dist/ordinal-wallet.js.map +1 -0
  50. package/dist/sign/sign-transaction.d.ts +2 -4
  51. package/dist/sign/sign-transaction.d.ts.map +1 -1
  52. package/dist/sign/sign-transaction.js +26 -22
  53. package/dist/sign/sign-transaction.js.map +1 -1
  54. package/dist/teleswap-wallet.d.ts +54 -0
  55. package/dist/teleswap-wallet.d.ts.map +1 -0
  56. package/dist/teleswap-wallet.js +87 -0
  57. package/dist/teleswap-wallet.js.map +1 -0
  58. package/dist/transaction-builder/bitcoin-transaction-builder.d.ts +2 -20
  59. package/dist/transaction-builder/bitcoin-transaction-builder.d.ts.map +1 -1
  60. package/dist/transaction-builder/bitcoin-transaction-builder.js +5 -4
  61. package/dist/transaction-builder/bitcoin-transaction-builder.js.map +1 -1
  62. package/dist/transaction-builder/index.d.ts +2 -1
  63. package/dist/transaction-builder/index.d.ts.map +1 -1
  64. package/dist/transaction-builder/index.js +2 -6
  65. package/dist/transaction-builder/index.js.map +1 -1
  66. package/dist/transaction-builder/ordinal-transaction-builder.d.ts +63 -0
  67. package/dist/transaction-builder/ordinal-transaction-builder.d.ts.map +1 -0
  68. package/dist/transaction-builder/ordinal-transaction-builder.js +131 -0
  69. package/dist/transaction-builder/ordinal-transaction-builder.js.map +1 -0
  70. package/dist/transaction-builder/transaction-builder.d.ts +10 -7
  71. package/dist/transaction-builder/transaction-builder.d.ts.map +1 -1
  72. package/dist/transaction-builder/transaction-builder.js +18 -9
  73. package/dist/transaction-builder/transaction-builder.js.map +1 -1
  74. package/dist/type.d.ts +43 -0
  75. package/dist/type.d.ts.map +1 -0
  76. package/dist/type.js +3 -0
  77. package/dist/type.js.map +1 -0
  78. package/dist/utils/tools.d.ts +4 -4
  79. package/dist/utils/tools.d.ts.map +1 -1
  80. package/dist/utils/tools.js +8 -5
  81. package/dist/utils/tools.js.map +1 -1
  82. package/package.json +6 -9
  83. package/src/bitcoin-interface-ordinal.ts +181 -0
  84. package/src/bitcoin-interface-teleswap.ts +255 -0
  85. package/src/bitcoin-interface-utils.ts +1 -1
  86. package/src/bitcoin-interface.ts +99 -303
  87. package/src/bitcoin-utils.ts +65 -90
  88. package/src/{bitcoin-base.ts → bitcoin-wallet-base.ts} +24 -19
  89. package/src/helper/brc20-helper.ts +181 -0
  90. package/src/helper/index.ts +3 -0
  91. package/src/helper/ordinal-helper.ts +118 -0
  92. package/src/helper/teleswap-helper.ts +300 -0
  93. package/src/index.ts +11 -3
  94. package/src/ordinal-wallet.ts +738 -0
  95. package/src/sign/sign-transaction.ts +42 -33
  96. package/src/teleswap-wallet.ts +155 -0
  97. package/src/transaction-builder/bitcoin-transaction-builder.ts +7 -24
  98. package/src/transaction-builder/index.ts +2 -1
  99. package/src/transaction-builder/ordinal-transaction-builder.ts +147 -0
  100. package/src/transaction-builder/transaction-builder.ts +33 -15
  101. package/src/type.ts +43 -0
  102. package/src/utils/tools.ts +17 -11
  103. package/tsconfig.json +1 -2
  104. package/dist/bitcoin-base.d.ts.map +0 -1
  105. package/dist/bitcoin-base.js.map +0 -1
  106. package/dist/bitcoin-utils-2.d.ts +0 -2
  107. package/dist/bitcoin-utils-2.d.ts.map +0 -1
  108. package/dist/bitcoin-utils-2.js +0 -13
  109. package/dist/bitcoin-utils-2.js.map +0 -1
  110. package/dist/bundle.js +0 -17
  111. package/dist/helper/burn-request-helper.d.ts +0 -7
  112. package/dist/helper/burn-request-helper.d.ts.map +0 -1
  113. package/dist/helper/burn-request-helper.js +0 -26
  114. package/dist/helper/burn-request-helper.js.map +0 -1
  115. package/dist/helper/teleport-request-helper.d.ts +0 -47
  116. package/dist/helper/teleport-request-helper.d.ts.map +0 -1
  117. package/dist/helper/teleport-request-helper.js +0 -146
  118. package/dist/helper/teleport-request-helper.js.map +0 -1
  119. package/dist/mempool-space.d.ts +0 -69
  120. package/dist/mempool-space.d.ts.map +0 -1
  121. package/dist/mempool-space.js +0 -266
  122. package/dist/mempool-space.js.map +0 -1
  123. package/dist/teleport-dao-payments.d.ts +0 -76
  124. package/dist/teleport-dao-payments.d.ts.map +0 -1
  125. package/dist/teleport-dao-payments.js +0 -217
  126. package/dist/teleport-dao-payments.js.map +0 -1
  127. package/src/helper/burn-request-helper.js +0 -27
  128. package/src/helper/teleport-request-helper.js +0 -181
  129. package/src/teleport-dao-payments.ts +0 -347
@@ -9,50 +9,53 @@ function tapTweakHash(pubKey: Buffer, h?: Buffer) {
9
9
  return crypto.taggedHash("TapTweak", Buffer.concat(h ? [pubKey, h] : [pubKey]))
10
10
  }
11
11
 
12
- class BitcoinLikeSignTransaction {
13
- network: Network
14
- constructor(network: Network) {
15
- this.network = network
12
+ function tweakSigner(
13
+ privateKey: Buffer,
14
+ network: Network,
15
+ opts = {} as {
16
+ [key: string]: Buffer
17
+ },
18
+ ) {
19
+ let newPrv = privateKey
20
+ let keyPair = ECPair.fromPrivateKey(privateKey, {
21
+ network,
22
+ compressed: true,
23
+ })
24
+
25
+ if (!keyPair.privateKey) throw new Error("private key not exist")
26
+
27
+ if (keyPair.publicKey.toString("hex").startsWith("03")) {
28
+ newPrv = ecc.privateNegate(keyPair.privateKey) as Buffer
16
29
  }
17
30
 
18
- static tweakSigner(
19
- privateKey: Buffer,
20
- opts = {} as {
21
- [key: string]: Buffer
22
- },
23
- network: Network,
24
- ) {
25
- let newPrv = privateKey
26
- let keyPair = ECPair.fromPrivateKey(privateKey, {
27
- network: network,
28
- compressed: true,
29
- })
30
-
31
- if (!keyPair.privateKey) throw new Error("private key not exist")
31
+ const tweakedPrivateKey = ecc.privateAdd(
32
+ newPrv,
33
+ tapTweakHash(Buffer.from(keyPair.publicKey.toString("hex").slice(2), "hex"), opts?.tweakHash),
34
+ )
35
+ if (!tweakedPrivateKey) {
36
+ throw new Error("Invalid tweaked private key!")
37
+ }
32
38
 
33
- if (keyPair.publicKey.toString("hex").startsWith("03")) {
34
- newPrv = ecc.privateNegate(keyPair.privateKey) as Buffer
35
- }
39
+ return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
40
+ network,
41
+ })
42
+ }
36
43
 
37
- const tweakedPrivateKey = ecc.privateAdd(
38
- newPrv,
39
- tapTweakHash(Buffer.from(keyPair.publicKey.toString("hex").slice(2), "hex"), opts?.tweakHash),
40
- )
41
- if (!tweakedPrivateKey) {
42
- throw new Error("Invalid tweaked private key!")
43
- }
44
+ class BitcoinLikeSignTransaction {
45
+ network: Network
44
46
 
45
- return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
46
- network: network,
47
- })
47
+ constructor(network: Network) {
48
+ this.network = network
48
49
  }
49
50
 
50
51
  async signPsbt(
51
52
  unsignedPsbt: {
52
53
  unsignedTransaction: string
54
+ inputsToSign?: number[]
53
55
  },
54
56
  privateKey: Buffer,
55
57
  sighashTypes?: any[],
58
+ usingTweakSignerIfNeeded = true,
56
59
  ) {
57
60
  const { network } = this
58
61
  const keyPair = ECPair.fromPrivateKey(privateKey, {
@@ -66,9 +69,15 @@ class BitcoinLikeSignTransaction {
66
69
  let numberOfInputs = psbt.inputCount
67
70
 
68
71
  for (let i = 0; i < numberOfInputs; i += 1) {
72
+ if (unsignedPsbt.inputsToSign && !unsignedPsbt.inputsToSign.includes(i)) {
73
+ // eslint-disable-next-line no-continue
74
+ continue
75
+ }
69
76
  let type = psbt.getInputType(i)
70
- if (type === "nonstandard") {
71
- let a = BitcoinLikeSignTransaction.tweakSigner(privateKey, undefined, this.network)
77
+
78
+ if (usingTweakSignerIfNeeded && type === "nonstandard") {
79
+ console.log("using tweak signer")
80
+ let a = tweakSigner(privateKey, this.network)
72
81
  await psbt.signInputAsync(i, a, sighashTypes)
73
82
  } else {
74
83
  await psbt.signInputAsync(i, keyPair, sighashTypes)
@@ -0,0 +1,155 @@
1
+ import type {
2
+ ExtendedUtxo,
3
+ SignerInfo,
4
+ TargetAddress,
5
+ } from "./transaction-builder/transaction-builder"
6
+ import { BitcoinBaseWallet } from "./bitcoin-wallet-base"
7
+ import { generateWrapOpReturn } from "./helper/teleswap-helper"
8
+
9
+ export type TransferRequest = {
10
+ changeAddress?: string
11
+ lockerAddress: string
12
+ amount: number
13
+ fullAmount?: boolean
14
+ //-----------
15
+ chainId: number
16
+ appId: number
17
+ recipientAddress: string // 20 bytes
18
+ percentageFee: number // 2 bytes in satoshi
19
+ speed?: number | boolean // 1 byte
20
+ isExchange?: boolean
21
+ exchangeTokenAddress?: string // 20 bytes
22
+ outputAmount?: number // 28 bytes
23
+ deadline?: number // 4 bytes
24
+ isFixedToken?: boolean // 1 byte
25
+ feeSpeed?: "normal" | "fast" | "slow"
26
+ staticFeeRate?: number
27
+ }
28
+
29
+ export class TeleswapWallet extends BitcoinBaseWallet {
30
+ // payment
31
+ async sendToMultipleAddress(
32
+ receivers: TargetAddress[],
33
+ feeSpeed: "normal" | "fast" | "slow" = "normal",
34
+ ) {
35
+ if (!this.signerInfo || !this.privateKey) {
36
+ throw new Error("account not initialized")
37
+ }
38
+ let extendedUtxo = await this.getExtendedUtxo(this.signerInfo)
39
+ let feeRate = await this.transactionBuilder._getFeeRate(feeSpeed)
40
+ let unsignedTx = await this.transactionBuilder.processUnsignedTransaction({
41
+ extendedUtxo,
42
+ targets: receivers,
43
+ changeAddress: this.currentAccount,
44
+ feeRate,
45
+ fullAmount: false,
46
+ })
47
+ let signedPsbt = await this.signer.signPsbt(unsignedTx, this.privateKey)
48
+ let signedTx = this.signer.finalizePsbts([signedPsbt])
49
+ let txId = await this.transactionBuilder.sendTx(signedTx)
50
+ return txId
51
+ }
52
+
53
+ // send
54
+
55
+ async wrapUnsigned(
56
+ recipientAddress: string,
57
+ amount: number,
58
+ percentageFee: number,
59
+ signer: SignerInfo,
60
+ lockerAddress: string,
61
+ exchange?: {
62
+ outputToken: string
63
+ outputAmount: string
64
+ deadline: string
65
+ isFixedToken?: boolean
66
+ },
67
+ {
68
+ chainId = 137, // 80001
69
+ appId = exchange ? 1 : 0,
70
+ } = {},
71
+ fullAmount = false,
72
+ staticExtendedUtxo?: ExtendedUtxo[],
73
+ staticFeeRate?: number,
74
+ changeAddress?: string,
75
+ ) {
76
+ const dataHex = generateWrapOpReturn({
77
+ chainId,
78
+ appId,
79
+ recipientAddress,
80
+ percentageFee,
81
+ speed: false,
82
+ isExchange: !!exchange,
83
+ outputAmount: exchange?.outputAmount,
84
+ outputToken: exchange?.outputToken,
85
+ deadline: exchange?.deadline,
86
+ isFixedToken: exchange?.isFixedToken || false,
87
+ })
88
+ let extendedUtxo = staticExtendedUtxo || (await this.getExtendedUtxo(signer))
89
+ let feeRate = staticFeeRate || (await this.transactionBuilder._getFeeRate("normal"))
90
+
91
+ const targets = fullAmount
92
+ ? [this.transactionBuilder.getOpReturnTarget(dataHex)]
93
+ : [
94
+ {
95
+ address: lockerAddress,
96
+ value: amount,
97
+ },
98
+ this.transactionBuilder.getOpReturnTarget(dataHex),
99
+ ]
100
+
101
+ const unsignedTx = this.transactionBuilder.processUnsignedTransaction({
102
+ extendedUtxo,
103
+ feeRate,
104
+ targets,
105
+ changeAddress: changeAddress || signer.address,
106
+ fullAmount,
107
+ })
108
+
109
+ return unsignedTx
110
+ }
111
+
112
+ async wrap(
113
+ recipientAddress: string,
114
+ amount: number,
115
+ percentageFee: number,
116
+ lockerAddress: string,
117
+ exchange?: {
118
+ outputToken: string
119
+ outputAmount: string
120
+ deadline: string
121
+ isFixedToken?: boolean
122
+ },
123
+ {
124
+ chainId = 137, // 80001
125
+ appId = exchange ? 1 : 0,
126
+ } = {},
127
+ fullAmount = false,
128
+ staticExtendedUtxo?: ExtendedUtxo[],
129
+ staticFeeRate?: number,
130
+ changeAddress?: string,
131
+ ) {
132
+ if (!this.signerInfo || !this.privateKey) {
133
+ throw new Error("account not initialized")
134
+ }
135
+ let unsignedTransaction = await this.wrapUnsigned(
136
+ recipientAddress,
137
+ amount,
138
+ percentageFee,
139
+ this.signerInfo,
140
+ lockerAddress,
141
+ exchange,
142
+ {
143
+ chainId,
144
+ appId,
145
+ },
146
+ fullAmount,
147
+ staticExtendedUtxo,
148
+ staticFeeRate,
149
+ changeAddress,
150
+ )
151
+ let signedPsbt = await this.signer.signPsbt(unsignedTransaction, this.privateKey)
152
+ return this.sendSignedPsbt(signedPsbt)
153
+ }
154
+ }
155
+ export default TeleswapWallet
@@ -1,26 +1,9 @@
1
1
  import { BaseTransactionBuilder } from "./transaction-builder"
2
2
  import { BitcoinInterface } from "../bitcoin-interface"
3
3
  import * as bitcoin from "bitcoinjs-lib"
4
+ import { BitcoinConnectionInfo } from "../type"
4
5
 
5
- export type BitcoinConnectionInfo = {
6
- rpc?: {
7
- enabled?: boolean
8
- url: string
9
- headers?: {
10
- [key: string]: string
11
- }
12
- auth?: {
13
- username: string
14
- password: string
15
- }
16
- }
17
- api: {
18
- enabled?: boolean
19
- token?: string
20
- provider: string
21
- }
22
- }
23
- class BitcoinTransactionBuilder extends BaseTransactionBuilder {
6
+ export class BitcoinTransactionBuilder extends BaseTransactionBuilder {
24
7
  btcInterface: BitcoinInterface
25
8
  constructor(
26
9
  connectionInfo: BitcoinConnectionInfo,
@@ -36,7 +19,7 @@ class BitcoinTransactionBuilder extends BaseTransactionBuilder {
36
19
  }
37
20
 
38
21
  async _getUtxo(userAddress: string) {
39
- let utxos = await this.btcInterface.getAddressesUtxo([userAddress])
22
+ let utxos = await this.btcInterface.getUtxo(userAddress)
40
23
  return utxos.map((tx) => ({
41
24
  hash: tx.txId as string,
42
25
  value: +tx.value,
@@ -49,13 +32,13 @@ class BitcoinTransactionBuilder extends BaseTransactionBuilder {
49
32
  }
50
33
 
51
34
  async _getTransactionHex(transactionId: string): Promise<string> {
52
- return this.btcInterface.provider.getRawTransaction(transactionId)
35
+ return this.btcInterface.getRawTransaction(transactionId)
53
36
  }
54
37
 
55
38
  async sendTx(txHex: string): Promise<string> {
56
- let txId = await this.btcInterface.provider.sendRawTransaction(txHex)
39
+ let txId = await (
40
+ this.btcInterface.rpcProvider || this.btcInterface.apiProvider
41
+ ).sendRawTransaction(txHex)
57
42
  return txId
58
43
  }
59
44
  }
60
-
61
- export default BitcoinTransactionBuilder
@@ -1,2 +1,3 @@
1
- export { default as BitcoinTransactionBuilder } from "./bitcoin-transaction-builder"
1
+ export * from "./bitcoin-transaction-builder"
2
+ export * from "./ordinal-transaction-builder"
2
3
  export * from "./transaction-builder"
@@ -0,0 +1,147 @@
1
+ import { ExtendedUtxo, Target, componentBytes } from "../"
2
+ import * as bitcoin from "bitcoinjs-lib"
3
+ import { LEAF_VERSION_TAPSCRIPT } from "bitcoinjs-lib/src/payments/bip341"
4
+ import { BitcoinTransactionBuilder } from "./bitcoin-transaction-builder"
5
+ import { getOrdinalScript, toXOnly } from "../helper/ordinal-helper"
6
+
7
+ export class OrdinalTransactionBuilder extends BitcoinTransactionBuilder {
8
+ async createNftPsbt({
9
+ extendedUtxo,
10
+ nftExtendedUtxo,
11
+ receiverAddress,
12
+ feeRate,
13
+ changeAddress,
14
+ otherTargets,
15
+ }: {
16
+ nftExtendedUtxo: ExtendedUtxo
17
+ extendedUtxo: ExtendedUtxo[]
18
+ feeRate: number
19
+ changeAddress: string
20
+ receiverAddress: string
21
+ otherTargets?: Target[]
22
+ }) {
23
+ let targets: Target[] = [
24
+ {
25
+ address: receiverAddress,
26
+ value: nftExtendedUtxo.value,
27
+ },
28
+ ]
29
+
30
+ if (otherTargets) targets.push(...otherTargets)
31
+
32
+ if (!changeAddress && targets.length === 0) throw new Error("no target")
33
+ let changeObject = {
34
+ address: changeAddress,
35
+ }
36
+ let { inputs, outputs, change, fee } = await this.filterAndConvertTxDataToStandardFormat({
37
+ extendedUtxo: [nftExtendedUtxo, ...extendedUtxo],
38
+ targets,
39
+ changeObject,
40
+ feeRate,
41
+ selectType: "inOrder",
42
+ })
43
+
44
+ let unsignedTx = this.createUnsignedTransaction({
45
+ inputs,
46
+ outputs,
47
+ change,
48
+ fee,
49
+ feeRate,
50
+ })
51
+
52
+ return unsignedTx
53
+ }
54
+
55
+ createOrdinalAddress(
56
+ file: {
57
+ buffer: Buffer
58
+ type: string
59
+ },
60
+ publicKey: Buffer,
61
+ ) {
62
+ const internalPublicKey = toXOnly(publicKey).toString("hex")
63
+ let leafScript = getOrdinalScript(file, internalPublicKey)
64
+
65
+ const scriptTree = {
66
+ output: leafScript,
67
+ }
68
+ const redeem = {
69
+ output: leafScript,
70
+ redeemVersion: LEAF_VERSION_TAPSCRIPT,
71
+ }
72
+
73
+ const p2trTapOrdinalScript = bitcoin.payments.p2tr({
74
+ internalPubkey: Buffer.from(internalPublicKey, "hex"),
75
+ scriptTree,
76
+ network: this.network,
77
+ redeem,
78
+ })
79
+ let ordinalAddress = p2trTapOrdinalScript.address!
80
+ const controlBlock = p2trTapOrdinalScript.witness![p2trTapOrdinalScript.witness!.length - 1]
81
+ return {
82
+ ordinalAddress,
83
+ ordinalScript: p2trTapOrdinalScript.output!,
84
+ redeem,
85
+ controlBlock,
86
+ }
87
+ }
88
+
89
+ createInscribeUnsignedTx(
90
+ ordinalSpendDetails: {
91
+ ordinalAddress: string
92
+ ordinalScript: Buffer
93
+ redeem: {
94
+ output: Buffer
95
+ redeemVersion: number
96
+ }
97
+ controlBlock: Buffer
98
+ },
99
+ inscribeDeposit: {
100
+ hash: string
101
+ index: number
102
+ value: number
103
+ },
104
+ receiverAddress: string,
105
+ ordinalAmount = 600,
106
+ ) {
107
+ const psbt = new bitcoin.Psbt({ network: this.network })
108
+ .addInput({
109
+ ...inscribeDeposit,
110
+ witnessUtxo: { value: inscribeDeposit.value, script: ordinalSpendDetails.ordinalScript },
111
+ // tapInternalKey: toXOnly(node.publicKey),
112
+ // tapMerkleRoot: p2trTapOrdinalScript.hash!,
113
+ tapLeafScript: [
114
+ {
115
+ leafVersion: ordinalSpendDetails.redeem.redeemVersion,
116
+ script: ordinalSpendDetails.redeem.output,
117
+ controlBlock: ordinalSpendDetails.controlBlock,
118
+ },
119
+ ],
120
+ })
121
+ .addOutput({
122
+ value: ordinalAmount,
123
+ address: receiverAddress,
124
+ })
125
+
126
+ return {
127
+ unsignedTransaction: psbt.toBase64(),
128
+ inputs: [inscribeDeposit],
129
+ outputs: [
130
+ {
131
+ value: ordinalAmount,
132
+ address: receiverAddress,
133
+ },
134
+ ],
135
+ fee: inscribeDeposit.value - ordinalAmount,
136
+ }
137
+ }
138
+
139
+ // use with caution. just segwit address
140
+ getUnsignedPsbtTxId(unsignedPsbt: string): string {
141
+ // use with caution
142
+ let psbt = bitcoin.Psbt.fromBase64(unsignedPsbt, {
143
+ network: this.network,
144
+ })
145
+ return (psbt as any).__CACHE.__TX.getId()
146
+ }
147
+ }
@@ -23,10 +23,7 @@ const coinselectAccumulative = require("coinselect/accumulative")
23
23
  // p2tr: 45, // 43
24
24
  // default: 35,
25
25
  // },
26
- // opReturn: {
27
- // dataLessThan75: 31,
28
- // dataMoreThan75: 91,
29
- // },
26
+ //
30
27
  // }
31
28
  export const componentBytes = {
32
29
  bytePerInput: {
@@ -34,6 +31,7 @@ export const componentBytes = {
34
31
  p2wpkh: 68, // 68
35
32
  "p2sh-p2wpkh": 91,
36
33
  p2tr: 58, // actual 58
34
+ default: 100,
37
35
  },
38
36
  baseTxBytes: 10 + 5, // +5 extra bytes to be sure
39
37
  bytePerOutput: {
@@ -42,14 +40,16 @@ export const componentBytes = {
42
40
  p2sh: 32, // 32
43
41
  p2tr: 43, // 43
44
42
  default: 35,
43
+ max: 45,
45
44
  },
46
- opReturn: {
47
- dataLessThan75: 31,
48
- dataMoreThan75: 91,
45
+
46
+ scriptExtraBytes: {
47
+ lessThan255: 12,
48
+ moreThan255: 15,
49
49
  },
50
50
  }
51
51
 
52
- const DUST = 1000
52
+ export const DUST = 1000
53
53
 
54
54
  export type Utxo = {
55
55
  hash: string
@@ -117,6 +117,22 @@ export type ExtendedUnsignedTransaction = {
117
117
  change: TargetAddress | undefined
118
118
  }
119
119
 
120
+ function coinSelectInOrder(
121
+ utxos: { hash: string; index: number; value: number }[],
122
+ outputs: {
123
+ address?: string
124
+ script?: Buffer
125
+ value: number
126
+ }[],
127
+ feeRate: number,
128
+ ) {
129
+ let response = coinselectAccumulative(utxos, outputs, 1)
130
+ return {
131
+ ...response,
132
+ fee: +(+response.fee * feeRate).toFixed(),
133
+ }
134
+ }
135
+
120
136
  export class BaseTransactionBuilder {
121
137
  testnet: boolean
122
138
  network: bitcoin.Network
@@ -224,10 +240,10 @@ export class BaseTransactionBuilder {
224
240
  }
225
241
 
226
242
  if (outP.script) {
227
- if (outP.script.byteLength < 75) {
228
- return componentBytes.opReturn.dataLessThan75
243
+ if (outP.script.byteLength < 255) {
244
+ return outP.script.byteLength + componentBytes.scriptExtraBytes.lessThan255
229
245
  }
230
- return componentBytes.opReturn.dataMoreThan75
246
+ return outP.script.byteLength + componentBytes.scriptExtraBytes.moreThan255
231
247
  }
232
248
 
233
249
  return componentBytes.bytePerOutput[
@@ -260,7 +276,7 @@ export class BaseTransactionBuilder {
260
276
  derivationPath?: string
261
277
  masterFingerprint?: string
262
278
  }
263
- selectType?: "normal" | "accumulative" | "full"
279
+ selectType?: "normal" | "accumulative" | "full" | "inOrder"
264
280
  }) {
265
281
  const filteredUtxo = extendedUtxo.filter(
266
282
  (u) =>
@@ -278,6 +294,9 @@ export class BaseTransactionBuilder {
278
294
  case "accumulative":
279
295
  selectResponse = coinselectAccumulative(filteredUtxo, targets, Math.round(feeRate))
280
296
  break
297
+ case "inOrder":
298
+ selectResponse = coinSelectInOrder(filteredUtxo, targets, Math.round(feeRate))
299
+ break
281
300
  case "full":
282
301
  if (!(targets[0] as TargetAddress).address) {
283
302
  throw new Error()
@@ -288,7 +307,6 @@ export class BaseTransactionBuilder {
288
307
  Math.round(feeRate),
289
308
  )
290
309
  break
291
-
292
310
  default:
293
311
  break
294
312
  }
@@ -404,7 +422,7 @@ export class BaseTransactionBuilder {
404
422
  derivationPath?: string
405
423
  masterFingerprint?: string
406
424
  }
407
- selectType?: "normal" | "accumulative" | "full"
425
+ selectType?: "normal" | "accumulative" | "full" | "inOrder"
408
426
  }) {
409
427
  let {
410
428
  inputs: filteredInputs,
@@ -658,7 +676,7 @@ export class BaseTransactionBuilder {
658
676
 
659
677
  changeAddress?: string | SignerInfo
660
678
  fullAmount?: boolean
661
- selectType?: "normal" | "accumulative" | "full"
679
+ selectType?: "normal" | "accumulative" | "full" | "inOrder"
662
680
  }) {
663
681
  if (!changeAddress && targets.length === 0) throw new Error("no target")
664
682
  let changeObject =
package/src/type.ts ADDED
@@ -0,0 +1,43 @@
1
+ export type Transaction = {
2
+ txId: string
3
+ version: number
4
+ locktime: number
5
+ blockNumber: number
6
+ blockHash: string
7
+ merkleProof?: {
8
+ intermediateNodes: string
9
+ transactionIndex: number
10
+ }
11
+ vout: {
12
+ address?: string
13
+ script: string
14
+ value: number
15
+ }[]
16
+ vin: {
17
+ txId: string
18
+ index: number
19
+ address?: string
20
+ script?: string
21
+ value?: number
22
+ }[]
23
+ address: string
24
+ addressScript: string
25
+ }
26
+
27
+ export type BitcoinConnectionInfo = {
28
+ rpc?: {
29
+ enabled?: boolean
30
+ url: string
31
+ headers?: {
32
+ [key: string]: string
33
+ }
34
+ auth?: {
35
+ username: string
36
+ password: string
37
+ }
38
+ }
39
+ api: {
40
+ token?: string
41
+ provider: string
42
+ }
43
+ }
@@ -4,27 +4,33 @@ function sleep(ms: number) {
4
4
  return new Promise((resolve) => setTimeout(resolve, ms))
5
5
  }
6
6
 
7
- async function runWithRetries(
8
- action: () => any,
9
- config = {
7
+ async function runWithRetries<T>(
8
+ action: () => Promise<T>,
9
+ config: {
10
+ maxTries?: number
11
+ retrySleep?: number
12
+ } = {
10
13
  maxTries: 2,
11
14
  retrySleep: 1000,
12
15
  },
13
- ) {
14
- const maxTries = config.maxTries || 2
15
- const retrySleep = config.retrySleep || 1000 // milliseconds
16
- let lastError
16
+ ): Promise<T> {
17
+ const maxTries = config.maxTries ?? 2
18
+ const retrySleep = config.retrySleep ?? 1000
19
+
20
+ let lastError: any
17
21
  for (let count = 0; count < maxTries; count += 1) {
18
22
  try {
19
23
  return await action()
20
24
  } catch (error: any) {
21
- console.log("error:" + error.message)
22
-
25
+ console.log(`Attempt ${count + 1} failed: ${error.message}`)
23
26
  lastError = error
27
+ if (count < maxTries - 1) {
28
+ await sleep(retrySleep)
29
+ }
24
30
  }
25
- await sleep(retrySleep)
26
31
  }
27
- throw lastError || new Error("function failed after retries")
32
+
33
+ throw lastError || new Error(`Function failed after ${maxTries} retries: ${lastError?.message}`)
28
34
  }
29
35
 
30
36
  function getRandomInteger(min: number, max: number) {
package/tsconfig.json CHANGED
@@ -2,8 +2,7 @@
2
2
  "extends": "../../tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "rootDir": "src" /* Specify the root folder within your source files. */,
5
- "outDir": "dist" /* Specify an output folder for all emitted files. */,
6
- "baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */
5
+ "outDir": "dist" /* Specify an output folder for all emitted files. */
7
6
  },
8
7
  "include": ["src"],
9
8
  "exclude": ["node_modules", "dist"]
@@ -1 +0,0 @@
1
- {"version":3,"file":"bitcoin-base.d.ts","sourceRoot":"","sources":["../src/bitcoin-base.ts"],"names":[],"mappings":"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"}