walletmodel.h raw
1 // Copyright (c) 2011-2022 The Limenka developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #ifndef LIMENKA_QT_WALLETMODEL_H
6 #define LIMENKA_QT_WALLETMODEL_H
7
8 #include <key.h>
9 #include <primitives/transaction.h>
10
11 #include <qt/walletmodeltransaction.h>
12
13 #include <interfaces/wallet.h>
14 #include <support/allocators/secure.h>
15
16 #include <string>
17 #include <vector>
18
19 #include <QObject>
20 #include <QValidator>
21
22 enum class OutputType;
23
24 class AddressTableModel;
25 class ClientModel;
26 class OptionsModel;
27 class PlatformStyle;
28 class RecentRequestsTableModel;
29 class SendCoinsRecipient;
30 class TransactionTableModel;
31 class WalletModelTransaction;
32
33 class CKeyID;
34 class COutPoint;
35 class CPubKey;
36 class uint256;
37
38 namespace interfaces {
39 class Node;
40 } // namespace interfaces
41 namespace wallet {
42 class CCoinControl;
43 } // namespace wallet
44
45 QT_BEGIN_NAMESPACE
46 class QTimer;
47 QT_END_NAMESPACE
48
49 /** Interface to Limenka wallet from Qt view code. */
50 class WalletModel : public QObject
51 {
52 Q_OBJECT
53
54 public:
55 explicit WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel& client_model, const PlatformStyle *platformStyle, QObject *parent = nullptr);
56 ~WalletModel();
57
58 enum StatusCode // Returned by sendCoins
59 {
60 OK,
61 InvalidAmount,
62 InvalidAddress,
63 AmountExceedsBalance,
64 AmountWithFeeExceedsBalance,
65 DuplicateAddress,
66 TransactionCreationFailed, // Error returned when wallet is still locked
67 AbsurdFee
68 };
69
70 enum EncryptionStatus
71 {
72 NoKeys, // wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)
73 Unencrypted, // !wallet->IsCrypted()
74 Locked, // wallet->IsCrypted() && wallet->IsLocked()
75 Unlocked // wallet->IsCrypted() && !wallet->IsLocked()
76 };
77
78 OptionsModel* getOptionsModel() const;
79 AddressTableModel* getAddressTableModel() const;
80 TransactionTableModel* getTransactionTableModel() const;
81 RecentRequestsTableModel* getRecentRequestsTableModel() const;
82
83 EncryptionStatus getEncryptionStatus() const;
84
85 // Check address for validity
86 bool validateAddress(const QString& address) const;
87 bool checkAddressForUsage(const std::vector<std::string>& addresses) const;
88 bool findAddressUsage(const QStringList& addresses, std::function<void(const QString&, const interfaces::WalletTx&, uint32_t)> callback) const;
89
90 // Return status record for SendCoins, contains error id + information
91 struct SendCoinsReturn
92 {
93 SendCoinsReturn(StatusCode _status = OK, QString _reasonCommitFailed = "")
94 : status(_status),
95 reasonCommitFailed(_reasonCommitFailed)
96 {
97 }
98 StatusCode status;
99 QString reasonCommitFailed;
100 };
101
102 // prepare transaction for getting txfee before sending coins
103 SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl& coinControl);
104
105 // Send coins to a list of recipients
106 void sendCoins(WalletModelTransaction& transaction);
107
108 // Wallet encryption
109 bool setWalletEncrypted(const SecureString& passphrase);
110 // Passphrase only needed when unlocking
111 bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
112 bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
113
114 // RAII object for unlocking wallet, returned by requestUnlock()
115 class UnlockContext
116 {
117 public:
118 UnlockContext(WalletModel *wallet, bool valid, bool relock);
119 ~UnlockContext();
120
121 bool isValid() const { return valid; }
122
123 // Disable unused copy/move constructors/assignments explicitly.
124 UnlockContext(const UnlockContext&) = delete;
125 UnlockContext(UnlockContext&&) = delete;
126 UnlockContext& operator=(const UnlockContext&) = delete;
127 UnlockContext& operator=(UnlockContext&&) = delete;
128
129 private:
130 WalletModel *wallet;
131 const bool valid;
132 const bool relock;
133 };
134
135 UnlockContext requestUnlock();
136
137 bool bumpFee(uint256 hash, uint256& new_hash);
138 void displayAddress(std::string sAddress) const;
139
140 static bool isWalletEnabled();
141
142 interfaces::Node& node() const { return m_node; }
143 interfaces::Wallet& wallet() const { return *m_wallet; }
144 ClientModel& clientModel() const { return *m_client_model; }
145 void setClientModel(ClientModel* client_model);
146
147 QString getWalletName() const;
148 QString getDisplayName() const;
149
150 bool isMultiwallet() const;
151
152 void refresh(bool pk_hash_only = false);
153
154 uint256 getLastBlockProcessed() const;
155
156 // Retrieve the cached wallet balance
157 interfaces::WalletBalances getCachedBalance() const;
158
159 //! Full-precision balance (sub-satoshi + confidential outputs) as a
160 //! lambda string with up to 26 decimals.
161 QString getPreciseBalance();
162
163 // If coin control has selected outputs, searches the total amount inside the wallet.
164 // Otherwise, uses the wallet's cached available balance.
165 CAmount getAvailableBalance(const wallet::CCoinControl* control);
166
167 private:
168 std::unique_ptr<interfaces::Wallet> m_wallet;
169 std::unique_ptr<interfaces::Handler> m_handler_unload;
170 std::unique_ptr<interfaces::Handler> m_handler_status_changed;
171 std::unique_ptr<interfaces::Handler> m_handler_address_book_changed;
172 std::unique_ptr<interfaces::Handler> m_handler_transaction_changed;
173 std::unique_ptr<interfaces::Handler> m_handler_show_progress;
174 std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed;
175 std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed;
176 ClientModel* m_client_model;
177 interfaces::Node& m_node;
178
179 bool fHaveWatchOnly;
180 bool fForceCheckBalanceChanged{false};
181
182 // Wallet has an options model for wallet-specific options
183 // (transaction fee, for example)
184 OptionsModel *optionsModel;
185
186 AddressTableModel* addressTableModel{nullptr};
187 TransactionTableModel* transactionTableModel{nullptr};
188 RecentRequestsTableModel* recentRequestsTableModel{nullptr};
189
190 // Cache some values to be able to detect changes
191 interfaces::WalletBalances m_cached_balances;
192 EncryptionStatus cachedEncryptionStatus{Unencrypted};
193 QTimer* timer;
194
195 // Block hash denoting when the last balance update was done.
196 uint256 m_cached_last_update_tip{};
197
198 void subscribeToCoreSignals();
199 void unsubscribeFromCoreSignals();
200 void checkBalanceChanged(const interfaces::WalletBalances& new_balances);
201
202 Q_SIGNALS:
203 // Signal that balance in wallet changed
204 void balanceChanged(const interfaces::WalletBalances& balances);
205
206 // Encryption status of wallet changed
207 void encryptionStatusChanged();
208
209 // Signal emitted when wallet needs to be unlocked
210 // It is valid behaviour for listeners to keep the wallet locked after this signal;
211 // this means that the unlocking failed or was cancelled.
212 void requireUnlock();
213
214 // Fired when a message should be reported to the user
215 void message(const QString &title, const QString &message, unsigned int style);
216
217 // Coins sent: from wallet, to recipient, in (serialized) transaction:
218 void coinsSent(WalletModel* wallet, SendCoinsRecipient recipient, QByteArray transaction);
219
220 // Show progress dialog e.g. for rescan
221 void showProgress(const QString &title, int nProgress);
222
223 // Watch-only address added
224 void notifyWatchonlyChanged(bool fHaveWatchonly);
225
226 // Signal that wallet is about to be removed
227 void unload();
228
229 // Notify that there are now keys in the keypool
230 void canGetAddressesChanged();
231
232 void timerTimeout();
233
234 public Q_SLOTS:
235 /* Starts a timer to periodically update the balance */
236 void startPollBalance();
237
238 /* Wallet status might have changed */
239 void updateStatus();
240 /* New transaction, or transaction changed status */
241 void updateTransaction();
242 /* New, updated or removed address book entry */
243 void updateAddressBook(const QString &address, const QString &label, bool isMine, wallet::AddressPurpose purpose, int status);
244 /* Watch-only added */
245 void updateWatchOnlyFlag(bool fHaveWatchonly);
246 /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */
247 void pollBalanceChanged();
248 };
249
250 class LimenkaAddressUnusedInWalletValidator : public QValidator
251 {
252 Q_OBJECT
253
254 const WalletModel& m_wallet_model;
255
256 public:
257 explicit LimenkaAddressUnusedInWalletValidator(const WalletModel&, QObject *parent=nullptr);
258
259 State validate(QString &input, int &pos) const override;
260 };
261
262 #endif // LIMENKA_QT_WALLETMODEL_H
263