Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions doc/tapyrus/colored_coin_gui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Tapyrus core GUI

Tapyrus GUI has been enhanced to allow Token transactions. Following are the changes made

### Overview Page
Overview in the new Tapyrus GUI shows tokens as well. _Prev_ and _Next_ buttons can be used to scroll through all the available tokens. Only TPC is shown when no other tokens are available.

![Overview Page with token](./images/Tapyrus-overview-token.png)

### Send Token
Sending a token is the same as sending TPC except that the new address must have been generated with the colorid

> ./src/tapyrus-cli -conf=~/.tapyrus/ getnewaddress "NFT" c3b8b7e3a2684c746d367420bd0899104005cfeeb59705a3f402fa37312f402624

Then the token lable would be populated automatically and "TOKEN" would be set in the token type drop down.
![Send coin page with token](./images/Tapyrus-send-token.png)

### Receive Token
Receiving tokens is also similar to receiving TPC. In addition to lable, message and amount, Token should also be populated.
![Receive token page](./images/Tapyrus-receive-token.png)

A new entry is added to the payment history table after the address is generated.
![Received payment dialog](./images/Tapyrus-receive-dialog.png)

A new column called Token is added to the transaction table. It shows the token name or TPC for every transaction output. Amount column for TPC is formatted according to wallet setting. For tokens, it is always the number of tokens.

![Transaction page](./images/Tapyrus-transaction-page.png)
Binary file added doc/tapyrus/images/Tapyrus-overview-token.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/tapyrus/images/Tapyrus-receive-token.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/tapyrus/images/Tapyrus-send-token.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/tapyrus/images/Tapyrus-transaction-page.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ option(BUILD_TAPYRUS_SEEDER "Build tapyrus-seeder" ON)
option(BUILD_TAPYRUS_CLI "Build tapyrus-cli" ON)
option(BUILD_TAPYRUS_GENESIS "Build tapyrus-genesis" ON)
option(BUILD_TAPYRUS_TX "Build tapyrus-tx" ON)

# TODO: Fix qt building problem and turn ON.
option(BUILD_TAPYRUS_QT "Build tapyrus-qt" ON)
option(ENABLE_QRCODE "Build QR support in wallet" OFF)

# Ensure that WINDRES_PREPROC is enabled when using windres.
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
Expand Down Expand Up @@ -308,4 +306,4 @@ if(BUILD_TAPYRUS_QT)
add_subdirectory(qt)
endif()

message(status "BUILD_TAPYRUS_QT=${BUILD_TAPYRUS_QT}")
message(STATUS "BUILD_TAPYRUS_QT=${BUILD_TAPYRUS_QT}")
7 changes: 7 additions & 0 deletions src/config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,12 @@ set(ENABLE_WALLET ${BUILD_TAPYRUS_WALLET})
# Activate ZeroMQ
set(ENABLE_ZMQ ${BUILD_TAPYRUS_ZMQ})

# Try to find libqrencode
# Only used in the wallet GUI
if(ENABLE_QRCODE AND BUILD_BITCOIN_WALLET AND BUILD_BITCOIN_QT)
find_package(QREncode REQUIRED)
set(USE_QRCODE 1 CACHE INTERNAL "QR code is enabled")
endif()

# Generate the config
configure_file(bitcoin-config.h.cmake.in bitcoin-config.h ESCAPE_QUOTES)
1 change: 1 addition & 0 deletions src/config/bitcoin-config.h.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,6 @@

#cmakedefine ENABLE_WALLET 1
#cmakedefine ENABLE_ZMQ 1
#cmakedefine ENABLE_QRCODE 0

#endif // BITCOIN_BITCOIN_CONFIG_H
2 changes: 1 addition & 1 deletion src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <amount.h> // For CAmount
#include <net.h> // For CConnman::NumConnections
#include <netaddress.h> // For Network
#include <coins.h>

#include <functional>
#include <memory>
Expand All @@ -21,7 +22,6 @@
class CCoinControl;
class CFeeRate;
class CNodeStats;
class Coin;
class RPCTimerInterface;
class UniValue;
class proxyType;
Expand Down
30 changes: 16 additions & 14 deletions src/interfaces/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class PendingWalletTxImpl : public PendingWalletTx
};

//! Construct wallet tx struct.
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
WalletTx MakeWalletTx(Node& node, CWallet& wallet, const CWalletTx& wtx)
{
WalletTx result;
result.tx = wtx.tx;
Expand All @@ -83,11 +83,13 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
result.time = wtx.GetTxTime();
result.value_map = wtx.mapValue;
result.is_coinbase = wtx.IsCoinBase();
result.is_tokenInput = result.isTokenInput(node);
result.is_tokenOutput = result.isTokenOutput();
return result;
}

