forked from dashpay/dash
-
Notifications
You must be signed in to change notification settings - Fork 717
/
coldstakingmodel.cpp
187 lines (154 loc) · 6.62 KB
/
coldstakingmodel.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// Copyright (c) 2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "qt/pivx/coldstakingmodel.h"
#include "uint256.h"
#include "bitcoinunits.h"
#include "guiutil.h"
#include <iostream>
#include "addressbook.h"
ColdStakingModel::ColdStakingModel(WalletModel* _model,
TransactionTableModel* _tableModel,
AddressTableModel* _addressTableModel,
QObject *parent) : QAbstractTableModel(parent), model(_model), tableModel(_tableModel), addressTableModel(_addressTableModel), cachedAmount(0){
}
void ColdStakingModel::updateCSList()
{
refresh();
QMetaObject::invokeMethod(this, "emitDataSetChanged", Qt::QueuedConnection);
}
void ColdStakingModel::emitDataSetChanged()
{
Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(cachedDelegations.size(), COLUMN_COUNT, QModelIndex()) );
}
void ColdStakingModel::refresh()
{
cachedDelegations.clear();
cachedAmount = 0;
// First get all of the p2cs utxo inside the wallet
std::vector<COutput> utxoList;
model->getAvailableP2CSCoins(utxoList);
if (!utxoList.empty()) {
// Loop over each COutput into a CSDelegation
for (const auto& utxo : utxoList) {
const auto *wtx = utxo.tx;
const QString txId = QString::fromStdString(wtx->GetHash().GetHex());
const CTxOut& out = wtx->tx->vout[utxo.i];
// First parse the cs delegation
CSDelegation delegation;
if (!parseCSDelegation(out, delegation, txId, utxo.i))
continue;
// it's spendable only when this wallet has the keys to spend it, a.k.a is the owner
delegation.isSpendable = utxo.fSpendable;
delegation.cachedTotalAmount += out.nValue;
delegation.delegatedUtxo.insert(txId, utxo.i);
// Now verify if the delegation exists in the cached list
int indexDel = cachedDelegations.indexOf(delegation);
if (indexDel == -1) {
// If it doesn't, let's append it.
cachedDelegations.append(delegation);
} else {
CSDelegation& del = cachedDelegations[indexDel];
del.delegatedUtxo.unite(delegation.delegatedUtxo);
del.cachedTotalAmount += delegation.cachedTotalAmount;
}
// add amount to cachedAmount if either:
// - this is a owned delegation
// - this is a staked delegation, and the owner is whitelisted
if (!delegation.isSpendable && !addressTableModel->isWhitelisted(delegation.ownerAddress)) continue;
cachedAmount += delegation.cachedTotalAmount;
}
}
}
bool ColdStakingModel::parseCSDelegation(const CTxOut& out, CSDelegation& ret, const QString& txId, const int utxoIndex)
{
txnouttype type;
std::vector<CTxDestination> addresses;
int nRequired;
if (!ExtractDestinations(out.scriptPubKey, type, addresses, nRequired) || addresses.size() != 2) {
return error("%s : Error extracting P2CS destinations for utxo: %s-%d",
__func__, txId.toStdString(), utxoIndex);
}
std::string stakingAddressStr = EncodeDestination(
addresses[0],
CChainParams::STAKING_ADDRESS
);
std::string ownerAddressStr = EncodeDestination(
addresses[1],
CChainParams::PUBKEY_ADDRESS
);
ret = CSDelegation(stakingAddressStr, ownerAddressStr);
return true;
}
int ColdStakingModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return cachedDelegations.size();
}
int ColdStakingModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return COLUMN_COUNT;
}
QVariant ColdStakingModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
int row = index.row();
CSDelegation rec = cachedDelegations[row];
if (role == Qt::DisplayRole || role == Qt::EditRole) {
switch (index.column()) {
case OWNER_ADDRESS:
return QString::fromStdString(rec.ownerAddress);
case OWNER_ADDRESS_LABEL:
return addressTableModel->labelForAddress(QString::fromStdString(rec.ownerAddress));
case STAKING_ADDRESS:
return QString::fromStdString(rec.stakingAddress);
case STAKING_ADDRESS_LABEL:
return addressTableModel->labelForAddress(QString::fromStdString(rec.stakingAddress));
case IS_WHITELISTED:
return addressTableModel->purposeForAddress(rec.ownerAddress).compare(AddressBook::AddressBookPurpose::DELEGATOR) == 0;
case IS_WHITELISTED_STRING:
return (addressTableModel->purposeForAddress(rec.ownerAddress) == AddressBook::AddressBookPurpose::DELEGATOR ? "Staking" : "Not staking");
case TOTAL_STACKEABLE_AMOUNT_STR:
return GUIUtil::formatBalance(rec.cachedTotalAmount);
case TOTAL_STACKEABLE_AMOUNT:
return qint64(rec.cachedTotalAmount);
case IS_RECEIVED_DELEGATION:
return !rec.isSpendable;
}
}
return QVariant();
}
bool ColdStakingModel::whitelist(const QModelIndex& modelIndex)
{
QString address = modelIndex.data(Qt::DisplayRole).toString();
if (addressTableModel->isWhitelisted(address.toStdString())) {
return error("trying to whitelist already whitelisted address");
}
if (!model->whitelistAddressFromColdStaking(address)) return false;
// address whitelisted - update cached amount and row data
const int idx = modelIndex.row();
cachedAmount += cachedDelegations[idx].cachedTotalAmount;
removeRowAndEmitDataChanged(idx);
return true;
}
bool ColdStakingModel::blacklist(const QModelIndex& modelIndex)
{
QString address = modelIndex.data(Qt::DisplayRole).toString();
if (!addressTableModel->isWhitelisted(address.toStdString())) {
return error("trying to blacklist already blacklisted address");
}
if (!model->blacklistAddressFromColdStaking(address)) return false;
// address blacklisted - update cached amount and row data
const int idx = modelIndex.row();
cachedAmount -= cachedDelegations[idx].cachedTotalAmount;
removeRowAndEmitDataChanged(idx);
return true;
}
void ColdStakingModel::removeRowAndEmitDataChanged(const int idx)
{
beginRemoveRows(QModelIndex(), idx, idx);
endRemoveRows();
Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, COLUMN_COUNT, QModelIndex()) );
}