diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index a10b5d7850..fc0bdcd4c5 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -158,6 +158,214 @@ WalletTxOut MakeWalletTxOut(const CWallet& wallet, return result; } +//! Construct token info. +CTokenInfo MakeTokenInfo(const TokenInfo& token) +{ + CTokenInfo result; + result.strContractAddress = token.contract_address; + result.strTokenName = token.token_name; + result.strTokenSymbol = token.token_symbol; + result.nDecimals = token.decimals; + result.strSenderAddress = token.sender_address; + result.nCreateTime = token.time; + result.blockHash = token.block_hash; + result.blockNumber = token.block_number; + return result; +} + +//! Construct wallet token info. +TokenInfo MakeWalletTokenInfo(const CTokenInfo& token) +{ + TokenInfo result; + result.contract_address = token.strContractAddress; + result.token_name = token.strTokenName; + result.token_symbol = token.strTokenSymbol; + result.decimals = token.nDecimals; + result.sender_address = token.strSenderAddress; + result.time = token.nCreateTime; + result.block_hash = token.blockHash; + result.block_number = token.blockNumber; + result.hash = token.GetHash(); + return result; +} + +//! Construct token transaction. +CTokenTx MakeTokenTx(const TokenTx& tokenTx) +{ + CTokenTx result; + result.strContractAddress = tokenTx.contract_address; + result.strSenderAddress = tokenTx.sender_address; + result.strReceiverAddress = tokenTx.receiver_address; + result.nValue = tokenTx.value; + result.transactionHash = tokenTx.tx_hash; + result.nCreateTime = tokenTx.time; + result.blockHash = tokenTx.block_hash; + result.blockNumber = tokenTx.block_number; + result.strLabel = tokenTx.label; + return result; +} + +//! Construct wallet token transaction. +TokenTx MakeWalletTokenTx(const CTokenTx& tokenTx) +{ + TokenTx result; + result.contract_address = tokenTx.strContractAddress; + result.sender_address = tokenTx.strSenderAddress; + result.receiver_address = tokenTx.strReceiverAddress; + result.value = tokenTx.nValue; + result.tx_hash = tokenTx.transactionHash; + result.time = tokenTx.nCreateTime; + result.block_hash = tokenTx.blockHash; + result.block_number = tokenTx.blockNumber; + result.label = tokenTx.strLabel; + result.hash = tokenTx.GetHash(); + return result; +} + +ContractBookData MakeContractBook(const std::string& id, const CContractBookData& data) +{ + ContractBookData result; + result.address = id; + result.name = data.name; + result.abi = data.abi; + return result; +} + +uint160 StringToKeyId(const std::string& strAddress) +{ + CTxDestination dest = DecodeDestination(strAddress); + if(std::holds_alternative(dest)) + { + PKHash keyID = std::get(dest); + return uint160(keyID); + } + return uint160(); +} + +std::string KeyIdToString(const uint160& keyID) +{ + return EncodeDestination(PKHash(keyID)); +} + +std::vector StringToKeyIdList(const std::vector& listAddress) +{ + std::vector ret; + for(auto address : listAddress) + { + ret.push_back(StringToKeyId(address)); + } + return ret; +} + +std::vector KeyIdToStringList(const std::vector& listKeyID) +{ + std::vector ret; + for(auto keyId : listKeyID) + { + ret.push_back(KeyIdToString(keyId)); + } + return ret; +} + +//! Construct delegation info. +CDelegationInfo MakeDelegationInfo(const DelegationInfo& delegation) +{ + CDelegationInfo result; + result.delegateAddress = StringToKeyId(delegation.delegate_address); + result.stakerAddress = StringToKeyId(delegation.staker_address); + result.strStakerName = delegation.staker_name; + result.nFee = delegation.fee; + result.nCreateTime = delegation.time; + result.blockNumber = delegation.block_number; + result.createTxHash = delegation.create_tx_hash; + result.removeTxHash = delegation.remove_tx_hash; + return result; +} + +//! Construct wallet delegation info. +DelegationInfo MakeWalletDelegationInfo(const CDelegationInfo& delegation) +{ + DelegationInfo result; + result.delegate_address = KeyIdToString(delegation.delegateAddress); + result.staker_address = KeyIdToString(delegation.stakerAddress); + result.staker_name = delegation.strStakerName; + result.fee = delegation.nFee; + result.time = delegation.nCreateTime; + result.block_number = delegation.blockNumber; + result.time = delegation.nCreateTime; + result.create_tx_hash = delegation.createTxHash; + result.remove_tx_hash = delegation.removeTxHash; + result.hash = delegation.GetHash(); + return result; +} + +//! Construct super staker info. +CSuperStakerInfo MakeSuperStakerInfo(const SuperStakerInfo& superStaker) +{ + CSuperStakerInfo result; + result.stakerAddress = StringToKeyId(superStaker.staker_address); + result.strStakerName = superStaker.staker_name; + result.nMinFee = superStaker.min_fee; + result.nCreateTime = superStaker.time; + result.fCustomConfig = superStaker.custom_config; + result.nMinDelegateUtxo = superStaker.min_delegate_utxo; + result.delegateAddressList = StringToKeyIdList(superStaker.delegate_address_list); + result.nDelegateAddressType = superStaker.delegate_address_type; + return result; +} + +//! Construct wallet super staker info. +SuperStakerInfo MakeWalletSuperStakerInfo(const CSuperStakerInfo& superStaker) +{ + SuperStakerInfo result; + result.staker_address = KeyIdToString(superStaker.stakerAddress); + result.staker_name = superStaker.strStakerName; + result.min_fee = superStaker.nMinFee; + result.time = superStaker.nCreateTime; + result.custom_config = superStaker.fCustomConfig; + result.min_delegate_utxo = superStaker.nMinDelegateUtxo; + result.delegate_address_list = KeyIdToStringList(superStaker.delegateAddressList); + result.delegate_address_type = superStaker.nDelegateAddressType; + result.hash = superStaker.GetHash(); + return result; +} + +//! Construct wallet delegation staker info. +DelegationStakerInfo MakeWalletDelegationStakerInfo(CWallet& wallet, const uint160& id, const Delegation& delegation) +{ + DelegationStakerInfo result; + result.delegate_address = EncodeDestination(PKHash(id)); + result.staker_address = EncodeDestination(PKHash(delegation.staker)); + result.PoD = HexStr(delegation.PoD); + result.fee = delegation.fee; + result.time = -1; + wallet.chain().findBlock(wallet.chain().getBlockHash(delegation.blockHeight), FoundBlock().time(result.time)); + result.block_number = delegation.blockHeight; + std::map::iterator it = wallet.m_delegations_weight.find(id); + if(it != wallet.m_delegations_weight.end()) + { + result.weight = it->second; + } + result.hash = id; + return result; +} + +bool TokenTxStatus(CWallet& wallet, const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) +{ + auto mi = wallet.mapTokenTx.find(txid); + if (mi == wallet.mapTokenTx.end()) { + return false; + } + block_number = mi->second.blockNumber; + auto it = wallet.mapWallet.find(mi->second.transactionHash); + if(it != wallet.mapWallet.end()) + { + in_mempool = it->second.InMempool(); + } + num_blocks = wallet.GetLastBlockHeight(); + return true; +} + class WalletImpl : public Wallet { public: @@ -653,145 +861,447 @@ class WalletImpl : public Wallet bool isLegacy() override { return m_wallet->IsLegacy(); } bool addTokenEntry(const TokenInfo &token) override { + return m_wallet->AddTokenEntry(MakeTokenInfo(token), true); } bool addTokenTxEntry(const TokenTx& tokenTx, bool fFlushOnClose) override { + return m_wallet->AddTokenTxEntry(MakeTokenTx(tokenTx), fFlushOnClose); } bool existTokenEntry(const TokenInfo &token) override { - return {}; + LOCK(m_wallet->cs_wallet); + + uint256 hash = MakeTokenInfo(token).GetHash(); + std::map::iterator it = m_wallet->mapToken.find(hash); + + return it != m_wallet->mapToken.end(); } bool removeTokenEntry(const std::string &sHash) override { - return {}; + return m_wallet->RemoveTokenEntry(uint256S(sHash), true); } std::vector getInvalidTokens() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector listInvalid; + for(auto& info : m_wallet->mapToken) + { + std::string strAddress = info.second.strSenderAddress; + CTxDestination address = DecodeDestination(strAddress); + if(!m_wallet->IsMine(address)) + { + listInvalid.push_back(MakeWalletTokenInfo(info.second)); + } + } + + return listInvalid; } TokenTx getTokenTx(const uint256& txid) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapTokenTx.find(txid); + if (mi != m_wallet->mapTokenTx.end()) { + return MakeWalletTokenTx(mi->second); + } return {}; } std::vector getTokenTxs() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapTokenTx.size()); + for (const auto& entry : m_wallet->mapTokenTx) { + result.emplace_back(MakeWalletTokenTx(entry.second)); + } + return result; } TokenInfo getToken(const uint256& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapToken.find(id); + if (mi != m_wallet->mapToken.end()) { + return MakeWalletTokenInfo(mi->second); + } return {}; } std::vector getTokens() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapToken.size()); + for (const auto& entry : m_wallet->mapToken) { + result.emplace_back(MakeWalletTokenInfo(entry.second)); + } + return result; } bool tryGetTokenTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) override { - return {}; + TRY_LOCK(m_wallet->cs_wallet, locked_wallet); + if (!locked_wallet) { + return false; + } + return TokenTxStatus(*m_wallet, txid, block_number, in_mempool, num_blocks); } bool getTokenTxStatus(const uint256& txid, int& block_number, bool& in_mempool, int& num_blocks) override { - return {}; + LOCK(m_wallet->cs_wallet); + + return TokenTxStatus(*m_wallet, txid, block_number, in_mempool, num_blocks); } bool getTokenTxDetails(const TokenTx &wtx, uint256& credit, uint256& debit, std::string& tokenSymbol, uint8_t& decimals) override { - return {}; + return m_wallet->GetTokenTxDetails(MakeTokenTx(wtx), credit, debit, tokenSymbol, decimals); } bool isTokenTxMine(const TokenTx &wtx) override { - return {}; + return m_wallet->IsTokenTxMine(MakeTokenTx(wtx)); } ContractBookData getContractBook(const std::string& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapContractBook.find(id); + if (mi != m_wallet->mapContractBook.end()) { + return MakeContractBook(id, mi->second); + } return {}; } std::vector getContractBooks() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapContractBook.size()); + for (const auto& entry : m_wallet->mapContractBook) { + result.emplace_back(MakeContractBook(entry.first, entry.second)); + } + return result; } bool existContractBook(const std::string& id) override { - return {}; + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapContractBook.find(id); + return mi != m_wallet->mapContractBook.end(); } bool delContractBook(const std::string& id) override { - return {}; + return m_wallet->DelContractBook(id); } bool setContractBook(const std::string& id, const std::string& name, const std::string& abi) override { - return {}; + return m_wallet->SetContractBook(id, name, abi); } uint32_t restoreDelegations() override { - return {}; + m_wallet->RefreshDelegates(true, false); + + LOCK(m_wallet->cs_wallet); + + int ret = 0; + for (const auto& item : m_wallet->m_my_delegations) { + DelegationDetails details = getDelegationDetails(KeyIdToString(item.first)); + if(!details.w_entry_exist && details.c_entry_exist) + { + DelegationInfo info = details.toInfo(false); + info.staker_name = info.staker_address; + if(addDelegationEntry(info)) + ret++; + } + } + + return ret; } bool addDelegationEntry(const DelegationInfo &delegation) override { - return {}; + return m_wallet->AddDelegationEntry(MakeDelegationInfo(delegation), true); } bool existDelegationEntry(const DelegationInfo &delegation) override { - return {}; + LOCK(m_wallet->cs_wallet); + + uint256 hash = MakeDelegationInfo(delegation).GetHash(); + std::map::iterator it = m_wallet->mapDelegation.find(hash); + + return it != m_wallet->mapDelegation.end(); } DelegationInfo getDelegation(const uint256& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapDelegation.find(id); + if (mi != m_wallet->mapDelegation.end()) { + return MakeWalletDelegationInfo(mi->second); + } return {}; } DelegationInfo getDelegationContract(const std::string &sHash, bool& validated, bool& contractRet) override { + LOCK(m_wallet->cs_wallet); + + uint256 id; + id.SetHex(sHash); + auto mi = m_wallet->mapDelegation.find(id); + if (mi != m_wallet->mapDelegation.end()) { + DelegationInfo info = MakeWalletDelegationInfo(mi->second); + Delegation delegation; + CTxDestination dest = DecodeDestination(info.delegate_address); + if(std::holds_alternative(dest)) + { + PKHash keyID = std::get(dest); + uint160 address(keyID); + contractRet = m_wallet->chain().getDelegation(address, delegation); + if(contractRet) + { + validated = m_wallet->chain().verifyDelegation(address, delegation); + info.staker_address = EncodeDestination(PKHash(delegation.staker)); + info.fee = delegation.fee; + info.block_number = delegation.blockHeight; + } + return info; + } + } return {}; } DelegationDetails getDelegationDetails(const std::string &sAddress) override { - return {}; + LOCK(m_wallet->cs_wallet); + DelegationDetails details; + + // Get wallet delegation details + for(auto mi : m_wallet->mapDelegation) + { + if(KeyIdToString(mi.second.delegateAddress) == sAddress) + { + details.w_entry_exist = true; + details.w_delegate_address = KeyIdToString(mi.second.delegateAddress); + details.w_staker_address = KeyIdToString(mi.second.stakerAddress); + details.w_staker_name = mi.second.strStakerName; + details.w_fee = mi.second.nFee; + details.w_time = mi.second.nCreateTime; + details.w_block_number = mi.second.blockNumber; + details.w_hash = mi.first; + details.w_create_tx_hash = mi.second.createTxHash; + details.w_remove_tx_hash = mi.second.removeTxHash; + break; + } + } + + // Get wallet create tx details + const CWalletTx* wtx = m_wallet->GetWalletTx(details.w_create_tx_hash); + if(wtx) + { + details.w_create_exist = true; + details.w_create_in_main_chain = m_wallet->IsTxInMainChain(*wtx); + details.w_create_in_mempool = wtx->InMempool(); + details.w_create_abandoned = wtx->isAbandoned(); + } + + // Get wallet remove tx details + wtx = m_wallet->GetWalletTx(details.w_remove_tx_hash); + if(wtx) + { + details.w_remove_exist = true; + details.w_remove_in_main_chain = m_wallet->IsTxInMainChain(*wtx); + details.w_remove_in_mempool = wtx->InMempool(); + details.w_remove_abandoned = wtx->isAbandoned(); + } + + // Delegation contract details + Delegation delegation; + CTxDestination dest = DecodeDestination(sAddress); + if(std::holds_alternative(dest)) + { + PKHash keyID = std::get(dest); + uint160 address(keyID); + details.c_contract_return = m_wallet->chain().getDelegation(address, delegation); + if(details.c_contract_return) + { + details.c_entry_exist = m_wallet->chain().verifyDelegation(address, delegation); + details.c_delegate_address = sAddress; + details.c_staker_address = EncodeDestination(PKHash(delegation.staker)); + details.c_fee = delegation.fee; + details.c_block_number = delegation.blockHeight; + } + } + + return details; } std::vector getDelegations() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapDelegation.size()); + for (const auto& entry : m_wallet->mapDelegation) { + result.emplace_back(MakeWalletDelegationInfo(entry.second)); + } + return result; } bool removeDelegationEntry(const std::string &sHash) override { - return {}; + return m_wallet->RemoveDelegationEntry(uint256S(sHash), true); } bool setDelegationRemoved(const std::string &sHash, const std::string &sTxid) override { - return {}; + bool found = false; + DelegationInfo info; + { + LOCK(m_wallet->cs_wallet); + + uint256 id; + id.SetHex(sHash); + + uint256 txid; + txid.SetHex(sTxid); + + auto mi = m_wallet->mapDelegation.find(id); + if (mi != m_wallet->mapDelegation.end()) { + info = MakeWalletDelegationInfo(mi->second); + info.remove_tx_hash = txid; + found = true; + } + } + + return found ? addDelegationEntry(info) : 0; } uint32_t restoreSuperStakers() override { - return {}; + m_wallet->RefreshDelegates(false, true); + + LOCK(m_wallet->cs_wallet); + + std::map stakerAddressExist; + for (const auto& item : m_wallet->m_delegations_staker) { + uint160 staker = item.second.staker; + if(!stakerAddressExist[staker]) + stakerAddressExist[staker] = true; + } + + int ret = 0; + for (const auto& item : stakerAddressExist) { + std::string staker_address = KeyIdToString(item.first); + if(!existSuperStaker(staker_address)) + { + SuperStakerInfo info; + info.staker_name = staker_address; + info.staker_address = staker_address; + if(addSuperStakerEntry(info)) + ret++; + } + } + + return ret; } bool existSuperStaker(const std::string &sAddress) override { - return {}; + LOCK(m_wallet->cs_wallet); + uint160 address = StringToKeyId(sAddress); + if(address.IsNull()) + return false; + + for (const auto& entry : m_wallet->mapSuperStaker) { + if(entry.second.stakerAddress == address) + return true; + } + + return false; } SuperStakerInfo getSuperStaker(const uint256& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->mapSuperStaker.find(id); + if (mi != m_wallet->mapSuperStaker.end()) { + return MakeWalletSuperStakerInfo(mi->second); + } return {}; } SuperStakerInfo getSuperStakerRecommendedConfig() override { - return {}; + LOCK(m_wallet->cs_wallet); + + // Set recommended config + SuperStakerInfo config; + config.custom_config = false; + config.min_fee = m_wallet->m_staking_min_fee; + config.min_delegate_utxo = m_wallet->m_staking_min_utxo_value; + config.delegate_address_type = SuperStakerAddressList::AcceptAll; + + // Get allow list + std::vector allowList; + for (const std::string& strAddress : gArgs.GetArgs("-stakingallowlist")) + { + if(!StringToKeyId(strAddress).IsNull()) + { + if(std::find(allowList.begin(), allowList.end(), strAddress) == allowList.end()) + allowList.push_back(strAddress); + } + } + + // Get exclude list + std::vector excludeList; + for (const std::string& strAddress : gArgs.GetArgs("-stakingexcludelist")) + { + if(!StringToKeyId(strAddress).IsNull()) + { + if(std::find(excludeList.begin(), excludeList.end(), strAddress) == excludeList.end()) + excludeList.push_back(strAddress); + } + } + + // Set the address list + if(!allowList.empty()) + { + config.delegate_address_type = SuperStakerAddressList::AllowList; + config.delegate_address_list = allowList; + } + else if(!excludeList.empty()) + { + config.delegate_address_type = SuperStakerAddressList::ExcludeList; + config.delegate_address_list = excludeList; + } + + return config; } std::vector getSuperStakers() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->mapSuperStaker.size()); + for (const auto& entry : m_wallet->mapSuperStaker) { + result.emplace_back(MakeWalletSuperStakerInfo(entry.second)); + } + return result; } bool addSuperStakerEntry(const SuperStakerInfo &superStaker) override { - return {}; + return m_wallet->AddSuperStakerEntry(MakeSuperStakerInfo(superStaker), true); } bool removeSuperStakerEntry(const std::string &sHash) override { - return {}; + return m_wallet->RemoveSuperStakerEntry(uint256S(sHash), true); } bool tryGetStakeWeight(uint64_t& nWeight) override { - return {}; + TRY_LOCK(m_wallet->cs_wallet, locked_wallet); + if (!locked_wallet) { + return false; + } + + nWeight = m_wallet->GetStakeWeight(); + return true; } uint64_t getStakeWeight() override { - return {}; + LOCK(m_wallet->cs_wallet); + return m_wallet->GetStakeWeight(); } int64_t getLastCoinStakeSearchInterval() override { @@ -807,7 +1317,7 @@ class WalletImpl : public Wallet } bool cleanTokenTxEntries() override { - return {}; + return m_wallet->CleanTokenTxEntries(); } void setEnabledStaking(bool enabled) override { @@ -824,31 +1334,176 @@ class WalletImpl : public Wallet } DelegationStakerInfo getDelegationStaker(const uint160& id) override { + LOCK(m_wallet->cs_wallet); + + auto mi = m_wallet->m_delegations_staker.find(id); + if (mi != m_wallet->m_delegations_staker.end()) { + return MakeWalletDelegationStakerInfo(*m_wallet, mi->first, mi->second); + } return {}; } std::vector getDelegationsStakers() override { - return {}; + LOCK(m_wallet->cs_wallet); + + std::vector result; + result.reserve(m_wallet->m_delegations_staker.size()); + for (const auto& entry : m_wallet->m_delegations_staker) { + result.emplace_back(MakeWalletDelegationStakerInfo(*m_wallet, entry.first, entry.second)); + } + return result; } uint64_t getSuperStakerWeight(const uint256& id) override { - return {}; + LOCK(m_wallet->cs_wallet); + SuperStakerInfo info = getSuperStaker(id); + CTxDestination dest = DecodeDestination(info.staker_address); + if(std::holds_alternative(dest)) + { + PKHash keyID = std::get(dest); + uint160 address(keyID); + return m_wallet->GetSuperStakerWeight(address); + } + + return 0; } bool isSuperStakerStaking(const uint256& id, CAmount& delegationsWeight) override { - return {}; + uint64_t lastCoinStakeSearchInterval = getEnabledStaking() ? getLastCoinStakeSearchInterval() : 0; + delegationsWeight = getSuperStakerWeight(id); + return lastCoinStakeSearchInterval && delegationsWeight; } bool getStakerAddressBalance(const std::string& staker, CAmount& balance, CAmount& stake, CAmount& weight) override { - return {}; + LOCK(m_wallet->cs_wallet); + + CTxDestination dest = DecodeDestination(staker); + if(std::holds_alternative(dest)) + { + PKHash keyID = std::get(dest); + m_wallet->GetStakerAddressBalance(keyID, balance, stake, weight); + return true; + } + + return false; } bool getAddDelegationData(const std::string& psbt, std::map& signData, std::string& error) override { - return {}; + LOCK(m_wallet->cs_wallet); + + try + { + // Decode transaction + PartiallySignedTransaction decoded_psbt; + if(!DecodeBase64PSBT(decoded_psbt, psbt, error)) + { + error = "Fail to decode PSBT transaction"; + return false; + } + + if(decoded_psbt.tx->HasOpCall()) + { + // Get sender destination + CTransaction tx(*(decoded_psbt.tx)); + CTxDestination txSenderDest; + if(m_wallet->GetSenderDest(tx, txSenderDest, false) == false) + { + error = "Fail to get sender destination"; + return false; + } + + // Get sender HD path + std::string strSender; + if(m_wallet->GetHDKeyPath(txSenderDest, strSender) == false) + { + error = "Fail to get HD key path for sender"; + return false; + } + + // Get unsigned staker + for(size_t i = 0; i < decoded_psbt.tx->vout.size(); i++){ + CTxOut v = decoded_psbt.tx->vout[i]; + if(v.scriptPubKey.HasOpCall()){ + std::vector data; + v.scriptPubKey.GetData(data); + if(delegationutils::IsAddBytecode(data)) + { + std::string hexStaker; + if(!delegationutils::GetUnsignedStaker(data, hexStaker)) + { + error = "Fail to get unsigned staker"; + return false; + } + + // Set data to sign + SignDelegation signDeleg; + signDeleg.delegate = strSender; + signDeleg.staker = hexStaker; + signData[i] = signDeleg; + } + } + } + } + } + catch(...) + { + error = "Unknown error happen"; + return false; + } + + return true; } bool setAddDelegationData(std::string& psbt, const std::map& signData, std::string& error) override { - return {}; + // Decode transaction + PartiallySignedTransaction decoded_psbt; + if(!DecodeBase64PSBT(decoded_psbt, psbt, error)) + { + error = "Fail to decode PSBT transaction"; + return false; + } + + // Set signed staker address + size_t size = decoded_psbt.tx->vout.size(); + for (auto it = signData.begin(); it != signData.end(); it++) + { + size_t n = it->first; + std::string PoD = it->second.PoD; + + if(n >= size) + { + error = "Output not found"; + return false; + } + + CTxOut& v = decoded_psbt.tx->vout[n]; + if(v.scriptPubKey.HasOpCall()){ + std::vector data; + v.scriptPubKey.GetData(data); + CScript scriptRet; + if(delegationutils::SetSignedStaker(data, PoD) && v.scriptPubKey.SetData(data, scriptRet)) + { + v.scriptPubKey = scriptRet; + } + else + { + error = "Fail to set PoD"; + return false; + } + } + else + { + error = "Output not op_call"; + return false; + } + } + + // Serialize the PSBT + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + ssTx << decoded_psbt; + psbt = EncodeBase64(ssTx.str()); + + return true; } void setStakerLedgerId(const std::string& ledgerId) override { @@ -862,7 +1517,8 @@ class WalletImpl : public Wallet } bool getHDKeyPath(const CTxDestination& dest, std::string& hdkeypath) override { - return {}; + LOCK(m_wallet->cs_wallet); + return m_wallet->GetHDKeyPath(dest, hdkeypath); } std::unique_ptr handleUnload(UnloadFn fn) override { @@ -945,13 +1601,19 @@ class WalletLoaderImpl : public WalletLoader //! ChainClient methods void registerRpcs() override { - for (const CRPCCommand& command : GetWalletRPCCommands()) { - m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) { - JSONRPCRequest wallet_request = request; - wallet_request.context = &m_context; - return command.actor(wallet_request, result, last_handler); - }, command.argNames, command.unique_id); - m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back())); + std::vector> commands; + commands.push_back(GetWalletRPCCommands()); + commands.push_back(m_context.chain->getContractRPCCommands()); + commands.push_back(m_context.chain->getMiningRPCCommands()); + for(size_t i = 0; i < commands.size(); i++) { + for (const CRPCCommand& command : commands[i]) { + m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) { + JSONRPCRequest& wallet_request = (JSONRPCRequest&)request; + wallet_request.context = &m_context; + return command.actor(wallet_request, result, last_handler); + }, command.argNames, command.unique_id); + m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back())); + } } } bool verify() override { return VerifyWallets(m_context); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 99c72307bb..c04e5eb277 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4718,22 +4718,22 @@ util::Result MigrateLegacyToDescriptor(const std::string& walle uint256 CTokenInfo::GetHash() const { - return {}; + return (CHashWriter{SERIALIZE_GETHASH} << *this).GetHash(); } uint256 CTokenTx::GetHash() const { - return {}; + return (CHashWriter{SERIALIZE_GETHASH} << *this).GetHash(); } uint256 CDelegationInfo::GetHash() const { - return {}; + return (CHashWriter{SERIALIZE_GETHASH} << *this).GetHash(); } uint256 CSuperStakerInfo::GetHash() const { - return {}; + return (CHashWriter{SERIALIZE_GETHASH} << *this).GetHash(); } bool CWallet::GetTokenTxDetails(const CTokenTx &wtx, uint256 &credit, uint256 &debit, std::string &tokenSymbol, uint8_t &decimals) const @@ -5234,6 +5234,10 @@ bool CWallet::GetSuperStaker(CSuperStakerInfo &info, const uint160 &stakerAddres return false; } +void CWallet::GetStakerAddressBalance(const PKHash &staker, CAmount &balance, CAmount &stake, CAmount& weight) const +{ +} + void CWallet::CleanCoinStake() { LOCK(cs_wallet); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 808c316d4a..243ad9de10 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -81,6 +81,7 @@ struct SignatureData; using LoadWalletFn = std::function wallet)>; struct bilingual_str; +static const int SERIALIZE_GETHASH = -1; namespace wallet { struct WalletContext; @@ -747,6 +748,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati bool HasAddressStakeScripts(const uint160& keyId, std::map* insertAddressStake = nullptr) const; void RefreshAddressStakeCache(); bool GetSuperStaker(CSuperStakerInfo &info, const uint160& stakerAddress) const; + void GetStakerAddressBalance(const PKHash& staker, CAmount& balance, CAmount& stake, CAmount& weight) const; void RefreshDelegates(bool myDelegates, bool stakerDelegates); /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */ @@ -1329,6 +1331,10 @@ class CTokenInfo } SERIALIZE_METHODS(CTokenInfo, obj) { + if (s.GetVersion() != SERIALIZE_GETHASH) + { + READWRITE(obj.nVersion, obj.nCreateTime, obj.strTokenName, obj.strTokenSymbol, obj.blockHash, obj.blockNumber); + } READWRITE(obj.nDecimals, obj.strContractAddress, obj.strSenderAddress); } @@ -1371,6 +1377,10 @@ class CTokenTx } SERIALIZE_METHODS(CTokenTx, obj) { + if (s.GetVersion() != SERIALIZE_GETHASH) + { + READWRITE(obj.nVersion, obj.nCreateTime, obj.blockHash, obj.blockNumber, LIMITED_STRING(obj.strLabel, 65536)); + } READWRITE(obj.strContractAddress, obj.strSenderAddress, obj.strReceiverAddress, obj.nValue, obj.transactionHash); } @@ -1422,6 +1432,10 @@ class CDelegationInfo } SERIALIZE_METHODS(CDelegationInfo, obj) { + if (s.GetVersion() != SERIALIZE_GETHASH) + { + READWRITE(obj.nVersion, obj.nCreateTime, obj.nFee, obj.blockNumber, obj.createTxHash, obj.removeTxHash); + } READWRITE(obj.delegateAddress, obj.stakerAddress, obj.strStakerName); } @@ -1461,6 +1475,10 @@ class CSuperStakerInfo } SERIALIZE_METHODS(CSuperStakerInfo, obj) { + if (s.GetVersion() != SERIALIZE_GETHASH) + { + READWRITE(obj.nVersion, obj.nCreateTime, obj.nMinFee, obj.fCustomConfig, obj.nMinDelegateUtxo, obj.delegateAddressList, obj.nDelegateAddressType); + } READWRITE(obj.stakerAddress, obj.strStakerName); }