mainnet-js 1.1.1 → 1.1.3
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/dist/index.html +1 -1
- package/dist/{mainnet-1.1.1.js → mainnet-1.1.3.js} +4 -4
- package/dist/module/libauth.d.ts +1 -1
- package/dist/module/libauth.d.ts.map +1 -1
- package/dist/module/libauth.js +1 -1
- package/dist/module/libauth.js.map +1 -1
- package/dist/module/transaction/Wif.d.ts +42 -7
- package/dist/module/transaction/Wif.d.ts.map +1 -1
- package/dist/module/transaction/Wif.js +132 -107
- package/dist/module/transaction/Wif.js.map +1 -1
- package/dist/module/wallet/Slp.d.ts.map +1 -1
- package/dist/module/wallet/Slp.js +11 -1
- package/dist/module/wallet/Slp.js.map +1 -1
- package/dist/module/wallet/Wif.d.ts +8 -4
- package/dist/module/wallet/Wif.d.ts.map +1 -1
- package/dist/module/wallet/Wif.js +119 -55
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/module/wallet/interface.d.ts +2 -0
- package/dist/module/wallet/interface.d.ts.map +1 -1
- package/dist/module/wallet/model.d.ts +4 -0
- package/dist/module/wallet/model.d.ts.map +1 -1
- package/dist/module/wallet/model.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/libauth.ts +1 -0
- package/src/transaction/Wif.ts +207 -155
- package/src/wallet/Cashtokens.test.headless.js +161 -0
- package/src/wallet/Cashtokens.test.ts +179 -1
- package/src/wallet/Slp.ts +10 -7
- package/src/wallet/Wif.test.ts +101 -1
- package/src/wallet/Wif.ts +160 -92
- package/src/wallet/interface.ts +2 -0
- package/src/wallet/model.ts +6 -0
package/src/transaction/Wif.ts
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
CompilationContextBCH,
|
|
13
13
|
Output,
|
|
14
14
|
hexToBin,
|
|
15
|
+
verifyTransactionTokens,
|
|
16
|
+
stringify,
|
|
15
17
|
} from "@bitauth/libauth";
|
|
16
18
|
import { NFTCapability, TokenI, UtxoI } from "../interface.js";
|
|
17
19
|
import { allocateFee } from "./allocateFee.js";
|
|
@@ -29,16 +31,27 @@ import { sumUtxoValue } from "../util/sumUtxoValue.js";
|
|
|
29
31
|
import { FeePaidByEnum } from "../wallet/enum.js";
|
|
30
32
|
|
|
31
33
|
// Build a transaction for a p2pkh transaction for a non HD wallet
|
|
32
|
-
export async function buildP2pkhNonHdTransaction(
|
|
33
|
-
inputs
|
|
34
|
-
outputs
|
|
35
|
-
signingKey
|
|
36
|
-
|
|
34
|
+
export async function buildP2pkhNonHdTransaction({
|
|
35
|
+
inputs,
|
|
36
|
+
outputs,
|
|
37
|
+
signingKey,
|
|
38
|
+
sourceAddress,
|
|
39
|
+
fee = 0,
|
|
37
40
|
discardChange = false,
|
|
38
|
-
slpOutputs
|
|
39
|
-
feePaidBy
|
|
40
|
-
changeAddress
|
|
41
|
-
|
|
41
|
+
slpOutputs = [],
|
|
42
|
+
feePaidBy = FeePaidByEnum.change,
|
|
43
|
+
changeAddress = "",
|
|
44
|
+
}: {
|
|
45
|
+
inputs: UtxoI[];
|
|
46
|
+
outputs: Array<SendRequest | TokenSendRequest | OpReturnData>;
|
|
47
|
+
signingKey: Uint8Array;
|
|
48
|
+
sourceAddress: string;
|
|
49
|
+
fee?: number;
|
|
50
|
+
discardChange?: boolean;
|
|
51
|
+
slpOutputs?: Output[];
|
|
52
|
+
feePaidBy?: FeePaidByEnum;
|
|
53
|
+
changeAddress?: string;
|
|
54
|
+
}) {
|
|
42
55
|
if (!signingKey) {
|
|
43
56
|
throw new Error("Missing signing key when building transaction");
|
|
44
57
|
}
|
|
@@ -59,7 +72,7 @@ export async function buildP2pkhNonHdTransaction(
|
|
|
59
72
|
|
|
60
73
|
outputs = allocateFee(outputs, fee, feePaidBy, changeAmount);
|
|
61
74
|
|
|
62
|
-
|
|
75
|
+
const lockedOutputs = await prepareOutputs(outputs);
|
|
63
76
|
|
|
64
77
|
if (discardChange !== true) {
|
|
65
78
|
if (changeAmount > DUST_UTXO_THRESHOLD) {
|
|
@@ -85,31 +98,56 @@ export async function buildP2pkhNonHdTransaction(
|
|
|
85
98
|
}
|
|
86
99
|
}
|
|
87
100
|
|
|
88
|
-
|
|
101
|
+
const { preparedInputs, sourceOutputs } = prepareInputs({
|
|
102
|
+
inputs,
|
|
103
|
+
compiler,
|
|
104
|
+
signingKey,
|
|
105
|
+
sourceAddress,
|
|
106
|
+
});
|
|
89
107
|
const result = generateTransaction({
|
|
90
|
-
inputs:
|
|
108
|
+
inputs: preparedInputs,
|
|
91
109
|
locktime: 0,
|
|
92
110
|
outputs: [...slpOutputs, ...lockedOutputs],
|
|
93
111
|
version: 2,
|
|
94
112
|
});
|
|
95
|
-
|
|
113
|
+
|
|
114
|
+
if (!result.success) {
|
|
115
|
+
throw Error("Error building transaction with fee");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const tokenValidationResult = verifyTransactionTokens(
|
|
119
|
+
result.transaction,
|
|
120
|
+
sourceOutputs
|
|
121
|
+
);
|
|
122
|
+
if (tokenValidationResult !== true && fee > 0) {
|
|
123
|
+
throw tokenValidationResult;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { transaction: result.transaction, sourceOutputs: sourceOutputs };
|
|
96
127
|
}
|
|
97
128
|
|
|
98
|
-
export function prepareInputs(
|
|
99
|
-
inputs
|
|
129
|
+
export function prepareInputs({
|
|
130
|
+
inputs,
|
|
131
|
+
compiler,
|
|
132
|
+
signingKey,
|
|
133
|
+
sourceAddress,
|
|
134
|
+
}: {
|
|
135
|
+
inputs: UtxoI[];
|
|
100
136
|
compiler: Compiler<
|
|
101
137
|
CompilationContextBCH,
|
|
102
138
|
AnyCompilerConfiguration<CompilationContextBCH>,
|
|
103
139
|
AuthenticationProgramStateCommon
|
|
104
|
-
|
|
105
|
-
signingKey: Uint8Array
|
|
106
|
-
|
|
107
|
-
|
|
140
|
+
>;
|
|
141
|
+
signingKey: Uint8Array;
|
|
142
|
+
sourceAddress: string;
|
|
143
|
+
}) {
|
|
144
|
+
const preparedInputs: any[] = [];
|
|
145
|
+
const sourceOutputs: any[] = [];
|
|
108
146
|
for (const i of inputs) {
|
|
109
147
|
const utxoTxnValue = i.satoshis;
|
|
110
148
|
const utxoIndex = i.vout;
|
|
111
149
|
// slice will create a clone of the array
|
|
112
|
-
|
|
150
|
+
const utxoOutpointTransactionHash = new Uint8Array(
|
|
113
151
|
i.txid.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16))
|
|
114
152
|
);
|
|
115
153
|
// reverse the cloned copy
|
|
@@ -122,30 +160,57 @@ export function prepareInputs(
|
|
|
122
160
|
amount: BigInt(i.token.amount),
|
|
123
161
|
category: hexToBin(i.token.tokenId),
|
|
124
162
|
nft:
|
|
125
|
-
i.token.capability || i.token.commitment
|
|
163
|
+
i.token.capability !== undefined || i.token.commitment !== undefined
|
|
126
164
|
? {
|
|
127
165
|
capability: i.token.capability,
|
|
128
|
-
commitment:
|
|
166
|
+
commitment:
|
|
167
|
+
i.token.commitment !== undefined &&
|
|
168
|
+
hexToBin(i.token.commitment!),
|
|
129
169
|
}
|
|
130
170
|
: undefined,
|
|
131
171
|
};
|
|
132
|
-
|
|
172
|
+
const newInput = signingKey?.length
|
|
173
|
+
? {
|
|
174
|
+
outpointIndex: utxoIndex,
|
|
175
|
+
outpointTransactionHash: utxoOutpointTransactionHash,
|
|
176
|
+
sequenceNumber: 0,
|
|
177
|
+
unlockingBytecode: {
|
|
178
|
+
compiler,
|
|
179
|
+
data: {
|
|
180
|
+
keys: { privateKeys: { key: signingKey } },
|
|
181
|
+
},
|
|
182
|
+
valueSatoshis: BigInt(utxoTxnValue),
|
|
183
|
+
script: "unlock",
|
|
184
|
+
token: libAuthToken,
|
|
185
|
+
},
|
|
186
|
+
}
|
|
187
|
+
: {
|
|
188
|
+
outpointIndex: utxoIndex,
|
|
189
|
+
outpointTransactionHash: utxoOutpointTransactionHash,
|
|
190
|
+
sequenceNumber: 0,
|
|
191
|
+
unlockingBytecode: Uint8Array.from([]),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
preparedInputs.push(newInput);
|
|
195
|
+
|
|
196
|
+
const lockingBytecode = cashAddressToLockingBytecode(sourceAddress);
|
|
197
|
+
if (typeof lockingBytecode === "string") {
|
|
198
|
+
throw lockingBytecode;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
sourceOutputs.push({
|
|
133
202
|
outpointIndex: utxoIndex,
|
|
134
203
|
outpointTransactionHash: utxoOutpointTransactionHash,
|
|
135
204
|
sequenceNumber: 0,
|
|
136
|
-
unlockingBytecode:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
token: libAuthToken,
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
signedInputs.push(newInput);
|
|
205
|
+
unlockingBytecode: Uint8Array.from([]),
|
|
206
|
+
|
|
207
|
+
// additional info for sourceOutputs
|
|
208
|
+
lockingBytecode: lockingBytecode.bytecode,
|
|
209
|
+
valueSatoshis: BigInt(utxoTxnValue),
|
|
210
|
+
token: libAuthToken,
|
|
211
|
+
});
|
|
147
212
|
}
|
|
148
|
-
return
|
|
213
|
+
return { preparedInputs, sourceOutputs };
|
|
149
214
|
}
|
|
150
215
|
|
|
151
216
|
/**
|
|
@@ -156,13 +221,12 @@ export function prepareInputs(
|
|
|
156
221
|
* @returns A promise to a list of unspent outputs
|
|
157
222
|
*/
|
|
158
223
|
export async function prepareOutputs(
|
|
159
|
-
outputs: Array<SendRequest | TokenSendRequest | OpReturnData
|
|
160
|
-
inputs: UtxoI[]
|
|
224
|
+
outputs: Array<SendRequest | TokenSendRequest | OpReturnData>
|
|
161
225
|
) {
|
|
162
|
-
|
|
226
|
+
const lockedOutputs: Output[] = [];
|
|
163
227
|
for (const output of outputs) {
|
|
164
228
|
if (output instanceof TokenSendRequest) {
|
|
165
|
-
lockedOutputs.push(prepareTokenOutputs(output
|
|
229
|
+
lockedOutputs.push(prepareTokenOutputs(output));
|
|
166
230
|
continue;
|
|
167
231
|
}
|
|
168
232
|
|
|
@@ -207,49 +271,9 @@ export function prepareOpReturnOutput(request: OpReturnData): Output {
|
|
|
207
271
|
*
|
|
208
272
|
* @returns A libauth Output
|
|
209
273
|
*/
|
|
210
|
-
export function prepareTokenOutputs(
|
|
211
|
-
request: TokenSendRequest,
|
|
212
|
-
inputs: UtxoI[]
|
|
213
|
-
): Output {
|
|
274
|
+
export function prepareTokenOutputs(request: TokenSendRequest): Output {
|
|
214
275
|
const token: TokenI = request;
|
|
215
|
-
const
|
|
216
|
-
let satValue = 0;
|
|
217
|
-
if (isGenesis) {
|
|
218
|
-
const genesisInputs = inputs.filter((val) => val.vout === 0);
|
|
219
|
-
if (genesisInputs.length === 0) {
|
|
220
|
-
throw new Error(
|
|
221
|
-
"No suitable inputs with vout=0 available for new token genesis"
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
token.tokenId = genesisInputs[0].txid;
|
|
225
|
-
satValue = request.value || 1000;
|
|
226
|
-
(request as any)._isGenesis = true;
|
|
227
|
-
} else {
|
|
228
|
-
const tokenInputs = inputs.filter(
|
|
229
|
-
(val) =>
|
|
230
|
-
val.token?.tokenId &&
|
|
231
|
-
val.token?.tokenId === request.tokenId &&
|
|
232
|
-
(val.token?.capability === "none"
|
|
233
|
-
? val.token.capability === request.capability &&
|
|
234
|
-
val.token?.commitment === request.commitment
|
|
235
|
-
: true)
|
|
236
|
-
);
|
|
237
|
-
if (!tokenInputs.length) {
|
|
238
|
-
throw new Error(
|
|
239
|
-
`No suitable token utxos available to send token with id "${request.tokenId}", capability "${request.capability}", commitment "${request.commitment}"`
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
if (!token.capability && tokenInputs[0].token?.capability) {
|
|
243
|
-
token.capability = tokenInputs[0].token!.capability;
|
|
244
|
-
}
|
|
245
|
-
if (!token.commitment && tokenInputs[0].token?.commitment) {
|
|
246
|
-
token.commitment = tokenInputs[0].token!.commitment;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
satValue = request.value || tokenInputs[0].satoshis;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
let outputLockingBytecode = cashAddressToLockingBytecode(request.cashaddr);
|
|
276
|
+
const outputLockingBytecode = cashAddressToLockingBytecode(request.cashaddr);
|
|
253
277
|
if (typeof outputLockingBytecode === "string")
|
|
254
278
|
throw new Error(outputLockingBytecode);
|
|
255
279
|
|
|
@@ -257,17 +281,18 @@ export function prepareTokenOutputs(
|
|
|
257
281
|
amount: BigInt(token.amount),
|
|
258
282
|
category: hexToBin(token.tokenId),
|
|
259
283
|
nft:
|
|
260
|
-
token.capability || token.commitment
|
|
284
|
+
token.capability !== undefined || token.commitment !== undefined
|
|
261
285
|
? {
|
|
262
286
|
capability: token.capability,
|
|
263
|
-
commitment:
|
|
287
|
+
commitment:
|
|
288
|
+
token.commitment !== undefined && hexToBin(token.commitment!),
|
|
264
289
|
}
|
|
265
290
|
: undefined,
|
|
266
291
|
};
|
|
267
292
|
|
|
268
293
|
return {
|
|
269
294
|
lockingBytecode: outputLockingBytecode.bytecode,
|
|
270
|
-
valueSatoshis: BigInt(
|
|
295
|
+
valueSatoshis: BigInt(request.value || 1000),
|
|
271
296
|
token: libAuthToken,
|
|
272
297
|
} as Output;
|
|
273
298
|
}
|
|
@@ -287,61 +312,72 @@ export async function getSuitableUtxos(
|
|
|
287
312
|
bestHeight: number,
|
|
288
313
|
feePaidBy: FeePaidByEnum,
|
|
289
314
|
requests: SendRequestType[],
|
|
290
|
-
ensureUtxos: UtxoI[] = []
|
|
315
|
+
ensureUtxos: UtxoI[] = [],
|
|
316
|
+
tokenOperation: "send" | "genesis" | "mint" | "burn" = "send"
|
|
291
317
|
): Promise<UtxoI[]> {
|
|
292
|
-
|
|
318
|
+
const suitableUtxos: UtxoI[] = [...ensureUtxos];
|
|
293
319
|
let amountAvailable = BigInt(0);
|
|
294
|
-
const tokenAmountsRequired: any[] = [];
|
|
295
320
|
const tokenRequests = requests.filter(
|
|
296
321
|
(val) => val instanceof TokenSendRequest
|
|
297
322
|
) as TokenSendRequest[];
|
|
298
323
|
|
|
299
|
-
|
|
300
|
-
const isTokenGenesis = tokenRequests.some(
|
|
301
|
-
(val) => !val.tokenId || (val as any)._isGenesis
|
|
302
|
-
);
|
|
303
|
-
const bchOnlyTransfer = tokenRequests.length === 0;
|
|
304
|
-
let filteredInputs =
|
|
305
|
-
isTokenGenesis || bchOnlyTransfer
|
|
306
|
-
? inputs.slice(0).filter((val) => !val.token)
|
|
307
|
-
: inputs.slice();
|
|
308
|
-
const tokenIds = tokenRequests
|
|
309
|
-
.map((val) => val.tokenId)
|
|
310
|
-
.filter((value, index, array) => array.indexOf(value) === index);
|
|
311
|
-
for (let tokenId of tokenIds) {
|
|
312
|
-
const requiredAmount = tokenRequests
|
|
313
|
-
.map((val) => val.amount)
|
|
314
|
-
.reduce((prev, cur) => prev + cur, 0);
|
|
315
|
-
tokenAmountsRequired.push({ tokenId, requiredAmount });
|
|
316
|
-
}
|
|
324
|
+
const availableInputs = inputs.slice();
|
|
317
325
|
|
|
318
|
-
// find
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
326
|
+
// find matching utxos for token transfers
|
|
327
|
+
if (tokenOperation === "send") {
|
|
328
|
+
for (const request of tokenRequests) {
|
|
329
|
+
const tokenInputs = availableInputs.filter(
|
|
330
|
+
(val) => val.token?.tokenId === request.tokenId
|
|
331
|
+
);
|
|
332
|
+
const sameCommitmentTokens = [...suitableUtxos, ...tokenInputs].filter(
|
|
333
|
+
(val) =>
|
|
334
|
+
val.token?.capability === request.capability &&
|
|
335
|
+
val.token?.commitment === request.commitment
|
|
336
|
+
);
|
|
337
|
+
if (sameCommitmentTokens.length) {
|
|
338
|
+
const input = sameCommitmentTokens[0];
|
|
339
|
+
const index = availableInputs.indexOf(input);
|
|
340
|
+
if (index !== -1) {
|
|
341
|
+
suitableUtxos.push(input);
|
|
342
|
+
availableInputs.splice(index, 1);
|
|
343
|
+
amountAvailable += BigInt(input.satoshis);
|
|
332
344
|
}
|
|
345
|
+
|
|
346
|
+
continue;
|
|
333
347
|
}
|
|
348
|
+
|
|
349
|
+
if (
|
|
350
|
+
request.capability === NFTCapability.minting ||
|
|
351
|
+
request.capability === NFTCapability.mutable
|
|
352
|
+
) {
|
|
353
|
+
const changeCommitmentTokens = [
|
|
354
|
+
...suitableUtxos,
|
|
355
|
+
...tokenInputs,
|
|
356
|
+
].filter((val) => val.token?.capability === request.capability);
|
|
357
|
+
if (changeCommitmentTokens.length) {
|
|
358
|
+
const input = changeCommitmentTokens[0];
|
|
359
|
+
const index = availableInputs.indexOf(input);
|
|
360
|
+
if (index !== -1) {
|
|
361
|
+
suitableUtxos.push(input);
|
|
362
|
+
availableInputs.splice(index, 1);
|
|
363
|
+
amountAvailable += BigInt(input.satoshis);
|
|
364
|
+
}
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
throw Error(
|
|
369
|
+
`No suitable token utxos available to send token with id "${request.tokenId}", capability "${request.capability}", commitment "${request.commitment}"`
|
|
370
|
+
);
|
|
334
371
|
}
|
|
335
372
|
}
|
|
336
|
-
|
|
337
373
|
// find plain bch outputs
|
|
338
|
-
for (const u of
|
|
374
|
+
for (const u of availableInputs) {
|
|
339
375
|
if (u.token) {
|
|
340
376
|
continue;
|
|
341
377
|
}
|
|
342
378
|
|
|
343
379
|
if (u.coinbase && u.height && bestHeight) {
|
|
344
|
-
|
|
380
|
+
const age = bestHeight - u.height;
|
|
345
381
|
if (age > 100) {
|
|
346
382
|
suitableUtxos.push(u);
|
|
347
383
|
amountAvailable += BigInt(u.satoshis);
|
|
@@ -357,8 +393,11 @@ export async function getSuitableUtxos(
|
|
|
357
393
|
}
|
|
358
394
|
|
|
359
395
|
const addEnsured = (suitableUtxos) => {
|
|
360
|
-
return [...
|
|
361
|
-
(val, index, array) =>
|
|
396
|
+
return [...ensureUtxos, ...suitableUtxos].filter(
|
|
397
|
+
(val, index, array) =>
|
|
398
|
+
array.findIndex(
|
|
399
|
+
(other) => other.txid === val.txid && other.vout === val.vout
|
|
400
|
+
) === index
|
|
362
401
|
);
|
|
363
402
|
};
|
|
364
403
|
|
|
@@ -371,7 +410,7 @@ export async function getSuitableUtxos(
|
|
|
371
410
|
if (typeof amountRequired === "undefined") {
|
|
372
411
|
return addEnsured(suitableUtxos);
|
|
373
412
|
} else if (amountAvailable < amountRequired) {
|
|
374
|
-
|
|
413
|
+
const e = Error(
|
|
375
414
|
`Amount required was not met, ${amountRequired} satoshis needed, ${amountAvailable} satoshis available`
|
|
376
415
|
);
|
|
377
416
|
e["data"] = {
|
|
@@ -388,6 +427,7 @@ export async function getFeeAmount({
|
|
|
388
427
|
utxos,
|
|
389
428
|
sendRequests,
|
|
390
429
|
privateKey,
|
|
430
|
+
sourceAddress,
|
|
391
431
|
relayFeePerByteInSatoshi,
|
|
392
432
|
slpOutputs,
|
|
393
433
|
feePaidBy,
|
|
@@ -396,6 +436,7 @@ export async function getFeeAmount({
|
|
|
396
436
|
utxos: UtxoI[];
|
|
397
437
|
sendRequests: Array<SendRequest | TokenSendRequest | OpReturnData>;
|
|
398
438
|
privateKey: Uint8Array;
|
|
439
|
+
sourceAddress: string;
|
|
399
440
|
relayFeePerByteInSatoshi: number;
|
|
400
441
|
slpOutputs: Output[];
|
|
401
442
|
feePaidBy: FeePaidByEnum;
|
|
@@ -404,15 +445,18 @@ export async function getFeeAmount({
|
|
|
404
445
|
// build transaction
|
|
405
446
|
if (utxos) {
|
|
406
447
|
// Build the transaction to get the approximate size
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
448
|
+
const { encodedTransaction: draftTransaction } =
|
|
449
|
+
await buildEncodedTransaction({
|
|
450
|
+
inputs: utxos,
|
|
451
|
+
outputs: sendRequests,
|
|
452
|
+
signingKey: privateKey,
|
|
453
|
+
sourceAddress,
|
|
454
|
+
fee: 0, //DUST_UTXO_THRESHOLD
|
|
455
|
+
discardChange: discardChange ?? false,
|
|
456
|
+
slpOutputs,
|
|
457
|
+
feePaidBy,
|
|
458
|
+
changeAddress: "",
|
|
459
|
+
});
|
|
416
460
|
|
|
417
461
|
return draftTransaction.length * relayFeePerByteInSatoshi + 1;
|
|
418
462
|
} else {
|
|
@@ -423,30 +467,38 @@ export async function getFeeAmount({
|
|
|
423
467
|
}
|
|
424
468
|
|
|
425
469
|
// Build encoded transaction
|
|
426
|
-
export async function buildEncodedTransaction(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
470
|
+
export async function buildEncodedTransaction({
|
|
471
|
+
inputs,
|
|
472
|
+
outputs,
|
|
473
|
+
signingKey,
|
|
474
|
+
sourceAddress,
|
|
475
|
+
fee = 0,
|
|
431
476
|
discardChange = false,
|
|
432
|
-
slpOutputs
|
|
433
|
-
feePaidBy
|
|
434
|
-
changeAddress
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
477
|
+
slpOutputs = [],
|
|
478
|
+
feePaidBy = FeePaidByEnum.change,
|
|
479
|
+
changeAddress = "",
|
|
480
|
+
}: {
|
|
481
|
+
inputs: UtxoI[];
|
|
482
|
+
outputs: Array<SendRequest | TokenSendRequest | OpReturnData>;
|
|
483
|
+
signingKey: Uint8Array;
|
|
484
|
+
sourceAddress: string;
|
|
485
|
+
fee?: number;
|
|
486
|
+
discardChange?: boolean;
|
|
487
|
+
slpOutputs?: Output[];
|
|
488
|
+
feePaidBy?: FeePaidByEnum;
|
|
489
|
+
changeAddress?: string;
|
|
490
|
+
}) {
|
|
491
|
+
const { transaction, sourceOutputs } = await buildP2pkhNonHdTransaction({
|
|
492
|
+
inputs,
|
|
493
|
+
outputs,
|
|
494
|
+
signingKey,
|
|
495
|
+
sourceAddress,
|
|
440
496
|
fee,
|
|
441
497
|
discardChange,
|
|
442
498
|
slpOutputs,
|
|
443
499
|
feePaidBy,
|
|
444
|
-
changeAddress
|
|
445
|
-
);
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return encodeTransaction(txn.transaction);
|
|
449
|
-
} else {
|
|
450
|
-
throw Error("Error building transaction with fee");
|
|
451
|
-
}
|
|
500
|
+
changeAddress,
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
return { encodedTransaction: encodeTransaction(transaction), sourceOutputs };
|
|
452
504
|
}
|