Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NFT fixes #991

Closed
wants to merge 12 commits into from
Closed
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
5 changes: 4 additions & 1 deletion src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,10 @@ RES_ICONS = \
qt/res/icons/delegate.png \
qt/res/icons/superstake.png \
qt/res/icons/ledger_on.png \
qt/res/icons/ledger_off.png
qt/res/icons/ledger_off.png \
qt/res/icons/hide.png \
qt/res/icons/play.png \
qt/res/icons/hidden.png

BITCOIN_QT_BASE_CPP = \
qt/bantablemodel.cpp \
Expand Down
7 changes: 1 addition & 6 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-muirglacierheight=<n>", "Use given block height to check contracts with EVM Muir Glacier (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-londonheight=<n>", "Use given block height to check contracts with EVM London (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-taprootheight=<n>", "Use given block height to check taproot (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-nftaddress=<adr>", "Use given contract nft address for non-fungible token (regtest-only)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-nftaddress=<adr>", "Use given NFT contract address for default contract address of non-fungible token", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);

SetupChainParamsBaseOptions(argsman);

Expand Down Expand Up @@ -1279,11 +1279,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
}

if (args.IsArgSet("-nftaddress")) {
// Allow overriding nft address for testing
if (!chainparams.MineBlocksOnDemand()) {
return InitError(Untranslated("nft address may only be overridden on regtest."));
}

std::string nftAddress = args.GetArg("-nftaddress", std::string());
if(IsHex(nftAddress))
{
Expand Down
14 changes: 12 additions & 2 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ class Wallet
virtual std::string getStakerLedgerId() = 0;

//! Add wallet nft entry.
virtual bool addNftEntry(const NftInfo &nft) = 0;
virtual bool addNftEntry(const NftInfo &nft, bool fCopyUserData = false) = 0;

//! Check if exist wallet nft entry.
virtual bool existNftEntry(const NftInfo &nft) = 0;
Expand Down Expand Up @@ -495,7 +495,13 @@ class Wallet
virtual bool tryGetNftTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) = 0;

//! Try to get updated name for a particular nft, if possible without blocking.
virtual bool tryGetNftName(const uint256& id, std::string& name) = 0;
virtual bool tryGetNftName(const uint256& id, const std::string& contract_address, std::string& name) = 0;

//! Set nft transaction from block.
virtual void setNftTxFromBlock(const std::string& contractAddress, const int64_t& fromBlock) = 0;

//! Set nft contract addresses.
virtual std::map<std::string, int64_t> getNftContractAddresses() = 0;

//! Register handler for unload message.
using UnloadFn = std::function<void()>;
Expand Down Expand Up @@ -829,6 +835,7 @@ struct SignDelegation
// Wallet nft information.
struct NftInfo
{
std::string contract_address;
std::string owner;
uint256 id;
uint256 NFTId;
Expand All @@ -839,11 +846,14 @@ struct NftInfo
int32_t count = 0;
uint256 hash;
std::string thumbnail;
bool show_thumbnail = true;
bool watch_nft = false;
};

// Wallet nft transaction
struct NftTx
{
std::string contract_address;
std::string sender;
std::string receiver;
uint256 id;
Expand Down
3 changes: 3 additions & 0 deletions src/qt/bitcoin.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
<file alias="superstake">res/icons/superstake.png</file>
<file alias="ledger_on">res/icons/ledger_on.png</file>
<file alias="ledger_off">res/icons/ledger_off.png</file>
<file alias="hide">res/icons/hide.png</file>
<file alias="play">res/icons/play.png</file>
<file alias="hidden">res/icons/hidden.png</file>
</qresource>
<qresource prefix="/animation">
<file alias="spinner-000">res/animation/spinner-000.png</file>
Expand Down
25 changes: 22 additions & 3 deletions src/qt/createnftdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ CreateNftDialog::CreateNftDialog(QWidget *parent) :
connect(ui->lineEditNftName, &QLineEdit::textChanged, this, &CreateNftDialog::on_updateConfirmButton);
connect(ui->lineEditNftDesc, &QLineEdit::textChanged, this, &CreateNftDialog::on_updateConfirmButton);
connect(ui->lineEditSenderAddress, &QComboBox::currentTextChanged, this, &CreateNftDialog::on_updateConfirmButton);
connect(ui->lineEditContractAddress, &QValidatedLineEdit::textChanged, this, &CreateNftDialog::on_updateConfirmButton);

ui->lineEditSenderAddress->setAddressColumn(AddressTableModel::Address);
ui->lineEditSenderAddress->setTypeRole(AddressTableModel::TypeRole);
Expand All @@ -64,13 +65,21 @@ CreateNftDialog::CreateNftDialog(QWidget *parent) :
ui->lineEditGasPrice->setSingleStep(SINGLE_STEP);
ui->lineEditGasLimit->setMaximum(DEFAULT_GAS_LIMIT_OP_CREATE);
ui->lineEditGasLimit->setValue(DEFAULT_GAS_LIMIT_OP_CREATE);
m_contractAddress = QString::fromStdString(m_nftABI->getAddress());
ui->lineEditContractAddress->setText(m_contractAddress);

// Set uri validator
QRegularExpression regEx;
regEx.setPattern(QString::fromStdString(NftConfig::Instance().GetUriRegex()));
QRegularExpressionValidator *uriValidator = new QRegularExpressionValidator(ui->lineEditNftUri);
uriValidator->setRegularExpression(regEx);
ui->lineEditNftUri->setCheckValidator(uriValidator);

// Set contract address validator
regEx.setPattern(paternAddress);
QRegularExpressionValidator *addressValidatr = new QRegularExpressionValidator(ui->lineEditContractAddress);
addressValidatr->setRegularExpression(regEx);
ui->lineEditContractAddress->setCheckValidator(addressValidatr);
}

CreateNftDialog::~CreateNftDialog()
Expand Down Expand Up @@ -101,6 +110,7 @@ void CreateNftDialog::clearAll()
ui->lineEditSenderAddress->setCurrentIndex(-1);
ui->lineEditGasLimit->setValue(DEFAULT_GAS_LIMIT_OP_CREATE);
ui->lineEditGasPrice->setValue(DEFAULT_GAS_PRICE);
ui->lineEditContractAddress->setText(m_contractAddress);
}

void CreateNftDialog::setModel(WalletModel *_model)
Expand Down Expand Up @@ -163,10 +173,12 @@ void CreateNftDialog::on_confirmButton_clicked()
std::string desc = ui->lineEditNftDesc->text().trimmed().toStdString();
int32_t count = ui->spinBoxNftAmount->value();
QString countFormated = QString::number(count);
std::string contractAddress = ui->lineEditContractAddress->text().trimmed().toStdString();

m_nftABI->setSender(owner);
m_nftABI->setGasLimit(QString::number(gasLimit).toStdString());
m_nftABI->setGasPrice(BitcoinUnits::format(unit, gasPrice, false, BitcoinUnits::SeparatorStyle::NEVER).toStdString());
m_nftABI->setAddress(contractAddress);

QString questionString;
if (bCreateUnsigned) {
Expand Down Expand Up @@ -221,6 +233,7 @@ void CreateNftDialog::on_confirmButton_clicked()
nftTx.value = count;
nftTx.id = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
nftTx.tx_hash = uint256S(m_nftABI->getTxId());
nftTx.contract_address = contractAddress;
m_model->wallet().addNftTxEntry(nftTx);
}
}
Expand Down Expand Up @@ -252,22 +265,28 @@ void CreateNftDialog::on_updateConfirmButton()
bool enabled = true;
QString sUrl = ui->lineEditNftUri->text().trimmed();
QUrl url(sUrl);
ui->lineEditContractAddress->checkValidity();
if(!url.isValid() || !NftConfig::Instance().IsUrlValid(sUrl.toStdString()))
{
enabled = false;
}
if(ui->lineEditNftName->text().trimmed().isEmpty())
else if(ui->lineEditNftName->text().trimmed().isEmpty())
{
enabled = false;
}
if(ui->lineEditNftDesc->text().trimmed().isEmpty())
else if(ui->lineEditNftDesc->text().trimmed().isEmpty())
{
enabled = false;
}
if(!ui->lineEditSenderAddress->isValidAddress())
else if(!ui->lineEditSenderAddress->isValidAddress())
{
enabled = false;
}
else if(!ui->lineEditContractAddress->isValid())
{
enabled = false;
}

ui->confirmButton->setEnabled(enabled);
}

