Skip to content

Commit a58302a

Browse files
committed
feat: psbtify cross-chain recovery transactions
Replace legacy transaction builder with PSBT for cross-chain recovery, aligning with the pattern used in backupKeyRecovery.ts. Changes: - Use UtxoPsbt for both signed and unsigned cross-chain recovery - Add signAndVerifyPsbt for signing with user key - Make txInfo optional in response interfaces (PSBT is self-contained) - Remove unused legacy functions (getTxInfo, old createSweepTransaction) Test updates: - Fix nested it() blocks that were never executing - Add 142 fixture files for cross-chain recovery combinations Ticket: BTC-2890 TICKET: BTC-2890
1 parent baa03cd commit a58302a

File tree

144 files changed

+1082
-175
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+1082
-175
lines changed

modules/abstract-utxo/src/recovery/crossChainRecovery.ts

Lines changed: 52 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ import { BitGoBase, IWallet, Keychain, Triple, Wallet } from '@bitgo/sdk-core';
55
import { decrypt } from '@bitgo/sdk-api';
66

77
import { AbstractUtxoCoin, TransactionInfo } from '../abstractUtxoCoin';
8-
import { signAndVerifyWalletTransaction } from '../transaction/fixedScript/signLegacyTransaction';
8+
import { signAndVerifyPsbt } from '../transaction/fixedScript/signPsbt';
99

10-
const { unspentSum, scriptTypeForChain, outputScripts } = utxolib.bitgo;
10+
const { unspentSum } = utxolib.bitgo;
1111
type RootWalletKeys = utxolib.bitgo.RootWalletKeys;
1212
type Unspent<TNumber extends number | bigint = number> = utxolib.bitgo.Unspent<TNumber>;
1313
type WalletUnspent<TNumber extends number | bigint = number> = utxolib.bitgo.WalletUnspent<TNumber>;
14-
type WalletUnspentLegacy<TNumber extends number | bigint = number> = utxolib.bitgo.WalletUnspentLegacy<TNumber>;
1514

