void transfer(std::shared_ptr<WalletInfo> walletInfo) { std::cout << InformationMsg("Note: You can type cancel at any time to " "cancel the transaction") << std::endl << std::endl; uint64_t balance = walletInfo->wallet.getActualBalance(); auto maybeAddress = getDestinationAddress(); if (!maybeAddress.isJust) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } std::string address = maybeAddress.x; auto maybeAmount = getTransferAmount(); if (!maybeAmount.isJust) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } uint64_t amount = maybeAmount.x; if (balance < amount) { std::cout << WarningMsg("You don't have enough funds to cover this " "transaction!") << std::endl << InformationMsg("Funds needed: " + formatAmount(amount)) << std::endl << SuccessMsg("Funds available: " + formatAmount(balance)) << std::endl; return; } auto maybeFee = getFee(); if (!maybeFee.isJust) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } uint64_t fee = maybeFee.x; if (balance < amount + fee) { std::cout << WarningMsg("You don't have enough funds to cover this " "transaction!") << std::endl << InformationMsg("Funds needed: " + formatAmount(amount + fee)) << std::endl << SuccessMsg("Funds available: " + formatAmount(balance)) << std::endl; return; } auto maybeMixin = getMixin(); if (!maybeMixin.isJust) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } uint16_t mixin = maybeMixin.x; auto maybeExtra = getPaymentID(); if (!maybeExtra.isJust) { std::cout << WarningMsg("Cancelling transaction.") << std::endl; return; } std::string extra = maybeExtra.x; doTransfer(mixin, address, amount, fee, extra, walletInfo); }
bool BlockchainExplorerDataBuilder::fillTransactionDetails(const Transaction& transaction, TransactionDetails& transactionDetails, uint64_t timestamp) { Crypto::Hash hash = getObjectHash(transaction); transactionDetails.hash = hash; transactionDetails.timestamp = timestamp; Crypto::Hash blockHash; uint32_t blockHeight; if (!core.getBlockContainingTx(hash, blockHash, blockHeight)) { transactionDetails.inBlockchain = false; transactionDetails.blockHeight = boost::value_initialized<uint32_t>(); transactionDetails.blockHash = boost::value_initialized<Crypto::Hash>(); } else { transactionDetails.inBlockchain = true; transactionDetails.blockHeight = blockHeight; transactionDetails.blockHash = blockHash; if (timestamp == 0) { Block block; if (!core.getBlockByHash(blockHash, block)) { return false; } transactionDetails.timestamp = block.timestamp; } } transactionDetails.size = getObjectBinarySize(transaction); transactionDetails.unlockTime = transaction.unlockTime; transactionDetails.totalOutputsAmount = get_outs_money_amount(transaction); uint64_t inputsAmount; if (!get_inputs_money_amount(transaction, inputsAmount)) { return false; } transactionDetails.totalInputsAmount = inputsAmount; if (transaction.inputs.size() > 0 && transaction.inputs.front().type() == typeid(BaseInput)) { //It's gen transaction transactionDetails.fee = 0; transactionDetails.mixin = 0; } else { uint64_t fee; if (!get_tx_fee(transaction, fee)) { return false; } transactionDetails.fee = fee; uint64_t mixin; if (!getMixin(transaction, mixin)) { return false; } transactionDetails.mixin = mixin; } Crypto::Hash paymentId; if (getPaymentId(transaction, paymentId)) { transactionDetails.paymentId = paymentId; } else { transactionDetails.paymentId = boost::value_initialized<Crypto::Hash>(); } fillTxExtra(transaction.extra, transactionDetails.extra); transactionDetails.signatures.reserve(transaction.signatures.size()); for (const std::vector<Crypto::Signature>& signatures : transaction.signatures) { std::vector<Crypto::Signature> signaturesDetails; signaturesDetails.reserve(signatures.size()); for (const Crypto::Signature& signature : signatures) { signaturesDetails.push_back(std::move(signature)); } transactionDetails.signatures.push_back(std::move(signaturesDetails)); } transactionDetails.inputs.reserve(transaction.inputs.size()); for (const TransactionInput& txIn : transaction.inputs) { TransactionInputDetails txInDetails; if (txIn.type() == typeid(BaseInput)) { TransactionInputGenerateDetails txInGenDetails; txInGenDetails.height = boost::get<BaseInput>(txIn).blockIndex; txInDetails.amount = 0; for (const TransactionOutput& out : transaction.outputs) { txInDetails.amount += out.amount; } txInDetails.input = txInGenDetails; } else if (txIn.type() == typeid(KeyInput)) { TransactionInputToKeyDetails txInToKeyDetails; const KeyInput& txInToKey = boost::get<KeyInput>(txIn); std::list<std::pair<Crypto::Hash, size_t>> outputReferences; if (!core.scanOutputkeysForIndices(txInToKey, outputReferences)) { return false; } txInDetails.amount = txInToKey.amount; txInToKeyDetails.outputIndexes = txInToKey.outputIndexes; txInToKeyDetails.keyImage = txInToKey.keyImage; txInToKeyDetails.mixin = txInToKey.outputIndexes.size(); txInToKeyDetails.output.number = outputReferences.back().second; txInToKeyDetails.output.transactionHash = outputReferences.back().first; txInDetails.input = txInToKeyDetails; } else if (txIn.type() == typeid(MultisignatureInput)) { TransactionInputMultisignatureDetails txInMultisigDetails; const MultisignatureInput& txInMultisig = boost::get<MultisignatureInput>(txIn); txInDetails.amount = txInMultisig.amount; txInMultisigDetails.signatures = txInMultisig.signatureCount; std::pair<Crypto::Hash, size_t> outputReference; if (!core.getMultisigOutputReference(txInMultisig, outputReference)) { return false; } txInMultisigDetails.output.number = outputReference.second; txInMultisigDetails.output.transactionHash = outputReference.first; txInDetails.input = txInMultisigDetails; } else { return false; } transactionDetails.inputs.push_back(std::move(txInDetails)); } transactionDetails.outputs.reserve(transaction.outputs.size()); std::vector<uint32_t> globalIndices; globalIndices.reserve(transaction.outputs.size()); if (!transactionDetails.inBlockchain || !core.get_tx_outputs_gindexs(hash, globalIndices)) { for (size_t i = 0; i < transaction.outputs.size(); ++i) { globalIndices.push_back(0); } } typedef boost::tuple<TransactionOutput, uint32_t> outputWithIndex; auto range = boost::combine(transaction.outputs, globalIndices); for (const outputWithIndex& txOutput : range) { TransactionOutputDetails txOutDetails; txOutDetails.amount = txOutput.get<0>().amount; txOutDetails.globalIndex = txOutput.get<1>(); if (txOutput.get<0>().target.type() == typeid(KeyOutput)) { TransactionOutputToKeyDetails txOutToKeyDetails; txOutToKeyDetails.txOutKey = boost::get<KeyOutput>(txOutput.get<0>().target).key; txOutDetails.output = txOutToKeyDetails; } else if (txOutput.get<0>().target.type() == typeid(MultisignatureOutput)) { TransactionOutputMultisignatureDetails txOutMultisigDetails; MultisignatureOutput txOutMultisig = boost::get<MultisignatureOutput>(txOutput.get<0>().target); txOutMultisigDetails.keys.reserve(txOutMultisig.keys.size()); for (const Crypto::PublicKey& key : txOutMultisig.keys) { txOutMultisigDetails.keys.push_back(std::move(key)); } txOutMultisigDetails.requiredSignatures = txOutMultisig.requiredSignatureCount; txOutDetails.output = txOutMultisigDetails; } else { return false; } transactionDetails.outputs.push_back(std::move(txOutDetails)); } return true; }