diff --git a/lib/plugins/wallet/bitcoind/bitcoind.js b/lib/plugins/wallet/bitcoind/bitcoind.js
index a64e99c3..7166f769 100644
--- a/lib/plugins/wallet/bitcoind/bitcoind.js
+++ b/lib/plugins/wallet/bitcoind/bitcoind.js
@@ -51,11 +51,32 @@ function balance (account, cryptoCode, settings, operatorId) {
return accountBalance(cryptoCode)
}
-function sendCoins (account, tx, settings, operatorId) {
+function estimateFee () {
+ return fetch('estimatesmartfee', [6, 'unset'])
+ .then(result => BN(result.feerate))
+ .catch(() => {})
+}
+
+function calculateFeeDiscount (feeMultiplier) {
+ // 0 makes bitcoind do automatic fee selection
+ const AUTOMATIC_FEE = 0
+ if (!feeMultiplier || feeMultiplier.eq(1)) return AUTOMATIC_FEE
+ return estimateFee()
+ .then(estimatedFee => {
+ if (!estimatedFee) return AUTOMATIC_FEE
+ const newFee = estimatedFee.times(feeMultiplier)
+ if (newFee.lt(0.00001) || newFee.gt(0.1)) return AUTOMATIC_FEE
+ return newFee
+ })
+}
+
+function sendCoins (account, tx, settings, operatorId, feeMultiplier) {
const { toAddress, cryptoAtoms, cryptoCode } = tx
const coins = cryptoAtoms.shiftedBy(-unitScale).toFixed(8)
return checkCryptoCode(cryptoCode)
+ .then(() => calculateFeeDiscount(feeMultiplier))
+ .then(newFee => fetch('settxfee', [newFee]))
.then(() => fetch('sendtoaddress', [toAddress, coins]))
.then((txId) => fetch('gettransaction', [txId]))
.then((res) => _.pick(['fee', 'txid'], res))
@@ -148,5 +169,6 @@ module.exports = {
getStatus,
newFunding,
cryptoNetwork,
- fetchRBF
+ fetchRBF,
+ estimateFee
}
diff --git a/lib/wallet.js b/lib/wallet.js
index f5078e12..9391addb 100644
--- a/lib/wallet.js
+++ b/lib/wallet.js
@@ -3,6 +3,7 @@ const mem = require('mem')
const hkdf = require('futoin-hkdf')
const configManager = require('./new-config-manager')
+const { loadLatestConfig } = require('./new-settings-loader')
const pify = require('pify')
const fs = pify(require('fs'))
@@ -59,7 +60,8 @@ function _balance (settings, cryptoCode) {
function sendCoins (settings, tx) {
return fetchWallet(settings, tx.cryptoCode)
.then(r => {
- return r.wallet.sendCoins(r.account, tx, settings, r.operatorId)
+ const feeMultiplier = settings[`wallets_${tx.cryptoCode}_feeMultiplier`]
+ return r.wallet.sendCoins(r.account, tx, settings, r.operatorId, feeMultiplier)
.then(res => {
mem.clear(module.exports.balance)
return res
@@ -69,7 +71,6 @@ function sendCoins (settings, tx) {
if (err.name === INSUFFICIENT_FUNDS_NAME) {
throw httpError(INSUFFICIENT_FUNDS_NAME, INSUFFICIENT_FUNDS_CODE)
}
-
throw err
})
}
diff --git a/migrations/1620954224627-add-fee-priority.js b/migrations/1620954224627-add-fee-priority.js
new file mode 100644
index 00000000..e1a46496
--- /dev/null
+++ b/migrations/1620954224627-add-fee-priority.js
@@ -0,0 +1,21 @@
+const _ = require('lodash/fp')
+const { saveConfig, loadLatest } = require('../lib/new-settings-loader')
+const { getCryptosFromWalletNamespace } = require('../lib/new-config-manager')
+
+exports.up = function (next) {
+ const newConfig = {}
+ return loadLatest()
+ .then(config => {
+ const coins = getCryptosFromWalletNamespace(config)
+ _.map(coin => { newConfig[`wallets_${coin}_feeMultiplier`] = '1' }, coins)
+ return saveConfig(newConfig)
+ })
+ .then(next)
+ .catch(err => {
+ return next(err)
+ })
+}
+
+module.exports.down = function (next) {
+ next()
+}
diff --git a/new-lamassu-admin/src/components/editableTable/Table.js b/new-lamassu-admin/src/components/editableTable/Table.js
index a6e7b77c..701f4b20 100644
--- a/new-lamassu-admin/src/components/editableTable/Table.js
+++ b/new-lamassu-admin/src/components/editableTable/Table.js
@@ -127,6 +127,7 @@ const ETable = ({
((enableToggle && toggleWidth) ?? 0)
const width = getWidth(elements) + actionColSize
+
const classes = useStyles({ width })
const showButtonOnEmpty = !data.length && enableCreate && !adding
diff --git a/new-lamassu-admin/src/pages/Wallet/Wallet.js b/new-lamassu-admin/src/pages/Wallet/Wallet.js
index 386cc1a6..b80ea805 100644
--- a/new-lamassu-admin/src/pages/Wallet/Wallet.js
+++ b/new-lamassu-admin/src/pages/Wallet/Wallet.js
@@ -1,18 +1,24 @@
import { useQuery, useMutation } from '@apollo/react-hooks'
+import { DialogActions, makeStyles, Box } from '@material-ui/core'
import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState } from 'react'
import Modal from 'src/components/Modal'
+import { IconButton, Button } from 'src/components/buttons'
import { NamespacedTable as EditableTable } from 'src/components/editableTable'
+import { RadioGroup } from 'src/components/inputs'
import TitleSection from 'src/components/layout/TitleSection'
+import { P, Label1 } from 'src/components/typography'
import FormRenderer from 'src/pages/Services/FormRenderer'
import schemas from 'src/pages/Services/schemas'
+import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg'
import { ReactComponent as ReverseSettingsIcon } from 'src/styling/icons/circle buttons/settings/white.svg'
import { ReactComponent as SettingsIcon } from 'src/styling/icons/circle buttons/settings/zodiac.svg'
import { fromNamespace, toNamespace } from 'src/utils/config'
import AdvancedWallet from './AdvancedWallet'
+import styles from './Wallet.styles.js'
import Wizard from './Wizard'
import { WalletSchema, getElements } from './helper'
@@ -46,9 +52,15 @@ const GET_INFO = gql`
}
}
`
+
const LOCALE = 'locale'
+const useStyles = makeStyles(styles)
+
const Wallet = ({ name: SCREEN_KEY }) => {
+ const classes = useStyles()
+ const [editingFeeDiscount, setEditingFeeDiscount] = useState(null)
+ const [selectedDiscount, setSelectedDiscount] = useState(null)
const [editingSchema, setEditingSchema] = useState(null)
const [onChangeFunction, setOnChangeFunction] = useState(null)
const [wizard, setWizard] = useState(false)
@@ -104,17 +116,51 @@ const Wallet = ({ name: SCREEN_KEY }) => {
return it
})
+ const saveFeeDiscount = rawConfig => {
+ const config = toNamespace(SCREEN_KEY)(rawConfig)
+ setEditingFeeDiscount(false)
+ return saveConfig({ variables: { config } })
+ }
+
+ const handleRadioButtons = evt => {
+ const selectedDiscount = R.path(['target', 'value'])(evt)
+ setSelectedDiscount(selectedDiscount)
+ }
+
+ const radioButtonOptions = [
+ { display: '+20%', code: '1.2' },
+ { display: 'Default', code: '1' },
+ { display: '-20%', code: '0.8' },
+ { display: '-40%', code: '0.6' },
+ { display: '-60%', code: '0.4' }
+ ]
+
return (
<>
-
{selectedDiscount}
++ Set a priority level for your outgoing BTC transactions, selecting a + percentage off of the fee estimate your wallet uses. +
+