1615
export interface BuildRecoveryTransactionOptions {
1716
wallet: string;
@@ -28,17 +27,17 @@ type FeeInfo = {
2827

2928
export interface CrossChainRecoveryUnsigned<TNumber extends number | bigint = number> {
3029
txHex: string;
31-
txInfo: TransactionInfo<TNumber>;
30+
txInfo?: TransactionInfo<TNumber>;
3231
walletId: string;
33-
feeInfo: FeeInfo;
32+
feeInfo?: FeeInfo;
3433
address: string;
3534
coin: string;
3635
}
3736

3837
export interface CrossChainRecoverySigned<TNumber extends number | bigint = number> {
3938
version: 1 | 2;
4039
txHex: string;
41-
txInfo: TransactionInfo<TNumber>;
40+
txInfo?: TransactionInfo<TNumber>;
4241
walletId: string;
4342
sourceCoin: string;
4443
recoveryCoin: string;
@@ -326,117 +325,51 @@ async function getPrv(xprv?: string, passphrase?: string, wallet?: IWallet | Wal
326325
}
327326

328327
/**
328+
* Create a sweep transaction for cross-chain recovery using PSBT
329329
* @param network
330+
* @param walletKeys
330331
* @param unspents
331332
* @param targetAddress
332333
* @param feeRateSatVB
333-
* @param signer - if set, sign transaction
334-
* @param amountType
335-
* @return transaction spending full input amount to targetAddress
334+
* @return unsigned PSBT
336335
*/
337336
function createSweepTransaction<TNumber extends number | bigint = number>(
338337
network: utxolib.Network,
338+
walletKeys: RootWalletKeys,
339339
unspents: WalletUnspent<TNumber>[],
340340
targetAddress: string,
341-
feeRateSatVB: number,
342-
signer?: utxolib.bitgo.WalletUnspentSigner<RootWalletKeys>,
343-
amountType: 'number' | 'bigint' = 'number'
344-
): utxolib.bitgo.UtxoTransaction<TNumber> {
345-
const inputValue = unspentSum<TNumber>(unspents, amountType);
341+
feeRateSatVB: number
342+
): utxolib.bitgo.UtxoPsbt {
343+
const inputValue = unspentSum<bigint>(
344+
unspents.map((u) => ({ ...u, value: BigInt(u.value) })),
345+
'bigint'
346+
);
346347
const vsize = Dimensions.fromUnspents(unspents, {
347348
p2tr: { scriptPathLevel: 1 },
348349
p2trMusig2: { scriptPathLevel: undefined },
349350
})
350351
.plus(Dimensions.fromOutput({ script: utxolib.address.toOutputScript(targetAddress, network) }))
351352
.getVSize();
352-
const fee = vsize * feeRateSatVB;
353+
const fee = BigInt(Math.round(vsize * feeRateSatVB));
354+
355+
const psbt = utxolib.bitgo.createPsbtForNetwork({ network });
356+
utxolib.bitgo.addXpubsToPsbt(psbt, walletKeys);
353357

354-
const transactionBuilder = utxolib.bitgo.createTransactionBuilderForNetwork<TNumber>(network);
355-
transactionBuilder.addOutput(
356-
targetAddress,
357-
utxolib.bitgo.toTNumber<TNumber>(BigInt(inputValue) - BigInt(fee), amountType)
358-
);
359358
unspents.forEach((unspent) => {
360-
utxolib.bitgo.addToTransactionBuilder(transactionBuilder, unspent);
359+
utxolib.bitgo.addWalletUnspentToPsbt(
360+
psbt,
361+
{ ...unspent, value: BigInt(unspent.value) },
362+
walletKeys,
363+
'user',
364+
'backup',
365+
{ skipNonWitnessUtxo: true }
366+
);
361367
});
362-
let transaction = transactionBuilder.buildIncomplete();
363-
if (signer) {
364-
transaction = signAndVerifyWalletTransaction<TNumber>(transactionBuilder, unspents, signer, {
365-
isLastSignature: false,
366-
});
367-
}
368-
return transaction;
369-
}
370368

371-
function getTxInfo<TNumber extends number | bigint = number>(
372-
transaction: utxolib.bitgo.UtxoTransaction<TNumber>,
373-
unspents: WalletUnspent<TNumber>[],
374-
walletId: string,
375-
walletKeys: RootWalletKeys,
376-
amountType: 'number' | 'bigint' = 'number'
377-
): TransactionInfo<TNumber> {
378-
const inputAmount = utxolib.bitgo.unspentSum<TNumber>(unspents, amountType);
379-
const outputAmount = utxolib.bitgo.toTNumber<TNumber>(
380-
transaction.outs.reduce((sum, o) => sum + BigInt(o.value), BigInt(0)),
381-
amountType
382-
);
383-
const outputs = transaction.outs.map((o) => ({
384-
address: utxolib.address.fromOutputScript(o.script, transaction.network),
385-
valueString: o.value.toString(),
386-
change: false,
387-
}));
388-
const inputs = unspents.map((u) => {
389-
// NOTE:
390-
// The `redeemScript` and `walletScript` properties are required for legacy versions of BitGoJS
391-
// which might require these scripts for signing. The Wallet Recovery Wizard (WRW) can create
392-
// unsigned prebuilds that are submitted to BitGoJS instances which are not necessarily the same
393-
// version.
394-
const addressKeys = walletKeys.deriveForChainAndIndex(u.chain, u.index);
395-
const scriptType = scriptTypeForChain(u.chain);
396-
const { redeemScript, witnessScript } = outputScripts.createOutputScript2of3(addressKeys.publicKeys, scriptType);
369+
const recoveryOutputScript = utxolib.address.toOutputScript(targetAddress, network);
370+
psbt.addOutput({ script: recoveryOutputScript, value: inputValue - fee });
397371

398-
return {
399-
...u,
400-
wallet: walletId,
401-
fromWallet: walletId,
402-
redeemScript: redeemScript?.toString('hex'),
403-
witnessScript: witnessScript?.toString('hex'),
404-
} as WalletUnspentLegacy<TNumber>;
405-
});
406-
return {
407-
inputAmount,
408-
outputAmount,
409-
minerFee: inputAmount - outputAmount,
410-
spendAmount: outputAmount,
411-
inputs,
412-
unspents: inputs,
413-
outputs,
414-
externalOutputs: outputs,
415-
changeOutputs: [],
416-
payGoFee: 0,
417-
} /* cast to TransactionInfo to allow extra fields may be required by legacy consumers of this data */ as TransactionInfo<TNumber>;
418-
}
419-
420-
function getFeeInfo<TNumber extends number | bigint = number>(
421-
transaction: utxolib.bitgo.UtxoTransaction<TNumber>,
422-
unspents: WalletUnspent<TNumber>[],
423-
amountType: 'number' | 'bigint' = 'number'
424-
): FeeInfo {
425-
const vsize = Dimensions.fromUnspents(unspents, {
426-
p2tr: { scriptPathLevel: 1 },
427-
p2trMusig2: { scriptPathLevel: undefined },
428-
})
429-
.plus(Dimensions.fromOutputs(transaction.outs))
430-
.getVSize();
431-
const inputAmount = utxolib.bitgo.unspentSum<TNumber>(unspents, amountType);
432-
const outputAmount = transaction.outs.reduce((sum, o) => sum + BigInt(o.value), BigInt(0));
433-
const fee = Number(BigInt(inputAmount) - outputAmount);
434-
return {
435-
size: vsize,
436-
fee,
437-
feeRate: fee / vsize,
438-
payGoFee: 0,
439-
};
372+
return psbt;
440373
}
441374

442375
type RecoverParams = {
@@ -484,45 +417,37 @@ export async function recoverCrossChain<TNumber extends number | bigint = number
484417
const walletKeys = await getWalletKeys(params.recoveryCoin, wallet);
485418
const prv =
486419
params.xprv || params.walletPassphrase ? await getPrv(params.xprv, params.walletPassphrase, wallet) : undefined;
487-
const signer = prv
488-
? new utxolib.bitgo.WalletUnspentSigner<RootWalletKeys>(walletKeys, prv, walletKeys.bitgo)
489-
: undefined;
490420
const feeRateSatVB = await getFeeRateSatVB(params.sourceCoin);
491-
const transaction = createSweepTransaction<TNumber>(
421+
422+
// Create PSBT for both signed and unsigned recovery
423+
const psbt = createSweepTransaction<TNumber>(
492424
params.sourceCoin.network,
425+
walletKeys,
493426
walletUnspents,
494427
params.recoveryAddress,
495-
feeRateSatVB,
496-
signer,
497-
params.sourceCoin.amountType
498-
);
499-
const recoveryAmount = transaction.outs[0].value;
500-
const txHex = transaction.toBuffer().toString('hex');
501-
const txInfo = getTxInfo<TNumber>(
502-
transaction,
503-
walletUnspents,
504-
params.walletId,
505-
walletKeys,
506-
params.sourceCoin.amountType
428+
feeRateSatVB
507429
);
508-
if (prv) {
509-
return {
510-
version: wallet instanceof Wallet ? 2 : 1,
511-
walletId: params.walletId,
512-
txHex,
513-
txInfo,
514-
sourceCoin: params.sourceCoin.getChain(),
515-
recoveryCoin: params.recoveryCoin.getChain(),
516-
recoveryAmount,
517-
};
518-
} else {
430+
431+
// For unsigned recovery, return unsigned PSBT hex
432+
if (!prv) {
519433
return {
520-
txHex,
521-
txInfo,
434+
txHex: psbt.toHex(),
522435
walletId: params.walletId,
523-
feeInfo: getFeeInfo(transaction, walletUnspents, params.sourceCoin.amountType),
524436
address: params.recoveryAddress,
525437
coin: params.sourceCoin.getChain(),
526438
};
527439
}
440+
441+
// For signed recovery, sign the PSBT with user key and return half-signed PSBT
442+
signAndVerifyPsbt(psbt, prv, { isLastSignature: false });
443+
const recoveryAmount = utxolib.bitgo.toTNumber<TNumber>(psbt.txOutputs[0].value, params.sourceCoin.amountType);
444+
445+
return {
446+
version: wallet instanceof Wallet ? 2 : 1,
447+
walletId: params.walletId,
448+
txHex: psbt.toHex(),
449+
sourceCoin: params.sourceCoin.getChain(),
450+
recoveryCoin: params.recoveryCoin.getChain(),
451+
recoveryAmount,
452+
};
528453
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"version": 2,
3+
"walletId": "5abacebe28d72fbd07e0b8cbba0ff39e",
4+
"txHex": "70736274ff0100530200000001526eda15b11314f6ca3ee949a43e3d0e045eb86cdb38515c573359fcdac94ce60000000000ffffffff0188c2f5050000000017a9149c4525e9e9fc92cdda2043d35ad699c343dbab0f87000000004f010488b21e0000000000000000004b256d3cf3524c8d7086e295a1923d6fa2f99b686699ed50084bb114495c982403a86864862a9e315221809501f2a4200cd9e057a70f9164d485d4cfbeb8e47c74048374ad864f010488b21e000000000000000000914cc440157319de14126a1a2e87ea86f3b983f923fb17693a157b721220d74c02e81e105716179975cc47afd117cae272519aafdd6bfff688e4280d384e13184f04e15f6f214f010488b21e000000000000000000da28679577f7faf0ed86164da220aa4a29c7edfb0de8bdabd97f19fd15e74bed03db2b42af97f60db6ec5a1500e246ef2107660c4fc02699ed69b82c2f3e9324ae0403a823910001012018ddf5050000000017a9141e57a925dd863a86af341037e700862bf66bf7b6872202037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e47483045022100baffdbce5b48a4744604041d3ac2ca021cad8124fb0779aa20e329d66d02fa500220381a4afa1d142a7ade7799d779e8b5216ec5ab9852ac79ae2773335a47cb510741010304410000000104695221037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e472102658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d3978702102641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b853ae220602641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b8148374ad8600000000000000000000000000000000220602658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d39787014e15f6f21000000000000000000000000000000002206037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e471403a82391000000000000000000000000000000000000",
5+
"sourceCoin": "bch",
6+
"recoveryCoin": "bsv",
7+
"recoveryAmount": 99992200
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"txHex": "70736274ff0100530200000001526eda15b11314f6ca3ee949a43e3d0e045eb86cdb38515c573359fcdac94ce60000000000ffffffff0188c2f5050000000017a9149c4525e9e9fc92cdda2043d35ad699c343dbab0f87000000004f010488b21e0000000000000000004b256d3cf3524c8d7086e295a1923d6fa2f99b686699ed50084bb114495c982403a86864862a9e315221809501f2a4200cd9e057a70f9164d485d4cfbeb8e47c74048374ad864f010488b21e000000000000000000914cc440157319de14126a1a2e87ea86f3b983f923fb17693a157b721220d74c02e81e105716179975cc47afd117cae272519aafdd6bfff688e4280d384e13184f04e15f6f214f010488b21e000000000000000000da28679577f7faf0ed86164da220aa4a29c7edfb0de8bdabd97f19fd15e74bed03db2b42af97f60db6ec5a1500e246ef2107660c4fc02699ed69b82c2f3e9324ae0403a823910001012018ddf5050000000017a9141e57a925dd863a86af341037e700862bf66bf7b687010304410000000104695221037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e472102658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d3978702102641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b853ae220602641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b8148374ad8600000000000000000000000000000000220602658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d39787014e15f6f21000000000000000000000000000000002206037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e471403a82391000000000000000000000000000000000000",
3+
"walletId": "5abacebe28d72fbd07e0b8cbba0ff39e",
4+
"address": "3FwJAxqdqfhe4esUv4smhM3zzbE3KAyD88",
5+
"coin": "bch"
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"version": 2,
3+
"walletId": "5abacebe28d72fbd07e0b8cbba0ff39e",
4+
"txHex": "70736274ff0100530200000001526eda15b11314f6ca3ee949a43e3d0e045eb86cdb38515c573359fcdac94ce60000000000ffffffff0188c2f5050000000017a9149c4525e9e9fc92cdda2043d35ad699c343dbab0f87000000004f010488b21e0000000000000000004b256d3cf3524c8d7086e295a1923d6fa2f99b686699ed50084bb114495c982403a86864862a9e315221809501f2a4200cd9e057a70f9164d485d4cfbeb8e47c74048374ad864f010488b21e000000000000000000914cc440157319de14126a1a2e87ea86f3b983f923fb17693a157b721220d74c02e81e105716179975cc47afd117cae272519aafdd6bfff688e4280d384e13184f04e15f6f214f010488b21e000000000000000000da28679577f7faf0ed86164da220aa4a29c7edfb0de8bdabd97f19fd15e74bed03db2b42af97f60db6ec5a1500e246ef2107660c4fc02699ed69b82c2f3e9324ae0403a823910001012018ddf5050000000017a9141e57a925dd863a86af341037e700862bf66bf7b6872202037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e47483045022100baffdbce5b48a4744604041d3ac2ca021cad8124fb0779aa20e329d66d02fa500220381a4afa1d142a7ade7799d779e8b5216ec5ab9852ac79ae2773335a47cb510741010304410000000104695221037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e472102658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d3978702102641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b853ae220602641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b8148374ad8600000000000000000000000000000000220602658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d39787014e15f6f21000000000000000000000000000000002206037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e471403a82391000000000000000000000000000000000000",
5+
"sourceCoin": "bch",
6+
"recoveryCoin": "btc",
7+
"recoveryAmount": 99992200
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"txHex": "70736274ff0100530200000001526eda15b11314f6ca3ee949a43e3d0e045eb86cdb38515c573359fcdac94ce60000000000ffffffff0188c2f5050000000017a9149c4525e9e9fc92cdda2043d35ad699c343dbab0f87000000004f010488b21e0000000000000000004b256d3cf3524c8d7086e295a1923d6fa2f99b686699ed50084bb114495c982403a86864862a9e315221809501f2a4200cd9e057a70f9164d485d4cfbeb8e47c74048374ad864f010488b21e000000000000000000914cc440157319de14126a1a2e87ea86f3b983f923fb17693a157b721220d74c02e81e105716179975cc47afd117cae272519aafdd6bfff688e4280d384e13184f04e15f6f214f010488b21e000000000000000000da28679577f7faf0ed86164da220aa4a29c7edfb0de8bdabd97f19fd15e74bed03db2b42af97f60db6ec5a1500e246ef2107660c4fc02699ed69b82c2f3e9324ae0403a823910001012018ddf5050000000017a9141e57a925dd863a86af341037e700862bf66bf7b687010304410000000104695221037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e472102658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d3978702102641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b853ae220602641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b8148374ad8600000000000000000000000000000000220602658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d39787014e15f6f21000000000000000000000000000000002206037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e471403a82391000000000000000000000000000000000000",
3+
"walletId": "5abacebe28d72fbd07e0b8cbba0ff39e",
4+
"address": "3FwJAxqdqfhe4esUv4smhM3zzbE3KAyD88",
5+
"coin": "bch"
6+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"version": 2,
3+
"walletId": "5abacebe28d72fbd07e0b8cbba0ff39e",
4+
"txHex": "70736274ff0100530200000001526eda15b11314f6ca3ee949a43e3d0e045eb86cdb38515c573359fcdac94ce60000000000ffffffff0188c2f5050000000017a9149c4525e9e9fc92cdda2043d35ad699c343dbab0f87000000004f010488b21e0000000000000000004b256d3cf3524c8d7086e295a1923d6fa2f99b686699ed50084bb114495c982403a86864862a9e315221809501f2a4200cd9e057a70f9164d485d4cfbeb8e47c74048374ad864f010488b21e000000000000000000914cc440157319de14126a1a2e87ea86f3b983f923fb17693a157b721220d74c02e81e105716179975cc47afd117cae272519aafdd6bfff688e4280d384e13184f04e15f6f214f010488b21e000000000000000000da28679577f7faf0ed86164da220aa4a29c7edfb0de8bdabd97f19fd15e74bed03db2b42af97f60db6ec5a1500e246ef2107660c4fc02699ed69b82c2f3e9324ae0403a823910001012018ddf5050000000017a9141e57a925dd863a86af341037e700862bf66bf7b6872202037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e47483045022100baffdbce5b48a4744604041d3ac2ca021cad8124fb0779aa20e329d66d02fa500220381a4afa1d142a7ade7799d779e8b5216ec5ab9852ac79ae2773335a47cb510741010304410000000104695221037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e472102658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d3978702102641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b853ae220602641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b8148374ad8600000000000000000000000000000000220602658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d39787014e15f6f21000000000000000000000000000000002206037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e471403a82391000000000000000000000000000000000000",
5+
"sourceCoin": "bch",
6+
"recoveryCoin": "doge",
7+
"recoveryAmount": 99992200
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"txHex": "70736274ff0100530200000001526eda15b11314f6ca3ee949a43e3d0e045eb86cdb38515c573359fcdac94ce60000000000ffffffff0188c2f5050000000017a9149c4525e9e9fc92cdda2043d35ad699c343dbab0f87000000004f010488b21e0000000000000000004b256d3cf3524c8d7086e295a1923d6fa2f99b686699ed50084bb114495c982403a86864862a9e315221809501f2a4200cd9e057a70f9164d485d4cfbeb8e47c74048374ad864f010488b21e000000000000000000914cc440157319de14126a1a2e87ea86f3b983f923fb17693a157b721220d74c02e81e105716179975cc47afd117cae272519aafdd6bfff688e4280d384e13184f04e15f6f214f010488b21e000000000000000000da28679577f7faf0ed86164da220aa4a29c7edfb0de8bdabd97f19fd15e74bed03db2b42af97f60db6ec5a1500e246ef2107660c4fc02699ed69b82c2f3e9324ae0403a823910001012018ddf5050000000017a9141e57a925dd863a86af341037e700862bf66bf7b687010304410000000104695221037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e472102658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d3978702102641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b853ae220602641ee6557561c9038242cafa7f538070d7646a969bcf6169f9950abfcfefd6b8148374ad8600000000000000000000000000000000220602658831a87322b3583515ca8725841335505755ada53ee133c70a6b4b8d39787014e15f6f21000000000000000000000000000000002206037acffd52bb7c39a4ac3d4c01af33ce0367afec45347e332edca63a38d1fb2e471403a82391000000000000000000000000000000000000",
3+
"walletId": "5abacebe28d72fbd07e0b8cbba0ff39e",
4+
"address": "3FwJAxqdqfhe4esUv4smhM3zzbE3KAyD88",
5+
"coin": "bch"
6+
}

0 commit comments

Comments
 (0)