Currency makeCurrency(SecretKey& issuer, std::string const& code) { Currency currency; currency.type(CURRENCY_TYPE_ALPHANUM); currency.alphaNum().issuer = issuer.getPublicKey(); strToCurrencyCode(currency.alphaNum().currencyCode, code); return currency; }
bool AllowTrustOpFrame::doCheckValid() { if (mAllowTrust.currency.type() != CURRENCY_TYPE_ALPHANUM) { innerResult().code(ALLOW_TRUST_MALFORMED); return false; } Currency ci; ci.type(CURRENCY_TYPE_ALPHANUM); ci.alphaNum().currencyCode = mAllowTrust.currency.currencyCode(); ci.alphaNum().issuer = getSourceID(); if (!isCurrencyValid(ci)) { innerResult().code(ALLOW_TRUST_MALFORMED); return false; } return true; }
bool AllowTrustOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager) { if (!(mSourceAccount->getAccount().flags & AUTH_REQUIRED_FLAG)) { // this account doesn't require authorization to hold credit innerResult().code(ALLOW_TRUST_TRUST_NOT_REQUIRED); return false; } if (!(mSourceAccount->getAccount().flags & AUTH_REVOCABLE_FLAG) && !mAllowTrust.authorize) { innerResult().code(ALLOW_TRUST_CANT_REVOKE); return false; } Currency ci; ci.type(CURRENCY_TYPE_ALPHANUM); ci.alphaNum().currencyCode = mAllowTrust.currency.currencyCode(); ci.alphaNum().issuer = getSourceID(); Database& db = ledgerManager.getDatabase(); TrustFrame::pointer trustLine; trustLine = TrustFrame::loadTrustLine(mAllowTrust.trustor, ci, db); if (!trustLine) { innerResult().code(ALLOW_TRUST_NO_TRUST_LINE); return false; } innerResult().code(ALLOW_TRUST_SUCCESS); trustLine->setAuthorized(mAllowTrust.authorize); trustLine->storeChange(delta, db); return true; }
// work backward to determine how much they need to send to get the // specified amount of currency to the recipient bool PaymentOpFrame::sendNoCreate(AccountFrame& destination, LedgerDelta& delta, LedgerManager& ledgerManager) { Database& db = ledgerManager.getDatabase(); bool multi_mode = mPayment.path.size() != 0; if (multi_mode) { innerResult().code(PAYMENT_SUCCESS_MULTI); } else { innerResult().code(PAYMENT_SUCCESS); } // tracks the last amount that was traded int64_t curBReceived = mPayment.amount; Currency curB = mPayment.currency; // update balances, walks backwards // update last balance in the chain { if (curB.type() == CURRENCY_TYPE_NATIVE) { destination.getAccount().balance += curBReceived; destination.storeChange(delta, db); } else { TrustFrame destLine; if (!TrustFrame::loadTrustLine(destination.getID(), curB, destLine, db)) { innerResult().code(PAYMENT_NO_TRUST); return false; } if (!destLine.isAuthorized()) { innerResult().code(PAYMENT_NOT_AUTHORIZED); return false; } if (!destLine.addBalance(curBReceived)) { innerResult().code(PAYMENT_LINE_FULL); return false; } destLine.storeChange(delta, db); } if (multi_mode) { innerResult().multi().last = SimplePaymentResult(destination.getID(), curB, curBReceived); } } if (multi_mode) { // now, walk the path backwards for (int i = (int)mPayment.path.size() - 1; i >= 0; i--) { int64_t curASent, actualCurBReceived; Currency const& curA = mPayment.path[i]; OfferExchange oe(delta, ledgerManager); // curA -> curB OfferExchange::ConvertResult r = oe.convertWithOffers(curA, INT64_MAX, curASent, curB, curBReceived, actualCurBReceived, nullptr); switch (r) { case OfferExchange::eFilterStop: assert(false); // no filter -> should not happen break; case OfferExchange::eOK: if (curBReceived == actualCurBReceived) { break; } // fall through case OfferExchange::ePartial: innerResult().code(PAYMENT_TOO_FEW_OFFERS); return false; } assert(curBReceived == actualCurBReceived); curBReceived = curASent; // next round, we need to send enough curB = curA; // add offers that got taken on the way // insert in front to match the path's order auto& offers = innerResult().multi().offers; offers.insert(offers.begin(), oe.getOfferTrail().begin(), oe.getOfferTrail().end()); } } // last step: we've reached the first account in the chain, update its // balance int64_t curBSent; curBSent = curBReceived; if (curBSent > mPayment.sendMax) { // make sure not over the max innerResult().code(PAYMENT_OVER_SENDMAX); return false; } if (curB.type() == CURRENCY_TYPE_NATIVE) { int64_t minBalance = mSourceAccount->getMinimumBalance(ledgerManager); if (mSourceAccount->getAccount().balance < (minBalance + curBSent)) { // they don't have enough to send innerResult().code(PAYMENT_UNDERFUNDED); return false; } mSourceAccount->getAccount().balance -= curBSent; mSourceAccount->storeChange(delta, db); } else { AccountFrame issuer; if (!AccountFrame::loadAccount(curB.alphaNum().issuer, issuer, db)) { throw std::runtime_error("sendCredit Issuer not found"); } TrustFrame sourceLineFrame; if (!TrustFrame::loadTrustLine(getSourceID(), curB, sourceLineFrame, db)) { innerResult().code(PAYMENT_UNDERFUNDED); return false; } if (!sourceLineFrame.addBalance(-curBSent)) { innerResult().code(PAYMENT_UNDERFUNDED); return false; } sourceLineFrame.storeChange(delta, db); } return true; }
bool PathPaymentOpFrame::doApply(medida::MetricsRegistry& metrics, LedgerDelta& delta, LedgerManager& ledgerManager) { AccountFrame::pointer destination; Database& db = ledgerManager.getDatabase(); destination = AccountFrame::loadAccount(mPathPayment.destination, db); if (!destination) { metrics.NewMeter({"op-path-payment", "failure", "no-destination"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_NO_DESTINATION); return false; } innerResult().code(PATH_PAYMENT_SUCCESS); // tracks the last amount that was traded int64_t curBReceived = mPathPayment.destAmount; Currency curB = mPathPayment.destCurrency; // update balances, walks backwards // build the full path to the destination, starting with sendCurrency std::vector<Currency> fullPath; fullPath.emplace_back(mPathPayment.sendCurrency); fullPath.insert(fullPath.end(), mPathPayment.path.begin(), mPathPayment.path.end()); // update last balance in the chain { if (curB.type() == CURRENCY_TYPE_NATIVE) { destination->getAccount().balance += curBReceived; destination->storeChange(delta, db); } else { TrustFrame::pointer destLine; destLine = TrustFrame::loadTrustLine(destination->getID(), curB, db); if (!destLine) { metrics.NewMeter({"op-path-payment", "failure", "no-trust"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_NO_TRUST); return false; } if (!destLine->isAuthorized()) { metrics.NewMeter( {"op-path-payment", "failure", "not-authorized"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_NOT_AUTHORIZED); return false; } if (!destLine->addBalance(curBReceived)) { metrics.NewMeter({"op-path-payment", "failure", "line-full"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_LINE_FULL); return false; } destLine->storeChange(delta, db); } innerResult().success().last = SimplePaymentResult(destination->getID(), curB, curBReceived); } // now, walk the path backwards for (int i = (int)fullPath.size() - 1; i >= 0; i--) { int64_t curASent, actualCurBReceived; Currency const& curA = fullPath[i]; if (curA == curB) { continue; } OfferExchange oe(delta, ledgerManager); // curA -> curB OfferExchange::ConvertResult r = oe.convertWithOffers(curA, INT64_MAX, curASent, curB, curBReceived, actualCurBReceived, nullptr); switch (r) { case OfferExchange::eFilterStop: assert(false); // no filter -> should not happen break; case OfferExchange::eOK: if (curBReceived == actualCurBReceived) { break; } // fall through case OfferExchange::ePartial: metrics.NewMeter({"op-path-payment", "failure", "too-few-offers"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_TOO_FEW_OFFERS); return false; } assert(curBReceived == actualCurBReceived); curBReceived = curASent; // next round, we need to send enough curB = curA; // add offers that got taken on the way // insert in front to match the path's order auto& offers = innerResult().success().offers; offers.insert(offers.begin(), oe.getOfferTrail().begin(), oe.getOfferTrail().end()); } // last step: we've reached the first account in the chain, update its // balance int64_t curBSent; curBSent = curBReceived; if (curBSent > mPathPayment.sendMax) { // make sure not over the max metrics.NewMeter({"op-path-payment", "failure", "over-send-max"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_OVER_SENDMAX); return false; } if (curB.type() == CURRENCY_TYPE_NATIVE) { int64_t minBalance = mSourceAccount->getMinimumBalance(ledgerManager); if ((mSourceAccount->getAccount().balance - curBSent) < minBalance) { // they don't have enough to send metrics.NewMeter({"op-path-payment", "failure", "underfunded"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_UNDERFUNDED); return false; } mSourceAccount->getAccount().balance -= curBSent; mSourceAccount->storeChange(delta, db); } else { AccountFrame::pointer issuer; issuer = AccountFrame::loadAccount(curB.alphaNum().issuer, db); if (!issuer) { metrics.NewMeter({"op-path-payment", "failure", "no-issuer"}, "operation").Mark(); throw std::runtime_error("sendCredit Issuer not found"); } TrustFrame::pointer sourceLineFrame; sourceLineFrame = TrustFrame::loadTrustLine(getSourceID(), curB, db); if (!sourceLineFrame) { metrics.NewMeter({"op-path-payment", "failure", "src-no-trust"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_SRC_NO_TRUST); return false; } if (!sourceLineFrame->isAuthorized()) { metrics.NewMeter( {"op-path-payment", "failure", "src-not-authorized"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_SRC_NOT_AUTHORIZED); return false; } if (!sourceLineFrame->addBalance(-curBSent)) { metrics.NewMeter({"op-path-payment", "failure", "underfunded"}, "operation").Mark(); innerResult().code(PATH_PAYMENT_UNDERFUNDED); return false; } sourceLineFrame->storeChange(delta, db); } metrics.NewMeter({"op-path-payment", "success", "apply"}, "operation") .Mark(); return true; }