@atomicfinance/bitcoin-dlc-provider 3.3.1 → 3.4.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.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +1 -1
- package/CHANGELOG.md +25 -0
- package/dist/BitcoinDlcProvider.d.ts +40 -3
- package/dist/BitcoinDlcProvider.js +313 -13
- package/dist/BitcoinDlcProvider.js.map +1 -1
- package/dist/utils/Utils.d.ts +2 -1
- package/dist/utils/Utils.js +7 -3
- package/dist/utils/Utils.js.map +1 -1
- package/lib/BitcoinDlcProvider.ts +696 -18
- package/lib/utils/Utils.ts +9 -2
- package/package.json +7 -7
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@atomicfinance/bitcoin-dlc-provider:build: cache hit, replaying output [
|
|
1
|
+
@atomicfinance/bitcoin-dlc-provider:build: cache hit, replaying output [2m00b63627c699c688[0m
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@atomicfinance/bitcoin-dlc-provider:test: cache hit, replaying output [
|
|
1
|
+
@atomicfinance/bitcoin-dlc-provider:test: cache hit, replaying output [2m31067a0dabb09d92[0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @atomicfinance/bitcoin-dlc-provider
|
|
2
2
|
|
|
3
|
+
## 3.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9781efe: Add getInputsForDualFunding functionality and bump @node-dlc
|
|
8
|
+
- Updated dependencies [9781efe]
|
|
9
|
+
- @atomicfinance/bitcoin-utils@3.4.1
|
|
10
|
+
- @atomicfinance/types@3.4.1
|
|
11
|
+
- @atomicfinance/provider@3.4.1
|
|
12
|
+
- @atomicfinance/utils@3.4.1
|
|
13
|
+
|
|
14
|
+
## 3.4.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 314d7d7: Add batch dlc funding transactions
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [314d7d7]
|
|
23
|
+
- @atomicfinance/types@3.4.0
|
|
24
|
+
- @atomicfinance/bitcoin-utils@3.4.0
|
|
25
|
+
- @atomicfinance/provider@3.4.0
|
|
26
|
+
- @atomicfinance/utils@3.4.0
|
|
27
|
+
|
|
3
28
|
## 3.3.1
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import Provider from '@atomicfinance/provider';
|
|
3
|
-
import { AddSignaturesToRefundTxRequest, AddSignaturesToRefundTxResponse, AddSignatureToFundTransactionRequest, AddSignatureToFundTransactionResponse, CreateCetAdaptorSignatureRequest, CreateCetAdaptorSignatureResponse, CreateCetAdaptorSignaturesRequest, CreateCetAdaptorSignaturesResponse, CreateCetRequest, CreateCetResponse, CreateDlcTransactionsRequest, CreateDlcTransactionsResponse, CreateFundTransactionRequest, CreateFundTransactionResponse, CreateRefundTransactionRequest, CreateRefundTransactionResponse, DlcProvider, GetRawFundTxSignatureRequest, GetRawFundTxSignatureResponse, GetRawRefundTxSignatureRequest, GetRawRefundTxSignatureResponse, Input, Messages, PayoutRequest, SignCetRequest, SignCetResponse, SignFundTransactionRequest, SignFundTransactionResponse, VerifyCetAdaptorSignatureRequest, VerifyCetAdaptorSignatureResponse, VerifyCetAdaptorSignaturesRequest, VerifyCetAdaptorSignaturesResponse, VerifyFundTxSignatureRequest, VerifyFundTxSignatureResponse, VerifyRefundTxSignatureRequest, VerifyRefundTxSignatureResponse } from '@atomicfinance/types';
|
|
3
|
+
import { AddSignaturesToRefundTxRequest, AddSignaturesToRefundTxResponse, AddSignatureToFundTransactionRequest, AddSignatureToFundTransactionResponse, CreateBatchDlcTransactionsRequest, CreateBatchDlcTransactionsResponse, CreateBatchFundTransactionRequest, CreateBatchFundTransactionResponse, CreateCetAdaptorSignatureRequest, CreateCetAdaptorSignatureResponse, CreateCetAdaptorSignaturesRequest, CreateCetAdaptorSignaturesResponse, CreateCetRequest, CreateCetResponse, CreateDlcTransactionsRequest, CreateDlcTransactionsResponse, CreateFundTransactionRequest, CreateFundTransactionResponse, CreateRefundTransactionRequest, CreateRefundTransactionResponse, DlcProvider, GetRawFundTxSignatureRequest, GetRawFundTxSignatureResponse, GetRawRefundTxSignatureRequest, GetRawRefundTxSignatureResponse, Input, Messages, PayoutRequest, SignCetRequest, SignCetResponse, SignFundTransactionRequest, SignFundTransactionResponse, VerifyCetAdaptorSignatureRequest, VerifyCetAdaptorSignatureResponse, VerifyCetAdaptorSignaturesRequest, VerifyCetAdaptorSignaturesResponse, VerifyFundTxSignatureRequest, VerifyFundTxSignatureResponse, VerifyRefundTxSignatureRequest, VerifyRefundTxSignatureResponse } from '@atomicfinance/types';
|
|
4
4
|
import { CetAdaptorSignaturesV0, ContractDescriptorV1, ContractInfo, DlcAccept, DlcClose, DlcCloseMetadata, DlcOffer, DlcSign, DlcTransactions, FundingInput, HyperbolaPayoutCurvePiece, OracleAttestationV0, PolynomialPayoutCurvePiece } from '@node-dlc/messaging';
|
|
5
5
|
import { Tx } from '@node-lightning/bitcoin';
|
|
6
6
|
import { BitcoinNetwork } from 'bitcoin-networks';
|
|
@@ -11,8 +11,9 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
11
11
|
private CfdLoaded;
|
|
12
12
|
private GetPrivKeysForInputs;
|
|
13
13
|
GetCfdNetwork(): Promise<string>;
|
|
14
|
-
GetInputsForAmount(
|
|
14
|
+
GetInputsForAmount(amounts: bigint[], feeRatePerVb: bigint, fixedInputs?: Input[]): Promise<Input[]>;
|
|
15
15
|
private Initialize;
|
|
16
|
+
private BatchInitialize;
|
|
16
17
|
/**
|
|
17
18
|
* TODO: Add GetPayoutFromOutcomes
|
|
18
19
|
*
|
|
@@ -28,6 +29,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
28
29
|
private GetIndicesFromPayouts;
|
|
29
30
|
private GetPayoutsFromContractDescriptor;
|
|
30
31
|
createDlcTxs(_dlcOffer: DlcOffer, _dlcAccept: DlcAccept): Promise<CreateDlcTxsResponse>;
|
|
32
|
+
createBatchDlcTxs(_dlcOffers: DlcOffer[], _dlcAccepts: DlcAccept[]): Promise<CreateBatchDlcTxsResponse>;
|
|
31
33
|
private GenerateEnumMessages;
|
|
32
34
|
private GenerateDigitDecompositionMessages;
|
|
33
35
|
private GenerateMessages;
|
|
@@ -66,6 +68,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
66
68
|
* @returns {Promise<DlcOffer>}
|
|
67
69
|
*/
|
|
68
70
|
createDlcOffer(contractInfo: ContractInfo, offerCollateralSatoshis: bigint, feeRatePerVb: bigint, cetLocktime: number, refundLocktime: number, fixedInputs?: Input[]): Promise<DlcOffer>;
|
|
71
|
+
batchCreateDlcOffer(contractInfos: ContractInfo[], offerCollaterals: bigint[], feeRatePerVb: bigint, cetLocktime: number, refundLocktimes: number[], fixedInputs?: Input[]): Promise<DlcOffer[]>;
|
|
69
72
|
/**
|
|
70
73
|
* Accept DLC Offer
|
|
71
74
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -73,6 +76,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
73
76
|
* @returns {Promise<AcceptDlcOfferResponse}
|
|
74
77
|
*/
|
|
75
78
|
acceptDlcOffer(_dlcOffer: DlcOffer, fixedInputs?: Input[]): Promise<AcceptDlcOfferResponse>;
|
|
79
|
+
batchAcceptDlcOffer(_dlcOffers: DlcOffer[], fixedInputs?: Input[]): Promise<BatchAcceptDlcOfferResponse>;
|
|
76
80
|
/**
|
|
77
81
|
* Sign Dlc Accept Message
|
|
78
82
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -80,6 +84,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
80
84
|
* @returns {Promise<SignDlcAcceptResponse}
|
|
81
85
|
*/
|
|
82
86
|
signDlcAccept(_dlcOffer: DlcOffer, _dlcAccept: DlcAccept): Promise<SignDlcAcceptResponse>;
|
|
87
|
+
batchSignDlcAccept(_dlcOffers: DlcOffer[], _dlcAccepts: DlcAccept[]): Promise<BatchSignDlcAcceptResponse>;
|
|
83
88
|
/**
|
|
84
89
|
* Finalize Dlc Sign
|
|
85
90
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -89,6 +94,7 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
89
94
|
* @returns {Promise<Tx>}
|
|
90
95
|
*/
|
|
91
96
|
finalizeDlcSign(_dlcOffer: DlcOffer, _dlcAccept: DlcAccept, _dlcSign: DlcSign, _dlcTxs: DlcTransactions): Promise<Tx>;
|
|
97
|
+
batchFinalizeDlcSign(_dlcOffers: DlcOffer[], _dlcAccepts: DlcAccept[], _dlcSigns: DlcSign[], _dlcTxsList: DlcTransactions[]): Promise<Tx>;
|
|
92
98
|
/**
|
|
93
99
|
* Execute DLC
|
|
94
100
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -170,7 +176,9 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
170
176
|
AddSignaturesToRefundTx(jsonObject: AddSignaturesToRefundTxRequest): Promise<AddSignaturesToRefundTxResponse>;
|
|
171
177
|
CreateCet(jsonObject: CreateCetRequest): Promise<CreateCetResponse>;
|
|
172
178
|
CreateDlcTransactions(jsonObject: CreateDlcTransactionsRequest): Promise<CreateDlcTransactionsResponse>;
|
|
179
|
+
CreateBatchDlcTransactions(jsonObject: CreateBatchDlcTransactionsRequest): Promise<CreateBatchDlcTransactionsResponse>;
|
|
173
180
|
CreateFundTransaction(jsonObject: CreateFundTransactionRequest): Promise<CreateFundTransactionResponse>;
|
|
181
|
+
CreateBatchFundTransaction(jsonObject: CreateBatchFundTransactionRequest): Promise<CreateBatchFundTransactionResponse>;
|
|
174
182
|
CreateRefundTransaction(jsonObject: CreateRefundTransactionRequest): Promise<CreateRefundTransactionResponse>;
|
|
175
183
|
GetRawFundTxSignature(jsonObject: GetRawFundTxSignatureRequest): Promise<GetRawFundTxSignatureResponse>;
|
|
176
184
|
GetRawRefundTxSignature(jsonObject: GetRawRefundTxSignatureRequest): Promise<GetRawRefundTxSignatureResponse>;
|
|
@@ -184,10 +192,23 @@ export default class BitcoinDlcProvider extends Provider implements Partial<DlcP
|
|
|
184
192
|
inputToFundingInput(input: Input): Promise<FundingInput>;
|
|
185
193
|
getConnectedNetwork(): Promise<BitcoinNetwork>;
|
|
186
194
|
}
|
|
187
|
-
export interface
|
|
195
|
+
export interface BasicInitializeResponse {
|
|
188
196
|
fundingPubKey: Buffer;
|
|
189
197
|
payoutSPK: Buffer;
|
|
190
198
|
payoutSerialId: bigint;
|
|
199
|
+
changeSPK: Buffer;
|
|
200
|
+
changeSerialId: bigint;
|
|
201
|
+
}
|
|
202
|
+
export interface InitializeResponse extends BasicInitializeResponse {
|
|
203
|
+
fundingInputs: FundingInput[];
|
|
204
|
+
}
|
|
205
|
+
export interface BatchBaseInitializeResponse {
|
|
206
|
+
fundingPubKey: Buffer;
|
|
207
|
+
payoutSPK: Buffer;
|
|
208
|
+
payoutSerialId: bigint;
|
|
209
|
+
}
|
|
210
|
+
export interface BatchInitializeResponse {
|
|
211
|
+
initializeResponses: BatchBaseInitializeResponse[];
|
|
191
212
|
fundingInputs: FundingInput[];
|
|
192
213
|
changeSPK: Buffer;
|
|
193
214
|
changeSerialId: bigint;
|
|
@@ -196,10 +217,18 @@ export interface AcceptDlcOfferResponse {
|
|
|
196
217
|
dlcAccept: DlcAccept;
|
|
197
218
|
dlcTransactions: DlcTransactions;
|
|
198
219
|
}
|
|
220
|
+
export interface BatchAcceptDlcOfferResponse {
|
|
221
|
+
dlcAccepts: DlcAccept[];
|
|
222
|
+
dlcTransactionsList: DlcTransactions[];
|
|
223
|
+
}
|
|
199
224
|
export interface SignDlcAcceptResponse {
|
|
200
225
|
dlcSign: DlcSign;
|
|
201
226
|
dlcTransactions: DlcTransactions;
|
|
202
227
|
}
|
|
228
|
+
export interface BatchSignDlcAcceptResponse {
|
|
229
|
+
dlcSigns: DlcSign[];
|
|
230
|
+
dlcTransactionsList: DlcTransactions[];
|
|
231
|
+
}
|
|
203
232
|
export interface GetPayoutsResponse {
|
|
204
233
|
payouts: PayoutRequest[];
|
|
205
234
|
payoutGroups: PayoutGroup[];
|
|
@@ -209,6 +238,10 @@ export interface CreateDlcTxsResponse {
|
|
|
209
238
|
dlcTransactions: DlcTransactions;
|
|
210
239
|
messagesList: Messages[];
|
|
211
240
|
}
|
|
241
|
+
export interface CreateBatchDlcTxsResponse {
|
|
242
|
+
dlcTransactionsList: DlcTransactions[];
|
|
243
|
+
nestedMessagesList: Messages[][];
|
|
244
|
+
}
|
|
212
245
|
export interface CreateCetAdaptorAndRefundSigsResponse {
|
|
213
246
|
cetSignatures: CetAdaptorSignaturesV0;
|
|
214
247
|
refundSignature: Buffer;
|
|
@@ -234,4 +267,8 @@ export interface InputsForAmountResponse {
|
|
|
234
267
|
outputs: Output[];
|
|
235
268
|
fee: number;
|
|
236
269
|
}
|
|
270
|
+
export interface InputsForDualAmountResponse {
|
|
271
|
+
inputs: Input[];
|
|
272
|
+
fee: number;
|
|
273
|
+
}
|
|
237
274
|
export {};
|
|
@@ -16,7 +16,6 @@ const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
|
16
16
|
const bitcoin_networks_1 = require("bitcoin-networks");
|
|
17
17
|
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
|
|
18
18
|
const Utils_1 = require("./utils/Utils");
|
|
19
|
-
const ESTIMATED_SIZE = 312;
|
|
20
19
|
class BitcoinDlcProvider extends provider_1.default {
|
|
21
20
|
constructor(network, cfdDlcJs) {
|
|
22
21
|
super();
|
|
@@ -53,23 +52,19 @@ class BitcoinDlcProvider extends provider_1.default {
|
|
|
53
52
|
return 'bitcoin';
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
|
-
async GetInputsForAmount(
|
|
57
|
-
if (
|
|
55
|
+
async GetInputsForAmount(amounts, feeRatePerVb, fixedInputs = []) {
|
|
56
|
+
if (amounts.length === 0)
|
|
58
57
|
return [];
|
|
59
|
-
const
|
|
60
|
-
{
|
|
61
|
-
address: BurnAddress,
|
|
62
|
-
value: Number(amount) + ESTIMATED_SIZE * (Number(feeRatePerVb) - 1),
|
|
63
|
-
},
|
|
64
|
-
];
|
|
58
|
+
const fixedUtxos = fixedInputs.map((input) => input.toUtxo());
|
|
65
59
|
let inputs;
|
|
66
60
|
try {
|
|
67
|
-
const inputsForAmount = await this.getMethod('
|
|
61
|
+
const inputsForAmount = await this.getMethod('getInputsForDualFunding')(amounts, feeRatePerVb, fixedUtxos);
|
|
68
62
|
inputs = inputsForAmount.inputs;
|
|
69
63
|
}
|
|
70
64
|
catch (e) {
|
|
65
|
+
const errorMessage = e instanceof Error ? e.message : 'Unknown error';
|
|
71
66
|
if (fixedInputs.length === 0) {
|
|
72
|
-
throw Error(
|
|
67
|
+
throw Error(`Not enough balance getInputsForAmount. Error: ${errorMessage}`);
|
|
73
68
|
}
|
|
74
69
|
else {
|
|
75
70
|
inputs = fixedInputs;
|
|
@@ -87,7 +82,7 @@ class BitcoinDlcProvider extends provider_1.default {
|
|
|
87
82
|
const fundingPubKey = Buffer.from(fundingAddress.publicKey, 'hex');
|
|
88
83
|
if (fundingAddress.address === payoutAddress.address)
|
|
89
84
|
throw Error('Address reuse');
|
|
90
|
-
const inputs = await this.GetInputsForAmount(collateral, feeRatePerVb, fixedInputs);
|
|
85
|
+
const inputs = await this.GetInputsForAmount([collateral], feeRatePerVb, fixedInputs);
|
|
91
86
|
const fundingInputs = await Promise.all(inputs.map(async (input) => {
|
|
92
87
|
return this.inputToFundingInput(input);
|
|
93
88
|
}));
|
|
@@ -102,6 +97,32 @@ class BitcoinDlcProvider extends provider_1.default {
|
|
|
102
97
|
changeSerialId,
|
|
103
98
|
};
|
|
104
99
|
}
|
|
100
|
+
async BatchInitialize(collaterals, feeRatePerVb, fixedInputs) {
|
|
101
|
+
const network = await this.getConnectedNetwork();
|
|
102
|
+
const inputs = await this.GetInputsForAmount(collaterals, feeRatePerVb, fixedInputs);
|
|
103
|
+
const fundingInputs = await Promise.all(inputs.map(async (input) => {
|
|
104
|
+
return this.inputToFundingInput(input);
|
|
105
|
+
}));
|
|
106
|
+
const initializeResponses = [];
|
|
107
|
+
const changeSerialId = Utils_1.generateSerialId();
|
|
108
|
+
const changeAddress = await this.client.wallet.getUnusedAddress(true);
|
|
109
|
+
const changeSPK = bitcoinjs_lib_1.address.toOutputScript(changeAddress.address, network);
|
|
110
|
+
for (let i = 0; i < collaterals.length; i++) {
|
|
111
|
+
const payoutAddress = await this.client.wallet.getUnusedAddress(false);
|
|
112
|
+
const payoutSPK = bitcoinjs_lib_1.address.toOutputScript(payoutAddress.address, network);
|
|
113
|
+
const fundingAddress = await this.client.wallet.getUnusedAddress(false);
|
|
114
|
+
const fundingPubKey = Buffer.from(fundingAddress.publicKey, 'hex');
|
|
115
|
+
if (fundingAddress.address === payoutAddress.address)
|
|
116
|
+
throw Error('Address reuse');
|
|
117
|
+
const payoutSerialId = Utils_1.generateSerialId();
|
|
118
|
+
initializeResponses.push({
|
|
119
|
+
fundingPubKey,
|
|
120
|
+
payoutSPK,
|
|
121
|
+
payoutSerialId,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return { fundingInputs, initializeResponses, changeSerialId, changeSPK };
|
|
125
|
+
}
|
|
105
126
|
/**
|
|
106
127
|
* TODO: Add GetPayoutFromOutcomes
|
|
107
128
|
*
|
|
@@ -290,6 +311,94 @@ class BitcoinDlcProvider extends provider_1.default {
|
|
|
290
311
|
});
|
|
291
312
|
return { dlcTransactions, messagesList };
|
|
292
313
|
}
|
|
314
|
+
async createBatchDlcTxs(_dlcOffers, _dlcAccepts) {
|
|
315
|
+
const dlcOffers = _dlcOffers.map((dlcOffer) => {
|
|
316
|
+
return Utils_1.checkTypes({ _dlcOffer: dlcOffer }).dlcOffer;
|
|
317
|
+
});
|
|
318
|
+
const dlcAccepts = _dlcAccepts.map((dlcAccept) => {
|
|
319
|
+
return Utils_1.checkTypes({ _dlcAccept: dlcAccept }).dlcAccept;
|
|
320
|
+
});
|
|
321
|
+
const localFundPubkeys = dlcOffers.map((dlcOffer) => dlcOffer.fundingPubKey.toString('hex'));
|
|
322
|
+
const remoteFundPubkeys = dlcAccepts.map((dlcAccept) => dlcAccept.fundingPubKey.toString('hex'));
|
|
323
|
+
const localFinalScriptPubkeys = dlcOffers.map((dlcOffer) => dlcOffer.payoutSPK.toString('hex'));
|
|
324
|
+
const remoteFinalScriptPubkeys = dlcAccepts.map((dlcAccept) => dlcAccept.payoutSPK.toString('hex'));
|
|
325
|
+
const localChangeScriptPubkey = dlcOffers[0].changeSPK.toString('hex');
|
|
326
|
+
const remoteChangeScriptPubkey = dlcAccepts[0].changeSPK.toString('hex');
|
|
327
|
+
const localInputs = await Promise.all(dlcOffers[0].fundingInputs.map(async (fundingInput) => {
|
|
328
|
+
const input = await this.fundingInputToInput(fundingInput, false);
|
|
329
|
+
return input.toUtxo();
|
|
330
|
+
}));
|
|
331
|
+
const remoteInputs = await Promise.all(dlcAccepts[0].fundingInputs.map(async (fundingInput) => {
|
|
332
|
+
const input = await this.fundingInputToInput(fundingInput, false);
|
|
333
|
+
return input.toUtxo();
|
|
334
|
+
}));
|
|
335
|
+
const localInputAmount = localInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
|
|
336
|
+
const remoteInputAmount = remoteInputs.reduce((prev, cur) => prev + cur.amount.GetSatoshiAmount(), 0);
|
|
337
|
+
const localPayouts = [];
|
|
338
|
+
const remotePayouts = [];
|
|
339
|
+
const numPayouts = [];
|
|
340
|
+
const nestedMessagesList = [];
|
|
341
|
+
// loop through all dlc offers, get payouts, and add to localPayouts and remotePayouts
|
|
342
|
+
for (const dlcOffer of dlcOffers) {
|
|
343
|
+
const payoutResponses = this.GetPayouts(dlcOffer);
|
|
344
|
+
const { payouts, messagesList } = this.FlattenPayouts(payoutResponses);
|
|
345
|
+
const tempLocalPayouts = payouts.map((payout) => payout.local);
|
|
346
|
+
const tempRemotePayouts = payouts.map((payout) => payout.remote);
|
|
347
|
+
localPayouts.push(...tempLocalPayouts);
|
|
348
|
+
remotePayouts.push(...tempRemotePayouts);
|
|
349
|
+
numPayouts.push(tempLocalPayouts.length);
|
|
350
|
+
nestedMessagesList.push(messagesList);
|
|
351
|
+
}
|
|
352
|
+
const batchDlcTxRequest = {
|
|
353
|
+
localPayouts,
|
|
354
|
+
remotePayouts,
|
|
355
|
+
numPayouts,
|
|
356
|
+
localFundPubkeys,
|
|
357
|
+
localFinalScriptPubkeys,
|
|
358
|
+
remoteFundPubkeys,
|
|
359
|
+
remoteFinalScriptPubkeys,
|
|
360
|
+
localInputAmount,
|
|
361
|
+
localCollateralAmounts: dlcOffers.map((dlcOffer) => dlcOffer.offerCollateralSatoshis),
|
|
362
|
+
localPayoutSerialIds: dlcOffers.map((dlcOffer) => dlcOffer.payoutSerialId),
|
|
363
|
+
localChangeSerialId: dlcOffers[0].changeSerialId,
|
|
364
|
+
remoteInputAmount,
|
|
365
|
+
remoteCollateralAmounts: dlcAccepts.map((dlcAccept) => dlcAccept.acceptCollateralSatoshis),
|
|
366
|
+
remotePayoutSerialIds: dlcAccepts.map((dlcAccept) => dlcAccept.payoutSerialId),
|
|
367
|
+
remoteChangeSerialId: dlcAccepts[0].changeSerialId,
|
|
368
|
+
refundLocktimes: dlcOffers.map((dlcOffer) => dlcOffer.refundLocktime),
|
|
369
|
+
localInputs,
|
|
370
|
+
remoteInputs,
|
|
371
|
+
localChangeScriptPubkey,
|
|
372
|
+
remoteChangeScriptPubkey,
|
|
373
|
+
feeRate: Number(dlcOffers[0].feeRatePerVb),
|
|
374
|
+
cetLockTime: dlcOffers[0].cetLocktime,
|
|
375
|
+
fundOutputSerialIds: dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
|
|
376
|
+
};
|
|
377
|
+
const dlcTxs = await this.CreateBatchDlcTransactions(batchDlcTxRequest);
|
|
378
|
+
const dlcTransactionsList = [];
|
|
379
|
+
let start = 0;
|
|
380
|
+
for (let i = 0; i < dlcTxs.refundTxHexList.length; i++) {
|
|
381
|
+
const dlcTransactions = new messaging_1.DlcTransactionsV0();
|
|
382
|
+
dlcTransactions.fundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.fundTxHex));
|
|
383
|
+
dlcTransactions.fundTxVout = [
|
|
384
|
+
BigInt(dlcOffers[i].changeSerialId),
|
|
385
|
+
BigInt(dlcAccepts[i].changeSerialId),
|
|
386
|
+
...dlcOffers.map((dlcOffer) => dlcOffer.fundOutputSerialId),
|
|
387
|
+
]
|
|
388
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
389
|
+
.findIndex((j) => BigInt(j) === BigInt(dlcOffers[i].fundOutputSerialId));
|
|
390
|
+
dlcTransactions.refundTx = bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(dlcTxs.refundTxHexList[i]));
|
|
391
|
+
// slice cetsHexList based on numPayouts
|
|
392
|
+
const end = start + Number(numPayouts[i]);
|
|
393
|
+
const cetsHexList = dlcTxs.cetsHexList.slice(start, end);
|
|
394
|
+
start = end;
|
|
395
|
+
dlcTransactions.cets = cetsHexList.map((cetHex) => {
|
|
396
|
+
return bitcoin_1.Tx.decode(bufio_1.StreamReader.fromHex(cetHex));
|
|
397
|
+
});
|
|
398
|
+
dlcTransactionsList.push(dlcTransactions);
|
|
399
|
+
}
|
|
400
|
+
return { dlcTransactionsList, nestedMessagesList };
|
|
401
|
+
}
|
|
293
402
|
GenerateEnumMessages(oracleEvent) {
|
|
294
403
|
throw Error('Only DigitDecomposition Oracle Events supported');
|
|
295
404
|
}
|
|
@@ -1064,6 +1173,54 @@ Payout Group found but incorrect group index');
|
|
|
1064
1173
|
dlcOffer.validate();
|
|
1065
1174
|
return dlcOffer;
|
|
1066
1175
|
}
|
|
1176
|
+
async batchCreateDlcOffer(contractInfos, offerCollaterals, feeRatePerVb, cetLocktime, refundLocktimes, fixedInputs) {
|
|
1177
|
+
if (contractInfos.length !== offerCollaterals.length ||
|
|
1178
|
+
contractInfos.length !== refundLocktimes.length) {
|
|
1179
|
+
throw new Error('The number of contractInfos, offerCollateralSatoshis, and refundLocktimes must be the same');
|
|
1180
|
+
}
|
|
1181
|
+
const dlcOffers = [];
|
|
1182
|
+
for (let i = 0; i < contractInfos.length; i++) {
|
|
1183
|
+
contractInfos[i].validate();
|
|
1184
|
+
}
|
|
1185
|
+
const network = await this.getConnectedNetwork();
|
|
1186
|
+
const { fundingInputs: _fundingInputs, changeSPK, changeSerialId, initializeResponses, } = await this.BatchInitialize(offerCollaterals, feeRatePerVb, fixedInputs);
|
|
1187
|
+
_fundingInputs.forEach((input) => assert_1.default(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
|
|
1188
|
+
const fundingInputs = _fundingInputs.map((input) => input);
|
|
1189
|
+
fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
|
|
1190
|
+
const fundOutputsSerialIds = Utils_1.generateSerialIds(contractInfos.length);
|
|
1191
|
+
for (let i = 0; i < contractInfos.length; i++) {
|
|
1192
|
+
const contractInfo = contractInfos[i];
|
|
1193
|
+
const offerCollateralSatoshis = offerCollaterals[i];
|
|
1194
|
+
const fundOutputSerialId = fundOutputsSerialIds[i];
|
|
1195
|
+
const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponses[i];
|
|
1196
|
+
const refundLocktime = refundLocktimes[i];
|
|
1197
|
+
const dlcOffer = new messaging_1.DlcOfferV0();
|
|
1198
|
+
dlcOffer.contractFlags = Buffer.from('00', 'hex');
|
|
1199
|
+
dlcOffer.chainHash = bitcoin_networks_1.chainHashFromNetwork(network);
|
|
1200
|
+
dlcOffer.contractInfo = contractInfo;
|
|
1201
|
+
dlcOffer.fundingPubKey = fundingPubKey;
|
|
1202
|
+
dlcOffer.payoutSPK = payoutSPK;
|
|
1203
|
+
dlcOffer.payoutSerialId = payoutSerialId;
|
|
1204
|
+
dlcOffer.offerCollateralSatoshis = offerCollateralSatoshis;
|
|
1205
|
+
dlcOffer.fundingInputs = fundingInputs;
|
|
1206
|
+
dlcOffer.changeSPK = changeSPK;
|
|
1207
|
+
dlcOffer.changeSerialId = changeSerialId;
|
|
1208
|
+
dlcOffer.fundOutputSerialId = fundOutputSerialId;
|
|
1209
|
+
dlcOffer.feeRatePerVb = feeRatePerVb;
|
|
1210
|
+
dlcOffer.cetLocktime = cetLocktime;
|
|
1211
|
+
dlcOffer.refundLocktime = refundLocktime;
|
|
1212
|
+
assert_1.default((() => {
|
|
1213
|
+
const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, null, null, null, dlcOffer.feeRatePerVb);
|
|
1214
|
+
const funding = fundingInputs.reduce((total, input) => {
|
|
1215
|
+
return total + input.prevTx.outputs[input.prevTxVout].value.sats;
|
|
1216
|
+
}, BigInt(0));
|
|
1217
|
+
return funding >= offerCollateralSatoshis + finalizer.offerFees;
|
|
1218
|
+
})(), 'fundingInputs for dlcOffer must be greater than offerCollateralSatoshis plus offerFees');
|
|
1219
|
+
dlcOffer.validate();
|
|
1220
|
+
dlcOffers.push(dlcOffer);
|
|
1221
|
+
}
|
|
1222
|
+
return dlcOffers;
|
|
1223
|
+
}
|
|
1067
1224
|
/**
|
|
1068
1225
|
* Accept DLC Offer
|
|
1069
1226
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -1120,6 +1277,75 @@ Payout Group found but incorrect group index');
|
|
|
1120
1277
|
dlcAccept.negotiationFields = new messaging_1.NegotiationFieldsV0();
|
|
1121
1278
|
return { dlcAccept, dlcTransactions: _dlcTransactions };
|
|
1122
1279
|
}
|
|
1280
|
+
async batchAcceptDlcOffer(_dlcOffers, fixedInputs) {
|
|
1281
|
+
const dlcOffers = _dlcOffers.map((_dlcOffer) => {
|
|
1282
|
+
const { dlcOffer } = Utils_1.checkTypes({ _dlcOffer });
|
|
1283
|
+
dlcOffer.validate();
|
|
1284
|
+
return dlcOffer;
|
|
1285
|
+
});
|
|
1286
|
+
const acceptCollaterals = dlcOffers.map((dlcOffer) => dlcOffer.contractInfo.totalCollateral -
|
|
1287
|
+
dlcOffer.offerCollateralSatoshis);
|
|
1288
|
+
const { fundingInputs: _fundingInputs, changeSPK, changeSerialId, initializeResponses, } = await this.BatchInitialize(acceptCollaterals, dlcOffers[0].feeRatePerVb, fixedInputs);
|
|
1289
|
+
// Check that none of the funding pubkeys are the same between the
|
|
1290
|
+
// dlcOffers and the dlcAccepts (from initializeResponses)
|
|
1291
|
+
dlcOffers.forEach((dlcOffer) => {
|
|
1292
|
+
initializeResponses.forEach((initializeResponse) => {
|
|
1293
|
+
assert_1.default(Buffer.compare(dlcOffer.fundingPubKey, initializeResponse.fundingPubKey) !== 0, 'DlcOffer and DlcAccept FundingPubKey cannot be the same');
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
_fundingInputs.forEach((input) => assert_1.default(input.type === messaging_1.MessageType.FundingInputV0, 'FundingInput must be V0'));
|
|
1297
|
+
const fundingInputs = _fundingInputs.map((input) => input);
|
|
1298
|
+
fundingInputs.sort((a, b) => Number(a.inputSerialId) - Number(b.inputSerialId));
|
|
1299
|
+
const dlcAccepts = [];
|
|
1300
|
+
initializeResponses.forEach((initializeResponse, i) => {
|
|
1301
|
+
const dlcOffer = dlcOffers[i];
|
|
1302
|
+
const dlcAccept = new messaging_1.DlcAcceptV0();
|
|
1303
|
+
const { fundingPubKey, payoutSPK, payoutSerialId } = initializeResponse;
|
|
1304
|
+
dlcAccept.tempContractId = crypto_1.sha256(dlcOffers[i].serialize());
|
|
1305
|
+
dlcAccept.acceptCollateralSatoshis = acceptCollaterals[i];
|
|
1306
|
+
dlcAccept.fundingPubKey = fundingPubKey;
|
|
1307
|
+
dlcAccept.payoutSPK = payoutSPK;
|
|
1308
|
+
dlcAccept.payoutSerialId = payoutSerialId;
|
|
1309
|
+
dlcAccept.fundingInputs = fundingInputs;
|
|
1310
|
+
dlcAccept.changeSPK = changeSPK;
|
|
1311
|
+
dlcAccept.changeSerialId = changeSerialId;
|
|
1312
|
+
assert_1.default(dlcAccept.changeSerialId !== dlcOffer.fundOutputSerialId, 'changeSerialId cannot equal the fundOutputSerialId');
|
|
1313
|
+
assert_1.default(dlcOffer.payoutSerialId !== dlcAccept.payoutSerialId, 'offer.payoutSerialId cannot equal accept.payoutSerialId');
|
|
1314
|
+
assert_1.default((() => {
|
|
1315
|
+
const ids = [
|
|
1316
|
+
dlcOffer.changeSerialId,
|
|
1317
|
+
dlcAccept.changeSerialId,
|
|
1318
|
+
dlcOffer.fundOutputSerialId,
|
|
1319
|
+
];
|
|
1320
|
+
return new Set(ids).size === ids.length;
|
|
1321
|
+
})(), 'offer.changeSerialID, accept.changeSerialId and fundOutputSerialId must be unique');
|
|
1322
|
+
dlcAccept.validate();
|
|
1323
|
+
assert_1.default((() => {
|
|
1324
|
+
const finalizer = new core_1.DualFundingTxFinalizer(dlcOffer.fundingInputs, dlcOffer.payoutSPK, dlcOffer.changeSPK, dlcAccept.fundingInputs, dlcAccept.payoutSPK, dlcAccept.changeSPK, dlcOffer.feeRatePerVb);
|
|
1325
|
+
const funding = fundingInputs.reduce((total, input) => {
|
|
1326
|
+
return total + input.prevTx.outputs[input.prevTxVout].value.sats;
|
|
1327
|
+
}, BigInt(0));
|
|
1328
|
+
return funding >= acceptCollaterals[i] + finalizer.acceptFees;
|
|
1329
|
+
})(), 'fundingInputs for dlcAccept must be greater than acceptCollateralSatoshis plus acceptFees');
|
|
1330
|
+
dlcAccepts.push(dlcAccept);
|
|
1331
|
+
});
|
|
1332
|
+
const { dlcTransactionsList, nestedMessagesList, } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
|
|
1333
|
+
for (let i = 0; i < dlcAccepts.length; i++) {
|
|
1334
|
+
const dlcOffer = dlcOffers[i];
|
|
1335
|
+
const dlcAccept = dlcAccepts[i];
|
|
1336
|
+
const dlcTransactions = dlcTransactionsList[i];
|
|
1337
|
+
const messagesList = nestedMessagesList[i];
|
|
1338
|
+
const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, false);
|
|
1339
|
+
assert_1.default(dlcTransactions.type === messaging_1.MessageType.DlcTransactionsV0, 'DlcTransactions must be V0');
|
|
1340
|
+
const _dlcTransactions = dlcTransactions;
|
|
1341
|
+
const contractId = crypto_1.xor(_dlcTransactions.fundTx.txId.serialize(), dlcAccept.tempContractId);
|
|
1342
|
+
_dlcTransactions.contractId = contractId;
|
|
1343
|
+
dlcAccepts[i].cetSignatures = cetSignatures;
|
|
1344
|
+
dlcAccepts[i].refundSignature = refundSignature;
|
|
1345
|
+
dlcAccepts[i].negotiationFields = new messaging_1.NegotiationFieldsV0();
|
|
1346
|
+
}
|
|
1347
|
+
return { dlcAccepts, dlcTransactionsList };
|
|
1348
|
+
}
|
|
1123
1349
|
/**
|
|
1124
1350
|
* Sign Dlc Accept Message
|
|
1125
1351
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -1149,6 +1375,39 @@ Payout Group found but incorrect group index');
|
|
|
1149
1375
|
dlcSign.fundingSignatures = fundingSignatures;
|
|
1150
1376
|
return { dlcSign, dlcTransactions: dlcTxs };
|
|
1151
1377
|
}
|
|
1378
|
+
async batchSignDlcAccept(_dlcOffers, _dlcAccepts) {
|
|
1379
|
+
const dlcOffers = _dlcOffers.map((_dlcOffer) => {
|
|
1380
|
+
const { dlcOffer } = Utils_1.checkTypes({ _dlcOffer });
|
|
1381
|
+
dlcOffer.validate();
|
|
1382
|
+
return dlcOffer;
|
|
1383
|
+
});
|
|
1384
|
+
const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
|
|
1385
|
+
const { dlcAccept } = Utils_1.checkTypes({ _dlcAccept });
|
|
1386
|
+
dlcAccept.validate();
|
|
1387
|
+
return dlcAccept;
|
|
1388
|
+
});
|
|
1389
|
+
const { dlcTransactionsList, nestedMessagesList, } = await this.createBatchDlcTxs(dlcOffers, dlcAccepts);
|
|
1390
|
+
const dlcSigns = [];
|
|
1391
|
+
const fundingSignatures = await this.CreateFundingSigs(dlcOffers[0], dlcAccepts[0], dlcTransactionsList[0], true);
|
|
1392
|
+
for (let i = 0; i < dlcAccepts.length; i++) {
|
|
1393
|
+
const dlcOffer = dlcOffers[i];
|
|
1394
|
+
const dlcAccept = dlcAccepts[i];
|
|
1395
|
+
const dlcTransactions = dlcTransactionsList[i];
|
|
1396
|
+
const messagesList = nestedMessagesList[i];
|
|
1397
|
+
const dlcSign = new messaging_1.DlcSignV0();
|
|
1398
|
+
await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTransactions, messagesList, true);
|
|
1399
|
+
const { cetSignatures, refundSignature, } = await this.CreateCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcTransactions, messagesList, true);
|
|
1400
|
+
const dlcTxs = dlcTransactions;
|
|
1401
|
+
const contractId = crypto_1.xor(dlcTxs.fundTx.txId.serialize(), dlcAccept.tempContractId);
|
|
1402
|
+
dlcTxs.contractId = contractId;
|
|
1403
|
+
dlcSign.contractId = contractId;
|
|
1404
|
+
dlcSign.cetSignatures = cetSignatures;
|
|
1405
|
+
dlcSign.refundSignature = refundSignature;
|
|
1406
|
+
dlcSign.fundingSignatures = fundingSignatures;
|
|
1407
|
+
dlcSigns.push(dlcSign);
|
|
1408
|
+
}
|
|
1409
|
+
return { dlcSigns, dlcTransactionsList };
|
|
1410
|
+
}
|
|
1152
1411
|
/**
|
|
1153
1412
|
* Finalize Dlc Sign
|
|
1154
1413
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -1172,6 +1431,39 @@ Payout Group found but incorrect group index');
|
|
|
1172
1431
|
const fundTx = await this.CreateFundingTx(dlcOffer, dlcAccept, dlcSign, dlcTxs, fundingSignatures);
|
|
1173
1432
|
return fundTx;
|
|
1174
1433
|
}
|
|
1434
|
+
async batchFinalizeDlcSign(_dlcOffers, _dlcAccepts, _dlcSigns, _dlcTxsList) {
|
|
1435
|
+
const dlcOffers = _dlcOffers.map((_dlcOffer) => {
|
|
1436
|
+
const { dlcOffer } = Utils_1.checkTypes({ _dlcOffer });
|
|
1437
|
+
dlcOffer.validate();
|
|
1438
|
+
return dlcOffer;
|
|
1439
|
+
});
|
|
1440
|
+
const dlcAccepts = _dlcAccepts.map((_dlcAccept) => {
|
|
1441
|
+
const { dlcAccept } = Utils_1.checkTypes({ _dlcAccept });
|
|
1442
|
+
dlcAccept.validate();
|
|
1443
|
+
return dlcAccept;
|
|
1444
|
+
});
|
|
1445
|
+
const dlcSigns = _dlcSigns.map((_dlcSign) => {
|
|
1446
|
+
const { dlcSign } = Utils_1.checkTypes({ _dlcSign });
|
|
1447
|
+
return dlcSign;
|
|
1448
|
+
});
|
|
1449
|
+
const dlcTxsList = _dlcTxsList.map((_dlcTxs) => {
|
|
1450
|
+
const { dlcTxs } = Utils_1.checkTypes({ _dlcTxs });
|
|
1451
|
+
return dlcTxs;
|
|
1452
|
+
});
|
|
1453
|
+
await this.VerifyFundingSigs(dlcOffers[0], dlcAccepts[0], dlcSigns[0], dlcTxsList[0], false);
|
|
1454
|
+
for (let i = 0; i < dlcOffers.length; i++) {
|
|
1455
|
+
const dlcOffer = dlcOffers[i];
|
|
1456
|
+
const dlcAccept = dlcAccepts[i];
|
|
1457
|
+
const dlcSign = dlcSigns[i];
|
|
1458
|
+
const dlcTxs = dlcTxsList[i];
|
|
1459
|
+
const payoutResponses = this.GetPayouts(dlcOffer);
|
|
1460
|
+
const { messagesList } = this.FlattenPayouts(payoutResponses);
|
|
1461
|
+
await this.VerifyCetAdaptorAndRefundSigs(dlcOffer, dlcAccept, dlcSign, dlcTxs, messagesList, false);
|
|
1462
|
+
}
|
|
1463
|
+
const fundingSignatures = await this.CreateFundingSigs(dlcOffers[0], dlcAccepts[0], dlcTxsList[0], false);
|
|
1464
|
+
const fundTx = await this.CreateFundingTx(dlcOffers[0], dlcAccepts[0], dlcSigns[0], dlcTxsList[0], fundingSignatures);
|
|
1465
|
+
return fundTx;
|
|
1466
|
+
}
|
|
1175
1467
|
/**
|
|
1176
1468
|
* Execute DLC
|
|
1177
1469
|
* @param _dlcOffer Dlc Offer Message
|
|
@@ -1270,7 +1562,7 @@ Payout Group found but incorrect group index');
|
|
|
1270
1562
|
// Initiate and build PSBT
|
|
1271
1563
|
let inputs = _inputs;
|
|
1272
1564
|
if (!_inputs) {
|
|
1273
|
-
const tempInputs = await this.GetInputsForAmount(BigInt(20000), dlcOffer.feeRatePerVb, _inputs);
|
|
1565
|
+
const tempInputs = await this.GetInputsForAmount([BigInt(20000)], dlcOffer.feeRatePerVb, _inputs);
|
|
1274
1566
|
_inputs = tempInputs;
|
|
1275
1567
|
}
|
|
1276
1568
|
inputs = _inputs.map((input) => {
|
|
@@ -1621,10 +1913,18 @@ Payout Group found but incorrect group index');
|
|
|
1621
1913
|
await this.CfdLoaded();
|
|
1622
1914
|
return this._cfdDlcJs.CreateDlcTransactions(jsonObject);
|
|
1623
1915
|
}
|
|
1916
|
+
async CreateBatchDlcTransactions(jsonObject) {
|
|
1917
|
+
await this.CfdLoaded();
|
|
1918
|
+
return this._cfdDlcJs.CreateBatchDlcTransactions(jsonObject);
|
|
1919
|
+
}
|
|
1624
1920
|
async CreateFundTransaction(jsonObject) {
|
|
1625
1921
|
await this.CfdLoaded();
|
|
1626
1922
|
return this._cfdDlcJs.CreateFundTransaction(jsonObject);
|
|
1627
1923
|
}
|
|
1924
|
+
async CreateBatchFundTransaction(jsonObject) {
|
|
1925
|
+
await this.CfdLoaded();
|
|
1926
|
+
return this._cfdDlcJs.CreateBatchFundTransaction(jsonObject);
|
|
1927
|
+
}
|
|
1628
1928
|
async CreateRefundTransaction(jsonObject) {
|
|
1629
1929
|
await this.CfdLoaded();
|
|
1630
1930
|
return this._cfdDlcJs.CreateRefundTransaction(jsonObject);
|