static duk_ret_t API__getnewaddress ( duk_context * ctx ) { const char * account; account = duk_require_string ( ctx, 0 ); if (!pwalletMain->IsLocked()) pwalletMain->TopUpKeyPool(); // Generate a new key that is added to wallet CPubKey newKey; if (!pwalletMain->GetKeyFromPool(newKey, false)) duk_error ( ctx, EMEROBOT_ERR_KEYPOOL_RAN_OUT, "Keypool ran out, please call keypoolrefill first" ); CKeyID keyID = newKey.GetID(); pwalletMain->SetAddressBookName ( keyID, account ); duk_push_string ( ctx, CBitcoinAddress(keyID).ToString().c_str() ); return 1; }
bool CMasternodeBroadcast::Create(CTxIn txin, CService service, CKey keyCollateralAddressNew, CPubKey pubKeyCollateralAddressNew, CKey keyMasternodeNew, CPubKey pubKeyMasternodeNew, std::string& strErrorRet, CMasternodeBroadcast& mnbRet) { // wait for reindex and/or import to finish if (fImporting || fReindex) return false; LogPrint("masternode", "CMasternodeBroadcast::Create -- pubKeyCollateralAddressNew = %s, pubKeyMasternodeNew.GetID() = %s\n", CBitcoinAddress(pubKeyCollateralAddressNew.GetID()).ToString(), pubKeyMasternodeNew.GetID().ToString()); CMasternodePing mnp(txin); if (!mnp.Sign(keyMasternodeNew, pubKeyMasternodeNew)) { strErrorRet = strprintf("Failed to sign ping, masternode=%s", txin.prevout.ToStringShort()); LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); mnbRet = CMasternodeBroadcast(); return false; } mnbRet = CMasternodeBroadcast(service, txin, pubKeyCollateralAddressNew, pubKeyMasternodeNew, PROTOCOL_VERSION); if (!mnbRet.IsValidNetAddr()) { strErrorRet = strprintf("Invalid IP address, masternode=%s", txin.prevout.ToStringShort()); LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); mnbRet = CMasternodeBroadcast(); return false; } mnbRet.lastPing = mnp; if (!mnbRet.Sign(keyCollateralAddressNew)) { strErrorRet = strprintf("Failed to sign broadcast, masternode=%s", txin.prevout.ToStringShort()); LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); mnbRet = CMasternodeBroadcast(); return false; } return true; }
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; std::vector<CTxDestination> addresses; int nRequired; out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); if (fIncludeHex) out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { out.pushKV("type", GetTxnOutputType(type)); return; } out.pushKV("reqSigs", nRequired); out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); for (const CTxDestination& addr : addresses) a.push_back(CBitcoinAddress(addr).ToString()); out.pushKV("addresses", a); }
bool MultisigDialog::addMultisig(int m, vector<string> keys){ try{ string error; CScript redeem; if(!createRedeemScript(m, keys, redeem, error)){ throw runtime_error(error.data()); } if (::IsMine(*pwalletMain, redeem) == ISMINE_SPENDABLE){ throw runtime_error("The wallet already contains this script"); } if(!pwalletMain->AddCScript(redeem)){ throw runtime_error("Failure: address invalid or already exists"); } CScriptID innerID(redeem); string label = ui->multisigAddressLabel->text().toStdString(); pwalletMain->SetAddressBook(innerID, label, "receive"); if (!pwalletMain->AddMultiSig(redeem)){ throw runtime_error("Failure: unable to add address as watch only"); } ui->addMultisigStatus->setStyleSheet("QLabel { color: black; }"); ui->addMultisigStatus->setText("Multisignature address " + QString::fromStdString(CBitcoinAddress(innerID).ToString()) + " has been added to the wallet.\nSend the redeem below for other owners to import:\n" + QString::fromStdString(redeem.ToString())); }catch(const runtime_error& e) { ui->addMultisigStatus->setStyleSheet("QLabel { color: red; }"); ui->addMultisigStatus->setText(tr(e.what())); return false; } return true; }
// Add addresses / update labels that we've sent to to the address book foreach(const SendCoinsRecipient &rcp, recipients) { std::string strAddress = rcp.address.toStdString(); CTxDestination dest = CBitcoinAddress(strAddress).Get(); std::string strLabel = rcp.label.toStdString(); { LOCK(wallet->cs_wallet); std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(dest); // Check if we have a new address or an updated label if (mi == wallet->mapAddressBook.end() || mi->second != strLabel) { wallet->SetAddressBookName(dest, strLabel); } } //12-8-2014 :: R Halford :: Implement SQL Coin Confirm std::string sFrom = DefaultWalletAddress(); //wtxIn.GetHash().ToString().c_str() if (txid.length() > 3 && rcp.CoinTracking) { //If Coin tracking enabled, Insert the SQL record into the P2P SQL Database std::string Narr = "Sending " + RoundToString(rcp.amount,4) + "GRC from " + sFrom + " to " + strAddress + " with tracking " + YesNo(rcp.CoinTracking) + " for TXID " + txid + " with hashBoinc " + hashBoinc + "."; //Insert via Boinc P2P SQL Server printf("%s",Narr.c_str()); #if defined(WIN32) && defined(QT_GUI) qtInsertConfirm((double)total,sFrom,strAddress,txid); #endif printf("Tracked "); } }
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { QString strHTML; { LOCK(wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); int nRequests = wtx.GetRequestCount(); if (nRequests != -1) { if (nRequests == 0) strHTML += tr(", has not been successfully broadcast yet"); else if (nRequests > 0) strHTML += tr(", broadcast through %n node(s)", "", nRequests); } strHTML += "<br>"; strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; // // From // if (wtx.IsCoinBase() || wtx.IsCoinStake()) { strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) { // Online transaction strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; } else { // Offline transaction if (nNet > 0) { // Credit BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wallet->IsMine(txout)) { CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { if (wallet->mapAddressBook.count(address)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].empty()) strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; else strHTML += " (" + tr("own address") + ")"; strHTML += "<br>"; } } break; } } } } // // To // if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty()) { // Online transaction std::string strAddress = wtx.mapValue["to"]; strHTML += "<b>" + tr("To") + ":</b> "; CTxDestination dest = CBitcoinAddress(strAddress).Get(); if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; } // // Amount // if (wtx.IsCoinBase() && nCredit == 0) { // // Coinbase // int64 nUnmatured = 0; BOOST_FOREACH(const CTxOut& txout, wtx.vout) nUnmatured += wallet->GetCredit(txout); strHTML += "<b>" + tr("Credit") + ":</b> "; if (wtx.IsInMainChain()) strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")"; else strHTML += "(" + tr("not accepted") + ")"; strHTML += "<br>"; }
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, const CCoinControl *coinControl) { qint64 total = 0; QSet<QString> setAddress; QString hex; std::string stxData; if(recipients.empty()) { return OK; } // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { if(!validateAddress(rcp.address)) { return InvalidAddress; } setAddress.insert(rcp.address); if(rcp.amount <= 0) { return InvalidAmount; } total += rcp.amount; if(!rcp.from.toStdString().empty()) { if (rcp.from.indexOf("@FROM=") != -1) { return InvalidMessage; } stxData = "@FROM=" + rcp.from.toStdString(); } if(!rcp.subject.toStdString().empty()) { if (rcp.subject.indexOf("@SUBJ=") != -1) { return InvalidMessage; } stxData += "@SUBJ=" + rcp.subject.toStdString(); } if(!rcp.message.toStdString().empty()) { if (rcp.message.indexOf("@MSG=") != -1) { return InvalidMessage; } stxData += "@MSG=" + rcp.message.toStdString(); } //printf("WalletModel::sendCoins: stxData [%s]\n", stxData.c_str()); //if (total < COIN) { return AmountExceedsBalance; } //if (!stxData.empty() && total < COIN) { return InvalidMessageAmount; } } if(recipients.size() > setAddress.size()) { return DuplicateAddress; } int64_t nBalance = 0; std::vector<COutput> vCoins; wallet->AvailableCoins(vCoins, true, coinControl); BOOST_FOREACH(const COutput& out, vCoins) nBalance += out.tx->vout[out.i].nValue; if(total > nBalance) { return AmountExceedsBalance; } if((total + nTransactionFee) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } { LOCK2(cs_main, wallet->cs_wallet); // Sendmany std::vector<std::pair<CScript, int64_t> > vecSend; foreach(const SendCoinsRecipient &rcp, recipients) { CScript scriptPubKey; scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); } CWalletTx wtx; CReserveKey keyChange(wallet); int64_t nFeeRequired = 0; bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, stxData, coinControl); if(!fCreated) { if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future { return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); } return TransactionCreationFailed; } if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) { return Aborted; } if(!wallet->CommitTransaction(wtx, keyChange)) { return TransactionCommitFailed; } hex = QString::fromStdString(wtx.GetHash().GetHex()); }
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) { if (tx.nType != TRANSACTION_PROVIDER_REGISTER) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-type"); } CProRegTx ptx; if (!GetTxPayload(tx, ptx)) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-payload"); } if (ptx.nVersion == 0 || ptx.nVersion > CProRegTx::CURRENT_VERSION) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-version"); } if (ptx.nType != 0) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-type"); } if (ptx.nMode != 0) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-mode"); } if (ptx.keyIDOwner.IsNull() || !ptx.pubKeyOperator.IsValid() || ptx.keyIDVoting.IsNull()) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-null"); } if (!ptx.scriptPayout.IsPayToPublicKeyHash() && !ptx.scriptPayout.IsPayToScriptHash()) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee"); } CTxDestination payoutDest; if (!ExtractDestination(ptx.scriptPayout, payoutDest)) { // should not happen as we checked script types before return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-dest"); } // don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server) if (payoutDest == CTxDestination(ptx.keyIDOwner) || payoutDest == CTxDestination(ptx.keyIDVoting)) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse"); } // It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later // If any of both is set, it must be valid however if (ptx.addr != CService() && !CheckService(tx.GetHash(), ptx, state)) { return false; } if (ptx.nOperatorReward > 10000) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-reward"); } CTxDestination collateralTxDest; CKeyID keyForPayloadSig; COutPoint collateralOutpoint; if (!ptx.collateralOutpoint.hash.IsNull()) { Coin coin; if (!GetUTXOCoin(ptx.collateralOutpoint, coin) || coin.out.nValue != 1000 * COIN) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral"); } if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-dest"); } // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH. // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx if (!CBitcoinAddress(collateralTxDest).GetKeyID(keyForPayloadSig)) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-pkh"); } collateralOutpoint = ptx.collateralOutpoint; } else { if (ptx.collateralOutpoint.n >= tx.vout.size()) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index"); } if (tx.vout[ptx.collateralOutpoint.n].nValue != 1000 * COIN) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral"); } if (!ExtractDestination(tx.vout[ptx.collateralOutpoint.n].scriptPubKey, collateralTxDest)) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-dest"); } collateralOutpoint = COutPoint(tx.GetHash(), ptx.collateralOutpoint.n); } // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server) // this check applies to internal and external collateral, but internal collaterals are not necessarely a P2PKH if (collateralTxDest == CTxDestination(ptx.keyIDOwner) || collateralTxDest == CTxDestination(ptx.keyIDVoting)) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse"); } if (pindexPrev) { auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash()); // only allow reusing of addresses when it's for the same collateral (which replaces the old MN) if (mnList.HasUniqueProperty(ptx.addr) && mnList.GetUniquePropertyMN(ptx.addr)->collateralOutpoint != collateralOutpoint) { return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-addr"); } // never allow duplicate keys, even if this ProTx would replace an existing MN if (mnList.HasUniqueProperty(ptx.keyIDOwner) || mnList.HasUniqueProperty(ptx.pubKeyOperator)) { return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key"); } if (!deterministicMNManager->IsDIP3Enforced(pindexPrev->nHeight)) { if (ptx.keyIDOwner != ptx.keyIDVoting) { return state.DoS(10, false, REJECT_INVALID, "bad-protx-key-not-same"); } } } if (!CheckInputsHash(tx, ptx, state)) { return false; } if (!keyForPayloadSig.IsNull()) { // collateral is not part of this ProRegTx, so we must verify ownership of the collateral if (!CheckStringSig(ptx, keyForPayloadSig, state)) { return false; } } else { // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer if (!ptx.vchSig.empty()) { return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig"); } } return true; }
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl) { CAmount total = 0; bool fSubtractFeeFromAmount = false; QList<SendCoinsRecipient> recipients = transaction.getRecipients(); std::vector<CRecipient> vecSend; if(recipients.empty()) { return OK; } QSet<QString> setAddress; // Used to detect duplicates int nAddresses = 0; // Pre-check input data for validity Q_FOREACH(const SendCoinsRecipient &rcp, recipients) { if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... CAmount subtotal = 0; const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); for (int i = 0; i < details.outputs_size(); i++) { const payments::Output& out = details.outputs(i); if (out.amount() <= 0) continue; subtotal += out.amount(); const unsigned char* scriptStr = (const unsigned char*)out.script().data(); CScript scriptPubKey(scriptStr, scriptStr+out.script().size()); CAmount nAmount = out.amount(); CRecipient recipient = {scriptPubKey, nAmount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); } if (subtotal <= 0) { return InvalidAmount; } total += subtotal; } else { // User-entered bitcoin address / amount: if(!validateAddress(rcp.address)) { return InvalidAddress; } if(rcp.amount <= 0) { return InvalidAmount; } setAddress.insert(rcp.address); ++nAddresses; CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); total += rcp.amount; } } if(setAddress.size() != nAddresses) { return DuplicateAddress; } CAmount nBalance = getBalance(coinControl); if(total > nBalance) { return AmountExceedsBalance; } { LOCK2(cs_main, wallet->cs_wallet); transaction.newPossibleKeyChange(wallet); CAmount nFeeRequired = 0; int nChangePosRet = -1; std::string strFailReason; CWalletTx *newTx = transaction.getTransaction(); CReserveKey *keyChange = transaction.getPossibleKeyChange(); bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl); transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && fCreated) transaction.reassignAmounts(nChangePosRet); if(!fCreated) { if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance); } Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } // reject absurdly high fee. (This can never happen because the // wallet caps the fee at maxTxFee. This merely serves as a // belt-and-suspenders check) if (nFeeRequired > maxTxFee) return AbsurdFee; } return SendCoinsReturn(OK); }
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, const CCoinControl *coinControl) { qint64 total = 0; QSet<QString> setAddress; QString hex; if(recipients.empty()) { return OK; } // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { if(!validateAddress(rcp.address)) { return InvalidAddress; } setAddress.insert(rcp.address); if(rcp.amount <= 0) { return InvalidAmount; } total += rcp.amount; } if(recipients.size() > setAddress.size()) { return DuplicateAddress; } // we do not use getBalance() here, because some coins could be locked or coin control could be active int64 nBalance = 0; std::vector<COutput> vCoins; wallet->AvailableCoins(vCoins, true, coinControl); BOOST_FOREACH(const COutput& out, vCoins) nBalance += out.tx->vout[out.i].nValue; if(total > nBalance) { return AmountExceedsBalance; } if((total + nTransactionFee) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } { LOCK2(cs_main, wallet->cs_wallet); // Sendmany std::vector<std::pair<CScript, int64> > vecSend; foreach(const SendCoinsRecipient &rcp, recipients) { CScript scriptPubKey; scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); } CWalletTx wtx; CReserveKey keyChange(wallet); int64 nFeeRequired = 0; bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, coinControl); if(!fCreated) { if((total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); } return TransactionCreationFailed; } if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) { return Aborted; } if(!wallet->CommitTransaction(wtx, keyChange)) { return TransactionCommitFailed; } hex = QString::fromStdString(wtx.GetHash().GetHex()); }
//spend void MultisigDialog::on_createButton_clicked() { if(!model) return; vector<CTxIn> vUserIn; vector<CTxOut> vUserOut; try{ //Add inputs from Coin Control if any are selected if (CoinControlDialog::coinControl->HasSelected()) { vector<COutPoint> vSelected; CoinControlDialog::coinControl->ListSelected(vSelected); for (auto outpoint : vSelected) vUserIn.emplace_back(CTxIn(outpoint)); }else{//check for raw inputs for(int i = 0; i < ui->inputsList->count(); i++){ QWidget* input = qobject_cast<QWidget*>(ui->inputsList->itemAt(i)->widget()); QLineEdit* txIdLine = input->findChild<QLineEdit*>("txInputId"); if(txIdLine->text().isEmpty()){ ui->createButtonStatus->setStyleSheet("QLabel { color: red; }"); ui->createButtonStatus->setText(tr("Invalid Tx Hash.")); return; } QSpinBox* txVoutLine = input->findChild<QSpinBox*>("txInputVout"); int nOutput = txVoutLine->value(); if(nOutput < 0){ ui->createButtonStatus->setStyleSheet("QLabel { color: red; }"); ui->createButtonStatus->setText(tr("Vout position must be positive.")); return; } uint256 txid = uint256S(txIdLine->text().toStdString()); CTxIn in(COutPoint(txid, nOutput)); vUserIn.emplace_back(in); } } //validate destinations bool validInput = true; for(int i = 0; i < ui->destinationsList->count(); i++){ QWidget* dest = qobject_cast<QWidget*>(ui->destinationsList->itemAt(i)->widget()); QValidatedLineEdit* addr = dest->findChild<QValidatedLineEdit*>("destinationAddress"); BitcoinAmountField* amt = dest->findChild<BitcoinAmountField*>("destinationAmount"); CBitcoinAddress address; bool validDest = true; if(!model->validateAddress(addr->text())){ addr->setValid(false); validDest = false; }else{ address = CBitcoinAddress(addr->text().toStdString()); } if(!amt->validate()){ amt->setValid(false); validDest = false; } if(!validDest){ validInput = false; continue; } CScript scriptPubKey = GetScriptForDestination(address.Get()); CTxOut out(amt->value(), scriptPubKey); vUserOut.push_back(out); } //if all user data valid create a multisig tx if(validInput){ //clear member variable multisigTx = CMutableTransaction(); string error; string fee; if(!createMultisigTransaction(vUserIn, vUserOut, fee, error)){ throw runtime_error(error); } //display status string ui->createButtonStatus->setStyleSheet("QTextEdit{ color: black }"); QString status(strprintf("Transaction has successfully created with a fee of %s.\n" "The transaction has been automatically imported to the sign tab.\n" "Please continue on to sign the tx from this wallet, to access the hex to send to other owners.", fee).c_str()); ui->createButtonStatus->setText(status); ui->transactionHex->setText(QString::fromStdString(EncodeHexTx(multisigTx))); } }catch(const runtime_error& e){ ui->createButtonStatus->setStyleSheet("QTextEdit{ color: red }"); ui->createButtonStatus->setText(tr(e.what())); } }
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, const CCoinControl *coinControl) { qint64 total = 0; QSet<QString> setAddress; QString hex; if(recipients.empty()) { return OK; } // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { if(!validateAddress(rcp.address)) { return InvalidAddress; } setAddress.insert(rcp.address); if(rcp.amount <= 0) { return InvalidAmount; } total += rcp.amount; } if(recipients.size() > setAddress.size()) { return DuplicateAddress; } int64_t nBalance = 0; std::vector<COutput> vCoins; wallet->AvailableCoins(vCoins, true, coinControl); BOOST_FOREACH(const COutput& out, vCoins) nBalance += out.tx->vout[out.i].nValue; if(total > nBalance) { return AmountExceedsBalance; } if((total + nTransactionFee) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } { LOCK2(cs_main, wallet->cs_wallet); // Sendmany std::vector<std::pair<CScript, int64_t> > vecSend; std::string sNarr; foreach(const SendCoinsRecipient &rcp, recipients) { CScript scriptPubKey; scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); sNarr = rcp.reference.toStdString(); if (sNarr.length() > 0) { if (sNarr.length() > 50) { printf("Reference is too long.\n"); return ReferenceTooLong; }; std::vector<uint8_t> vNarr(sNarr.c_str(), sNarr.c_str() + sNarr.length()); CScript scriptN = CScript() << OP_RETURN << vNarr; vecSend.push_back(make_pair(scriptN, 0)); } } CWalletTx wtx; if (sNarr.length() > 0) { wtx.mapValue["reference"] = sNarr; } CReserveKey keyChange(wallet); int64_t nFeeRequired = 0; bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, coinControl); if(!fCreated) { if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future { return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); } return TransactionCreationFailed; } if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) { return Aborted; } if(!wallet->CommitTransaction(wtx, keyChange)) { return TransactionCommitFailed; } hex = QString::fromStdString(wtx.GetHash().GetHex()); }
void ReceiveCoinsDialog::loadBuyViewFinished(bool bOk) { #if defined(HAVE_WEBENGINE_VIEW) || defined(HAVE_WEBKIT) if (bOk) { if (buyReceiveAddress) { delete buyReceiveAddress; buyReceiveAddress = NULL; } buyReceiveAddress = new CReserveKey(pwalletMain, currentAccount, KEYCHAIN_EXTERNAL); CPubKey pubKey; QString guldenAddress; if (!buyReceiveAddress->GetReservedKey(pubKey)) { guldenAddress = "error"; } else { CKeyID keyID = pubKey.GetID(); guldenAddress = QString::fromStdString(CBitcoinAddress(keyID).ToString()); } QString emailAddress = QString(""); QString paymentMethod = QString(""); QString paymentDetails = QString(""); #if defined(HAVE_WEBENGINE_VIEW) buyView->page()->runJavaScript(QString("NocksBuyFormFillDetails('%1', '%2')").arg(guldenAddress, emailAddress)); buyView->page()->runJavaScript(QString("$('.extra-row').hide()")); #else QVariant ret = buyView->page()->mainFrame()->evaluateJavaScript(QString("NocksBuyFormFillDetails('%1', '%2')").arg(guldenAddress, emailAddress)); QString temp = ret.toString(); buyView->page()->mainFrame()->evaluateJavaScript(QString("$('.extra-row').hide()")); #endif #if defined(HAVE_WEBENGINE_VIEW) #if QT_VERSION < QT_VERSION_CHECK(5, 6, 2) || QT_VERSION == QT_VERSION_CHECK(5, 7, 0) buyView->page()->runJavaScript(QString("$('a[href]').attr('target', '_blank');")); buyView->page()->runJavaScript(QString("$('form').attr('target', '_blank');")); #endif #else buyView->page()->mainFrame()->evaluateJavaScript(QString("$('a[href]').attr('target', '_blank');")); buyView->page()->mainFrame()->evaluateJavaScript(QString("$('form').attr('target', '_blank');")); #endif { QFile fontFile(":/Gulden/fontawesome"); fontFile.open(QIODevice::ReadOnly); QString rawCSS = "@font-face{ font-family: FontAwesome;src: url(data:font/ttf;base64," + fontFile.readAll().toBase64() + ") format('truetype');"; std::string encodedCSS = EncodeBase64(rawCSS.toStdString()); QString insertFontScript = QString("(function() {") + "var parent = document.getElementsByTagName('head').item(0);" + "var style = document.createElement('style');" + "style.type = 'text/css';" + "style.innerHTML = window.atob('" + encodedCSS.c_str() + "');" + "parent.appendChild(style)" + "})()"; #if defined(HAVE_WEBENGINE_VIEW) buyView->page()->runJavaScript(insertFontScript); #else buyView->page()->mainFrame()->evaluateJavaScript(insertFontScript); #endif } ui->loadingAnimationLabel->setVisible(false); buyView->setVisible(true); } else { ui->loadingAnimationLabel->setText(tr("Error loading the buy page, please check your connection and try again later.")); ui->loadingAnimationLabel->setVisible(true); buyView->setVisible(false); } #endif }
void ReceiveCoinsDialog::generateRequest() { CReserveKey reservekey(pwalletMain, model->getActiveAccount(), KEYCHAIN_EXTERNAL); CPubKey vchPubKey; if (!reservekey.GetReservedKey(vchPubKey)) { return; } reservekey.KeepKey(); ui->receiveCoinsStackedWidget->setCurrentIndex(3); ui->accountRequestPaymentButtonComposite->setVisible(false); ui->accountBuyGuldenButton->setVisible(false); ui->accountSaveQRButtonComposite->setVisible(true); ui->accountCopyToClipboardButtonComposite->setVisible(true); ui->cancelButton->setVisible(false); ui->closeButton->setVisible(true); ui->cancelButtonGroup->setVisible(true); ui->generateRequestButton->setVisible(false); ui->generateAnotherRequestButton->setVisible(true); ui->accountBuyButton->setVisible(false); ui->accountCopyToClipboardButton->setText(tr("Copy request to clipboard")); CAmount amount = ui->requestAmount->value(); if (amount > 0) { ui->labelPaymentRequestHeading->setText(tr("Request %1 Gulden").arg(BitcoinUnits::format(BitcoinUnits::BTC, amount, false, BitcoinUnits::separatorStandard, 2))); } else { ui->labelPaymentRequestHeading->setText(tr("Request Gulden")); } QString args; QString label = QUrl::toPercentEncoding(ui->requestLabel->text()); QString strAmount; if (!label.isEmpty()) { label = "label=" + label; } if (amount > 0) { strAmount = "amount=" + QUrl::toPercentEncoding(BitcoinUnits::format(BitcoinUnits::BTC, amount, false, BitcoinUnits::separatorNever, -1)); while (strAmount.endsWith("0")) { strAmount.chop(1); } if (strAmount.endsWith(".")) { strAmount.chop(1); } } if (!strAmount.isEmpty() && !label.isEmpty()) { args = "?" + label + "&" + strAmount; } else if (!strAmount.isEmpty()) { args = "?" + strAmount; } else if (!label.isEmpty()) { args = "?" + label; } QString uri = QString("Gulden:") + QString::fromStdString(CBitcoinAddress(vchPubKey.GetID()).ToString()) + args; ui->labelPaymentRequest->setText(uri); if (!uri.isEmpty()) { if (uri.length() > MAX_URI_LENGTH) { ui->requestQRImage->setFixedWidth(900); ui->requestQRImage->setText(tr("Resulting URI too long, try to reduce the text for the label.")); } else { ui->requestQRImage->setText(""); ui->requestQRImage->setFixedWidth(ui->requestQRImage->height()); ui->requestQRImage->setCode(uri); } } pwalletMain->SetAddressBook(CBitcoinAddress(vchPubKey.GetID()).ToString(), ui->requestLabel->text().toStdString(), "receive"); }
WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction) { QByteArray transaction_array; /* store serialized transaction */ if(isAnonymizeOnlyUnlocked()) { return AnonymizeOnlyUnlocked; } { LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); QList<SendCoinsRecipient> recipients = transaction.getRecipients(); // Store PaymentRequests in wtx.vOrderForm in wallet. foreach(const SendCoinsRecipient &rcp, recipients) { if (rcp.paymentRequest.IsInitialized()) { std::string key("PaymentRequest"); std::string value; rcp.paymentRequest.SerializeToString(&value); newTx->vOrderForm.push_back(make_pair(key, value)); } else if (!rcp.message.isEmpty()) // Message from normal limecoinx:URI (limecoinx:XyZ...?message=example) { newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); } } CReserveKey *keyChange = transaction.getPossibleKeyChange(); transaction.getRecipients(); if(!wallet->CommitTransaction(*newTx, *keyChange, (recipients[0].useInstantX) ? "txlreq" : "tx")) return TransactionCommitFailed; CTransaction* t = (CTransaction*)newTx; CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << *t; transaction_array.append(&(ssTx[0]), ssTx.size()); } // Add addresses / update labels that we've sent to to the address book, // and emit coinsSent signal for each recipient foreach(const SendCoinsRecipient &rcp, transaction.getRecipients()) { // Don't touch the address book when we have a payment request if (!rcp.paymentRequest.IsInitialized()) { std::string strAddress = rcp.address.toStdString(); CTxDestination dest = CBitcoinAddress(strAddress).Get(); std::string strLabel = rcp.label.toStdString(); { LOCK(wallet->cs_wallet); std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest); // Check if we have a new address or an updated label if (mi == wallet->mapAddressBook.end()) { wallet->SetAddressBook(dest, strLabel, "send"); } else if (mi->second.name != strLabel) { wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose } } } emit coinsSent(wallet, rcp, transaction_array); } return SendCoinsReturn(OK); }
bool CBasicKeyStore::AddKey(const CKey& key) { CRITICAL_BLOCK(cs_KeyStore) mapKeys[CBitcoinAddress(key.GetPubKey())] = key.GetSecret(); return true; }
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl) { CAmount total = 0; bool fSubtractFeeFromAmount = false; QList<SendCoinsRecipient> recipients = transaction.getRecipients(); std::vector<CRecipient> vecSend; if(recipients.empty()) { return OK; } // This should never really happen, yet another safety check, just in case. if(wallet->IsLocked()) { return TransactionCreationFailed; } QSet<QString> setAddress; // Used to detect duplicates int nAddresses = 0; // Pre-check input data for validity Q_FOREACH(const SendCoinsRecipient &rcp, recipients) { if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... CAmount subtotal = 0; const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); for (int i = 0; i < details.outputs_size(); i++) { const payments::Output& out = details.outputs(i); if (out.amount() <= 0) continue; subtotal += out.amount(); const unsigned char* scriptStr = (const unsigned char*)out.script().data(); CScript scriptPubKey(scriptStr, scriptStr+out.script().size()); CAmount nAmount = out.amount(); CRecipient recipient = {scriptPubKey, nAmount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); } if (subtotal <= 0) { return InvalidAmount; } total += subtotal; } else { // User-entered dash address / amount: if(!validateAddress(rcp.address)) { return InvalidAddress; } if(rcp.amount <= 0) { return InvalidAmount; } setAddress.insert(rcp.address); ++nAddresses; CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount}; vecSend.push_back(recipient); total += rcp.amount; } } if(setAddress.size() != nAddresses) { return DuplicateAddress; } CAmount nBalance = getBalance(coinControl); if(total > nBalance) { return AmountExceedsBalance; } { LOCK2(cs_main, wallet->cs_wallet); transaction.newPossibleKeyChange(wallet); CAmount nFeeRequired = 0; int nChangePosRet = -1; std::string strFailReason; CWalletTx *newTx = transaction.getTransaction(); CReserveKey *keyChange = transaction.getPossibleKeyChange(); if(recipients[0].fUseInstantSend && total > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN){ Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, nChangePosRet, strFailReason, coinControl, true, recipients[0].inputType, recipients[0].fUseInstantSend); transaction.setTransactionFee(nFeeRequired); if (fSubtractFeeFromAmount && fCreated) transaction.reassignAmounts(nChangePosRet); if(recipients[0].fUseInstantSend) { if(newTx->tx->GetValueOut() > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { Q_EMIT message(tr("Send Coins"), tr("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH.").arg(sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } if(newTx->tx->vin.size() > CTxLockRequest::WARN_MANY_INPUTS) { Q_EMIT message(tr("Send Coins"), tr("Used way too many inputs (>%1) for this InstantSend transaction, fees could be huge.").arg(CTxLockRequest::WARN_MANY_INPUTS), CClientUIInterface::MSG_WARNING); } } if(!fCreated) { if(!fSubtractFeeFromAmount && (total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance); } Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } // reject absurdly high fee. (This can never happen because the // wallet caps the fee at maxTxFee. This merely serves as a // belt-and-suspenders check) if (nFeeRequired > maxTxFee) return AbsurdFee; } return SendCoinsReturn(OK); }
void AddEditStormNode::on_okButton_clicked() { if(ui->aliasLineEdit->text() == "") { QMessageBox msg; msg.setText("Please enter an alias."); msg.exec(); return; } else if(ui->addressLineEdit->text() == "") { QMessageBox msg; msg.setText("Please enter an address."); msg.exec(); return; } else { CStormNodeConfig c; c.sAlias = ui->aliasLineEdit->text().toStdString(); c.sAddress = ui->addressLineEdit->text().toStdString(); CKey secret; secret.MakeNewKey(false); c.sStormnodePrivKey = CBitcoinSecret(secret).ToString(); CWalletDB walletdb(pwalletMain->strWalletFile); CAccount account; walletdb.ReadAccount(c.sAlias, account); bool bKeyUsed = false; bool bForceNew = false; // Check if the current key has been used if (account.vchPubKey.IsValid()) { CScript scriptPubKey; scriptPubKey.SetDestination(account.vchPubKey.GetID()); for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); ++it) { const CWalletTx& wtx = (*it).second; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (txout.scriptPubKey == scriptPubKey) bKeyUsed = true; } } // Generate a new key if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed) { if (!pwalletMain->GetKeyFromPool(account.vchPubKey)) { QMessageBox msg; msg.setText("Keypool ran out, please call keypoolrefill first."); msg.exec(); return; } pwalletMain->SetAddressBookName(account.vchPubKey.GetID(), c.sAlias); walletdb.WriteAccount(c.sAlias, account); } c.sCollateralAddress = CBitcoinAddress(account.vchPubKey.GetID()).ToString(); pwalletMain->mapMyStormNodes.insert(make_pair(c.sAddress, c)); walletdb.WriteStormNodeConfig(c.sAddress, c); uiInterface.NotifyStormNodeChanged(c); accept(); }
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl) { qint64 total = 0; QList<SendCoinsRecipient> recipients = transaction.getRecipients(); std::vector<std::pair<CScript, int64_t> > vecSend; if(recipients.empty()) { return OK; } QSet<QString> setAddress; // Used to detect duplicates int nAddresses = 0; // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... int64_t subtotal = 0; const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); for (int i = 0; i < details.outputs_size(); i++) { const payments::Output& out = details.outputs(i); if (out.amount() <= 0) continue; subtotal += out.amount(); const unsigned char* scriptStr = (const unsigned char*)out.script().data(); CScript scriptPubKey(scriptStr, scriptStr+out.script().size()); vecSend.push_back(std::pair<CScript, int64_t>(scriptPubKey, out.amount())); } if (subtotal <= 0) { return InvalidAmount; } total += subtotal; } else { // User-entered bitcoin address / amount: if(!validateAddress(rcp.address)) { return InvalidAddress; } if(rcp.amount <= 0) { return InvalidAmount; } setAddress.insert(rcp.address); ++nAddresses; CScript scriptPubKey; scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(std::pair<CScript, int64_t>(scriptPubKey, rcp.amount)); total += rcp.amount; } } if(setAddress.size() != nAddresses) { return DuplicateAddress; } qint64 nBalance = getBalance(coinControl); if(total > nBalance) { return AmountExceedsBalance; } if((total + nTransactionFee) > nBalance) { transaction.setTransactionFee(nTransactionFee); return SendCoinsReturn(AmountWithFeeExceedsBalance); } { LOCK2(cs_main, wallet->cs_wallet); transaction.newPossibleKeyChange(wallet); int64_t nFeeRequired = 0; std::string strFailReason; CWalletTx *newTx = transaction.getTransaction(); CReserveKey *keyChange = transaction.getPossibleKeyChange(); bool fCreated = wallet->CreateTransaction(vecSend, *newTx, *keyChange, nFeeRequired, strFailReason, coinControl); transaction.setTransactionFee(nFeeRequired); if(!fCreated) { if((total + nFeeRequired) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance); } emit message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } } return SendCoinsReturn(OK); }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; const bool combineOutputs = (wtx.cUnit == 'S'); if (wtx.IsCoinStake()) // ppcoin: coinstake transaction { parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut())); } else if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // QMap<CScript, TransactionRecord*> outputParts; BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { if (wtx.IsUnpark()) sub.type = TransactionRecord::Unpark; else // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address, wtx.cUnit).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated sub.type = TransactionRecord::Generated; } if (combineOutputs) { QMap<CScript, TransactionRecord*>::const_iterator it = outputParts.find(txout.scriptPubKey); if (it != outputParts.end()) { TransactionRecord& previous = *it.value(); previous.credit += sub.credit; continue; } } parts.append(sub); if (combineOutputs) outputParts[txout.scriptPubKey] = &parts.back(); } } }
WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &transaction) { QByteArray transaction_array; /* store serialized transaction */ { LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) { if (rcp.paymentRequest.IsInitialized()) { // Make sure any payment requests involved are still valid. if (PaymentServer::verifyExpired(rcp.paymentRequest.getDetails())) { return PaymentRequestExpired; } // Store PaymentRequests in wtx.vOrderForm in wallet. std::string key("PaymentRequest"); std::string value; rcp.paymentRequest.SerializeToString(&value); newTx->vOrderForm.push_back(make_pair(key, value)); } else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example) newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); } CReserveKey *keyChange = transaction.getPossibleKeyChange(); if(!wallet->CommitTransaction(*newTx, *keyChange)) return TransactionCommitFailed; CTransaction* t = (CTransaction*)newTx; CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << *t; transaction_array.append(&(ssTx[0]), ssTx.size()); } // Add addresses / update labels that we've sent to to the address book, // and emit coinsSent signal for each recipient Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) { // Don't touch the address book when we have a payment request if (!rcp.paymentRequest.IsInitialized()) { std::string strAddress = rcp.address.toStdString(); CTxDestination dest = CBitcoinAddress(strAddress).Get(); std::string strLabel = rcp.label.toStdString(); { LOCK(wallet->cs_wallet); std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(dest); // Check if we have a new address or an updated label if (mi == wallet->mapAddressBook.end()) { wallet->SetAddressBook(dest, strLabel, "send"); } else if (mi->second.name != strLabel) { wallet->SetAddressBook(dest, strLabel, ""); // "" means don't change purpose } } } Q_EMIT coinsSent(wallet, rcp, transaction_array); } checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits return SendCoinsReturn(OK); }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); int64_t nCredMOIN, nCredMoinX; wtx.GetCredit(nCredMOIN, nCredMoinX, true); int64_t nCredit = nCredMOIN + nCredMoinX; int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map<std::string, std::string> mapValue = wtx.mapValue; char cbuf[256]; if (wtx.nVersion == ANON_TXN_VERSION) { if (nNet > 0 && nCredMoinX > 0) { // -- credit TransactionRecord sub(hash, nTime, TransactionRecord::RecvMoinX, "", "", nNet, 0); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { // display 1st transaction snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) { sub.narration = mi->second; break; }; }; parts.append(sub); return parts; } else if (nNet <= 0) { // -- debit TransactionRecord sub(hash, nTime, TransactionRecord::SendMoinX, "", "", nNet, 0); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { // display 1st transaction snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) { sub.narration = mi->second; break; } }; parts.append(sub); return parts; }; // continue on }; if (nNet > 0 || wtx.IsCoinBase() || wtx.IsCoinStake()) { // // Credit // for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { const CScript &s = txout.scriptPubKey; CKeyID ckidD = CPubKey(&s[2+1], 33).GetID(); if (wallet->HaveKey(ckidD)) { TransactionRecord sub(hash, nTime); sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; sub.type = TransactionRecord::RecvMoinX; sub.address = CBitcoinAddress(ckidD).ToString(); //sub.address = wallet->mapAddressBook[ckidD] snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; parts.append(sub); }; }; if (wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); sub.idx = parts.size(); // sequence number CTxDestination address; sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsDestMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; if (wtx.IsCoinBase()) { // Generated (proof-of-work) sub.type = TransactionRecord::Generated; }; if (wtx.IsCoinStake()) { // Generated (proof-of-stake) if (hashPrev == hash) continue; // last coinstake output sub.type = TransactionRecord::Generated; sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit; hashPrev = hash; }; parts.append(sub); } } } else { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) { if (wtx.nVersion == ANON_TXN_VERSION && txin.IsAnonInput()) { std::vector<uint8_t> vchImage; txin.ExtractKeyImage(vchImage); CWalletDB walletdb(wallet->strWalletFile, "r"); COwnedAnonOutput oao; if (!walletdb.ReadOwnedAnonOutput(vchImage, oao)) { fAllFromMe = false; break; // display as send/recv moinx }; continue; }; if (wallet->IsMine(txin)) continue; fAllFromMe = false; break; }; bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { fAllToMe = false; break; // display as send/recv moinx } opcodetype firstOpCode; CScript::const_iterator pc = txout.scriptPubKey.begin(); if (txout.scriptPubKey.GetOp(pc, firstOpCode) && firstOpCode == OP_RETURN) continue; if (wallet->IsMine(txout)) continue; fAllToMe = false; break; }; if (fAllFromMe && fAllToMe) { // Payment to self int64_t nChange = wtx.GetChange(); std::string narration(""); mapValue_t::const_iterator mi; for (mi = wtx.mapValue.begin(); mi != wtx.mapValue.end(); ++mi) { if (mi->first.compare(0, 2, "n_") != 0) continue; narration = mi->second; break; }; parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", narration, -(nDebit - nChange), nCredit - nChange)); } else if (fAllFromMe) { // // Debit // int64_t nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { const CScript &s = txout.scriptPubKey; CKeyID ckidD = CPubKey(&s[2+1], 33).GetID(); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; sub.type = TransactionRecord::SendMoinX; sub.address = CBitcoinAddress(ckidD).ToString(); } else { opcodetype firstOpCode; CScript::const_iterator pc = txout.scriptPubKey.begin(); if (txout.scriptPubKey.GetOp(pc, firstOpCode) && firstOpCode == OP_RETURN) continue; if (wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } }; snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; int64_t nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // TransactionRecord sub(hash, nTime, TransactionRecord::Other, "", "", nNet, 0); /* for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { // display 1st transaction snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; break; }; */ parts.append(sub); } } return parts; }
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, const CCoinControl *coinControl) { qint64 total = 0; QSet<QString> setAddress; QString hex; if(recipients.empty()) { return OK; } // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { if(!validateAddress(rcp.address)) { return InvalidAddress; } setAddress.insert(rcp.address); if(rcp.amount <= 0) { return InvalidAmount; } total += rcp.amount; } if(recipients.size() > setAddress.size()) { return DuplicateAddress; } if(total > getBalance()) { return AmountExceedsBalance; } if((total + nTransactionFee) > getBalance()) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } { LOCK2(cs_main, wallet->cs_wallet); // Sendmany std::vector<std::pair<CScript, int64> > vecSend; foreach(const SendCoinsRecipient &rcp, recipients) { CScript scriptPubKey; scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); } CWalletTx wtx; CReserveKey keyChange(wallet); int64 nFeeRequired = 0; std::string strFailReason; bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason, coinControl); if(!fCreated) { if((total + nFeeRequired) > wallet->GetBalance()) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); } emit message(tr("Send Coins"), QString::fromStdString(strFailReason), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } if(!uiInterface.ThreadSafeAskFee(nFeeRequired)) { return Aborted; } if(!wallet->CommitTransaction(wtx, keyChange)) { return TransactionCommitFailed; } hex = QString::fromStdString(wtx.GetHash().GetHex()); }
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { QString strHTML; QString explorer(fTestNet ? "http://explorer.butterflycoin.info/" : "http://explorer.butterflycoin.info/"); LOCK2(cs_main, wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); int nRequests = wtx.GetRequestCount(); if (nRequests != -1) { if (nRequests == 0) strHTML += tr(", has not been successfully broadcast yet"); else if (nRequests > 0) strHTML += tr(", broadcast through %n node(s)", "", nRequests); }; strHTML += "<br>"; strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; // // From // if (wtx.IsCoinBase() || wtx.IsCoinStake()) { strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) { // Online transaction strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; } else { // Offline transaction if (nNet > 0) { // Credit BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { const CScript &s = txout.scriptPubKey; CKeyID ckidD = CPubKey(&s[2+1], 33).GetID(); std::string sAnonPrefix("ao "); if (wallet->HaveKey(ckidD) && (wallet->mapAddressBook[ckidD].empty() || !wallet->mapAddressBook[ckidD].compare(0, sAnonPrefix.length(), sAnonPrefix) == 0)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> <a href='"+explorer+"address.asp?address="; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(ckidD).ToString())+"' target='_blank'>"; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(ckidD).ToString()); if (!wallet->mapAddressBook[ckidD].empty()) strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[ckidD]) + ")"; else strHTML += " (" + tr("own address") + ")"; strHTML += "</a><br>"; }; continue; } if (wallet->IsMine(txout)) { CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { if (wallet->mapAddressBook.count(address)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> <a href='"+explorer+"address.asp?address="; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString())+"' target='_blank'>"; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].empty()) strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; else strHTML += " (" + tr("own address") + ")"; strHTML += "</a><br>"; }; }; break; }; }; }; };
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; if (showTransaction(wtx)) { if (wtx.IsCoinStake()) // ppcoin: coinstake transaction { TransactionRecord sub(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut()); CTxDestination address; CTxOut txout = wtx.vout[1]; if(ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) sub.address = CBitcoinAddress(address).ToString(); parts.append(sub); } else if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated sub.type = TransactionRecord::Generated; } parts.append(sub); } } } else {
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { QString strHTML; LOCK2(cs_main, wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); int nRequests = wtx.GetRequestCount(); if (nRequests != -1) { if (nRequests == 0) strHTML += tr(", has not been successfully broadcast yet"); else if (nRequests > 0) strHTML += tr(", broadcast through %n node(s)", "", nRequests); } strHTML += "<br>"; strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; // // From // if (wtx.IsCoinBase() || wtx.IsCoinStake()) { strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) { // Online transaction strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; } else { // Offline transaction if (nNet > 0) { // Credit BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wallet->IsMine(txout)) { CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { if (wallet->mapAddressBook.count(address)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].empty()) strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; else strHTML += " (" + tr("own address") + ")"; strHTML += "<br>"; } } break; } } } }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(true); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map<std::string, std::string> mapValue = wtx.mapValue; if (nNet > 0 || wtx.IsCoinBase() || wtx.IsCoinStake()) { // // Credit - Calculate Net from CryptoLottery Rob Halford - 4-3-2015-1 // for (auto const& txout : wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated (proof-of-work) sub.type = TransactionRecord::Generated; } if (wtx.IsCoinStake()) { // Generated (proof-of-stake) if (hashPrev == hash) continue; // last coinstake output if (wtx.vout.size()==2) { //Standard POR CoinStake sub.type = TransactionRecord::Generated; sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit; hashPrev = hash; } else { //CryptoLottery - CoinStake - 4-3-2015 sub.type = TransactionRecord::Generated; if (nDebit == 0) { sub.credit = GetMyValueOut(wallet,wtx); sub.RemoteFlag = 1; } else { sub.credit = nNet > 0 ? nNet : GetMyValueOut(wallet,wtx) - nDebit; } hashPrev = hash; } } parts.append(sub); } } } else { bool fAllFromMe = true; for (auto const& txin : wtx.vin) fAllFromMe = fAllFromMe && wallet->IsMine(txin); bool fAllToMe = true; for (auto const& txout : wtx.vout) fAllToMe = fAllToMe && wallet->IsMine(txout); if (fAllFromMe && fAllToMe) { // Payment to self int64_t nChange = wtx.GetChange(); parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); } else if (fAllFromMe) { // // Debit // int64_t nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); if(wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } int64_t nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); } } return parts; }
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() { CBitcoinAddress addr(ui->addressIn_VM->text().toStdString()); if (!addr.IsValid()) { ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } CKeyID keyID; if (!addr.GetKeyID(keyID)) { ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); return; } bool fInvalid = false; std::vector<unsigned char> vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid); if (fInvalid) { ui->signatureIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again.")); return; } CDataStream ss(SER_GETHASH, 0); ss << strMessageMagic; ss << ui->messageIn_VM->document()->toPlainText().toStdString(); // get the public key from UI fInvalid = false; std::vector<unsigned char> vchPubKey = DecodeBase64(ui->pubkeyIn_VM->text().toStdString().c_str(), &fInvalid); if (fInvalid) { ui->pubkeyIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The public key could not be decoded.") + QString(" ") + tr("Please check it and try again.")); return; } CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) { ui->pubkeyIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The public key is not valid.") + QString(" ") + tr("Please check it and try again.")); return; } CKey key; if (!key.SetPubKey(pubkey)) { ui->pubkeyIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The public key cannot be added.") + QString(" ") + tr("Please check it and try again.")); return; } if (!key.Verify(HashKeccak(ss.begin(), ss.end()), vchSig)) { ui->signatureIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again.")); return; } // TODO // add the public key //key.SetPubKey(); if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")); return; } ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }"); ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>")); }
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int unit) { QString strHTML; { LOCK(wallet->cs_wallet); strHTML.reserve(4000); strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx) + "<br>"; strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; // // From // if (wtx.IsCoinBase()) { strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty()) { // Online transaction strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; } else { // Offline transaction if (nNet > 0) { // Credit BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wallet->IsMine(txout)) { CTxDestination address = CKeyID(txout.pubKey); if (wallet->IsMine(txout.pubKey)) { if (wallet->mapAddressBook.count(address)) { strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; strHTML += "<b>" + tr("To") + ":</b> "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].name.empty()) strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + ")"; else strHTML += " (" + tr("own address") + ")"; strHTML += "<br>"; } } break; } } } } // // To // if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty()) { // Online transaction std::string strAddress = wtx.mapValue["to"]; strHTML += "<b>" + tr("To") + ":</b> "; CTxDestination dest = CBitcoinAddress(strAddress).Get(); if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " "; strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>"; } // // Amount // if (nNet > 0) { // // Credit // strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nNet) + "<br>"; } else { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) fAllFromMe = fAllFromMe && wallet->IsMine(txin); bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) fAllToMe = fAllToMe && wallet->IsMine(txout); if (fAllFromMe) { // // Debit // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wallet->IsMine(txout)) continue; if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty()) { // Offline transaction CTxDestination address = CKeyID(txout.pubKey); strHTML += "<b>" + tr("To") + ":</b> "; if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); strHTML += "<br>"; } strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -txout.nValue) + "<br>"; } if (fAllToMe) { // Payment to self strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nDebit) + "<br>"; strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nCredit) + "<br>"; } uint64_t nTxFee = nDebit - wtx.GetValueOut(); if (nTxFee > 0) strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nTxFee) + "<br>"; } else { // // Mixed debit transaction // BOOST_FOREACH(const CTxIn& txin, wtx.vin) if (wallet->IsMine(txin)) strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetDebit(txin)) + "<br>"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (wallet->IsMine(txout)) strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout)) + "<br>"; } }
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients, const CCoinControl *coinControl) { qint64 total = 0; QSet<QString> setAddress; QString hex; if(recipients.empty()) { return OK; } // Pre-check input data for validity foreach(const SendCoinsRecipient &rcp, recipients) { if(!validateAddress(rcp.address)) { return InvalidAddress; } setAddress.insert(rcp.address); if(rcp.amount <= 0) { return InvalidAmount; } total += rcp.amount; } if(recipients.size() > setAddress.size()) { return DuplicateAddress; } int64_t nBalance = 0; std::vector<COutput> vCoins; wallet->AvailableCoins(vCoins, true, coinControl); BOOST_FOREACH(const COutput& out, vCoins) nBalance += out.tx->vout[out.i].nValue; if(total > nBalance) { return AmountExceedsBalance; } if((total + nTransactionFee) > nBalance) { return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee); } std::string txid = ""; std::string messages = ""; std::string hashBoinc = ""; { LOCK2(cs_main, wallet->cs_wallet); // Sendmany std::vector<std::pair<CScript, int64_t> > vecSend; bool coinTracking = false; foreach(const SendCoinsRecipient &rcp, recipients) { CScript scriptPubKey; scriptPubKey.SetDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); vecSend.push_back(make_pair(scriptPubKey, rcp.amount)); if (rcp.CoinTracking) coinTracking=true; messages += "<MESSAGE>" + AdvancedCrypt(FromQStringW(rcp.Message)) + "</MESSAGE>"; } CWalletTx wtx; CReserveKey keyChange(wallet); int64_t nFeeRequired = 0; if (coinTracking) { printf("Creating tracked tx : old hashboinc %s",wtx.hashBoinc.c_str()); wtx.hashBoinc = "<TRACK>" + wtx.GetHash().ToString() + "</TRACK>"; //Run time code execution feature - 12-7-2014 std::string q = "\""; std::string code = "MsgBox(" + q + "Hello!" + q + ",MsgBoxStyle.Critical," + q + "Message Title" + q + ")\r\n"; wtx.hashBoinc += "<CODE>" + code + "</CODE>"; } if (!msAttachmentGuid.empty()) { printf("Adding attachment to tx %s",wtx.hashBoinc.c_str()); wtx.hashBoinc += "<ATTACHMENT><TXID>" + wtx.GetHash().ToString() + "</TXID><ATTACHMENTGUID>" + msAttachmentGuid + "</ATTACHMENTGUID></ATTACHMENT>"; } wtx.hashBoinc += messages; bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, coinControl); if(!fCreated) { if((total + nFeeRequired) > nBalance) // FIXME: could cause collisions in the future { return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired); } return TransactionCreationFailed; } if (coinTracking) { printf("Tracking hashBoinc %s",wtx.hashBoinc.c_str()); } std::string samt = FormatMoney(wtx.vout[0].nValue); double dblAmt = dblFromAmount(wtx.vout[0].nValue); if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString())) { return Aborted; } if(!wallet->CommitTransaction(wtx, keyChange)) { return TransactionCommitFailed; } hex = QString::fromStdString(wtx.GetHash().GetHex()); txid = wtx.GetHash().GetHex(); hashBoinc = wtx.hashBoinc; }