edge-currency-plugins 3.13.0 → 3.14.0
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/android/src/main/assets/edge-currency-plugins/edge-currency-plugins.js +45 -45
- package/lib/common/constants.js +4 -1
- package/lib/common/fees/calcMinerFeePerByte.js +19 -5
- package/lib/common/fees/calcReplacementFeeRate.js +25 -0
- package/lib/common/fees/processMempoolSpaceFees.js +12 -16
- package/lib/common/utxobased/engine/UtxoEngine.js +16 -3
- package/lib/common/utxobased/info/bitcoin.js +1 -1
- package/lib/common/utxobased/info/bitcointestnet.js +1 -1
- package/lib/common/utxobased/info/bitcointestnet4.js +1 -1
- package/lib/common/utxobased/info/ecash.js +4 -1
- package/lib/common/utxobased/info/pivx.js +4 -4
- package/lib/common/utxobased/keymanager/utxopicker/accumulative.js +4 -4
- package/lib/common/utxobased/keymanager/utxopicker/forceUseUtxo.js +5 -5
- package/lib/common/utxobased/keymanager/utxopicker/subtractFee.js +1 -1
- package/lib/common/utxobased/keymanager/utxopicker/utils.js +27 -3
- package/lib/src/common/constants.d.ts +1 -1
- package/lib/src/common/fees/calcReplacementFeeRate.d.ts +15 -0
- package/lib/src/common/utxobased/keymanager/utxopicker/utils.d.ts +12 -0
- package/lib/test/common/fees/calcReplacementFeeRate.spec.d.ts +1 -0
- package/lib/test/common/fees/processMempoolSpaceFees.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/utxopicker/decimalFeeRate.spec.d.ts +1 -0
- package/lib/test/common/utxobased/keymanager/utxopicker/utils.spec.d.ts +1 -0
- package/package.json +1 -1
package/lib/common/constants.js
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
// Fees
|
|
4
4
|
const FEES_PATH = 'fees.json'; exports.FEES_PATH = FEES_PATH
|
|
5
5
|
const MAX_FEE = 999999999.0; exports.MAX_FEE = MAX_FEE
|
|
6
|
-
|
|
6
|
+
// Fee rates are sat/vB and may be fractional. Three decimal places matches the
|
|
7
|
+
// precision of the mempool.space `/fees/precise` endpoint, which is the most
|
|
8
|
+
// precise rate source we consume.
|
|
9
|
+
const FEE_RATE_DECIMALS = 3; exports.FEE_RATE_DECIMALS = FEE_RATE_DECIMALS
|
|
7
10
|
const MAX_HIGH_DELAY = 200; exports.MAX_HIGH_DELAY = MAX_HIGH_DELAY
|
|
8
11
|
const MAX_STANDARD_DELAY = 6; exports.MAX_STANDARD_DELAY = MAX_STANDARD_DELAY
|
|
9
12
|
const MIN_STANDARD_DELAY = 2; exports.MIN_STANDARD_DELAY = MIN_STANDARD_DELAY
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _biggystring = require('biggystring');
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
var _constants = require('../constants');
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
|
|
@@ -29,10 +30,20 @@
|
|
|
29
30
|
} = feeInfo
|
|
30
31
|
let { highFee, lowFee, standardFeeHigh, standardFeeLow } = feeInfo
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Fee rates may be fractional, so these round to FEE_RATE_DECIMALS places
|
|
34
|
+
// rather than to a whole sat/vB. biggystring's `round` takes the power of ten
|
|
35
|
+
// to round at, so the precision is negated: -3 means three decimal places.
|
|
36
|
+
const feeRatePlaces = -_constants.FEE_RATE_DECIMALS
|
|
37
|
+
highFee = _biggystring.round.call(void 0, _biggystring.mul.call(void 0, highFee, highFeeFudgeFactor), feeRatePlaces)
|
|
38
|
+
lowFee = _biggystring.round.call(void 0, _biggystring.mul.call(void 0, lowFee, lowFeeFudgeFactor), feeRatePlaces)
|
|
39
|
+
standardFeeHigh = _biggystring.round.call(void 0,
|
|
40
|
+
_biggystring.mul.call(void 0, standardFeeHigh, standardFeeHighFudgeFactor),
|
|
41
|
+
feeRatePlaces
|
|
42
|
+
)
|
|
43
|
+
standardFeeLow = _biggystring.round.call(void 0,
|
|
44
|
+
_biggystring.mul.call(void 0, standardFeeLow, standardFeeLowFudgeFactor),
|
|
45
|
+
feeRatePlaces
|
|
46
|
+
)
|
|
36
47
|
|
|
37
48
|
switch (networkFeeOption) {
|
|
38
49
|
case 'low':
|
|
@@ -55,7 +66,10 @@
|
|
|
55
66
|
|
|
56
67
|
// Add this much to the low fee = (amountDiffFromLow * lowHighFeeDiff) / lowHighAmountDiff)
|
|
57
68
|
const temp1 = _biggystring.mul.call(void 0, amountDiffFromLow, lowHighFeeDiff)
|
|
58
|
-
|
|
69
|
+
// `div` defaults to zero decimal places, which would truncate the
|
|
70
|
+
// interpolated rate back to a whole sat/vB. Unlike `round` above, its
|
|
71
|
+
// precision argument is the number of decimal places, not a power of ten.
|
|
72
|
+
const addFeeToLow = _biggystring.div.call(void 0, temp1, lowHighAmountDiff, _constants.FEE_RATE_DECIMALS)
|
|
59
73
|
return _biggystring.add.call(void 0, standardFeeLow, addFeeToLow)
|
|
60
74
|
}
|
|
61
75
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _constants = require('../constants');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Calculate the sat/vB fee rate for a transaction that replaces another by fee:
|
|
5
|
+
* double the rate the replaced transaction paid.
|
|
6
|
+
*
|
|
7
|
+
* The rate rounds up to FEE_RATE_DECIMALS places. Rounding up means the
|
|
8
|
+
* replacement never pays less than double, and a positive rate never rounds
|
|
9
|
+
* down to zero, which the UTXO picker would accept as a valid rate. Rounding
|
|
10
|
+
* to a fixed number of places keeps the rate readable where it is reported as
|
|
11
|
+
* `feeRateUsed`.
|
|
12
|
+
*
|
|
13
|
+
* @param replacedFee The fee the replaced transaction paid, in satoshis
|
|
14
|
+
* @param replacedVBytes The replaced transaction's virtual size
|
|
15
|
+
* @returns {number}
|
|
16
|
+
*/
|
|
17
|
+
const calcReplacementFeeRate = (
|
|
18
|
+
replacedFee,
|
|
19
|
+
replacedVBytes
|
|
20
|
+
) => {
|
|
21
|
+
const scale = 10 ** _constants.FEE_RATE_DECIMALS
|
|
22
|
+
// The fee and size are whole numbers, so this division is exact whenever the
|
|
23
|
+
// scaled rate is, and Math.ceil sees no floating point noise.
|
|
24
|
+
return Math.ceil((replacedFee * 2 * scale) / replacedVBytes) / scale
|
|
25
|
+
}; exports.calcReplacementFeeRate = calcReplacementFeeRate
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }var _biggystring = require('biggystring'); var bs = _interopRequireWildcard(_biggystring);
|
|
2
2
|
var _cleaners = require('cleaners');
|
|
3
3
|
|
|
4
|
-
var _constants = require('../constants');
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
const asMempoolSpaceFees = _cleaners.asObject.call(void 0, {
|
|
@@ -12,13 +11,16 @@ var _constants = require('../constants');
|
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Calculates the FeeRates object from MempoolSpace
|
|
15
|
-
* Sets the minimum of LOW_FEE on all fee levels
|
|
16
14
|
* @param fees
|
|
17
15
|
* @returns Partial<FeeRates>
|
|
18
16
|
*/
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
// The `/fees/precise` endpoint reports rates with up to three decimal places,
|
|
19
|
+
// so the multipliers run through biggystring rather than JS numbers. A float
|
|
20
|
+
// multiply would reintroduce noise (0.575 * 1.3 is 0.7474999999999999) that
|
|
21
|
+
// biggystring carries exactly.
|
|
22
|
+
const STANDARD_FEE_HIGH_MULTIPLIER = '1.3'
|
|
23
|
+
const HIGH_FEE_MULTIPLIER = '2'
|
|
22
24
|
|
|
23
25
|
const processMempoolSpaceFees = (fees) => {
|
|
24
26
|
let mempoolFees
|
|
@@ -28,19 +30,13 @@ const HIGH_FEE_MULTIPLIER = 2
|
|
|
28
30
|
return null
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const lowFee = halfHourFee.toString()
|
|
34
|
-
const standardFeeLow = fastestFee.toString()
|
|
35
|
-
const standardFeeHigh = Math.round(
|
|
36
|
-
fastestFee * STANDARD_FEE_HIGH_MULTIPLIER
|
|
37
|
-
).toString()
|
|
38
|
-
const highFee = Math.round(fastestFee * HIGH_FEE_MULTIPLIER).toString()
|
|
33
|
+
const fastestFee = mempoolFees.fastestFee.toString()
|
|
34
|
+
const halfHourFee = mempoolFees.halfHourFee.toString()
|
|
39
35
|
|
|
40
36
|
return {
|
|
41
|
-
lowFee:
|
|
42
|
-
standardFeeLow:
|
|
43
|
-
standardFeeHigh: bs.
|
|
44
|
-
highFee: bs.
|
|
37
|
+
lowFee: halfHourFee,
|
|
38
|
+
standardFeeLow: fastestFee,
|
|
39
|
+
standardFeeHigh: bs.mul(fastestFee, STANDARD_FEE_HIGH_MULTIPLIER),
|
|
40
|
+
highFee: bs.mul(fastestFee, HIGH_FEE_MULTIPLIER)
|
|
45
41
|
}
|
|
46
42
|
}; exports.processMempoolSpaceFees = processMempoolSpaceFees
|
|
@@ -20,6 +20,7 @@ var _edgecorejs = require('edge-core-js');
|
|
|
20
20
|
|
|
21
21
|
var _filterUndefined = require('../../../util/filterUndefined');
|
|
22
22
|
var _unixTime = require('../../../util/unixTime');
|
|
23
|
+
var _calcReplacementFeeRate = require('../../fees/calcReplacementFeeRate');
|
|
23
24
|
var _makeFees = require('../../fees/makeFees');
|
|
24
25
|
var _EngineEmitter = require('../../plugin/EngineEmitter');
|
|
25
26
|
var _Metadata = require('../../plugin/Metadata');
|
|
@@ -187,9 +188,12 @@ var _UtxoWalletTools = require('./UtxoWalletTools');
|
|
|
187
188
|
// Must not be confirmed or dropped.
|
|
188
189
|
if (replacedTx.blockHeight !== 0) return null
|
|
189
190
|
|
|
190
|
-
// Double the fee used
|
|
191
|
+
// Double the fee rate used by the replaced transaction:
|
|
191
192
|
const vBytes = _utils.transactionSizeFromHex.call(void 0, replacedTx.hex)
|
|
192
|
-
const newFeeRate =
|
|
193
|
+
const newFeeRate = _calcReplacementFeeRate.calcReplacementFeeRate.call(void 0,
|
|
194
|
+
parseInt(replacedTx.fees),
|
|
195
|
+
vBytes
|
|
196
|
+
)
|
|
193
197
|
|
|
194
198
|
const replacedTxInputs = replacedTx.inputs
|
|
195
199
|
// Recreate UTXOs from DataLayer transaction and mark them as unspent:
|
|
@@ -631,7 +635,16 @@ var _UtxoWalletTools = require('./UtxoWalletTools');
|
|
|
631
635
|
freshAddress.segwitAddress)), () => (
|
|
632
636
|
freshAddress.publicAddress))
|
|
633
637
|
|
|
634
|
-
|
|
638
|
+
// Fee rates may be fractional (e.g. a 1.8 sat/vB custom fee), so this
|
|
639
|
+
// must not be truncated to an integer. The picker rounds the satoshi
|
|
640
|
+
// amounts it derives from this rate up to whole satoshis. Number rejects
|
|
641
|
+
// any string that is not entirely a number, where parseFloat would read a
|
|
642
|
+
// comma-decimal '1,8' as 1 and charge the wrong rate without an error.
|
|
643
|
+
const feeRateString = await fees.getRate(edgeSpendInfo)
|
|
644
|
+
const feeRate = Number(feeRateString)
|
|
645
|
+
if (!isFinite(feeRate) || feeRate <= 0) {
|
|
646
|
+
throw new Error(`Invalid fee rate: ${feeRateString}`)
|
|
647
|
+
}
|
|
635
648
|
|
|
636
649
|
let maxUtxo
|
|
637
650
|
if (txOptions.CPFP != null) {
|
|
@@ -65,7 +65,7 @@ const engineInfo = {
|
|
|
65
65
|
forks: ['bitcoincash', 'bitcoingold'],
|
|
66
66
|
gapLimit: 25,
|
|
67
67
|
feeUpdateInterval: 60000,
|
|
68
|
-
mempoolSpaceFeeInfoServer: 'https://mempool.space/api/v1/fees/
|
|
68
|
+
mempoolSpaceFeeInfoServer: 'https://mempool.space/api/v1/fees/precise',
|
|
69
69
|
defaultFeeInfo: {
|
|
70
70
|
lowFeeFudgeFactor: undefined,
|
|
71
71
|
standardFeeLowFudgeFactor: undefined,
|
|
@@ -45,7 +45,7 @@ var _commonInfo = require('./commonInfo');
|
|
|
45
45
|
forks: ['bitcoincash', 'bitcoingold'],
|
|
46
46
|
gapLimit: 25,
|
|
47
47
|
feeUpdateInterval: 60000,
|
|
48
|
-
mempoolSpaceFeeInfoServer: 'https://mempool.space/api/v1/fees/
|
|
48
|
+
mempoolSpaceFeeInfoServer: 'https://mempool.space/api/v1/fees/precise',
|
|
49
49
|
defaultFeeInfo: {
|
|
50
50
|
lowFeeFudgeFactor: undefined,
|
|
51
51
|
standardFeeLowFudgeFactor: undefined,
|
|
@@ -49,7 +49,7 @@ var _commonInfo = require('./commonInfo');
|
|
|
49
49
|
gapLimit: 25,
|
|
50
50
|
feeUpdateInterval: 60000,
|
|
51
51
|
mempoolSpaceFeeInfoServer:
|
|
52
|
-
'https://mempool.space/testnet4/api/v1/fees/
|
|
52
|
+
'https://mempool.space/testnet4/api/v1/fees/precise',
|
|
53
53
|
defaultFeeInfo: {
|
|
54
54
|
lowFeeFudgeFactor: undefined,
|
|
55
55
|
standardFeeLowFudgeFactor: undefined,
|
|
@@ -32,7 +32,10 @@ const currencyInfo = {
|
|
|
32
32
|
..._commonInfo.legacyMemoInfo,
|
|
33
33
|
defaultSettings: {
|
|
34
34
|
customFeeSettings: ['satPerByte'],
|
|
35
|
-
blockbookServers: [
|
|
35
|
+
blockbookServers: [
|
|
36
|
+
'wss://blockbook.fabien.cash/websocket',
|
|
37
|
+
'wss://xec-blockbook.nownodes.io/wss/%{nowNodesApiKey}'
|
|
38
|
+
],
|
|
36
39
|
enableCustomServers: false
|
|
37
40
|
},
|
|
38
41
|
displayName: 'eCash',
|
|
@@ -18,9 +18,9 @@ const currencyInfo = {
|
|
|
18
18
|
walletType: 'wallet:pivx',
|
|
19
19
|
|
|
20
20
|
// Explorers:
|
|
21
|
-
addressExplorer: 'https://
|
|
22
|
-
blockExplorer: 'https://
|
|
23
|
-
transactionExplorer: 'https://
|
|
21
|
+
addressExplorer: 'https://explorer.duddino.com/address/%s',
|
|
22
|
+
blockExplorer: 'https://explorer.duddino.com/block/%s',
|
|
23
|
+
transactionExplorer: 'https://explorer.duddino.com/tx/%s',
|
|
24
24
|
|
|
25
25
|
denominations: [
|
|
26
26
|
{
|
|
@@ -34,7 +34,7 @@ const currencyInfo = {
|
|
|
34
34
|
..._commonInfo.legacyMemoInfo,
|
|
35
35
|
defaultSettings: {
|
|
36
36
|
customFeeSettings: ['satPerByte'],
|
|
37
|
-
blockbookServers: ['wss://pivx-eusa1.edge.app'
|
|
37
|
+
blockbookServers: ['wss://pivx-eusa1.edge.app'],
|
|
38
38
|
enableCustomServers: false
|
|
39
39
|
},
|
|
40
40
|
displayName: 'PIVX',
|
|
@@ -6,7 +6,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
6
6
|
function accumulative(args) {
|
|
7
7
|
const { utxos, targets, feeRate, changeScript } = args
|
|
8
8
|
|
|
9
|
-
if (!isFinite(utils.
|
|
9
|
+
if (!isFinite(utils.feeRateOrNaN(feeRate))) {
|
|
10
10
|
throw new Error('No rate provided')
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
24
24
|
const utxo = utxos[i]
|
|
25
25
|
|
|
26
26
|
// skip detrimental input
|
|
27
|
-
const utxoFee = feeRate
|
|
27
|
+
const utxoFee = utils.feeForBytes(feeRate, utils.inputBytes(utxo))
|
|
28
28
|
if (utxoFee > utxo.value) {
|
|
29
29
|
if (i === utxos.length - 1) {
|
|
30
30
|
break
|
|
@@ -37,7 +37,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
37
37
|
inValue += utxo.value
|
|
38
38
|
|
|
39
39
|
const bytes = utils.transactionBytes(inputs, outputs)
|
|
40
|
-
const fee = bytes
|
|
40
|
+
const fee = utils.feeForBytes(feeRate, bytes)
|
|
41
41
|
|
|
42
42
|
// go again?
|
|
43
43
|
if (inValue < targetValue + fee) continue
|
|
@@ -47,7 +47,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
47
47
|
|
|
48
48
|
return {
|
|
49
49
|
changeUsed: false,
|
|
50
|
-
fee:
|
|
50
|
+
fee: utils.feeForBytes(feeRate, utils.transactionBytes(inputs, outputs)),
|
|
51
51
|
inputs
|
|
52
52
|
}
|
|
53
53
|
} exports.accumulative = accumulative;
|
|
@@ -7,7 +7,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
7
7
|
function forceUseUtxo(args) {
|
|
8
8
|
const { utxos, useUtxos, targets, feeRate, changeScript } = args
|
|
9
9
|
|
|
10
|
-
if (!isFinite(utils.
|
|
10
|
+
if (!isFinite(utils.feeRateOrNaN(feeRate))) {
|
|
11
11
|
throw new Error('No rate provided')
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
21
21
|
let inValue = inputs.reduce((n, { value }) => n + value, 0)
|
|
22
22
|
const targetValue = utils.sumOrNaN(targets)
|
|
23
23
|
const bytes = utils.transactionBytes(inputs, outputs)
|
|
24
|
-
const fee = bytes
|
|
24
|
+
const fee = utils.feeForBytes(feeRate, bytes)
|
|
25
25
|
// if the new feeRate is already covered by lowering the change amount, return
|
|
26
26
|
if (inValue >= targetValue + fee) {
|
|
27
27
|
return utils.finalize(inputs, outputs, feeRate, changeScript)
|
|
@@ -31,7 +31,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
31
31
|
const utxo = utxos[i]
|
|
32
32
|
|
|
33
33
|
// skip detrimental input
|
|
34
|
-
const utxoFee = feeRate
|
|
34
|
+
const utxoFee = utils.feeForBytes(feeRate, utils.inputBytes(utxo))
|
|
35
35
|
if (utxoFee > utxo.value) {
|
|
36
36
|
if (i === utxos.length - 1) {
|
|
37
37
|
break
|
|
@@ -44,7 +44,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
44
44
|
inValue += utxo.value
|
|
45
45
|
|
|
46
46
|
const bytes = utils.transactionBytes(inputs, outputs)
|
|
47
|
-
const fee = bytes
|
|
47
|
+
const fee = utils.feeForBytes(feeRate, bytes)
|
|
48
48
|
|
|
49
49
|
// go again?
|
|
50
50
|
if (inValue < targetValue + fee) continue
|
|
@@ -54,7 +54,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
54
54
|
|
|
55
55
|
return {
|
|
56
56
|
changeUsed: false,
|
|
57
|
-
fee:
|
|
57
|
+
fee: utils.feeForBytes(feeRate, utils.transactionBytes(inputs, outputs)),
|
|
58
58
|
inputs
|
|
59
59
|
}
|
|
60
60
|
} exports.forceUseUtxo = forceUseUtxo;
|
|
@@ -10,7 +10,7 @@ var _utils = require('./utils'); var utils = _interopRequireWildcard(_utils);
|
|
|
10
10
|
scriptPubkey: Buffer.from(target.script, 'hex')
|
|
11
11
|
}))
|
|
12
12
|
|
|
13
|
-
const fee =
|
|
13
|
+
const fee = utils.feeForBytes(feeRate, utils.transactionBytes(utxos, outputs))
|
|
14
14
|
targets[0].value -= fee
|
|
15
15
|
outputs[0].value -= fee
|
|
16
16
|
|
|
@@ -73,7 +73,7 @@ const scriptSizeMap = (() => {
|
|
|
73
73
|
} exports.outputBytes = outputBytes;
|
|
74
74
|
|
|
75
75
|
function dustThreshold(output, feeRate) {
|
|
76
|
-
return outputBytes(output)
|
|
76
|
+
return feeForBytes(feeRate, outputBytes(output))
|
|
77
77
|
} exports.dustThreshold = dustThreshold;
|
|
78
78
|
|
|
79
79
|
function witnessCount(inputs) {
|
|
@@ -122,6 +122,30 @@ function witnessCount(inputs) {
|
|
|
122
122
|
return v
|
|
123
123
|
} exports.uintOrNaN = uintOrNaN;
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Validates a fee rate in satoshis per byte. Fee rates may be fractional,
|
|
127
|
+
* unlike the satoshi values they produce: a rate is always multiplied by a
|
|
128
|
+
* byte count and rounded up before it becomes a satoshi amount.
|
|
129
|
+
*/
|
|
130
|
+
function feeRateOrNaN(v) {
|
|
131
|
+
if (!isFinite(v)) return NaN
|
|
132
|
+
if (v < 0) return NaN
|
|
133
|
+
return v
|
|
134
|
+
} exports.feeRateOrNaN = feeRateOrNaN;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Returns the whole number of satoshis required to pay for `bytes` at
|
|
138
|
+
* `feeRate` satoshis per byte. Always rounds up, so a fractional rate can
|
|
139
|
+
* never produce a fractional satoshi amount and can never underpay.
|
|
140
|
+
*/
|
|
141
|
+
function feeForBytes(feeRate, bytes) {
|
|
142
|
+
// Multiplying a fractional rate carries floating point noise: `1.1 * 10` is
|
|
143
|
+
// 11.000000000000002, which would round an exact satoshi amount up to the
|
|
144
|
+
// next satoshi. Snap the product back to 12 significant digits first, which
|
|
145
|
+
// is far more precision than any real fee needs, but well short of the noise.
|
|
146
|
+
return Math.ceil(parseFloat((feeRate * bytes).toPrecision(12)))
|
|
147
|
+
} exports.feeForBytes = feeForBytes;
|
|
148
|
+
|
|
125
149
|
function sumForgiving(range) {
|
|
126
150
|
return range.reduce((a, x) => a + (isFinite(x.value) ? x.value : 0), 0)
|
|
127
151
|
} exports.sumForgiving = sumForgiving;
|
|
@@ -139,7 +163,7 @@ function witnessCount(inputs) {
|
|
|
139
163
|
const inValue = sumOrNaN(inputs)
|
|
140
164
|
const outValue = sumOrNaN(outputs)
|
|
141
165
|
let txSize = transactionBytes(inputs, outputs)
|
|
142
|
-
let fee =
|
|
166
|
+
let fee = feeForBytes(feeRate, txSize)
|
|
143
167
|
|
|
144
168
|
const changeValue = inValue - (outValue + fee)
|
|
145
169
|
const changeOutput = {
|
|
@@ -149,7 +173,7 @@ function witnessCount(inputs) {
|
|
|
149
173
|
}
|
|
150
174
|
const changeOutputSize = outputBytes(changeOutput)
|
|
151
175
|
txSize += changeOutputSize
|
|
152
|
-
const changeFee = feeRate
|
|
176
|
+
const changeFee = feeForBytes(feeRate, changeOutputSize)
|
|
153
177
|
changeOutput.value -= changeFee
|
|
154
178
|
let changeUsed = false
|
|
155
179
|
if (changeOutput.value > dustThreshold(changeOutput, feeRate)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const INFO_SERVER_URI = "https://info1.edge.app";
|
|
2
2
|
export declare const FEES_PATH = "fees.json";
|
|
3
3
|
export declare const MAX_FEE = 999999999;
|
|
4
|
-
export declare const
|
|
4
|
+
export declare const FEE_RATE_DECIMALS = 3;
|
|
5
5
|
export declare const MAX_HIGH_DELAY = 200;
|
|
6
6
|
export declare const MAX_STANDARD_DELAY = 6;
|
|
7
7
|
export declare const MIN_STANDARD_DELAY = 2;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate the sat/vB fee rate for a transaction that replaces another by fee:
|
|
3
|
+
* double the rate the replaced transaction paid.
|
|
4
|
+
*
|
|
5
|
+
* The rate rounds up to FEE_RATE_DECIMALS places. Rounding up means the
|
|
6
|
+
* replacement never pays less than double, and a positive rate never rounds
|
|
7
|
+
* down to zero, which the UTXO picker would accept as a valid rate. Rounding
|
|
8
|
+
* to a fixed number of places keeps the rate readable where it is reported as
|
|
9
|
+
* `feeRateUsed`.
|
|
10
|
+
*
|
|
11
|
+
* @param replacedFee The fee the replaced transaction paid, in satoshis
|
|
12
|
+
* @param replacedVBytes The replaced transaction's virtual size
|
|
13
|
+
* @returns {number}
|
|
14
|
+
*/
|
|
15
|
+
export declare const calcReplacementFeeRate: (replacedFee: number, replacedVBytes: number) => number;
|
|
@@ -7,6 +7,18 @@ export declare function dustThreshold(output: Output, feeRate: number): number;
|
|
|
7
7
|
export declare function transactionBytes(inputs: UTXO[], outputs: Output[]): number;
|
|
8
8
|
export declare const transactionSizeFromHex: (hex: string) => number;
|
|
9
9
|
export declare function uintOrNaN(v: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* Validates a fee rate in satoshis per byte. Fee rates may be fractional,
|
|
12
|
+
* unlike the satoshi values they produce: a rate is always multiplied by a
|
|
13
|
+
* byte count and rounded up before it becomes a satoshi amount.
|
|
14
|
+
*/
|
|
15
|
+
export declare function feeRateOrNaN(v: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* Returns the whole number of satoshis required to pay for `bytes` at
|
|
18
|
+
* `feeRate` satoshis per byte. Always rounds up, so a fractional rate can
|
|
19
|
+
* never produce a fractional satoshi amount and can never underpay.
|
|
20
|
+
*/
|
|
21
|
+
export declare function feeForBytes(feeRate: number, bytes: number): number;
|
|
10
22
|
export declare function sumForgiving(range: Array<{
|
|
11
23
|
value: number;
|
|
12
24
|
}>): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edge-currency-plugins",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.14.0",
|
|
4
4
|
"description": "Edge currency plugins to fetch and process wallet accounts, balances and transactions.",
|
|
5
5
|
"homepage": "https://edge.app/",
|
|
6
6
|
"repository": "https://github.com/EdgeApp/edge-currency-plugins",
|