mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-20 10:22:18 +01:00
Merge pull request #1851 from ManfredKarrer/merged-sq-bonded-reputation
Bonded reputation
This commit is contained in:
commit
c4862cdded
@ -943,7 +943,8 @@ message PersistableEnvelope {
|
||||
MeritList merit_list = 23;
|
||||
BondedRoleList bonded_role_list = 24;
|
||||
RemovedAssetList removed_asset_list = 25;
|
||||
DaoStateStore dao_state_store = 28;
|
||||
DaoStateStore dao_state_store = 26;
|
||||
BondedReputationList bonded_reputation_list = 27;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1554,6 +1555,16 @@ message BondedRoleList {
|
||||
repeated BondedRole bonded_role = 1;
|
||||
}
|
||||
|
||||
message BondedReputation {
|
||||
string salt = 1;
|
||||
string lockup_tx_id = 2;
|
||||
string unlock_tx_id = 3;
|
||||
}
|
||||
|
||||
message BondedReputationList {
|
||||
repeated BondedReputation bonded_reputation = 1;
|
||||
}
|
||||
|
||||
message TempProposalPayload {
|
||||
Proposal proposal = 1;
|
||||
bytes owner_pub_key_encoded = 2;
|
||||
|
@ -17,11 +17,14 @@
|
||||
|
||||
package bisq.core.app.misc;
|
||||
|
||||
import bisq.core.dao.DaoOptionKeys;
|
||||
import bisq.core.dao.DaoSetup;
|
||||
import bisq.core.dao.bonding.bond.BondedReputationService;
|
||||
import bisq.core.dao.governance.asset.AssetService;
|
||||
import bisq.core.dao.governance.ballot.BallotListService;
|
||||
import bisq.core.dao.governance.blindvote.MyBlindVoteListService;
|
||||
import bisq.core.dao.governance.myvote.MyVoteListService;
|
||||
import bisq.core.dao.governance.proposal.MyProposalListService;
|
||||
import bisq.core.dao.governance.role.BondedRolesService;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.payment.AccountAgeWitnessService;
|
||||
@ -33,6 +36,7 @@ import bisq.network.p2p.P2PService;
|
||||
import bisq.common.crypto.KeyRing;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -51,8 +55,11 @@ public class AppSetupWithP2PAndDAO extends AppSetupWithP2P {
|
||||
MyVoteListService myVoteListService,
|
||||
BallotListService ballotListService,
|
||||
MyBlindVoteListService myBlindVoteListService,
|
||||
MyProposalListService myProposalListService,
|
||||
BondedRolesService bondedRolesService,
|
||||
AssetService assetService) {
|
||||
BondedReputationService bondedReputationService,
|
||||
AssetService assetService,
|
||||
@Named(DaoOptionKeys.DAO_ACTIVATED) boolean daoActivated) {
|
||||
super(encryptionService,
|
||||
keyRing,
|
||||
p2PService,
|
||||
@ -62,11 +69,16 @@ public class AppSetupWithP2PAndDAO extends AppSetupWithP2P {
|
||||
|
||||
this.daoSetup = daoSetup;
|
||||
|
||||
persistedDataHosts.add(myVoteListService);
|
||||
persistedDataHosts.add(ballotListService);
|
||||
persistedDataHosts.add(myBlindVoteListService);
|
||||
persistedDataHosts.add(bondedRolesService);
|
||||
persistedDataHosts.add(assetService);
|
||||
// TODO Should be refactored/removed. In the meantime keep in sync with CorePersistedDataHost
|
||||
if (daoActivated) {
|
||||
persistedDataHosts.add(myVoteListService);
|
||||
persistedDataHosts.add(ballotListService);
|
||||
persistedDataHosts.add(myBlindVoteListService);
|
||||
persistedDataHosts.add(myProposalListService);
|
||||
persistedDataHosts.add(bondedRolesService);
|
||||
persistedDataHosts.add(bondedReputationService);
|
||||
persistedDataHosts.add(assetService);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,9 @@ package bisq.core.dao;
|
||||
|
||||
import bisq.core.btc.exceptions.TransactionVerificationException;
|
||||
import bisq.core.btc.exceptions.WalletException;
|
||||
import bisq.core.dao.bonding.bond.BondWithHash;
|
||||
import bisq.core.dao.bonding.bond.BondedReputation;
|
||||
import bisq.core.dao.bonding.bond.BondedReputationService;
|
||||
import bisq.core.dao.bonding.lockup.LockupService;
|
||||
import bisq.core.dao.bonding.lockup.LockupType;
|
||||
import bisq.core.dao.bonding.unlock.UnlockService;
|
||||
@ -111,6 +114,7 @@ public class DaoFacade implements DaoSetupService {
|
||||
private final GenericProposalService genericProposalService;
|
||||
private final RemoveAssetProposalService removeAssetProposalService;
|
||||
private final BondedRolesService bondedRolesService;
|
||||
private final BondedReputationService bondedReputationService;
|
||||
private final LockupService lockupService;
|
||||
private final UnlockService unlockService;
|
||||
private final DaoStateStorageService daoStateStorageService;
|
||||
@ -134,6 +138,7 @@ public class DaoFacade implements DaoSetupService {
|
||||
GenericProposalService genericProposalService,
|
||||
RemoveAssetProposalService removeAssetProposalService,
|
||||
BondedRolesService bondedRolesService,
|
||||
BondedReputationService bondedReputationService,
|
||||
LockupService lockupService,
|
||||
UnlockService unlockService,
|
||||
DaoStateStorageService daoStateStorageService) {
|
||||
@ -153,6 +158,7 @@ public class DaoFacade implements DaoSetupService {
|
||||
this.genericProposalService = genericProposalService;
|
||||
this.removeAssetProposalService = removeAssetProposalService;
|
||||
this.bondedRolesService = bondedRolesService;
|
||||
this.bondedReputationService = bondedReputationService;
|
||||
this.lockupService = lockupService;
|
||||
this.unlockService = unlockService;
|
||||
this.daoStateStorageService = daoStateStorageService;
|
||||
@ -277,6 +283,10 @@ public class DaoFacade implements DaoSetupService {
|
||||
return bondedRolesService.getBondedRoleList();
|
||||
}
|
||||
|
||||
public List<BondedReputation> getBondedReputationList() {
|
||||
return bondedReputationService.getBondedReputationList();
|
||||
}
|
||||
|
||||
// Show fee
|
||||
public Coin getProposalFee(int chainHeight) {
|
||||
return ProposalConsensus.getFee(daoStateService, chainHeight);
|
||||
@ -474,9 +484,9 @@ public class DaoFacade implements DaoSetupService {
|
||||
// Use case: Bonding
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondedRole bondedRole,
|
||||
public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondWithHash bondWithHash,
|
||||
ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
lockupService.publishLockupTx(lockupAmount, lockTime, lockupType, bondedRole, resultHandler, exceptionHandler);
|
||||
lockupService.publishLockupTx(lockupAmount, lockTime, lockupType, bondWithHash, resultHandler, exceptionHandler);
|
||||
}
|
||||
|
||||
public void publishUnlockTx(String lockupTxId, ResultHandler resultHandler,
|
||||
@ -504,6 +514,10 @@ public class DaoFacade implements DaoSetupService {
|
||||
return bondedRolesService.getValidBondedRoleList();
|
||||
}
|
||||
|
||||
/*public List<BondedReputation> getValidBondedReputationList() {
|
||||
return bondedReputationService.getValidBondedReputationList();
|
||||
}*/
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Use case: Present transaction related state
|
||||
@ -549,6 +563,10 @@ public class DaoFacade implements DaoSetupService {
|
||||
return daoStateService.getLockupTxOutput(txId);
|
||||
}
|
||||
|
||||
public Optional<TxOutput> getLockupOpReturnTxOutput(String txId) {
|
||||
return daoStateService.getLockupOpReturnTxOutput(txId);
|
||||
}
|
||||
|
||||
public long getTotalBurntFee() {
|
||||
return daoStateService.getTotalBurntFee();
|
||||
}
|
||||
@ -605,8 +623,12 @@ public class DaoFacade implements DaoSetupService {
|
||||
return bondedRolesService.getBondedRoleFromHash(hash);
|
||||
}
|
||||
|
||||
public boolean isUnlocking(BondedRole bondedRole) {
|
||||
return daoStateService.isUnlocking(bondedRole);
|
||||
public Optional<BondedReputation> getBondedReputationFromHash(byte[] hash) {
|
||||
return bondedReputationService.getBondedReputationFromHash(hash);
|
||||
}
|
||||
|
||||
public boolean isUnlocking(BondWithHash bondWithHash) {
|
||||
return daoStateService.isUnlocking(bondWithHash);
|
||||
}
|
||||
|
||||
public Coin getMinCompensationRequestAmount() {
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package bisq.core.dao;
|
||||
|
||||
import bisq.core.dao.bonding.bond.BondedReputationService;
|
||||
import bisq.core.dao.bonding.lockup.LockupService;
|
||||
import bisq.core.dao.bonding.unlock.UnlockService;
|
||||
import bisq.core.dao.governance.asset.AssetService;
|
||||
@ -186,6 +187,7 @@ public class DaoModule extends AppModule {
|
||||
bind(LockupService.class).in(Singleton.class);
|
||||
bind(UnlockService.class).in(Singleton.class);
|
||||
bind(BondedRolesService.class).in(Singleton.class);
|
||||
bind(BondedReputationService.class).in(Singleton.class);
|
||||
|
||||
// Asset
|
||||
bind(AssetService.class).in(Singleton.class);
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
package bisq.core.dao.bonding;
|
||||
|
||||
import bisq.core.dao.bonding.bond.BondWithHash;
|
||||
import bisq.core.dao.bonding.lockup.LockupType;
|
||||
import bisq.core.dao.governance.role.BondedRole;
|
||||
import bisq.core.dao.state.blockchain.OpReturnType;
|
||||
|
||||
import bisq.common.app.Version;
|
||||
@ -89,11 +89,7 @@ public class BondingConsensus {
|
||||
return Arrays.copyOfRange(opReturnData, 5, 25);
|
||||
}
|
||||
|
||||
public static byte[] getHash(LockupType lockupType, BondedRole bondedRole) {
|
||||
if (lockupType == LockupType.BONDED_ROLE) {
|
||||
return bondedRole.getHash();
|
||||
} else {
|
||||
throw new RuntimeException("Trade bonds not implemented yet");
|
||||
}
|
||||
public static byte[] getHash(BondWithHash bondWithHash) {
|
||||
return bondWithHash.getHash();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.dao.bonding.bond;
|
||||
|
||||
public interface BondWithHash {
|
||||
|
||||
String getUnlockTxId();
|
||||
byte[] getHash();
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.dao.bonding.bond;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
import bisq.common.crypto.Hash;
|
||||
import bisq.common.proto.network.NetworkPayload;
|
||||
import bisq.common.proto.persistable.PersistablePayload;
|
||||
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Getter
|
||||
public final class BondedReputation implements PersistablePayload, NetworkPayload, BondWithHash {
|
||||
private final String salt;
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
private String lockupTxId;
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
private String unlockTxId;
|
||||
|
||||
public BondedReputation(@Nullable String salt) {
|
||||
this(salt,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static BondedReputation createBondedReputation() {
|
||||
return new BondedReputation(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public BondedReputation(String salt,
|
||||
@Nullable String lockupTxId,
|
||||
@Nullable String unlockTxId) {
|
||||
this.salt = salt;
|
||||
this.lockupTxId = lockupTxId;
|
||||
this.unlockTxId = unlockTxId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PB.BondedReputation toProtoMessage() {
|
||||
PB.BondedReputation.Builder builder = PB.BondedReputation.newBuilder()
|
||||
.setSalt(salt);
|
||||
Optional.ofNullable(lockupTxId).ifPresent(builder::setLockupTxId);
|
||||
Optional.ofNullable(unlockTxId).ifPresent(builder::setUnlockTxId);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static BondedReputation fromProto(PB.BondedReputation proto) {
|
||||
return new BondedReputation(proto.getSalt(),
|
||||
proto.getLockupTxId().isEmpty() ? null : proto.getLockupTxId(),
|
||||
proto.getUnlockTxId().isEmpty() ? null : proto.getUnlockTxId());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public String getUnlockTxId() {
|
||||
return unlockTxId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getHash() {
|
||||
// We use the salt as input for the hash
|
||||
byte[] bytes = salt.getBytes(Charsets.UTF_8);
|
||||
byte[] hash = Hash.getSha256Ripemd160hash(bytes);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public String getDisplayString() {
|
||||
return Res.get("dao.bond.bondedReputation");
|
||||
}
|
||||
|
||||
public boolean isLockedUp() {
|
||||
return lockupTxId != null;
|
||||
}
|
||||
|
||||
public boolean isUnlocked() {
|
||||
return unlockTxId != null;
|
||||
}
|
||||
|
||||
public boolean isUnlocking(DaoFacade daoFacade) {
|
||||
return daoFacade.isUnlocking(this);
|
||||
}
|
||||
|
||||
public boolean isUnlocking(DaoStateService daoStateService) {
|
||||
return daoStateService.isUnlocking(this);
|
||||
}
|
||||
|
||||
// We use only the immutable data
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BondedReputation that = (BondedReputation) o;
|
||||
return Objects.equals(salt, that.salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(salt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BondedReputation{" +
|
||||
"\n salt='" + salt + '\'' +
|
||||
",\n lockupTxId='" + lockupTxId + '\'' +
|
||||
",\n unlockTxId='" + unlockTxId + '\'' +
|
||||
"\n}";
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.dao.bonding.bond;
|
||||
|
||||
import bisq.common.proto.persistable.PersistableList;
|
||||
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* PersistableEnvelope wrapper for list of BondedReputations.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BondedReputationList extends PersistableList<BondedReputation> {
|
||||
|
||||
public BondedReputationList(List<BondedReputation> list) {
|
||||
super(list);
|
||||
}
|
||||
|
||||
public BondedReputationList() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public PB.PersistableEnvelope toProtoMessage() {
|
||||
return PB.PersistableEnvelope.newBuilder().setBondedReputationList(getBuilder()).build();
|
||||
}
|
||||
|
||||
public PB.BondedReputationList.Builder getBuilder() {
|
||||
return PB.BondedReputationList.newBuilder()
|
||||
.addAllBondedReputation(getList().stream()
|
||||
.map(BondedReputation::toProtoMessage)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static BondedReputationList fromProto(PB.BondedReputationList proto) {
|
||||
return new BondedReputationList(new ArrayList<>(proto.getBondedReputationList().stream()
|
||||
.map(BondedReputation::fromProto)
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "List of salts in BondedReputationList: " + getList().stream()
|
||||
.map(BondedReputation::getSalt)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.core.dao.bonding.bond;
|
||||
|
||||
import bisq.core.app.BisqEnvironment;
|
||||
import bisq.core.dao.bonding.BondingConsensus;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.dao.state.blockchain.Block;
|
||||
import bisq.core.dao.state.blockchain.SpentInfo;
|
||||
import bisq.core.dao.state.blockchain.TxType;
|
||||
|
||||
import bisq.common.proto.persistable.PersistedDataHost;
|
||||
import bisq.common.storage.Storage;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class BondedReputationService implements PersistedDataHost, DaoStateListener {
|
||||
|
||||
public interface BondedReputationListChangeListener {
|
||||
void onListChanged(List<BondedReputation> list);
|
||||
}
|
||||
|
||||
private final DaoStateService daoStateService;
|
||||
private final Storage<BondedReputationList> storage;
|
||||
private final BondedReputationList bondedReputationList = new BondedReputationList();
|
||||
|
||||
@Getter
|
||||
private final List<BondedReputationListChangeListener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public BondedReputationService(Storage<BondedReputationList> storage, DaoStateService daoStateService) {
|
||||
this.storage = storage;
|
||||
this.daoStateService = daoStateService;
|
||||
|
||||
daoStateService.addBsqStateListener(this);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PersistedDataHost
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void readPersisted() {
|
||||
if (BisqEnvironment.isDAOActivatedAndBaseCurrencySupportingBsq()) {
|
||||
BondedReputationList persisted = storage.initAndGetPersisted(bondedReputationList, 100);
|
||||
if (persisted != null) {
|
||||
bondedReputationList.clear();
|
||||
bondedReputationList.addAll(persisted.getList());
|
||||
listeners.forEach(l -> l.onListChanged(bondedReputationList.getList()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DaoStateListener
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onNewBlockHeight(int blockHeight) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParseTxsComplete(Block block) {
|
||||
bondedReputationList.getList().forEach(bondedReputation -> {
|
||||
daoStateService.getLockupTxOutputs().forEach(lockupTxOutput -> {
|
||||
String lockupTxId = lockupTxOutput.getTxId();
|
||||
daoStateService.getTx(lockupTxId)
|
||||
.ifPresent(lockupTx -> {
|
||||
byte[] opReturnData = lockupTx.getLastTxOutput().getOpReturnData();
|
||||
byte[] hash = BondingConsensus.getHashFromOpReturnData(opReturnData);
|
||||
Optional<BondedReputation> candidate = getBondedReputationFromHash(hash);
|
||||
if (candidate.isPresent() && bondedReputation.equals(candidate.get())) {
|
||||
if (bondedReputation.getLockupTxId() == null) {
|
||||
bondedReputation.setLockupTxId(lockupTxId);
|
||||
persist();
|
||||
}
|
||||
|
||||
if (!daoStateService.isUnspent(lockupTxOutput.getKey())) {
|
||||
daoStateService.getSpentInfo(lockupTxOutput)
|
||||
.map(SpentInfo::getTxId)
|
||||
.map(daoStateService::getTx)
|
||||
.map(Optional::get)
|
||||
// TODO(sq): What if the tx is burnt and not unlocked, need to check on that
|
||||
.filter(unlockTx -> unlockTx.getTxType() == TxType.UNLOCK)
|
||||
.ifPresent(unlockTx -> {
|
||||
if (bondedReputation.getUnlockTxId() == null) {
|
||||
bondedReputation.setUnlockTxId(unlockTx.getId());
|
||||
persist();
|
||||
}
|
||||
|
||||
// TODO check lock time
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParseBlockChainComplete() {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void start() {
|
||||
}
|
||||
|
||||
public void addListener(BondedReputationListChangeListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
// public void addAcceptedBondedReputation(BondedReputation bondedReputation) {
|
||||
// if (bondedReputationList.getList().stream().noneMatch(role -> role.equals(bondedReputation))) {
|
||||
// bondedReputationList.add(bondedReputation);
|
||||
// persist();
|
||||
// listeners.forEach(l -> l.onListChanged(bondedReputationList.getList()));
|
||||
// }
|
||||
// }
|
||||
|
||||
public List<BondedReputation> getBondedReputationList() {
|
||||
return bondedReputationList.getList();
|
||||
}
|
||||
|
||||
/* public List<BondedReputation> getValidBondedReputationList() {
|
||||
//TODO validation ???
|
||||
return bondedReputationList.getList();
|
||||
}*/
|
||||
|
||||
public Optional<BondedReputation> getBondedReputationFromHash(byte[] hash) {
|
||||
return bondedReputationList.getList().stream()
|
||||
.filter(bondedReputation -> {
|
||||
byte[] candidateHash = bondedReputation.getHash();
|
||||
/* log.error("getBondedReputationFromHash: equals?={}, hash={}, candidateHash={}\bondedReputation={}",
|
||||
Arrays.equals(candidateHash, hash),
|
||||
Utilities.bytesAsHexString(hash),
|
||||
Utilities.bytesAsHexString(candidateHash),
|
||||
bondedReputation.toString());*/
|
||||
return Arrays.equals(candidateHash, hash);
|
||||
})
|
||||
.findAny();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void persist() {
|
||||
storage.queueUpForSave(20);
|
||||
}
|
||||
|
||||
|
||||
/*public static Optional<BondedReputation> getBondedReputationByLockupTxId(String lockupTxId) {
|
||||
return BondedReputations.stream()
|
||||
.filter(BondedReputation -> BondedReputation.getLockupTxId().equals(lockupTxId)).
|
||||
findAny();
|
||||
}*/
|
||||
|
||||
/* public static Optional<BondedReputation> getBondedReputationByHashOfBondId(byte[] hash) {
|
||||
return Optional.empty();
|
||||
*//* BondedReputations.stream()
|
||||
.filter(BondedReputation -> Arrays.equals(BondedReputation.getHash(), hash))
|
||||
.findAny();*//*
|
||||
}*/
|
||||
}
|
@ -26,6 +26,7 @@ import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.TxBroadcaster;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.dao.bonding.BondingConsensus;
|
||||
import bisq.core.dao.bonding.bond.BondWithHash;
|
||||
import bisq.core.dao.governance.role.BondedRole;
|
||||
import bisq.core.dao.governance.role.BondedRolesService;
|
||||
|
||||
@ -65,13 +66,13 @@ public class LockupService {
|
||||
this.btcWalletService = btcWalletService;
|
||||
}
|
||||
|
||||
public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondedRole bondedRole,
|
||||
public void publishLockupTx(Coin lockupAmount, int lockTime, LockupType lockupType, BondWithHash bondWithHash,
|
||||
ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
checkArgument(lockTime <= BondingConsensus.getMaxLockTime() &&
|
||||
lockTime >= BondingConsensus.getMinLockTime(), "lockTime not in rage");
|
||||
try {
|
||||
|
||||
byte[] hash = BondingConsensus.getHash(lockupType, bondedRole);
|
||||
byte[] hash = BondingConsensus.getHash(bondWithHash);
|
||||
byte[] opReturnData = BondingConsensus.getLockupOpReturnData(lockTime, lockupType, hash);
|
||||
final Transaction lockupTx = getLockupTx(lockupAmount, opReturnData);
|
||||
|
||||
@ -79,6 +80,14 @@ public class LockupService {
|
||||
walletsManager.publishAndCommitBsqTx(lockupTx, new TxBroadcaster.Callback() {
|
||||
@Override
|
||||
public void onSuccess(Transaction transaction) {
|
||||
|
||||
// TODO we should not support repeated locks
|
||||
if (bondWithHash instanceof BondedRole) {
|
||||
BondedRole bondedRole = (BondedRole) bondWithHash;
|
||||
bondedRole.setLockupTxId(transaction.getHashAsString());
|
||||
bondedRole.setUnlockTxId(null);
|
||||
}
|
||||
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
package bisq.core.dao.governance.role;
|
||||
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.bonding.bond.BondWithHash;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.locale.Res;
|
||||
|
||||
@ -42,7 +43,7 @@ import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
public final class BondedRole implements PersistablePayload, NetworkPayload {
|
||||
public final class BondedRole implements PersistablePayload, NetworkPayload, BondWithHash {
|
||||
private final String uid;
|
||||
private final String name;
|
||||
private final String link;
|
||||
@ -133,9 +134,15 @@ public final class BondedRole implements PersistablePayload, NetworkPayload {
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
// BondWithHash implementation
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public String getUnlockTxId() {
|
||||
return unlockTxId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getHash() {
|
||||
// We use only the immutable data as input for hash
|
||||
byte[] bytes = BigInteger.valueOf(hashCode()).toByteArray();
|
||||
@ -145,6 +152,11 @@ public final class BondedRole implements PersistablePayload, NetworkPayload {
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getDisplayString() {
|
||||
return name + " / " + Res.get("dao.bond.bondedRoleType." + bondedRoleType.name());
|
||||
}
|
||||
|
@ -68,8 +68,8 @@ public class BondedRoleList extends PersistableList<BondedRole> implements Conse
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "List of UID's in BondedRoleList: " + getList().stream()
|
||||
.map(BondedRole::getUid)
|
||||
return "List of lockupTxIds in BondedRoleList: " + getList().stream()
|
||||
.map(BondedRole::getLockupTxId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ import lombok.Getter;
|
||||
|
||||
// Data here must not be changed as it would break backward compatibility! In case we need to change we need to add a new
|
||||
// entry and maintain the old one. Once all the role holders of an old deprecated role have revoked the role might get removed.
|
||||
|
||||
// Add entry to translation file "dao.bond.bondedRoleType...."
|
||||
public enum BondedRoleType {
|
||||
// admins
|
||||
GITHUB_ADMIN(50_000, 60, "https://github.com/bisq-network/roles/issues/16", true),
|
||||
@ -70,7 +72,8 @@ public enum BondedRoleType {
|
||||
*/
|
||||
BondedRoleType(long requiredBondInBsq, int unlockTimeInDays, String link, boolean allowMultipleHolders) {
|
||||
this.requiredBond = requiredBondInBsq * 100;
|
||||
this.unlockTimeInBlocks = unlockTimeInDays * 144;
|
||||
this.unlockTimeInBlocks = 5; // TODO for dev testing
|
||||
//this.unlockTimeInBlocks = unlockTimeInDays * 144;
|
||||
this.link = link;
|
||||
this.allowMultipleHolders = allowMultipleHolders;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import bisq.core.app.BisqEnvironment;
|
||||
import bisq.core.dao.bonding.BondingConsensus;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.DaoStateService;
|
||||
import bisq.core.dao.state.blockchain.BaseTxOutput;
|
||||
import bisq.core.dao.state.blockchain.Block;
|
||||
import bisq.core.dao.state.blockchain.SpentInfo;
|
||||
import bisq.core.dao.state.blockchain.TxType;
|
||||
@ -179,25 +180,46 @@ public class BondedRolesService implements PersistedDataHost, DaoStateListener {
|
||||
.findAny();
|
||||
}
|
||||
|
||||
public Optional<BondedRole> getBondedRoleFromLockupTxId(String lockupTxId) {
|
||||
return bondedRoleList.getList().stream()
|
||||
.filter(bondedRole -> lockupTxId.equals(bondedRole.getLockupTxId()))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
|
||||
public Optional<BondedRoleType> getBondedRoleType(String lockUpTxId) {
|
||||
Optional<BondedRoleType> bondedRoleType = getBondedRoleFromLockupTxId(lockUpTxId).map(BondedRole::getBondedRoleType);
|
||||
return bondedRoleType;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private Optional<byte[]> getOpReturnData(String lockUpTxId) {
|
||||
return daoStateService.getLockupOpReturnTxOutput(lockUpTxId).map(BaseTxOutput::getOpReturnData);
|
||||
}
|
||||
|
||||
private void persist() {
|
||||
storage.queueUpForSave(20);
|
||||
}
|
||||
|
||||
/* private Optional<LockupType> getOptionalLockupType(String lockUpTxId) {
|
||||
return getOpReturnData(lockUpTxId)
|
||||
.flatMap(BondingConsensus::getLockupType);
|
||||
}*/
|
||||
|
||||
/*public static Optional<BondedRole> getBondedRoleByLockupTxId(String lockupTxId) {
|
||||
return bondedRoles.stream()
|
||||
.filter(bondedRole -> bondedRole.getLockupTxId().equals(lockupTxId)).
|
||||
findAny();
|
||||
}*/
|
||||
|
||||
/*
|
||||
public static Optional<BondedRole> getBondedRoleByHashOfBondId(byte[] hash) {
|
||||
return Optional.empty();
|
||||
/* bondedRoles.stream()
|
||||
*//* bondedRoles.stream()
|
||||
.filter(bondedRole -> Arrays.equals(bondedRole.getHash(), hash))
|
||||
.findAny();*/
|
||||
}
|
||||
.findAny();*//*
|
||||
}*/
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package bisq.core.dao.state;
|
||||
|
||||
import bisq.core.dao.DaoSetupService;
|
||||
import bisq.core.dao.bonding.BondingConsensus;
|
||||
import bisq.core.dao.governance.role.BondedRole;
|
||||
import bisq.core.dao.bonding.bond.BondWithHash;
|
||||
import bisq.core.dao.governance.voteresult.DecryptedBallotsWithMerits;
|
||||
import bisq.core.dao.governance.voteresult.EvaluatedProposal;
|
||||
import bisq.core.dao.state.blockchain.Block;
|
||||
@ -646,6 +646,10 @@ public class DaoStateService implements DaoSetupService {
|
||||
.findFirst());
|
||||
}
|
||||
|
||||
public Optional<TxOutput> getLockupOpReturnTxOutput(String txId) {
|
||||
return getTx(txId).map(Tx::getLastTxOutput);
|
||||
}
|
||||
|
||||
// Returns amount of all LOCKUP txOutputs (they might have been unlocking or unlocked in the meantime)
|
||||
public long getTotalAmountOfLockupTxOutputs() {
|
||||
return getLockupTxOutputs().stream()
|
||||
@ -752,8 +756,8 @@ public class DaoStateService implements DaoSetupService {
|
||||
// txOutput.setTxOutputType(TxOutputType.BTC_OUTPUT);
|
||||
}
|
||||
|
||||
public boolean isUnlocking(BondedRole bondedRole) {
|
||||
Optional<Tx> optionalTx = getTx(bondedRole.getUnlockTxId());
|
||||
public boolean isUnlocking(BondWithHash bondWithHash) {
|
||||
Optional<Tx> optionalTx = getTx(bondWithHash.getUnlockTxId());
|
||||
return optionalTx.isPresent() && isUnlockingOutput(optionalTx.get().getTxOutputs().get(0));
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ public enum Param {
|
||||
// TODO for dev testing we use short periods...
|
||||
// Period phase ("11 blocks atm)
|
||||
PHASE_UNDEFINED("0", ParamType.BLOCK),
|
||||
PHASE_PROPOSAL("2", ParamType.BLOCK, 3, 3),
|
||||
PHASE_PROPOSAL("4", ParamType.BLOCK, 3, 3),
|
||||
PHASE_BREAK1("1", ParamType.BLOCK, 3, 3),
|
||||
PHASE_BLIND_VOTE("2", ParamType.BLOCK, 3, 3),
|
||||
PHASE_BREAK2("1", ParamType.BLOCK, 3, 23),
|
||||
|
@ -20,6 +20,7 @@ package bisq.core.setup;
|
||||
import bisq.core.arbitration.DisputeManager;
|
||||
import bisq.core.btc.model.AddressEntryList;
|
||||
import bisq.core.dao.DaoOptionKeys;
|
||||
import bisq.core.dao.bonding.bond.BondedReputationService;
|
||||
import bisq.core.dao.governance.asset.AssetService;
|
||||
import bisq.core.dao.governance.ballot.BallotListService;
|
||||
import bisq.core.dao.governance.blindvote.MyBlindVoteListService;
|
||||
@ -68,6 +69,7 @@ public class CorePersistedDataHost {
|
||||
persistedDataHosts.add(injector.getInstance(MyVoteListService.class));
|
||||
persistedDataHosts.add(injector.getInstance(MyProposalListService.class));
|
||||
persistedDataHosts.add(injector.getInstance(BondedRolesService.class));
|
||||
persistedDataHosts.add(injector.getInstance(BondedReputationService.class));
|
||||
persistedDataHosts.add(injector.getInstance(AssetService.class));
|
||||
}
|
||||
return persistedDataHosts;
|
||||
|
@ -1323,6 +1323,8 @@ dao.bonding.lock.sendFunds.headline=Confirm lockup transaction
|
||||
dao.bonding.lock.sendFunds.details=Lockup amount: {0}\nLockup time: {1} block(s)\n\nAre you sure you want to proceed?
|
||||
dao.bonding.unlock.time=Lock time
|
||||
dao.bonding.unlock.unlock=Unlock
|
||||
dao.bonding.unlock.type=Type
|
||||
dao.bonding.unlock.reputation=Reputation
|
||||
dao.bonding.unlock.sendTx.headline=Confirm unlock transaction
|
||||
dao.bonding.unlock.sendTx.details=Unlock amount: {0}\nLockup time: {1} block(s)\n\nAre you sure you want to proceed?
|
||||
dao.bonding.dashboard.bondsHeadline=Bonded BSQ
|
||||
@ -1333,12 +1335,41 @@ dao.bonding.dashboard.unlockingAmount=Unlocking funds (wait until lock time is o
|
||||
dao.bond.lockupType.BONDED_ROLE=Bonded role
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.lockupType.REPUTATION=Bonded reputation
|
||||
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.ARBITRATOR=Arbitrator
|
||||
dao.bond.bondedRoleType.GITHUB_ADMIN=Github admin
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.FORUM_ADMIN=Forum admin
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.TWITTER_ADMIN=Twitter admin
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.SLACK_ADMIN=Slack admin
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.YOUTUBE_ADMIN=Youtube admin
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.BISQ_MAINTAINER=Bisq maintainer
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.WEBSITE_OPERATOR=Website operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.FORUM_OPERATOR=Forum operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.SEED_NODE_OPERATOR=Seed node operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.PRICE_NODE_OPERATOR=Price node operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.BTC_NODE_OPERATOR=Btc node operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.MARKETS_OPERATOR=Markets operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.BSQ_EXPLORER_OPERATOR=BSQ explorer operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.DOMAIN_NAME_HOLDER=Domain name holder
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.SEED_NODE_OPERATOR=Seed node operator
|
||||
dao.bond.bondedRoleType.DNS_ADMIN=DNS admin
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.MEDIATOR=Mediator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.ARBITRATOR=Arbitrator
|
||||
|
||||
dao.bond.bondedRoleType.details.header=Role details
|
||||
dao.bond.bondedRoleType.details.role=Role
|
||||
@ -1348,6 +1379,8 @@ dao.bond.bondedRoleType.details.link=Link to role description
|
||||
dao.bond.bondedRoleType.details.isSingleton=Can be taken by multiple role holders
|
||||
dao.bond.bondedRoleType.details.blocks={0} blocks
|
||||
|
||||
dao.bond.bondedReputation=Bonded Reputation
|
||||
|
||||
dao.bond.table.header=Bonded roles
|
||||
dao.bond.table.column.header.name=Name
|
||||
dao.bond.table.column.header.linkToAccount=Account
|
||||
|
@ -26,6 +26,8 @@ import bisq.desktop.util.GUIUtil;
|
||||
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.bonding.bond.BondWithHash;
|
||||
import bisq.core.dao.bonding.bond.BondedReputation;
|
||||
import bisq.core.dao.bonding.lockup.LockupType;
|
||||
import bisq.core.dao.governance.role.BondedRole;
|
||||
import bisq.core.dao.governance.role.BondedRoleType;
|
||||
@ -35,6 +37,7 @@ import bisq.core.util.BsqFormatter;
|
||||
|
||||
import bisq.network.p2p.P2PService;
|
||||
|
||||
import bisq.common.app.DevEnv;
|
||||
import bisq.common.handlers.ResultHandler;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
@ -65,39 +68,55 @@ public class BondingViewUtils {
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
}
|
||||
|
||||
public void lockupBondForBondedRole(BondedRole bondedRole, ResultHandler resultHandler) {
|
||||
private void lockupBond(BondWithHash bondWithHash, Coin lockupAmount, int lockupTime, LockupType lockupType,
|
||||
ResultHandler resultHandler) {
|
||||
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
||||
BondedRoleType bondedRoleType = bondedRole.getBondedRoleType();
|
||||
Coin lockupAmount = Coin.valueOf(bondedRoleType.getRequiredBond());
|
||||
int lockupTime = bondedRoleType.getUnlockTimeInBlocks();
|
||||
LockupType lockupType = LockupType.BONDED_ROLE;
|
||||
new Popup<>().headLine(Res.get("dao.bonding.lock.sendFunds.headline"))
|
||||
.confirmation(Res.get("dao.bonding.lock.sendFunds.details",
|
||||
bsqFormatter.formatCoinWithCode(lockupAmount),
|
||||
lockupTime
|
||||
))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> {
|
||||
daoFacade.publishLockupTx(lockupAmount,
|
||||
lockupTime,
|
||||
lockupType,
|
||||
bondedRole,
|
||||
() -> {
|
||||
new Popup<>().feedback(Res.get("dao.tx.published.success")).show();
|
||||
},
|
||||
this::handleError
|
||||
);
|
||||
if (resultHandler != null)
|
||||
resultHandler.handleResult();
|
||||
})
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.show();
|
||||
if (!DevEnv.isDevMode()) {
|
||||
new Popup<>().headLine(Res.get("dao.bonding.lock.sendFunds.headline"))
|
||||
.confirmation(Res.get("dao.bonding.lock.sendFunds.details",
|
||||
bsqFormatter.formatCoinWithCode(lockupAmount),
|
||||
lockupTime
|
||||
))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> publishLockupTx(bondWithHash, lockupAmount, lockupTime, lockupType, resultHandler))
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.show();
|
||||
} else {
|
||||
publishLockupTx(bondWithHash, lockupAmount, lockupTime, lockupType, resultHandler);
|
||||
}
|
||||
} else {
|
||||
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
|
||||
}
|
||||
}
|
||||
|
||||
public void unLock(String lockupTxId) {
|
||||
private void publishLockupTx(BondWithHash bondWithHash, Coin lockupAmount, int lockupTime, LockupType lockupType, ResultHandler resultHandler) {
|
||||
daoFacade.publishLockupTx(lockupAmount,
|
||||
lockupTime,
|
||||
lockupType,
|
||||
bondWithHash,
|
||||
() -> {
|
||||
if (!DevEnv.isDevMode())
|
||||
new Popup<>().feedback(Res.get("dao.tx.published.success")).show();
|
||||
},
|
||||
this::handleError
|
||||
);
|
||||
if (resultHandler != null)
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
||||
public void lockupBondForBondedRole(BondedRole bondedRole, ResultHandler resultHandler) {
|
||||
BondedRoleType bondedRoleType = bondedRole.getBondedRoleType();
|
||||
Coin lockupAmount = Coin.valueOf(bondedRoleType.getRequiredBond());
|
||||
int lockupTime = bondedRoleType.getUnlockTimeInBlocks();
|
||||
lockupBond(bondedRole, lockupAmount, lockupTime, LockupType.BONDED_ROLE, resultHandler);
|
||||
}
|
||||
|
||||
public void lockupBondForReputation(Coin lockupAmount, int lockupTime, ResultHandler resultHandler) {
|
||||
BondedReputation bondedReputation = BondedReputation.createBondedReputation();
|
||||
lockupBond(bondedReputation, lockupAmount, lockupTime, LockupType.REPUTATION, resultHandler);
|
||||
}
|
||||
|
||||
public void unLock(String lockupTxId, ResultHandler resultHandler) {
|
||||
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
|
||||
Optional<TxOutput> lockupTxOutput = daoFacade.getLockupTxOutput(lockupTxId);
|
||||
if (!lockupTxOutput.isPresent()) {
|
||||
@ -110,22 +129,19 @@ public class BondingViewUtils {
|
||||
int lockTime = opLockTime.orElse(-1);
|
||||
|
||||
try {
|
||||
new Popup<>().headLine(Res.get("dao.bonding.unlock.sendTx.headline"))
|
||||
.confirmation(Res.get("dao.bonding.unlock.sendTx.details",
|
||||
bsqFormatter.formatCoinWithCode(unlockAmount),
|
||||
lockTime
|
||||
))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> {
|
||||
daoFacade.publishUnlockTx(lockupTxId,
|
||||
() -> {
|
||||
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
||||
},
|
||||
errorMessage -> new Popup<>().warning(errorMessage.toString()).show()
|
||||
);
|
||||
})
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.show();
|
||||
if (!DevEnv.isDevMode()) {
|
||||
new Popup<>().headLine(Res.get("dao.bonding.unlock.sendTx.headline"))
|
||||
.confirmation(Res.get("dao.bonding.unlock.sendTx.details",
|
||||
bsqFormatter.formatCoinWithCode(unlockAmount),
|
||||
lockTime
|
||||
))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> publishUnlockTx(lockupTxId, resultHandler))
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.show();
|
||||
} else {
|
||||
publishUnlockTx(lockupTxId, resultHandler);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.error(t.toString());
|
||||
t.printStackTrace();
|
||||
@ -137,6 +153,18 @@ public class BondingViewUtils {
|
||||
log.info("unlock tx: {}", lockupTxId);
|
||||
}
|
||||
|
||||
private void publishUnlockTx(String lockupTxId, ResultHandler resultHandler) {
|
||||
daoFacade.publishUnlockTx(lockupTxId,
|
||||
() -> {
|
||||
if (!DevEnv.isDevMode())
|
||||
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
|
||||
|
||||
resultHandler.handleResult();
|
||||
},
|
||||
errorMessage -> new Popup<>().warning(errorMessage.toString()).show()
|
||||
);
|
||||
}
|
||||
|
||||
private void handleError(Throwable throwable) {
|
||||
if (throwable instanceof InsufficientMoneyException) {
|
||||
final Coin missingCoin = ((InsufficientMoneyException) throwable).missing;
|
||||
|
@ -20,6 +20,7 @@ package bisq.desktop.main.dao.bonding.lockup;
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.components.InputTextField;
|
||||
import bisq.desktop.components.TitledGroupBg;
|
||||
import bisq.desktop.main.dao.bonding.BondingViewUtils;
|
||||
import bisq.desktop.main.dao.wallet.BsqBalanceUtil;
|
||||
import bisq.desktop.util.FormBuilder;
|
||||
@ -28,7 +29,6 @@ import bisq.desktop.util.validation.BsqValidator;
|
||||
|
||||
import bisq.core.btc.listeners.BsqBalanceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.Restrictions;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.bonding.BondingConsensus;
|
||||
import bisq.core.dao.bonding.lockup.LockupType;
|
||||
@ -73,10 +73,11 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
private ComboBox<LockupType> lockupTypeComboBox;
|
||||
private ComboBox<BondedRole> bondedRolesComboBox;
|
||||
private Button lockupButton;
|
||||
private ChangeListener<Boolean> focusOutListener;
|
||||
private ChangeListener<String> inputTextFieldListener;
|
||||
private ChangeListener<Boolean> amountFocusOutListener, timeFocusOutListener;
|
||||
private ChangeListener<String> amountInputTextFieldListener, timeInputTextFieldListener;
|
||||
private ChangeListener<BondedRole> bondedRolesListener;
|
||||
private ChangeListener<LockupType> lockupTypeListener;
|
||||
private TitledGroupBg titledGroupBg;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -106,19 +107,27 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
public void initialize() {
|
||||
gridRow = bsqBalanceUtil.addGroup(root, gridRow);
|
||||
|
||||
addTitledGroupBg(root, ++gridRow, 4, Res.get("dao.bonding.lock.lockBSQ"), Layout.GROUP_DISTANCE);
|
||||
int columnSpan = 3;
|
||||
titledGroupBg = addTitledGroupBg(root, ++gridRow, 3, Res.get("dao.bonding.lock.lockBSQ"),
|
||||
Layout.GROUP_DISTANCE);
|
||||
GridPane.setColumnSpan(titledGroupBg, columnSpan);
|
||||
|
||||
amountInputTextField = addInputTextField(root, gridRow, Res.get("dao.bonding.lock.amount"),
|
||||
Layout.FIRST_ROW_AND_GROUP_DISTANCE);
|
||||
amountInputTextField.setPromptText(Res.get("dao.bonding.lock.setAmount", bsqFormatter.formatCoinWithCode(Restrictions.getMinNonDustOutput())));
|
||||
//amountInputTextField.setPromptText(Res.get("dao.bonding.lock.setAmount", bsqFormatter.formatCoinWithCode(Restrictions.getMinNonDustOutput())));
|
||||
amountInputTextField.setValidator(bsqValidator);
|
||||
GridPane.setColumnSpan(amountInputTextField, columnSpan);
|
||||
|
||||
timeInputTextField = FormBuilder.addInputTextField(root, ++gridRow, Res.get("dao.bonding.lock.time"));
|
||||
timeInputTextField.setPromptText(Res.get("dao.bonding.lock.setTime",
|
||||
String.valueOf(BondingConsensus.getMinLockTime()), String.valueOf(BondingConsensus.getMaxLockTime())));
|
||||
|
||||
/* timeInputTextField.setPromptText(Res.get("dao.bonding.lock.setTime",
|
||||
String.valueOf(BondingConsensus.getMinLockTime()), String.valueOf(BondingConsensus.getMaxLockTime())));*/
|
||||
|
||||
timeInputTextField.setValidator(timeInputTextFieldValidator);
|
||||
GridPane.setColumnSpan(timeInputTextField, columnSpan);
|
||||
|
||||
lockupTypeComboBox = FormBuilder.<LockupType>addComboBox(root, ++gridRow, Res.get("dao.bonding.lock.type"));
|
||||
GridPane.setColumnSpan(lockupTypeComboBox, columnSpan);
|
||||
lockupTypeComboBox.setConverter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(LockupType lockupType) {
|
||||
@ -135,11 +144,24 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
if (newValue != null) {
|
||||
bondedRolesComboBox.getSelectionModel().clearSelection();
|
||||
}
|
||||
};
|
||||
//TODO handle trade type
|
||||
lockupTypeComboBox.getSelectionModel().select(0);
|
||||
int lockupRows = 3;
|
||||
if (newValue == LockupType.BONDED_ROLE) {
|
||||
bondedRolesComboBox.setVisible(true);
|
||||
lockupRows++;
|
||||
|
||||
bondedRolesComboBox = FormBuilder.<BondedRole>addComboBox(root, ++gridRow, Res.get("dao.bonding.lock.bondedRoles"));
|
||||
bondedRolesComboBox.setItems(FXCollections.observableArrayList(daoFacade.getBondedRoleList()));
|
||||
} else {
|
||||
bondedRolesComboBox.setVisible(false);
|
||||
bondedRolesComboBox.getItems().clear();
|
||||
}
|
||||
GridPane.setRowSpan(titledGroupBg, lockupRows);
|
||||
GridPane.setRowIndex(lockupButton, GridPane.getRowIndex(amountInputTextField) + lockupRows);
|
||||
};
|
||||
|
||||
|
||||
bondedRolesComboBox = FormBuilder.addComboBox(root, ++gridRow, Res.get("dao.bonding.lock.bondedRoles"));
|
||||
GridPane.setColumnSpan(bondedRolesComboBox, columnSpan);
|
||||
bondedRolesComboBox.setVisible(false);
|
||||
bondedRolesComboBox.setConverter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(BondedRole bondedRole) {
|
||||
@ -169,36 +191,60 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
}
|
||||
};
|
||||
|
||||
lockupButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.bonding.lock.lockupButton"));
|
||||
lockupButton = addButtonAfterGroup(root, gridRow, Res.get("dao.bonding.lock.lockupButton"));
|
||||
lockupButton.setOnAction((event) -> {
|
||||
bondingViewUtils.lockupBondForBondedRole(bondedRolesComboBox.getValue(),
|
||||
() -> {
|
||||
bondedRolesComboBox.getSelectionModel().clearSelection();
|
||||
});
|
||||
switch (lockupTypeComboBox.getValue()) {
|
||||
case BONDED_ROLE:
|
||||
if (bondedRolesComboBox.getValue() != null) {
|
||||
bondingViewUtils.lockupBondForBondedRole(bondedRolesComboBox.getValue(),
|
||||
() -> bondedRolesComboBox.getSelectionModel().clearSelection());
|
||||
}
|
||||
break;
|
||||
case REPUTATION:
|
||||
bondingViewUtils.lockupBondForReputation(bsqFormatter.parseToCoin(amountInputTextField.getText()),
|
||||
Integer.parseInt(timeInputTextField.getText()),
|
||||
() -> {
|
||||
amountInputTextField.setText("");
|
||||
timeInputTextField.setText("");
|
||||
});
|
||||
break;
|
||||
default:
|
||||
log.error("Unknown lockup option=" + lockupTypeComboBox.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
focusOutListener = (observable, oldValue, newValue) -> {
|
||||
amountFocusOutListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
updateButtonState();
|
||||
onUpdateBalances();
|
||||
}
|
||||
};
|
||||
inputTextFieldListener = (observable, oldValue, newValue) -> updateButtonState();
|
||||
timeFocusOutListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
updateButtonState();
|
||||
onUpdateBalances();
|
||||
}
|
||||
};
|
||||
amountInputTextFieldListener = (observable, oldValue, newValue) -> updateButtonState();
|
||||
timeInputTextFieldListener = (observable, oldValue, newValue) -> updateButtonState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
bsqBalanceUtil.activate();
|
||||
|
||||
amountInputTextField.textProperty().addListener(inputTextFieldListener);
|
||||
timeInputTextField.textProperty().addListener(inputTextFieldListener);
|
||||
amountInputTextField.focusedProperty().addListener(focusOutListener);
|
||||
amountInputTextField.textProperty().addListener(amountInputTextFieldListener);
|
||||
timeInputTextField.textProperty().addListener(timeInputTextFieldListener);
|
||||
amountInputTextField.focusedProperty().addListener(amountFocusOutListener);
|
||||
timeInputTextField.focusedProperty().addListener(timeFocusOutListener);
|
||||
lockupTypeComboBox.getSelectionModel().selectedItemProperty().addListener(lockupTypeListener);
|
||||
bondedRolesComboBox.getSelectionModel().selectedItemProperty().addListener(bondedRolesListener);
|
||||
|
||||
bsqWalletService.addBsqBalanceListener(this);
|
||||
|
||||
bondedRolesComboBox.setItems(FXCollections.observableArrayList(daoFacade.getBondedRoleList()));
|
||||
lockupTypeComboBox.getSelectionModel().clearSelection();
|
||||
bondedRolesComboBox.getSelectionModel().clearSelection();
|
||||
|
||||
onUpdateBalances();
|
||||
}
|
||||
|
||||
@ -206,9 +252,10 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
protected void deactivate() {
|
||||
bsqBalanceUtil.deactivate();
|
||||
|
||||
amountInputTextField.textProperty().removeListener(inputTextFieldListener);
|
||||
timeInputTextField.textProperty().removeListener(inputTextFieldListener);
|
||||
amountInputTextField.focusedProperty().removeListener(focusOutListener);
|
||||
amountInputTextField.textProperty().removeListener(amountInputTextFieldListener);
|
||||
timeInputTextField.textProperty().removeListener(timeInputTextFieldListener);
|
||||
amountInputTextField.focusedProperty().removeListener(amountFocusOutListener);
|
||||
timeInputTextField.focusedProperty().removeListener(timeFocusOutListener);
|
||||
lockupTypeComboBox.getSelectionModel().selectedItemProperty().removeListener(lockupTypeListener);
|
||||
bondedRolesComboBox.getSelectionModel().selectedItemProperty().removeListener(bondedRolesListener);
|
||||
|
||||
|
@ -96,7 +96,6 @@ class BondedRolesListItem implements DaoStateListener {
|
||||
boolean isLockedUp = bondedRole.isLockedUp();
|
||||
boolean isUnlocked = bondedRole.isUnlocked();
|
||||
boolean isUnlocking = bondedRole.isUnlocking(daoFacade);
|
||||
log.error("name={}, isLockedUp={}, isUnlocked={}, isUnlocking={}", bondedRole.getName(), isLockedUp, isUnlocked, isUnlocking);
|
||||
|
||||
String text;
|
||||
if (!isLockedUp)
|
||||
|
@ -433,12 +433,11 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
|
||||
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
column.setMinWidth(80);
|
||||
column.setCellFactory(
|
||||
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
|
||||
BondedRolesListItem>>() {
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
|
||||
BondedRolesListItem> column) {
|
||||
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
|
||||
return new TableCell<>() {
|
||||
Button button;
|
||||
|
||||
@Override
|
||||
@ -450,7 +449,11 @@ public class BondedRolesView extends ActivatableView<GridPane, Void> implements
|
||||
button = item.getButton();
|
||||
item.setOnAction(() -> {
|
||||
if (item.isBonded())
|
||||
bondingViewUtils.unLock(item.getBondedRole().getLockupTxId());
|
||||
bondingViewUtils.unLock(item.getBondedRole().getLockupTxId(),
|
||||
() -> {
|
||||
// TODO
|
||||
button.setDisable(true);
|
||||
});
|
||||
else
|
||||
bondingViewUtils.lockupBondForBondedRole(item.getBondedRole(), null);
|
||||
});
|
||||
|
@ -25,6 +25,12 @@ import bisq.core.btc.listeners.TxConfidenceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.bonding.BondingConsensus;
|
||||
import bisq.core.dao.bonding.lockup.LockupType;
|
||||
import bisq.core.dao.governance.role.BondedRole;
|
||||
import bisq.core.dao.governance.role.BondedRoleType;
|
||||
import bisq.core.dao.governance.role.BondedRolesService;
|
||||
import bisq.core.dao.state.blockchain.BaseTxOutput;
|
||||
import bisq.core.dao.state.blockchain.TxOutput;
|
||||
import bisq.core.dao.state.blockchain.TxType;
|
||||
import bisq.core.locale.Res;
|
||||
@ -38,16 +44,19 @@ import java.util.Optional;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Slf4j
|
||||
class LockupTxListItem extends TxConfidenceListItem {
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final DaoFacade daoFacade;
|
||||
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BondedRolesService bondedRolesService;
|
||||
private final Date date;
|
||||
|
||||
private Coin amount = Coin.ZERO;
|
||||
@ -62,12 +71,14 @@ class LockupTxListItem extends TxConfidenceListItem {
|
||||
BsqWalletService bsqWalletService,
|
||||
BtcWalletService btcWalletService,
|
||||
DaoFacade daoFacade,
|
||||
BondedRolesService bondedRolesService,
|
||||
Date date,
|
||||
BsqFormatter bsqFormatter) {
|
||||
super(transaction, bsqWalletService);
|
||||
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.daoFacade = daoFacade;
|
||||
this.bondedRolesService = bondedRolesService;
|
||||
this.date = date;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
|
||||
@ -88,7 +99,18 @@ class LockupTxListItem extends TxConfidenceListItem {
|
||||
}
|
||||
|
||||
public boolean isLockupAndUnspent() {
|
||||
return !isSpent() && getTxType() == TxType.LOCKUP;
|
||||
boolean isLocked;
|
||||
Optional<BondedRole> optionalBondedRole = bondedRolesService.getBondedRoleFromLockupTxId(txId);
|
||||
if (optionalBondedRole.isPresent()) {
|
||||
BondedRole bondedRole = optionalBondedRole.get();
|
||||
//TODO
|
||||
//isLocked = bondedRole.getLockupTxId() != null && bondedRole.getUnlockTxId() == null;
|
||||
//log.error("isLocked {}, tx={}",isLocked,bondedRole.getLockupTxId());
|
||||
} else {
|
||||
//TODO get reputation
|
||||
isLocked = true;
|
||||
}
|
||||
return /*isLocked && */!isSpent() && getTxType() == TxType.LOCKUP;
|
||||
}
|
||||
|
||||
private boolean isSpent() {
|
||||
@ -103,4 +125,28 @@ class LockupTxListItem extends TxConfidenceListItem {
|
||||
.flatMap(tx -> daoFacade.getOptionalTxType(tx.getId()))
|
||||
.orElse(confirmations == 0 ? TxType.UNVERIFIED : TxType.UNDEFINED_TX_TYPE);
|
||||
}
|
||||
|
||||
private Optional<LockupType> getOptionalLockupType() {
|
||||
return getOpReturnData()
|
||||
.flatMap(BondingConsensus::getLockupType);
|
||||
}
|
||||
|
||||
private Optional<byte[]> getOpReturnData() {
|
||||
return daoFacade.getLockupOpReturnTxOutput(txId).map(BaseTxOutput::getOpReturnData);
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
Optional<BondedRoleType> optionalRoleType = bondedRolesService.getBondedRoleType(txId);
|
||||
if (optionalRoleType.isPresent()) {
|
||||
return optionalRoleType.get().getDisplayString();
|
||||
} else {
|
||||
Optional<LockupType> optionalLockupType = getOptionalLockupType();
|
||||
if (optionalLockupType.isPresent()) {
|
||||
LockupType lockupType = optionalLockupType.get();
|
||||
if (lockupType == LockupType.REPUTATION)
|
||||
return Res.get("dao.bonding.unlock.reputation");
|
||||
}
|
||||
}
|
||||
return Res.get("shared.na");
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import bisq.core.btc.listeners.BsqBalanceListener;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.dao.DaoFacade;
|
||||
import bisq.core.dao.governance.role.BondedRolesService;
|
||||
import bisq.core.dao.state.DaoStateListener;
|
||||
import bisq.core.dao.state.blockchain.Block;
|
||||
import bisq.core.dao.state.blockchain.TxType;
|
||||
@ -79,6 +80,7 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
private final BsqBalanceUtil bsqBalanceUtil;
|
||||
private final BsqValidator bsqValidator;
|
||||
private final BondingViewUtils bondingViewUtils;
|
||||
private final BondedRolesService bondedRolesService;
|
||||
private final DaoFacade daoFacade;
|
||||
private final Preferences preferences;
|
||||
|
||||
@ -103,6 +105,7 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
BsqBalanceUtil bsqBalanceUtil,
|
||||
BsqValidator bsqValidator,
|
||||
BondingViewUtils bondingViewUtils,
|
||||
BondedRolesService bondedRolesService,
|
||||
DaoFacade daoFacade,
|
||||
Preferences preferences) {
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
@ -111,6 +114,7 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
this.bsqBalanceUtil = bsqBalanceUtil;
|
||||
this.bsqValidator = bsqValidator;
|
||||
this.bondingViewUtils = bondingViewUtils;
|
||||
this.bondedRolesService = bondedRolesService;
|
||||
this.daoFacade = daoFacade;
|
||||
this.preferences = preferences;
|
||||
}
|
||||
@ -123,6 +127,7 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
tableView.setPrefHeight(300);
|
||||
addTxIdColumn();
|
||||
addInfoColumn();
|
||||
addAmountColumn();
|
||||
addLockTimeColumn();
|
||||
addUnlockColumn();
|
||||
@ -230,6 +235,7 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
bsqWalletService,
|
||||
btcWalletService,
|
||||
daoFacade,
|
||||
bondedRolesService,
|
||||
transaction.getUpdateTime(),
|
||||
bsqFormatter);
|
||||
})
|
||||
@ -280,6 +286,34 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void addInfoColumn() {
|
||||
TableColumn<LockupTxListItem, LockupTxListItem> column =
|
||||
new AutoTooltipTableColumn<>(Res.get("dao.bonding.unlock.type"));
|
||||
column.setMinWidth(160);
|
||||
column.setMaxWidth(column.getMinWidth());
|
||||
|
||||
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
column.setCellFactory(new Callback<>() {
|
||||
|
||||
@Override
|
||||
public TableCell<LockupTxListItem, LockupTxListItem> call(TableColumn<LockupTxListItem,
|
||||
LockupTxListItem> column) {
|
||||
return new TableCell<>() {
|
||||
|
||||
@Override
|
||||
public void updateItem(final LockupTxListItem item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null && !empty) {
|
||||
setText(item.getInfo());
|
||||
} else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void addAmountColumn() {
|
||||
TableColumn<LockupTxListItem, LockupTxListItem> column =
|
||||
new AutoTooltipTableColumn<>(Res.get("shared.amountWithCur", "BSQ"));
|
||||
@ -348,16 +382,12 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
TableColumn<LockupTxListItem, LockupTxListItem> unlockColumn = new TableColumn<>();
|
||||
unlockColumn.setMinWidth(130);
|
||||
unlockColumn.setMaxWidth(unlockColumn.getMinWidth());
|
||||
|
||||
unlockColumn.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
|
||||
|
||||
unlockColumn.setCellFactory(new Callback<TableColumn<LockupTxListItem, LockupTxListItem>,
|
||||
TableCell<LockupTxListItem, LockupTxListItem>>() {
|
||||
|
||||
unlockColumn.setCellFactory(new Callback<>() {
|
||||
@Override
|
||||
public TableCell<LockupTxListItem, LockupTxListItem> call(TableColumn<LockupTxListItem,
|
||||
LockupTxListItem> column) {
|
||||
return new TableCell<LockupTxListItem, LockupTxListItem>() {
|
||||
return new TableCell<>() {
|
||||
Button button;
|
||||
|
||||
@Override
|
||||
@ -367,7 +397,10 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
|
||||
if (item != null && !empty) {
|
||||
if (button == null) {
|
||||
button = item.getButton();
|
||||
button.setOnAction(e -> bondingViewUtils.unLock(item.getTxId()));
|
||||
button.setOnAction(e -> bondingViewUtils.unLock(item.getTxId(), () -> {
|
||||
//TODO
|
||||
button.setDisable(true);
|
||||
}));
|
||||
setGraphic(button);
|
||||
}
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user