Expand Down
1 change: 1 addition & 0 deletions src/qt/createnftdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ private Q_SLOTS:
WalletModel* m_model;
ClientModel* m_clientModel;
bool bCreateUnsigned = false;
QString m_contractAddress;
};

#endif // CREATENFTDIALOG_H
16 changes: 13 additions & 3 deletions src/qt/forms/createnftdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelNftSymbol">
<widget class="QLabel" name="labelNftDescription">
<property name="minimumSize">
<size>
<width>120</width>
Expand All @@ -84,7 +84,7 @@
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelDecimals">
<widget class="QLabel" name="labelCopies">
<property name="minimumSize">
<size>
<width>120</width>
Expand All @@ -107,7 +107,7 @@
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelContractAddress">
<widget class="QLabel" name="labelNftUrl">
<property name="minimumSize">
<size>
<width>120</width>
Expand Down Expand Up @@ -222,6 +222,16 @@
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="labelContractAddress">
<property name="text">
<string>Contract Address</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QValidatedLineEdit" name="lineEditContractAddress"/>
</item>
</layout>
</item>
<item>
Expand Down
7 changes: 7 additions & 0 deletions src/qt/forms/nftitemwidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,13 @@
</property>
</spacer>
</item>
<item>
<widget class="QtumPushButton" name="toolShow">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QtumPushButton" name="buttonSend">
<property name="text">
Expand Down
80 changes: 55 additions & 25 deletions src/qt/nftitemmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class NftItemEntry
id = nftInfo.id;
NFTId = nftInfo.NFTId;
thumbnail = QString::fromStdString(nftInfo.thumbnail);
showThumbnail = nftInfo.show_thumbnail;
contractAddress = QString::fromStdString(nftInfo.contract_address);
watchNft = nftInfo.watch_nft;
}

