bool
PaymentOpFrame::doApply(medida::MetricsRegistry& metrics, LedgerDelta& delta,
                        LedgerManager& ledgerManager)
{
    // if sending to self directly, just mark as success
    if (mPayment.destination == getSourceID())
    {
        metrics.NewMeter({"op-payment", "success", "apply"}, "operation")
            .Mark();
        innerResult().code(PAYMENT_SUCCESS);
        return true;
    }

    // build a pathPaymentOp
    Operation op;
    op.sourceAccount = mOperation.sourceAccount;
    op.body.type(PATH_PAYMENT);
    PathPaymentOp& ppOp = op.body.pathPaymentOp();
    ppOp.sendAsset = mPayment.asset;
    ppOp.destAsset = mPayment.asset;

    ppOp.destAmount = mPayment.amount;
    ppOp.sendMax = mPayment.amount;

    ppOp.destination = mPayment.destination;

    OperationResult opRes;
    opRes.code(opINNER);
    opRes.tr().type(PATH_PAYMENT);
    PathPaymentOpFrame ppayment(op, opRes, mParentTx);
    ppayment.setSourceAccountPtr(mSourceAccount);

    if (!ppayment.doCheckValid(metrics) ||
        !ppayment.doApply(metrics, delta, ledgerManager))
    {
        if (ppayment.getResultCode() != opINNER)
        {
            throw std::runtime_error("Unexpected error code from pathPayment");
        }
        PaymentResultCode res;

        switch (PathPaymentOpFrame::getInnerCode(ppayment.getResult()))
        {
        case PATH_PAYMENT_UNDERFUNDED:
            metrics.NewMeter({"op-payment", "failure", "underfunded"},
                             "operation").Mark();
            res = PAYMENT_UNDERFUNDED;
            break;
        case PATH_PAYMENT_SRC_NOT_AUTHORIZED:
            metrics.NewMeter({"op-payment", "failure", "src-not-authorized"},
                             "operation").Mark();
            res = PAYMENT_SRC_NOT_AUTHORIZED;
            break;
        case PATH_PAYMENT_SRC_NO_TRUST:
            metrics.NewMeter({"op-payment", "failure", "src-no-trust"},
                             "operation").Mark();
            res = PAYMENT_SRC_NO_TRUST;
            break;
        case PATH_PAYMENT_NO_DESTINATION:
            metrics.NewMeter({"op-payment", "failure", "no-destination"},
                             "operation").Mark();
            res = PAYMENT_NO_DESTINATION;
            break;
        case PATH_PAYMENT_NO_TRUST:
            metrics.NewMeter({"op-payment", "failure", "no-trust"}, "operation")
                .Mark();
            res = PAYMENT_NO_TRUST;
            break;
        case PATH_PAYMENT_NOT_AUTHORIZED:
            metrics.NewMeter({"op-payment", "failure", "not-authorized"},
                             "operation").Mark();
            res = PAYMENT_NOT_AUTHORIZED;
            break;
        case PATH_PAYMENT_LINE_FULL:
            metrics.NewMeter({"op-payment", "failure", "line-full"},
                             "operation").Mark();
            res = PAYMENT_LINE_FULL;
            break;
        case PATH_PAYMENT_NO_ISSUER:
            metrics.NewMeter({"op-payment", "failure", "no-issuer"},
                             "operation").Mark();
            res = PAYMENT_NO_ISSUER;
            break;
        default:
            throw std::runtime_error("Unexpected error code from pathPayment");
        }
        innerResult().code(res);
        return false;
    }

    assert(PathPaymentOpFrame::getInnerCode(ppayment.getResult()) ==
           PATH_PAYMENT_SUCCESS);

    metrics.NewMeter({"op-payment", "success", "apply"}, "operation").Mark();
    innerResult().code(PAYMENT_SUCCESS);

    return true;
}
bool
PaymentOpFrame::doApply(LedgerDelta& delta, LedgerManager& ledgerManager)
{
    AccountFrame destination;

    // if sending to self directly, just mark as success
    if (mPayment.destination == getSourceID())
    {
        innerResult().code(PAYMENT_SUCCESS);
        return true;
    }

    Database& db = ledgerManager.getDatabase();

    if (!AccountFrame::loadAccount(mPayment.destination, destination, db))
    {
        innerResult().code(PAYMENT_NO_DESTINATION);
        return false;
    }

    // build a pathPaymentOp
    Operation op;
    op.sourceAccount = mOperation.sourceAccount;
    op.body.type(PATH_PAYMENT);
    PathPaymentOp& ppOp = op.body.pathPaymentOp();
    ppOp.sendCurrency = mPayment.currency;
    ppOp.destCurrency = mPayment.currency;

    ppOp.destAmount = mPayment.amount;
    ppOp.sendMax = mPayment.amount;

    ppOp.destination = mPayment.destination;

    OperationResult opRes;
    opRes.code(opINNER);
    opRes.tr().type(PATH_PAYMENT);
    PathPaymentOpFrame ppayment(op, opRes, mParentTx);
    ppayment.setSourceAccountPtr(mSourceAccount);

    if (!ppayment.doCheckValid() || !ppayment.doApply(delta, ledgerManager))
    {
        if (ppayment.getResultCode() != opINNER)
        {
            throw std::runtime_error("Unexpected error code from pathPayment");
        }
        PaymentResultCode res;

        switch (PathPaymentOpFrame::getInnerCode(ppayment.getResult()))
        {
        case PATH_PAYMENT_UNDERFUNDED:
            res = PAYMENT_UNDERFUNDED;
            break;
        case PATH_PAYMENT_NO_DESTINATION:
            res = PAYMENT_NO_DESTINATION;
            break;
        case PATH_PAYMENT_NO_TRUST:
            res = PAYMENT_NO_TRUST;
            break;
        case PATH_PAYMENT_NOT_AUTHORIZED:
            res = PAYMENT_NOT_AUTHORIZED;
            break;
        case PATH_PAYMENT_LINE_FULL:
            res = PAYMENT_LINE_FULL;
            break;
        default:
            throw std::runtime_error("Unexpected error code from pathPayment");
        }
        innerResult().code(res);
        return false;
    }

    assert(PathPaymentOpFrame::getInnerCode(ppayment.getResult()) ==
           PATH_PAYMENT_SUCCESS);

    innerResult().code(PAYMENT_SUCCESS);

    return true;
}