Merge pull request #2577 from ManfredKarrer/mk-lock-bond-fees

Added mining fee to un/lock bond popup
This commit is contained in:
Manfred Karrer 2019-03-24 19:12:35 -05:00 committed by GitHub
commit 497e202420
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 27 deletions

View file

@ -90,6 +90,8 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@ -509,11 +511,21 @@ public class DaoFacade implements DaoSetupService {
lockupTxService.publishLockupTx(lockupAmount, lockTime, lockupReason, hash, resultHandler, exceptionHandler);
}
public Tuple2<Coin, Integer> getLockupTxMiningFeeAndTxSize(Coin lockupAmount, int lockTime, LockupReason lockupReason, byte[] hash)
throws InsufficientMoneyException, IOException, TransactionVerificationException, WalletException {
return lockupTxService.getMiningFeeAndTxSize(lockupAmount, lockTime, lockupReason, hash);
}
public void publishUnlockTx(String lockupTxId, Consumer<String> resultHandler,
ExceptionHandler exceptionHandler) {
unlockTxService.publishUnlockTx(lockupTxId, resultHandler, exceptionHandler);
}
public Tuple2<Coin, Integer> getUnlockTxMiningFeeAndTxSize(String lockupTxId)
throws InsufficientMoneyException, TransactionVerificationException, WalletException {
return unlockTxService.getMiningFeeAndTxSize(lockupTxId);
}
public long getTotalLockupAmount() {
return daoStateService.getTotalLockupAmount();
}

View file