NftItemEntry( const NftItemEntry &obj)
Expand All @@ -49,6 +52,9 @@ class NftItemEntry
id = obj.id;
NFTId = obj.NFTId;
thumbnail = obj.thumbnail;
showThumbnail = obj.showThumbnail;
contractAddress = obj.contractAddress;
watchNft = obj.watchNft;
}

~NftItemEntry()
Expand All @@ -60,10 +66,13 @@ class NftItemEntry
QString owner;
QString url;
QString desc;
int32_t balance;
int32_t balance = 0;
uint256 id;
uint256 NFTId;
QString thumbnail;
bool showThumbnail = true;
QString contractAddress;
bool watchNft = false;
};

class NftTxWorker : public QObject
Expand All @@ -72,8 +81,6 @@ class NftTxWorker : public QObject
public:
WalletModel *walletModel;
Nft nftAbi;
int64_t fromBlock = 0;
int64_t toBlock = -1;
bool initThumbnail = true;
QMap<QString, QString> thumbnailCache;
QMap<QString, QDateTime> thumbnailTime;
Expand Down Expand Up @@ -124,38 +131,52 @@ private Q_SLOTS:
return;

// Get current height and block hash
toBlock = walletModel->node().getNumBlocks();
if(fromBlock < toBlock)
int64_t toBlock = walletModel->node().getNumBlocks();
std::map<std::string, int64_t> mapContractAddresses = walletModel->wallet().getNftContractAddresses();
for(std::map<std::string, int64_t>::iterator it = mapContractAddresses.begin(); it != mapContractAddresses.end(); it++)
{
// List the events and update the nft tx
std::vector<NftEvent> nftEvents;
std::vector<interfaces::NftTx> nftTxs;
nftAbi.transferEvents(nftEvents, fromBlock, toBlock);
for(size_t i = 0; i < nftEvents.size(); i++)
// Get transfers events
std::string contractAddress = it->first;
int64_t fromBlock = it->second;
if(fromBlock < toBlock)
{
NftEvent event = nftEvents[i];
interfaces::NftTx nftTx;
nftTx.sender = event.sender;
nftTx.receiver = event.receiver;
nftTx.id = event.id;
nftTx.value = event.value;
nftTx.tx_hash = event.transactionHash;
nftTx.block_hash = event.blockHash;
nftTx.block_number = event.blockNumber;
nftTxs.push_back(nftTx);
// List the events and update the nft tx
std::vector<NftEvent> nftEvents;
std::vector<interfaces::NftTx> nftTxs;
nftAbi.setAddress(contractAddress);
if(!nftAbi.supportsInterface())
continue;
nftAbi.transferEvents(nftEvents, fromBlock, toBlock);
for(size_t i = 0; i < nftEvents.size(); i++)
{
NftEvent event = nftEvents[i];
interfaces::NftTx nftTx;
nftTx.contract_address = event.address;
nftTx.sender = event.sender;
nftTx.receiver = event.receiver;
nftTx.id = event.id;
nftTx.value = event.value;
nftTx.tx_hash = event.transactionHash;
nftTx.block_hash = event.blockHash;
nftTx.block_number = event.blockNumber;
nftTxs.push_back(nftTx);
}
walletModel->wallet().addNftTxEntries(nftTxs);
fromBlock = toBlock - 10;
if(fromBlock < 0) fromBlock = 0;
walletModel->wallet().setNftTxFromBlock(contractAddress, fromBlock);
}
walletModel->wallet().addNftTxEntries(nftTxs);
fromBlock = toBlock - 10;
if(fromBlock < 0) fromBlock = 0;
}