//! Construct wallet tx status struct.
WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
WalletTxStatus MakeWalletTxStatus(Node& node, const CWalletTx& wtx)
{
WalletTxStatus result;
auto mi = ::mapBlockIndex.find(wtx.hashBlock);
Expand Down Expand Up @@ -274,26 +276,26 @@ class WalletImpl : public Wallet
}
return {};
}
WalletTx getWalletTx(const uint256& txid) override
WalletTx getWalletTx(Node& node, const uint256& txid) override
{
LOCK2(::cs_main, m_wallet.cs_wallet);
auto mi = m_wallet.mapWallet.find(txid);
if (mi != m_wallet.mapWallet.end()) {
return MakeWalletTx(m_wallet, mi->second);
return MakeWalletTx(node, m_wallet, mi->second);
}
return {};
}
std::vector<WalletTx> getWalletTxs() override
std::vector<WalletTx> getWalletTxs(Node& node) override
{
LOCK2(::cs_main, m_wallet.cs_wallet);
std::vector<WalletTx> result;
result.reserve(m_wallet.mapWallet.size());
for (const auto& entry : m_wallet.mapWallet) {
result.emplace_back(MakeWalletTx(m_wallet, entry.second));
result.emplace_back(MakeWalletTx(node, m_wallet, entry.second));
}
return result;
}
bool tryGetTxStatus(const uint256& txid,
bool tryGetTxStatus(Node& node, const uint256& txid,
interfaces::WalletTxStatus& tx_status,
int& num_blocks,
int64_t& adjusted_time) override
Expand All @@ -312,10 +314,10 @@ class WalletImpl : public Wallet
}
num_blocks = ::chainActive.Height();
adjusted_time = GetAdjustedTime();
tx_status = MakeWalletTxStatus(mi->second);
tx_status = MakeWalletTxStatus(node, mi->second);
return true;
}
WalletTx getWalletTxDetails(const uint256& txid,
WalletTx getWalletTxDetails(Node& node, const uint256& txid,
WalletTxStatus& tx_status,
WalletOrderForm& order_form,
bool& in_mempool,
Expand All @@ -329,8 +331,8 @@ class WalletImpl : public Wallet
adjusted_time = GetAdjustedTime();
in_mempool = mi->second.InMempool();
order_form = mi->second.vOrderForm;
tx_status = MakeWalletTxStatus(mi->second);
return MakeWalletTx(m_wallet, mi->second);
tx_status = MakeWalletTxStatus(node, mi->second);
return MakeWalletTx(node, m_wallet, mi->second);
}
return {};
}
Expand Down Expand Up @@ -358,10 +360,10 @@ class WalletImpl : public Wallet
num_blocks = ::chainActive.Height();
return true;
}
CAmount getBalance() override { return m_wallet.GetBalance()[ColorIdentifier()]; }
CAmount getAvailableBalance(const CCoinControl& coin_control) override
CAmount getBalance(ColorIdentifier colorId) override { return m_wallet.GetBalance()[colorId]; }
CAmount getAvailableBalance(const CCoinControl& coin_control, ColorIdentifier colorId) override
{
return m_wallet.GetAvailableBalance(&coin_control)[ColorIdentifier()];
return m_wallet.GetAvailableBalance(&coin_control)[colorId];
}
isminetype txinIsMine(const CTxIn& txin) override
{
Expand Down
115 changes: 101 additions & 14 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
#include <ui_interface.h> // For ChangeType
#include "node.h"

#include <functional>
#include <map>
Expand Down Expand Up @@ -166,19 +167,19 @@ class Wallet
virtual CTransactionRef getTx(const uint256& txid) = 0;

//! Get transaction information.
virtual WalletTx getWalletTx(const uint256& txid) = 0;
virtual WalletTx getWalletTx(Node& node, const uint256& txid) = 0;

//! Get list of all wallet transactions.
virtual std::vector<WalletTx> getWalletTxs() = 0;
virtual std::vector<WalletTx> getWalletTxs(Node& node) = 0;

//! Try to get updated status for a particular transaction, if possible without blocking.
virtual bool tryGetTxStatus(const uint256& txid,
virtual bool tryGetTxStatus(Node& node, const uint256& txid,
WalletTxStatus& tx_status,
int& num_blocks,
int64_t& adjusted_time) = 0;

//! Get transaction details.
virtual WalletTx getWalletTxDetails(const uint256& txid,
virtual WalletTx getWalletTxDetails(Node& node, const uint256& txid,
WalletTxStatus& tx_status,
WalletOrderForm& order_form,
bool& in_mempool,
Expand All @@ -192,10 +193,10 @@ class Wallet
virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0;

//! Get balance.
virtual CAmount getBalance() = 0;
virtual CAmount getBalance(ColorIdentifier colorId = ColorIdentifier()) = 0;

//! Get available balance.
virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 0;
virtual CAmount getAvailableBalance(const CCoinControl& coin_control, ColorIdentifier colorId = ColorIdentifier()) = 0;

//! Return whether transaction input belongs to wallet.
virtual isminetype txinIsMine(const CTxIn& txin) = 0;
Expand Down Expand Up @@ -311,32 +312,35 @@ struct WalletBalances
bool have_watch_only;
TxColoredCoinBalancesMap watch_only_balances;
TxColoredCoinBalancesMap unconfirmed_watch_only_balances;
std::set<ColorIdentifier> tokens;
std::set<ColorIdentifier>::iterator tokenIndex;

WalletBalances(){
have_watch_only = false;
tokenIndex = tokens.begin();
}

CAmount getBalance(const ColorIdentifier& colorId = ColorIdentifier()) const
CAmount getBalance() const
{
auto it = balances.find(colorId);
auto it = balances.find(*tokenIndex);
return it != balances.end() ? it->second : 0;
}

CAmount getUnconfirmedBalance(const ColorIdentifier& colorId = ColorIdentifier()) const
CAmount getUnconfirmedBalance() const
{
auto it = unconfirmed_balances.find(colorId);
auto it = unconfirmed_balances.find(*tokenIndex);
return it != unconfirmed_balances.end() ? it->second : 0;
}

CAmount getWatchOnlyBalance(const ColorIdentifier& colorId = ColorIdentifier()) const
CAmount getWatchOnlyBalance() const
{
auto it = watch_only_balances.find(colorId);
auto it = watch_only_balances.find(*tokenIndex);
return it != watch_only_balances.end() ? it->second : 0;
}

CAmount getUnconfirmedWatchOnlyBalance(const ColorIdentifier& colorId = ColorIdentifier()) const
CAmount getUnconfirmedWatchOnlyBalance() const
{
auto it = unconfirmed_watch_only_balances.find(colorId);
auto it = unconfirmed_watch_only_balances.find(*tokenIndex);
return it != unconfirmed_watch_only_balances.end() ? it->second : 0;
}

Expand All @@ -346,6 +350,53 @@ struct WalletBalances
watch_only_balances != prev.watch_only_balances ||
unconfirmed_watch_only_balances != prev.unconfirmed_watch_only_balances;
}

//collect all tokens in the wallet from all the balance lists
void refreshTokens() {
tokens.clear();

for(auto pair:balances)
tokens.insert(pair.first);
for(auto pair:unconfirmed_balances)
tokens.insert(pair.first);
for(auto pair:watch_only_balances)
tokens.insert(pair.first);
for(auto pair:unconfirmed_watch_only_balances)
tokens.insert(pair.first);

tokenIndex = tokens.begin();
}

void prev()
{
if(tokenIndex != tokens.begin())
tokenIndex--;
else
{
tokenIndex = tokens.end();
tokenIndex--;
}
}

void next()
{
if(tokenIndex != tokens.end())
{
tokenIndex++;
if(tokenIndex == tokens.end())
tokenIndex = tokens.begin();
}
}

bool isToken()
{
return (*tokenIndex).type != TokenTypes::NONE;
}

std::string getTokenName()
{
return (*tokenIndex).toHexString();
}
};

// Wallet transaction information.
Expand All @@ -362,6 +413,8 @@ struct WalletTx
int64_t time;
std::map<std::string, std::string> value_map;
bool is_coinbase;
bool is_tokenInput;
bool is_tokenOutput;

CAmount getCredit(const ColorIdentifier& colorId = ColorIdentifier()) const
{
Expand All @@ -380,6 +433,40 @@ struct WalletTx
auto it = changes.find(colorId);
return it != changes.end() ? it->second : 0;
}

std::set<ColorIdentifier> getAllColorIds(Node& node) const
{
std::set<ColorIdentifier> txColorIdSet{ColorIdentifier()};
//Get all color ids from all inputs and outputs
for(auto in :tx->vin)
{
Coin prev;
if(node.getUnspentOutput(in.prevout, prev))
txColorIdSet.insert(GetColorIdFromScript(prev.out.scriptPubKey));
}
for(auto out:tx->vout)
txColorIdSet.insert(GetColorIdFromScript(out.scriptPubKey));

return txColorIdSet;
}

bool isTokenInput(Node& node) const
{
Coin prev;
for(auto in :tx->vin)
if(node.getUnspentOutput(in.prevout, prev) && GetColorIdFromScript(prev.out.scriptPubKey).type != TokenTypes::NONE)
return true;
return false;
}

bool isTokenOutput() const
{
for(auto out:tx->vout)
if(GetColorIdFromScript(out.scriptPubKey).type != TokenTypes::NONE)
return true;

return false;
}
};

//! Updated transaction status.
Expand Down
18 changes: 18 additions & 0 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,21 @@ bool IsValidDestinationString(const std::string& str)
{
return IsValidDestinationString(str, Params());
}

bool IsColoredDestination(const std::string& str, ColorIdentifier* colorId)
{
CTxDestination dest = DecodeDestination(str, Params());
if(dest.which() == 3)
{
if(colorId)
*colorId = boost::get<CColorKeyID>(dest).color;
return true;
}
else if(dest.which() == 4)
{
if(colorId)
*colorId = boost::get<CColorScriptID>(dest).color;
return true;
}
return false;
}
Loading