@bitpay-labs/bitcore-wallet-service 11.9.0 → 11.10.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/package.json +4 -4
- package/src/externalservices/moonpay.ts +3 -3
- package/src/lib/chain/eth/index.ts +8 -7
- package/src/lib/chain/index.ts +1 -1
- package/src/lib/chain/sol/index.ts +4 -4
- package/src/lib/chain/xrp/index.ts +3 -3
- package/src/lib/errors/errordefinitions.ts +2 -0
- package/src/lib/expressapp.ts +6 -3
- package/src/lib/model/txnote.ts +3 -0
- package/src/lib/model/txproposal.ts +153 -68
- package/src/lib/model/txproposal_legacy.ts +5 -4
- package/src/lib/model/txproposalaction.ts +9 -0
- package/src/lib/routes/context.ts +10 -1
- package/src/lib/routes/transactions.ts +17 -2
- package/src/lib/routes/wallets.ts +8 -2
- package/src/lib/server.ts +62 -9
- package/src/lib/storage.ts +13 -12
- package/src/types/expressapp.d.ts +2 -1
- package/test/chain/bch.test.ts +8 -1
- package/test/chain/btc.test.ts +2 -2
- package/test/chain/doge.test.ts +4 -6
- package/test/chain/ltc.test.ts +4 -5
- package/test/chain/xrp.test.ts +4 -39
- package/test/model/txproposal.test.ts +64 -1
- package/ts_build/package.json +3 -3
- package/ts_build/src/externalservices/moonpay.js +3 -3
- package/ts_build/src/externalservices/moonpay.js.map +1 -1
- package/ts_build/src/lib/chain/eth/index.d.ts +6 -5
- package/ts_build/src/lib/chain/eth/index.d.ts.map +1 -1
- package/ts_build/src/lib/chain/eth/index.js +5 -5
- package/ts_build/src/lib/chain/eth/index.js.map +1 -1
- package/ts_build/src/lib/chain/index.d.ts +1 -1
- package/ts_build/src/lib/chain/index.d.ts.map +1 -1
- package/ts_build/src/lib/chain/index.js.map +1 -1
- package/ts_build/src/lib/chain/sol/index.js +4 -4
- package/ts_build/src/lib/chain/sol/index.js.map +1 -1
- package/ts_build/src/lib/chain/xrp/index.js +3 -3
- package/ts_build/src/lib/chain/xrp/index.js.map +1 -1
- package/ts_build/src/lib/errors/errordefinitions.d.ts +1 -0
- package/ts_build/src/lib/errors/errordefinitions.d.ts.map +1 -1
- package/ts_build/src/lib/errors/errordefinitions.js +1 -0
- package/ts_build/src/lib/errors/errordefinitions.js.map +1 -1
- package/ts_build/src/lib/expressapp.d.ts.map +1 -1
- package/ts_build/src/lib/expressapp.js +5 -3
- package/ts_build/src/lib/expressapp.js.map +1 -1
- package/ts_build/src/lib/model/txnote.d.ts +1 -0
- package/ts_build/src/lib/model/txnote.d.ts.map +1 -1
- package/ts_build/src/lib/model/txnote.js +1 -0
- package/ts_build/src/lib/model/txnote.js.map +1 -1
- package/ts_build/src/lib/model/txproposal.d.ts +72 -52
- package/ts_build/src/lib/model/txproposal.d.ts.map +1 -1
- package/ts_build/src/lib/model/txproposal.js +69 -17
- package/ts_build/src/lib/model/txproposal.js.map +1 -1
- package/ts_build/src/lib/model/txproposal_legacy.d.ts +3 -3
- package/ts_build/src/lib/model/txproposal_legacy.d.ts.map +1 -1
- package/ts_build/src/lib/model/txproposal_legacy.js +1 -0
- package/ts_build/src/lib/model/txproposal_legacy.js.map +1 -1
- package/ts_build/src/lib/model/txproposalaction.d.ts +2 -0
- package/ts_build/src/lib/model/txproposalaction.d.ts.map +1 -1
- package/ts_build/src/lib/model/txproposalaction.js +2 -0
- package/ts_build/src/lib/model/txproposalaction.js.map +1 -1
- package/ts_build/src/lib/routes/context.d.ts +1 -0
- package/ts_build/src/lib/routes/context.d.ts.map +1 -1
- package/ts_build/src/lib/routes/context.js +8 -1
- package/ts_build/src/lib/routes/context.js.map +1 -1
- package/ts_build/src/lib/routes/transactions.d.ts +1 -0
- package/ts_build/src/lib/routes/transactions.d.ts.map +1 -1
- package/ts_build/src/lib/routes/transactions.js +14 -2
- package/ts_build/src/lib/routes/transactions.js.map +1 -1
- package/ts_build/src/lib/routes/wallets.d.ts +1 -0
- package/ts_build/src/lib/routes/wallets.d.ts.map +1 -1
- package/ts_build/src/lib/routes/wallets.js +7 -2
- package/ts_build/src/lib/routes/wallets.js.map +1 -1
- package/ts_build/src/lib/server.d.ts +6 -2
- package/ts_build/src/lib/server.d.ts.map +1 -1
- package/ts_build/src/lib/server.js +45 -3
- package/ts_build/src/lib/server.js.map +1 -1
- package/ts_build/src/lib/storage.d.ts +6 -6
- package/ts_build/src/lib/storage.d.ts.map +1 -1
- package/ts_build/src/lib/storage.js +6 -6
- package/ts_build/src/lib/storage.js.map +1 -1
- package/ts_build/test/chain/bch.test.js +7 -0
- package/ts_build/test/chain/bch.test.js.map +1 -1
- package/ts_build/test/chain/btc.test.js +2 -2
- package/ts_build/test/chain/btc.test.js.map +1 -1
- package/ts_build/test/chain/doge.test.js +3 -5
- package/ts_build/test/chain/doge.test.js.map +1 -1
- package/ts_build/test/chain/ltc.test.js +3 -4
- package/ts_build/test/chain/ltc.test.js.map +1 -1
- package/ts_build/test/chain/xrp.test.js +3 -38
- package/ts_build/test/chain/xrp.test.js.map +1 -1
- package/ts_build/test/model/txproposal.test.js +57 -0
- package/ts_build/test/model/txproposal.test.js.map +1 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@bitpay-labs/bitcore-wallet-service",
|
|
3
3
|
"description": "A service for Mutisig HD Bitcoin Wallets",
|
|
4
4
|
"author": "BitPay Inc",
|
|
5
|
-
"version": "11.
|
|
5
|
+
"version": "11.10.1",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "ts_build/src/index.js",
|
|
8
8
|
"types": "./ts_build/src/index.d.ts",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@bitpay-labs/bitcore-logging": "^11.8.1",
|
|
47
|
-
"@bitpay-labs/bitcore-tss": "^11.
|
|
48
|
-
"@bitpay-labs/crypto-wallet-core": "^11.
|
|
47
|
+
"@bitpay-labs/bitcore-tss": "^11.10.0",
|
|
48
|
+
"@bitpay-labs/crypto-wallet-core": "^11.10.0",
|
|
49
49
|
"@sendgrid/mail": "6.5.4",
|
|
50
50
|
"abi-decoder": "2.4.0",
|
|
51
51
|
"async": "0.9.2",
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"email": "kjoseph@bitpay.com"
|
|
127
127
|
}
|
|
128
128
|
],
|
|
129
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "efb35cf0d7a9f4f5e773f63ade0168321bbea84f"
|
|
130
130
|
}
|
|
@@ -456,7 +456,7 @@ export class MoonpayService {
|
|
|
456
456
|
|
|
457
457
|
const headers = {
|
|
458
458
|
'Content-Type': 'application/json',
|
|
459
|
-
|
|
459
|
+
'X-Api-Key': SECRET_KEY,
|
|
460
460
|
};
|
|
461
461
|
|
|
462
462
|
const body: any = {
|
|
@@ -466,7 +466,7 @@ export class MoonpayService {
|
|
|
466
466
|
if (req.body.email) body.email = req.body.email;
|
|
467
467
|
if (req.body.phoneNumber) body.phoneNumber = req.body.phoneNumber;
|
|
468
468
|
|
|
469
|
-
const URL = API + '/platform/v1/
|
|
469
|
+
const URL = API + '/platform/v1/sessions';
|
|
470
470
|
|
|
471
471
|
this.request.post(
|
|
472
472
|
URL,
|
|
@@ -498,7 +498,7 @@ export class MoonpayService {
|
|
|
498
498
|
|
|
499
499
|
const headers = {
|
|
500
500
|
Accept: 'application/json',
|
|
501
|
-
|
|
501
|
+
'X-Api-Key': SECRET_KEY
|
|
502
502
|
};
|
|
503
503
|
|
|
504
504
|
const URL = API + '/platform/v1/sessions?externalCustomerId=' + encodeURIComponent(req.body.externalCustomerId);
|
|
@@ -3,13 +3,14 @@ import _ from 'lodash';
|
|
|
3
3
|
import { IWallet } from 'src/lib/model';
|
|
4
4
|
import { IAddress } from 'src/lib/model/address';
|
|
5
5
|
import { WalletService } from 'src/lib/server';
|
|
6
|
-
import { IChain } from '../../../types/chain';
|
|
7
6
|
import { Common } from '../../common';
|
|
8
7
|
import { ClientError } from '../../errors/clienterror';
|
|
9
8
|
import { Errors } from '../../errors/errordefinitions';
|
|
10
9
|
import logger from '../../logger';
|
|
11
10
|
import { ERC20Abi } from './abi-erc20';
|
|
12
11
|
import { InvoiceAbi } from './abi-invoice';
|
|
12
|
+
import type { IChain } from '../../../types/chain';
|
|
13
|
+
import type { TxProposal } from '../../model/txproposal';
|
|
13
14
|
|
|
14
15
|
const {
|
|
15
16
|
Constants,
|
|
@@ -98,24 +99,24 @@ export class EthChain implements IChain {
|
|
|
98
99
|
// getPendingTxs returns all txps when given a native currency
|
|
99
100
|
server.getPendingTxs(opts, (err, txps) => {
|
|
100
101
|
if (err) return cb(err);
|
|
101
|
-
let fees =
|
|
102
|
-
let amounts =
|
|
102
|
+
let fees = 0n;
|
|
103
|
+
let amounts = 0n;
|
|
103
104
|
|
|
104
105
|
txps.filter(txp => {
|
|
105
106
|
// Add gas used for tokens when getting native balance
|
|
106
107
|
if (!opts.tokenAddress) {
|
|
107
|
-
fees += txp.fee
|
|
108
|
+
fees += txp.fee ? BigInt(txp.fee) : 0n;
|
|
108
109
|
}
|
|
109
110
|
// Filter tokens when getting native balance
|
|
110
111
|
if (txp.tokenAddress && !opts.tokenAddress) {
|
|
111
112
|
return false;
|
|
112
113
|
}
|
|
113
|
-
amounts += txp.amount;
|
|
114
|
+
amounts += txp.amount ? BigInt(txp.amount) : 0n;
|
|
114
115
|
return true;
|
|
115
116
|
});
|
|
116
117
|
|
|
117
118
|
// TODO support big int
|
|
118
|
-
const lockedSum = (amounts + fees) || 0; // previously set to 0 if opts.multisigContractAddress
|
|
119
|
+
const lockedSum = Number(amounts + fees) || 0; // previously set to 0 if opts.multisigContractAddress
|
|
119
120
|
const convertedBalance = this.convertBitcoreBalance(balance, lockedSum);
|
|
120
121
|
server.storage.fetchAddresses(server.walletId, (err, addresses: IAddress[]) => {
|
|
121
122
|
if (err) return cb(err);
|
|
@@ -286,7 +287,7 @@ export class EthChain implements IChain {
|
|
|
286
287
|
});
|
|
287
288
|
}
|
|
288
289
|
|
|
289
|
-
getBitcoreTx(txp, opts = { signed: true }) {
|
|
290
|
+
getBitcoreTx(txp: TxProposal, opts = { signed: true }) {
|
|
290
291
|
const {
|
|
291
292
|
data,
|
|
292
293
|
outputs,
|
package/src/lib/chain/index.ts
CHANGED
|
@@ -94,7 +94,7 @@ class ChainProxy {
|
|
|
94
94
|
return this.get(wallet.chain).getFee(server, wallet, opts);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
getBitcoreTx(txp: TxProposal
|
|
97
|
+
getBitcoreTx(txp: TxProposal<any>, opts = { signed: true }) {
|
|
98
98
|
return this.get(txp.chain).getBitcoreTx(txp, { signed: opts.signed });
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -56,18 +56,18 @@ export class SolChain implements IChain {
|
|
|
56
56
|
const { fees, amounts } = txps.reduce((acc, txp) => {
|
|
57
57
|
// Add gas used for tokens when getting native balance
|
|
58
58
|
if (!opts.tokenAddress) {
|
|
59
|
-
acc.fees += txp.fee
|
|
59
|
+
acc.fees += txp.fee ? BigInt(txp.fee) : 0n;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Filter tokens when getting native balance
|
|
63
63
|
if (!(txp.tokenAddress && !opts.tokenAddress)) {
|
|
64
|
-
acc.amounts += txp.amount;
|
|
64
|
+
acc.amounts += txp.amount ? BigInt(txp.amount) : 0n;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
return acc;
|
|
68
|
-
}, { fees:
|
|
68
|
+
}, { fees: 0n, amounts: 0n });
|
|
69
69
|
|
|
70
|
-
const lockedSum = (amounts + fees) || 0; // previously set to 0 if opts.multisigContractAddress
|
|
70
|
+
const lockedSum = Number(amounts + fees) || 0; // previously set to 0 if opts.multisigContractAddress
|
|
71
71
|
const reserveAmount = opts.tokenAddress ? 0 : reserve;
|
|
72
72
|
const convertedBalance = this.convertBitcoreBalance(balance, lockedSum, reserveAmount);
|
|
73
73
|
server.storage.fetchAddresses(server.walletId, (err, addresses: IAddress[]) => {
|
|
@@ -65,9 +65,9 @@ export class XrpChain implements IChain {
|
|
|
65
65
|
server.getPendingTxs(opts, (err, txps) => {
|
|
66
66
|
if (err) return cb(err);
|
|
67
67
|
const lockedSum = txps.reduce((sum, txp) => {
|
|
68
|
-
return sum + txp.amount + (txp.fee || 0);
|
|
69
|
-
},
|
|
70
|
-
const convertedBalance = this.convertBitcoreBalance(balance, lockedSum, reserve);
|
|
68
|
+
return sum + BigInt(txp.amount || 0) + BigInt(txp.fee || 0);
|
|
69
|
+
}, 0n) || 0n;
|
|
70
|
+
const convertedBalance = this.convertBitcoreBalance(balance, Number(lockedSum), reserve);
|
|
71
71
|
server.storage.fetchAddresses(server.walletId, (err, addresses: IAddress[]) => {
|
|
72
72
|
if (err) return cb(err);
|
|
73
73
|
if (addresses.length > 0) {
|
|
@@ -61,6 +61,7 @@ interface Errors<T> {
|
|
|
61
61
|
WALLET_NOT_FOUND: T;
|
|
62
62
|
WALLET_NEED_SCAN: T;
|
|
63
63
|
WRONG_SIGNING_METHOD: T;
|
|
64
|
+
INVALID_NUMBER_FORMAT: T;
|
|
64
65
|
TSS_SESSION_NOT_FOUND: T;
|
|
65
66
|
TSS_INVALID_PASSWORD: T;
|
|
66
67
|
TSS_ROUND_ALREADY_DONE: T;
|
|
@@ -132,6 +133,7 @@ const errors: Errors<string> = {
|
|
|
132
133
|
WALLET_NOT_FOUND: 'Wallet not found',
|
|
133
134
|
WALLET_NEED_SCAN: 'Wallet needs addresses scan',
|
|
134
135
|
WRONG_SIGNING_METHOD: 'Wrong signed method for coin/network',
|
|
136
|
+
INVALID_NUMBER_FORMAT: 'Invalid number format. Supported formats are: number, string, hex',
|
|
135
137
|
TSS_SESSION_NOT_FOUND: 'Session not found',
|
|
136
138
|
TSS_INVALID_PASSWORD: 'Invalid password',
|
|
137
139
|
TSS_ROUND_ALREADY_DONE: 'Your message is for a round that has already finished',
|
package/src/lib/expressapp.ts
CHANGED
|
@@ -49,7 +49,8 @@ export class ExpressApp {
|
|
|
49
49
|
getServerWithAuth,
|
|
50
50
|
getServerWithMultiAuth,
|
|
51
51
|
logDeprecated,
|
|
52
|
-
setPublicCache
|
|
52
|
+
setPublicCache,
|
|
53
|
+
checkNumberFormat
|
|
53
54
|
} = createRouteHelpers(returnError);
|
|
54
55
|
|
|
55
56
|
registerWalletRoutes(router, {
|
|
@@ -58,12 +59,14 @@ export class ExpressApp {
|
|
|
58
59
|
getServerWithAuth,
|
|
59
60
|
getServerWithMultiAuth,
|
|
60
61
|
logDeprecated,
|
|
61
|
-
returnError
|
|
62
|
+
returnError,
|
|
63
|
+
checkNumberFormat
|
|
62
64
|
});
|
|
63
65
|
|
|
64
66
|
registerTransactionRoutes(router, {
|
|
65
67
|
getServerWithAuth,
|
|
66
|
-
returnError
|
|
68
|
+
returnError,
|
|
69
|
+
checkNumberFormat
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
registerAdvertisementRoutes(router, {
|
package/src/lib/model/txnote.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { Utils as CWCUtils } from '@bitpay-labs/crypto-wallet-core';
|
|
1
2
|
import _ from 'lodash';
|
|
2
3
|
import { singleton } from 'preconditions';
|
|
3
4
|
import Uuid from 'uuid';
|
|
4
5
|
import { ChainService } from '../chain/index';
|
|
5
6
|
import { Common } from '../common';
|
|
6
7
|
import logger from '../logger';
|
|
7
|
-
import { IAddress } from './address';
|
|
8
|
-
import {
|
|
8
|
+
import { type IAddress } from './address';
|
|
9
|
+
import { type ITxNote, TxNote } from './txnote';
|
|
10
|
+
import { type ITxProposalLegacy, TxProposalLegacy } from './txproposal_legacy';
|
|
9
11
|
import { TxProposalAction } from './txproposalaction';
|
|
10
12
|
|
|
11
13
|
const $ = singleton();
|
|
@@ -13,9 +15,9 @@ const { Constants, Defaults, Utils } = Common;
|
|
|
13
15
|
|
|
14
16
|
type TxProposalStatus = 'temporary' | 'pending' | 'accepted' | 'rejected' | 'broadcasted';
|
|
15
17
|
|
|
16
|
-
export interface ITxProposal {
|
|
18
|
+
export interface ITxProposal<NumberType = number> {
|
|
19
|
+
version: number;
|
|
17
20
|
type?: string;
|
|
18
|
-
creatorName: string;
|
|
19
21
|
createdOn: number;
|
|
20
22
|
txid: string;
|
|
21
23
|
txids?: Array<string>;
|
|
@@ -28,19 +30,20 @@ export interface ITxProposal {
|
|
|
28
30
|
message: string;
|
|
29
31
|
payProUrl?: string;
|
|
30
32
|
from: string;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
sendMax?: boolean;
|
|
34
|
+
changeAddress?: Partial<IAddress>;
|
|
35
|
+
escrowAddress?: Partial<IAddress>;
|
|
33
36
|
inputs: any[];
|
|
34
37
|
outputs: Array<{
|
|
35
|
-
amount:
|
|
36
|
-
address
|
|
38
|
+
amount: NumberType;
|
|
39
|
+
address?: string;
|
|
37
40
|
toAddress?: string;
|
|
38
41
|
sourceAddress?: string;
|
|
39
42
|
message?: string;
|
|
40
43
|
data?: string;
|
|
41
|
-
gasLimit?:
|
|
44
|
+
gasLimit?: NumberType;
|
|
42
45
|
script?: string;
|
|
43
|
-
satoshis?:
|
|
46
|
+
satoshis?: NumberType;
|
|
44
47
|
tag?: number;
|
|
45
48
|
}>;
|
|
46
49
|
outputOrder: number[];
|
|
@@ -51,13 +54,12 @@ export interface ITxProposal {
|
|
|
51
54
|
status: TxProposalStatus;
|
|
52
55
|
actions: any[];
|
|
53
56
|
feeLevel: string;
|
|
54
|
-
feePerKb:
|
|
57
|
+
feePerKb: NumberType;
|
|
55
58
|
excludeUnconfirmedUtxos: boolean;
|
|
56
59
|
addressType: string;
|
|
57
60
|
customData: any;
|
|
58
|
-
amount:
|
|
59
|
-
fee:
|
|
60
|
-
version: number;
|
|
61
|
+
amount: NumberType;
|
|
62
|
+
fee: NumberType;
|
|
61
63
|
broadcastedOn: number;
|
|
62
64
|
inputPaths: string | any[];
|
|
63
65
|
proposalSignature: string;
|
|
@@ -65,41 +67,51 @@ export interface ITxProposal {
|
|
|
65
67
|
proposalSignaturePubKeySig: string;
|
|
66
68
|
signingMethod: string;
|
|
67
69
|
lowFees?: boolean;
|
|
68
|
-
|
|
70
|
+
raw?: Array<string> | string;
|
|
71
|
+
nonce?: NumberType | string;
|
|
69
72
|
deferNonce?: boolean;
|
|
70
|
-
gasPrice?:
|
|
71
|
-
maxGasFee?:
|
|
72
|
-
priorityGasFee?:
|
|
73
|
+
gasPrice?: NumberType;
|
|
74
|
+
maxGasFee?: NumberType;
|
|
75
|
+
priorityGasFee?: NumberType;
|
|
73
76
|
txType?: number | string;
|
|
74
|
-
gasLimit?:
|
|
77
|
+
gasLimit?: NumberType; // Backward compatibility for BWC <= 8.9.0
|
|
75
78
|
data?: string; // Backward compatibility for BWC <= 8.9.0
|
|
76
79
|
tokenAddress?: string;
|
|
77
80
|
multisigContractAddress?: string;
|
|
81
|
+
multisigTxId?: string;
|
|
78
82
|
destinationTag?: string;
|
|
79
83
|
invoiceID?: string;
|
|
80
|
-
lockUntilBlockHeight?:
|
|
81
|
-
instantAcceptanceEscrow?:
|
|
84
|
+
lockUntilBlockHeight?: NumberType;
|
|
85
|
+
instantAcceptanceEscrow?: NumberType;
|
|
82
86
|
isTokenSwap?: boolean;
|
|
87
|
+
multiSendContractAddress?: string;
|
|
83
88
|
enableRBF?: boolean;
|
|
84
89
|
replaceTxByFee?: boolean;
|
|
85
90
|
multiTx?: boolean; // proposal contains multiple transactions
|
|
86
|
-
space?:
|
|
91
|
+
space?: NumberType;
|
|
87
92
|
nonceAddress?: string;
|
|
88
93
|
blockHash?: string;
|
|
89
|
-
blockHeight?:
|
|
94
|
+
blockHeight?: NumberType;
|
|
90
95
|
category?: string;
|
|
91
|
-
priorityFee?:
|
|
92
|
-
computeUnits?:
|
|
96
|
+
priorityFee?: NumberType;
|
|
97
|
+
computeUnits?: NumberType;
|
|
93
98
|
memo?: string;
|
|
94
99
|
fromAta?: string;
|
|
95
100
|
decimals?: number;
|
|
96
101
|
refreshOnPublish?: boolean;
|
|
97
102
|
prePublishRaw?: string;
|
|
103
|
+
|
|
104
|
+
// Non-persistent fields - populated on fetch
|
|
105
|
+
creatorName: string;
|
|
106
|
+
derivationStrategy?: string;
|
|
107
|
+
note?: ITxNote;
|
|
98
108
|
}
|
|
99
109
|
|
|
100
|
-
export
|
|
110
|
+
export type NumberFormat = 'hex' | 'number' | 'string' | 'bigint';
|
|
111
|
+
|
|
112
|
+
export class TxProposal<NumberType = number> implements ITxProposal<NumberType> {
|
|
113
|
+
version: number;
|
|
101
114
|
type?: string;
|
|
102
|
-
creatorName: string;
|
|
103
115
|
createdOn: number;
|
|
104
116
|
id: string;
|
|
105
117
|
txid: string;
|
|
@@ -112,19 +124,20 @@ export class TxProposal implements ITxProposal {
|
|
|
112
124
|
message: string;
|
|
113
125
|
payProUrl?: string;
|
|
114
126
|
from: string;
|
|
115
|
-
|
|
116
|
-
|
|
127
|
+
sendMax?: boolean;
|
|
128
|
+
changeAddress?: Partial<IAddress>;
|
|
129
|
+
escrowAddress?: Partial<IAddress>;
|
|
117
130
|
inputs: any[];
|
|
118
131
|
outputs: Array<{
|
|
119
|
-
amount:
|
|
120
|
-
address
|
|
132
|
+
amount: NumberType;
|
|
133
|
+
address?: string;
|
|
121
134
|
toAddress?: string;
|
|
122
135
|
sourceAddress?: string;
|
|
123
136
|
message?: string;
|
|
124
137
|
data?: string;
|
|
125
|
-
gasLimit?:
|
|
138
|
+
gasLimit?: NumberType;
|
|
126
139
|
script?: string;
|
|
127
|
-
satoshis?:
|
|
140
|
+
satoshis?: NumberType;
|
|
128
141
|
tag?: number;
|
|
129
142
|
}>;
|
|
130
143
|
outputOrder: number[];
|
|
@@ -135,13 +148,12 @@ export class TxProposal implements ITxProposal {
|
|
|
135
148
|
status: TxProposalStatus;
|
|
136
149
|
actions: any[] = [];
|
|
137
150
|
feeLevel: string;
|
|
138
|
-
feePerKb:
|
|
151
|
+
feePerKb: NumberType;
|
|
139
152
|
excludeUnconfirmedUtxos: boolean;
|
|
140
153
|
addressType: string;
|
|
141
154
|
customData: any;
|
|
142
|
-
amount:
|
|
143
|
-
fee:
|
|
144
|
-
version: number;
|
|
155
|
+
amount: NumberType;
|
|
156
|
+
fee: NumberType;
|
|
145
157
|
broadcastedOn: number;
|
|
146
158
|
inputPaths: string | any[];
|
|
147
159
|
proposalSignature: string;
|
|
@@ -150,38 +162,43 @@ export class TxProposal implements ITxProposal {
|
|
|
150
162
|
signingMethod: string;
|
|
151
163
|
lowFees?: boolean;
|
|
152
164
|
raw?: Array<string> | string;
|
|
153
|
-
nonce?:
|
|
165
|
+
nonce?: NumberType;
|
|
154
166
|
deferNonce?: boolean;
|
|
155
|
-
gasPrice?:
|
|
156
|
-
maxGasFee?:
|
|
157
|
-
priorityGasFee?:
|
|
167
|
+
gasPrice?: NumberType;
|
|
168
|
+
maxGasFee?: NumberType;
|
|
169
|
+
priorityGasFee?: NumberType;
|
|
158
170
|
txType?: number | string;
|
|
159
|
-
gasLimit?:
|
|
171
|
+
gasLimit?: NumberType; // Backward compatibility for BWC <= 8.9.0
|
|
160
172
|
data?: string; // Backward compatibility for BWC <= 8.9.0
|
|
161
173
|
tokenAddress?: string;
|
|
162
174
|
multisigContractAddress?: string;
|
|
163
175
|
multisigTxId?: string;
|
|
164
176
|
destinationTag?: string;
|
|
165
177
|
invoiceID?: string;
|
|
166
|
-
lockUntilBlockHeight?:
|
|
167
|
-
instantAcceptanceEscrow?:
|
|
178
|
+
lockUntilBlockHeight?: NumberType;
|
|
179
|
+
instantAcceptanceEscrow?: NumberType;
|
|
168
180
|
isTokenSwap?: boolean;
|
|
169
181
|
multiSendContractAddress?: string;
|
|
170
182
|
enableRBF?: boolean;
|
|
171
183
|
replaceTxByFee?: boolean;
|
|
172
184
|
multiTx?: boolean;
|
|
173
|
-
space?:
|
|
185
|
+
space?: NumberType;
|
|
174
186
|
nonceAddress?: string;
|
|
175
187
|
blockHash?: string;
|
|
176
|
-
blockHeight?:
|
|
188
|
+
blockHeight?: NumberType;
|
|
177
189
|
category?: string;
|
|
178
|
-
priorityFee?:
|
|
179
|
-
computeUnits?:
|
|
190
|
+
priorityFee?: NumberType;
|
|
191
|
+
computeUnits?: NumberType;
|
|
180
192
|
memo?: string;
|
|
181
193
|
fromAta?: string;
|
|
182
194
|
decimals?: number;
|
|
183
195
|
refreshOnPublish?: boolean;
|
|
184
196
|
prePublishRaw?: string;
|
|
197
|
+
|
|
198
|
+
// Non-persistent fields - populated on fetch
|
|
199
|
+
creatorName: string;
|
|
200
|
+
derivationStrategy?: string;
|
|
201
|
+
note?: TxNote;
|
|
185
202
|
|
|
186
203
|
static create(opts) {
|
|
187
204
|
opts = opts || {};
|
|
@@ -211,6 +228,7 @@ export class TxProposal implements ITxProposal {
|
|
|
211
228
|
x.signingMethod = opts.signingMethod;
|
|
212
229
|
x.message = opts.message;
|
|
213
230
|
x.payProUrl = opts.payProUrl;
|
|
231
|
+
x.sendMax = opts.sendMax;
|
|
214
232
|
x.changeAddress = opts.changeAddress;
|
|
215
233
|
x.escrowAddress = opts.escrowAddress;
|
|
216
234
|
x.instantAcceptanceEscrow = opts.instantAcceptanceEscrow;
|
|
@@ -305,6 +323,8 @@ export class TxProposal implements ITxProposal {
|
|
|
305
323
|
return x;
|
|
306
324
|
}
|
|
307
325
|
|
|
326
|
+
static fromObj(obj: Partial<ITxProposal>): TxProposal;
|
|
327
|
+
static fromObj(obj: Partial<ITxProposalLegacy>): TxProposalLegacy;
|
|
308
328
|
static fromObj(obj) {
|
|
309
329
|
if (!(obj.version >= 3)) {
|
|
310
330
|
return TxProposalLegacy.fromObj(obj);
|
|
@@ -317,6 +337,7 @@ export class TxProposal implements ITxProposal {
|
|
|
317
337
|
x.id = obj.id;
|
|
318
338
|
x.walletId = obj.walletId;
|
|
319
339
|
x.creatorId = obj.creatorId;
|
|
340
|
+
x.creatorName = obj.creatorName;
|
|
320
341
|
x.coin = obj.coin || Defaults.COIN;
|
|
321
342
|
x.chain = obj.chain?.toLowerCase() || Utils.getChain(x.coin); // getChain -> backwards compatibility
|
|
322
343
|
x.network = obj.network;
|
|
@@ -324,6 +345,8 @@ export class TxProposal implements ITxProposal {
|
|
|
324
345
|
x.amount = obj.amount;
|
|
325
346
|
x.message = obj.message;
|
|
326
347
|
x.payProUrl = obj.payProUrl;
|
|
348
|
+
x.derivationStrategy = obj.derivationStrategy;
|
|
349
|
+
x.sendMax = obj.sendMax;
|
|
327
350
|
x.changeAddress = obj.changeAddress;
|
|
328
351
|
x.escrowAddress = obj.escrowAddress;
|
|
329
352
|
x.instantAcceptanceEscrow = obj.instantAcceptanceEscrow;
|
|
@@ -337,9 +360,7 @@ export class TxProposal implements ITxProposal {
|
|
|
337
360
|
x.txids = obj.txids;
|
|
338
361
|
x.broadcastedOn = obj.broadcastedOn;
|
|
339
362
|
x.inputPaths = obj.inputPaths;
|
|
340
|
-
x.actions =
|
|
341
|
-
return TxProposalAction.fromObj(action);
|
|
342
|
-
});
|
|
363
|
+
x.actions = (obj.actions || []).map(action => TxProposalAction.fromObj(action));
|
|
343
364
|
x.outputOrder = obj.outputOrder;
|
|
344
365
|
x.fee = obj.fee;
|
|
345
366
|
x.feeLevel = obj.feeLevel;
|
|
@@ -410,7 +431,7 @@ export class TxProposal implements ITxProposal {
|
|
|
410
431
|
|
|
411
432
|
setInputs(inputs) {
|
|
412
433
|
this.inputs = inputs || [];
|
|
413
|
-
this.inputPaths =
|
|
434
|
+
this.inputPaths = this.inputs.map(input => input.path);
|
|
414
435
|
}
|
|
415
436
|
|
|
416
437
|
_updateStatus() {
|
|
@@ -440,8 +461,10 @@ export class TxProposal implements ITxProposal {
|
|
|
440
461
|
return signatures;
|
|
441
462
|
}
|
|
442
463
|
|
|
443
|
-
getRawTx() {
|
|
444
|
-
|
|
464
|
+
getRawTx(numberFormat?: NumberFormat) {
|
|
465
|
+
// Casting numberFormat to 'number' is to sidestep TS errors, but is not necessarily true.
|
|
466
|
+
const txp = numberFormat ? TxProposal.formatNumbers(this, numberFormat as 'number') : this as TxProposal<number>;
|
|
467
|
+
const t = ChainService.getBitcoreTx(txp);
|
|
445
468
|
return t.uncheckedSerialize();
|
|
446
469
|
}
|
|
447
470
|
|
|
@@ -451,7 +474,7 @@ export class TxProposal implements ITxProposal {
|
|
|
451
474
|
* @return {Number} total amount of all outputs excluding change output
|
|
452
475
|
*/
|
|
453
476
|
getTotalAmount() {
|
|
454
|
-
return Number((this.outputs || []).reduce((total, o) => total += BigInt(o.amount), 0n));
|
|
477
|
+
return Number(((this as TxProposal<number>).outputs || []).reduce((total, o) => total += BigInt(o.amount), 0n));
|
|
455
478
|
}
|
|
456
479
|
|
|
457
480
|
/**
|
|
@@ -460,7 +483,7 @@ export class TxProposal implements ITxProposal {
|
|
|
460
483
|
* @return {String[]} copayerIds that performed actions in this proposal (accept / reject)
|
|
461
484
|
*/
|
|
462
485
|
getActors() {
|
|
463
|
-
return
|
|
486
|
+
return (this.actions || []).map(a => a.copayerId);
|
|
464
487
|
}
|
|
465
488
|
|
|
466
489
|
/**
|
|
@@ -469,12 +492,9 @@ export class TxProposal implements ITxProposal {
|
|
|
469
492
|
* @return {String[]} copayerIds that approved the tx proposal (accept)
|
|
470
493
|
*/
|
|
471
494
|
getApprovers() {
|
|
472
|
-
return
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}),
|
|
476
|
-
'copayerId'
|
|
477
|
-
);
|
|
495
|
+
return (this.actions || [])
|
|
496
|
+
.filter(a => a.type == 'accept')
|
|
497
|
+
.map(a => a.copayerId);
|
|
478
498
|
}
|
|
479
499
|
|
|
480
500
|
/**
|
|
@@ -484,9 +504,7 @@ export class TxProposal implements ITxProposal {
|
|
|
484
504
|
* @return {Object} type / createdOn
|
|
485
505
|
*/
|
|
486
506
|
getActionBy(copayerId) {
|
|
487
|
-
return
|
|
488
|
-
copayerId
|
|
489
|
-
});
|
|
507
|
+
return (this.actions || []).find(a => a.copayerId == copayerId);
|
|
490
508
|
}
|
|
491
509
|
|
|
492
510
|
addAction(copayerId, type, comment, signatures?, xpub?) {
|
|
@@ -501,10 +519,11 @@ export class TxProposal implements ITxProposal {
|
|
|
501
519
|
this._updateStatus();
|
|
502
520
|
}
|
|
503
521
|
|
|
504
|
-
sign(copayerId, signatures, xpub) {
|
|
522
|
+
sign(copayerId, signatures, xpub, numberFormat?: NumberFormat) {
|
|
505
523
|
try {
|
|
506
|
-
//
|
|
507
|
-
const
|
|
524
|
+
// numberFormat as 'number' is to sidestep TS errors, but is not necessarily true.
|
|
525
|
+
const txp = numberFormat ? TxProposal.formatNumbers(this, numberFormat as 'number') : this as TxProposal<number>;
|
|
526
|
+
const tx = ChainService.getBitcoreTx(txp);
|
|
508
527
|
ChainService.addSignaturesToBitcoreTx(
|
|
509
528
|
this.chain,
|
|
510
529
|
tx,
|
|
@@ -570,4 +589,70 @@ export class TxProposal implements ITxProposal {
|
|
|
570
589
|
this.status = 'broadcasted';
|
|
571
590
|
this.broadcastedOn = Math.floor(Date.now() / 1000);
|
|
572
591
|
}
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Replaces tx-building number values with the specified number format.
|
|
596
|
+
* This is to ensure consistency across BWC and BWS when handling large numbers, especially for chains like ETH and SOL.
|
|
597
|
+
* @param {TxProposal|ITxProposal} txp Transaction Proposal
|
|
598
|
+
* @param {'number'|'string'|'bigint'|'hex'} numberFormat The desired number format for the tx-building values. Can be 'number', 'string', 'bigint', or 'hex'.
|
|
599
|
+
*/
|
|
600
|
+
static formatNumbers<T>(txp: TxProposal<T>, numberFormat: 'string'): TxProposal<string>;
|
|
601
|
+
static formatNumbers<T>(txp: TxProposal<T>, numberFormat: 'hex'): TxProposal<string>;
|
|
602
|
+
static formatNumbers<T>(txp: TxProposal<T>, numberFormat: 'bigint'): TxProposal<bigint>;
|
|
603
|
+
static formatNumbers<T>(txp: TxProposal<T>, numberFormat: 'number'): TxProposal<number>;
|
|
604
|
+
static formatNumbers<T>(txp: ITxProposal<T>, numberFormat: 'string'): ITxProposal<string>;
|
|
605
|
+
static formatNumbers<T>(txp: ITxProposal<T>, numberFormat: 'hex'): ITxProposal<string>;
|
|
606
|
+
static formatNumbers<T>(txp: ITxProposal<T>, numberFormat: 'bigint'): ITxProposal<bigint>;
|
|
607
|
+
static formatNumbers<T>(txp: ITxProposal<T>, numberFormat: 'number'): ITxProposal<number>;
|
|
608
|
+
static formatNumbers<T>(txp: TxProposal<T> | ITxProposal<T>, numberFormat: NumberFormat = 'number') {
|
|
609
|
+
let convertFn;
|
|
610
|
+
switch (numberFormat) {
|
|
611
|
+
case 'number':
|
|
612
|
+
convertFn = parseInt;
|
|
613
|
+
break;
|
|
614
|
+
case 'string':
|
|
615
|
+
convertFn = (n) => typeof n === 'string' && n.startsWith('0x') ? BigInt(n).toString() : n.toString();
|
|
616
|
+
break;
|
|
617
|
+
case 'hex':
|
|
618
|
+
convertFn = (n) => CWCUtils.toHex(n);
|
|
619
|
+
break;
|
|
620
|
+
case 'bigint':
|
|
621
|
+
convertFn = (n) => BigInt(n);
|
|
622
|
+
break;
|
|
623
|
+
default:
|
|
624
|
+
logger.warn(`Invalid numberFormat: ${numberFormat}, no conversion will be applied to tx proposal ${txp.id}`);
|
|
625
|
+
return txp;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const primitiveTypes = new Set(['number', 'string', 'bigint']);
|
|
629
|
+
const convert = (key, value) => {
|
|
630
|
+
if ((numberFormat === 'hex' || typeof value !== numberFormat) && primitiveTypes.has(typeof value)) {
|
|
631
|
+
try {
|
|
632
|
+
value = convertFn(value);
|
|
633
|
+
} catch (e) {
|
|
634
|
+
logger.warn(`Failed to convert ${txp.id} > ${key} with value ${value} to ${numberFormat}: ${e.message}`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return value;
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
const _txp = txp instanceof TxProposal ? TxProposal.fromObj(txp.toObject()) : TxProposal.fromObj(txp as ITxProposal<number>).toObject();
|
|
641
|
+
|
|
642
|
+
const topKeys = ['amount', 'feePerKb', 'fee', 'nonce', 'gasPrice', 'maxGasFee', 'priorityGasFee', 'gasLimit', 'lockUntilBlockHeight', 'instantAcceptanceEscrow', 'space', 'blockHeight', 'computeUnits', 'decimals'];
|
|
643
|
+
for (const key of topKeys) {
|
|
644
|
+
const value = _txp[key];
|
|
645
|
+
_txp[key] = convert(key, value);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const outputKeys = ['amount', 'gasLimit', 'satoshis'];
|
|
649
|
+
for (let i = 0; i < _txp.outputs.length; i++) {
|
|
650
|
+
for (const key of outputKeys) {
|
|
651
|
+
const value = _txp.outputs[i][key];
|
|
652
|
+
_txp.outputs[i][key] = convert(`output.${i}.${key}`, value);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return _txp;
|
|
657
|
+
}
|
|
573
658
|
}
|
|
@@ -15,7 +15,7 @@ function throwUnsupportedError() {
|
|
|
15
15
|
throw new Error(msg);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export interface
|
|
18
|
+
export interface ITxProposalLegacy {
|
|
19
19
|
version: string;
|
|
20
20
|
type: string;
|
|
21
21
|
createdOn: number;
|
|
@@ -35,7 +35,7 @@ export interface ITxProposal {
|
|
|
35
35
|
walletN: number;
|
|
36
36
|
status: string;
|
|
37
37
|
txid: string;
|
|
38
|
-
broadcastedOn:
|
|
38
|
+
broadcastedOn: number;
|
|
39
39
|
inputPaths: string;
|
|
40
40
|
actions: any[];
|
|
41
41
|
outputOrder: number;
|
|
@@ -49,8 +49,9 @@ export interface ITxProposal {
|
|
|
49
49
|
addressType: string;
|
|
50
50
|
derivationStrategy: string;
|
|
51
51
|
customData: any;
|
|
52
|
-
}
|
|
53
|
-
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export class TxProposalLegacy implements ITxProposalLegacy {
|
|
54
55
|
version: string;
|
|
55
56
|
type: string;
|
|
56
57
|
createdOn: number;
|