std::map<uint256, WalletNFTInfo> listNftInfo;
std::map<std::string, std::map<uint256, WalletNFTInfo>> contractNftInfo;
for(interfaces::NftInfo nft : walletModel->wallet().getRawNftFromTx())
{
bool isOk = true;
WalletNFTInfo info;
std::map<uint256, WalletNFTInfo>& listNftInfo = contractNftInfo[nft.contract_address];
auto search = listNftInfo.find(nft.id);
nftAbi.setSender(nft.owner);
nftAbi.setAddress(nft.contract_address);
if(search != listNftInfo.end())
{
info = search->second;
Expand All @@ -180,7 +201,7 @@ private Q_SLOTS:

if(!isOk) continue;
nft.count = count;
walletModel->wallet().addNftEntry(nft);
walletModel->wallet().addNftEntry(nft, true);
}
}

Expand Down Expand Up @@ -437,6 +458,15 @@ QVariant NftItemModel::data(const QModelIndex &index, int role) const
case NftItemModel::ThumbnailRole:
return rec->thumbnail;
break;
case NftItemModel::ShowThumbnailRole:
return rec->showThumbnail;
break;
case NftItemModel::AddressRole:
return rec->contractAddress;
break;
case NftItemModel::WatchRole:
return rec->watchNft;
break;
default:
break;
}
Expand Down
3 changes: 3 additions & 0 deletions src/qt/nftitemmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class NftItemModel : public QAbstractItemModel
DescRole = Qt::UserRole + 7,
NftIdRole = Qt::UserRole + 8,
ThumbnailRole = Qt::UserRole + 9,
ShowThumbnailRole = Qt::UserRole + 10,
AddressRole = Qt::UserRole + 11,
WatchRole = Qt::UserRole + 12,
};

NftItemModel(WalletModel *parent = 0);
Expand Down
Loading