@ -28,6 +28,7 @@ import bisq.core.dao.governance.bond.BondConsensus;
import bisq.core.dao.state.model.blockchain.TxType;
import bisq.common.handlers.ExceptionHandler;
import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
@ -71,9 +72,7 @@ public class LockupTxService {
checkArgument(lockTime <= BondConsensus.getMaxLockTime() &&
lockTime >= BondConsensus.getMinLockTime(), "lockTime not in range");
try {
byte[] opReturnData = BondConsensus.getLockupOpReturnData(lockTime, lockupReason, hash);
Transaction lockupTx = createLockupTx(lockupAmount, opReturnData);
Transaction lockupTx = getLockupTx(lockupAmount, lockTime, lockupReason, hash);
walletsManager.publishAndCommitBsqTx(lockupTx, TxType.LOCKUP, new TxBroadcaster.Callback() {
@Override
public void onSuccess(Transaction transaction) {
@ -92,8 +91,17 @@ public class LockupTxService {
}
}
private Transaction createLockupTx(Coin lockupAmount, byte[] opReturnData)
throws InsufficientMoneyException, WalletException, TransactionVerificationException {
public Tuple2<Coin, Integer> getMiningFeeAndTxSize(Coin lockupAmount, int lockTime, LockupReason lockupReason, byte[] hash)
throws InsufficientMoneyException, WalletException, TransactionVerificationException, IOException {
Transaction tx = getLockupTx(lockupAmount, lockTime, lockupReason, hash);
Coin miningFee = tx.getFee();
int txSize = tx.bitcoinSerialize().length;
return new Tuple2<>(miningFee, txSize);
}
private Transaction getLockupTx(Coin lockupAmount, int lockTime, LockupReason lockupReason, byte[] hash)
throws InsufficientMoneyException, WalletException, TransactionVerificationException, IOException {
byte[] opReturnData = BondConsensus.getLockupOpReturnData(lockTime, lockupReason, hash);
Transaction preparedTx = bsqWalletService.getPreparedLockupTx(lockupAmount);
Transaction txWithBtcFee = btcWalletService.completePreparedBsqTx(preparedTx, true, opReturnData);
Transaction transaction = bsqWalletService.signTx(txWithBtcFee);

View file

@ -29,7 +29,9 @@ import bisq.core.dao.state.model.blockchain.TxOutput;
import bisq.core.dao.state.model.blockchain.TxType;
import bisq.common.handlers.ExceptionHandler;
import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
@ -70,10 +72,7 @@ public class UnlockTxService {
public void publishUnlockTx(String lockupTxId, Consumer<String> resultHandler, ExceptionHandler exceptionHandler) {
try {
Optional<TxOutput> optionalLockupTxOutput = daoStateService.getLockupTxOutput(lockupTxId);
checkArgument(optionalLockupTxOutput.isPresent(), "lockupTxOutput must be present");
TxOutput lockupTxOutput = optionalLockupTxOutput.get();
Transaction unlockTx = getUnlockTx(lockupTxOutput);
Transaction unlockTx = getUnlockTx(lockupTxId);
walletsManager.publishAndCommitBsqTx(unlockTx, TxType.UNLOCK, new TxBroadcaster.Callback() {
@Override
public void onSuccess(Transaction transaction) {
@ -90,8 +89,19 @@ public class UnlockTxService {
}
}
private Transaction getUnlockTx(TxOutput lockupTxOutput)
public Tuple2<Coin, Integer> getMiningFeeAndTxSize(String lockupTxId)
throws InsufficientMoneyException, WalletException, TransactionVerificationException {
Transaction tx = getUnlockTx(lockupTxId);
Coin miningFee = tx.getFee();
int txSize = tx.bitcoinSerialize().length;
return new Tuple2<>(miningFee, txSize);
}
private Transaction getUnlockTx(String lockupTxId)
throws InsufficientMoneyException, WalletException, TransactionVerificationException {
Optional<TxOutput> optionalLockupTxOutput = daoStateService.getLockupTxOutput(lockupTxId);
checkArgument(optionalLockupTxOutput.isPresent(), "lockupTxOutput must be present");
TxOutput lockupTxOutput = optionalLockupTxOutput.get();
Transaction preparedTx = bsqWalletService.getPreparedUnlockTx(lockupTxOutput);
Transaction txWithBtcFee = btcWalletService.completePreparedBsqTx(preparedTx, true, null);
Transaction transaction = bsqWalletService.signTx(txWithBtcFee);

View file

@ -1460,9 +1460,11 @@ dao.bond.reputation.salt=Salt
dao.bond.reputation.hash=Hash
dao.bond.reputation.lockupButton=Lockup
dao.bond.reputation.lockup.headline=Confirm lockup transaction
dao.bond.reputation.lockup.details=Lockup amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nAre you sure you want to proceed?
dao.bond.reputation.lockup.details=Lockup amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\n\
Mining fee: {3} ({4} Satoshis/byte)\nTransaction size: {5} Kb\n\nAre you sure you want to proceed?
dao.bond.reputation.unlock.headline=Confirm unlock transaction
dao.bond.reputation.unlock.details=Unlock amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\nAre you sure you want to proceed?
dao.bond.reputation.unlock.details=Unlock amount: {0}\nUnlock time: {1} block(s) (≈{2})\n\n\
Mining fee: {3} ({4} Satoshis/byte)\nTransaction size: {5} Kb\n\nAre you sure you want to proceed?
dao.bond.allBonds.header=All bonds

View file

@ -36,10 +36,12 @@ import bisq.core.dao.state.model.governance.RoleProposal;
import bisq.core.locale.Res;
import bisq.core.util.BSFormatter;
import bisq.core.util.BsqFormatter;
import bisq.core.util.CoinUtil;
import bisq.network.p2p.P2PService;
import bisq.common.app.DevEnv;
import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
@ -104,27 +106,39 @@ public class BondingViewUtils {
Consumer<String> resultHandler) {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
if (!DevEnv.isDevMode()) {
BSFormatter formatter = new BSFormatter();
String duration = formatter.formatDurationAsWords(lockupTime * 10 * 60 * 1000L, false, false);
new Popup<>().headLine(Res.get("dao.bond.reputation.lockup.headline"))
.confirmation(Res.get("dao.bond.reputation.lockup.details",
bsqFormatter.formatCoinWithCode(lockupAmount),
lockupTime,
duration
))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> publishLockupTx(hash, lockupAmount, lockupTime, lockupReason, resultHandler))
.closeButtonText(Res.get("shared.cancel"))
.show();
try {
Tuple2<Coin, Integer> miningFeeAndTxSize = daoFacade.getLockupTxMiningFeeAndTxSize(lockupAmount, lockupTime, lockupReason, hash);
Coin miningFee = miningFeeAndTxSize.first;
int txSize = miningFeeAndTxSize.second;
BSFormatter formatter = new BSFormatter();
String duration = formatter.formatDurationAsWords(lockupTime * 10 * 60 * 1000L, false, false);
new Popup<>().headLine(Res.get("dao.bond.reputation.lockup.headline"))
.confirmation(Res.get("dao.bond.reputation.lockup.details",
bsqFormatter.formatCoinWithCode(lockupAmount),
lockupTime,
duration,
formatter.formatCoinWithCode(miningFee),
CoinUtil.getFeePerByte(miningFee, txSize),
txSize
))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> publishLockupTx(lockupAmount, lockupTime, lockupReason, hash, resultHandler))
.closeButtonText(Res.get("shared.cancel"))
.show();
} catch (Throwable e) {
log.error(e.toString());
e.printStackTrace();
new Popup<>().warning(e.getMessage()).show();
}
} else {
publishLockupTx(hash, lockupAmount, lockupTime, lockupReason, resultHandler);
publishLockupTx(lockupAmount, lockupTime, lockupReason, hash, resultHandler);
}
} else {
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
}
}
private void publishLockupTx(byte[] hash, Coin lockupAmount, int lockupTime, LockupReason lockupReason, Consumer<String> resultHandler) {
private void publishLockupTx(Coin lockupAmount, int lockupTime, LockupReason lockupReason, byte[] hash, Consumer<String> resultHandler) {
daoFacade.publishLockupTx(lockupAmount,
lockupTime,
lockupReason,
@ -154,13 +168,19 @@ public class BondingViewUtils {
try {
if (!DevEnv.isDevMode()) {
Tuple2<Coin, Integer> miningFeeAndTxSize = daoFacade.getUnlockTxMiningFeeAndTxSize(lockupTxId);
Coin miningFee = miningFeeAndTxSize.first;
int txSize = miningFeeAndTxSize.second;
BSFormatter formatter = new BSFormatter();
String duration = formatter.formatDurationAsWords(lockTime * 10 * 60 * 1000L, false, false);
new Popup<>().headLine(Res.get("dao.bond.reputation.unlock.headline"))
.confirmation(Res.get("dao.bond.reputation.unlock.details",
bsqFormatter.formatCoinWithCode(unlockAmount),
lockTime,
duration
duration,
formatter.formatCoinWithCode(miningFee),
CoinUtil.getFeePerByte(miningFee, txSize),
txSize
))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> publishUnlockTx(lockupTxId, resultHandler))