Example #1
0
// The trade stores a copy of the Offer in string form.
// This function verifies that offer against the trade,
// and also verifies the signature on the offer.
//
// The Nym's ID is compared to offer's SenderNymID, and then the Signature
// is checked
// on the offer.  It also compares the server ID, asset and currency IDs,
// transaction #, etc
// between this trade and the offer, in order to fully verify the offer's
// authenticity.
//
bool OTTrade::VerifyOffer(OTOffer& offer) const
{
    // At this point, I have a working, loaded, model of the Offer.
    // Let's verify the thing.

    if (GetTransactionNum() != offer.GetTransactionNum()) {
        otErr << "While verifying offer, failed matching transaction number.\n";
        return false;
    }
    else if (GetNotaryID() != offer.GetNotaryID()) {
        otErr << "While verifying offer, failed matching Notary ID.\n";
        return false;
    }
    else if (GetInstrumentDefinitionID() !=
               offer.GetInstrumentDefinitionID()) {
        otErr << "While verifying offer, failed matching instrument definition "
                 "ID.\n";
        return false;
    }
    else if (GetCurrencyID() != offer.GetCurrencyID()) {
        otErr << "While verifying offer, failed matching currency type ID.\n";
        return false;
    }

    // the Offer validates properly for this Trade.
    //
    return true;
}
Example #2
0
// This is called by the client side. First you call MakeOffer() to set up the
// Offer,
// then you call IssueTrade() and pass the Offer into it here.
bool OTTrade::IssueTrade(OTOffer& offer, char stopSign, int64_t stopPrice)
{
    // Make sure the Stop Sign is within parameters (0, '<', or '>')
    if ((stopSign == 0) || (stopSign == '<') || (stopSign == '>'))
        stopSign_ = stopSign;
    else {
        otErr << "Bad data in Stop Sign while issuing trade: " << stopSign
              << "\n";
        return false;
    }

    // Make sure, if this IS a Stop order, that the price is within parameters
    // and set.
    if ((stopSign_ == '<') || (stopSign_ == '>')) {
        if (0 >= stopPrice) {
            otErr << "Expected Stop Price for trade.\n";
            return false;
        }

        stopPrice_ = stopPrice;
    }

    tradesAlreadyDone_ = 0;

    SetCreationDate(
        OTTimeGetCurrentTime()); // This time is set to TODAY NOW  (OTCronItem)

    // Validate the Notary ID, Instrument Definition ID, Currency Type ID, and
    // Date Range.
    if ((GetNotaryID() != offer.GetNotaryID()) ||
        (GetCurrencyID() != offer.GetCurrencyID()) ||
        (GetInstrumentDefinitionID() != offer.GetInstrumentDefinitionID()) ||
        (offer.GetValidFrom() < OT_TIME_ZERO) ||
        (offer.GetValidTo() < offer.GetValidFrom())) {
        return false;
    }

    //    currencyTypeID_ // This is already set in the constructors of this
    // and the offer. (And compared.)
    //    currencyAcctID_ // This is already set in the constructor of this.

    // Set the (now validated) date range as per the Offer.
    SetValidFrom(offer.GetValidFrom());
    SetValidTo(offer.GetValidTo());

    // Get the transaction number from the Offer.
    SetTransactionNum(offer.GetTransactionNum());

    // Save a copy of the offer, in XML form, here on this Trade.
    String strOffer(offer);
    marketOffer_.Set(strOffer);

    return true;
}
Example #3
0
void Cheque::UpdateContents()
{
    String INSTRUMENT_DEFINITION_ID(GetInstrumentDefinitionID()),
        NOTARY_ID(GetNotaryID()), SENDER_ACCT_ID(GetSenderAcctID()),
        SENDER_NYM_ID(GetSenderNymID()), RECIPIENT_NYM_ID(GetRecipientNymID()),
        REMITTER_NYM_ID(GetRemitterNymID()),
        REMITTER_ACCT_ID(GetRemitterAcctID());

    std::string from = formatTimestamp(GetValidFrom());
    std::string to = formatTimestamp(GetValidTo());

    // I release this because I'm about to repopulate it.
    m_xmlUnsigned.Release();

    Tag tag("cheque");

    tag.add_attribute("version", m_strVersion.Get());
    tag.add_attribute("amount", formatLong(m_lAmount));
    tag.add_attribute("instrumentDefinitionID", INSTRUMENT_DEFINITION_ID.Get());
    tag.add_attribute("transactionNum", formatLong(GetTransactionNum()));
    tag.add_attribute("notaryID", NOTARY_ID.Get());
    tag.add_attribute("senderAcctID", SENDER_ACCT_ID.Get());
    tag.add_attribute("senderNymID", SENDER_NYM_ID.Get());
    tag.add_attribute("hasRecipient", formatBool(m_bHasRecipient));
    tag.add_attribute("recipientNymID",
                      m_bHasRecipient ? RECIPIENT_NYM_ID.Get() : "");
    tag.add_attribute("hasRemitter", formatBool(m_bHasRemitter));
    tag.add_attribute("remitterNymID",
                      m_bHasRemitter ? REMITTER_NYM_ID.Get() : "");
    tag.add_attribute("remitterAcctID",
                      m_bHasRemitter ? REMITTER_ACCT_ID.Get() : "");

    tag.add_attribute("validFrom", from);
    tag.add_attribute("validTo", to);

    if (m_strMemo.Exists() && m_strMemo.GetLength() > 2) {
        OTASCIIArmor ascMemo(m_strMemo);
        tag.add_tag("memo", ascMemo.Get());
    }

    std::string str_result;
    tag.output(str_result);

    m_xmlUnsigned.Concatenate("%s", str_result.c_str());
}
// PayDividendVisitor::Trigger() is used in
// OTUnitDefinition::VisitAccountRecords()
// cppcheck-suppress unusedFunction
bool PayDividendVisitor::Trigger(
    const Account& theSharesAccount)  // theSharesAccount
                                      // is, say, a Pepsi
                                      // shares
// account.  Here, we'll send a dollars voucher
// to its owner.
{
    const std::int64_t lPayoutAmount =
        (theSharesAccount.GetBalance() * GetPayoutPerShare());

    if (lPayoutAmount <= 0) {
        otOut << "PayDividendVisitor::Trigger: nothing to pay, "
                 "since this account owns no shares. (Returning "
                 "true.)";
        return true;  // nothing to pay, since this account owns no shares.
                      // Success!
    }
    OT_ASSERT(false == GetNotaryID()->empty());
    const auto theNotaryID = GetNotaryID();
    OT_ASSERT(!GetPayoutUnitTypeId()->empty());
    const Identifier& payoutUnitTypeId_ = (Identifier::Factory());
    OT_ASSERT(!GetVoucherAcctID()->empty());
    const Identifier& theVoucherAcctID = (GetVoucherAcctID());
    Nym& theServerNym = const_cast<Nym&>(server_.GetServerNym());
    const auto theServerNymID = Identifier::Factory(theServerNym);
    const Identifier& RECIPIENT_ID = theSharesAccount.GetNymID();
    OT_ASSERT(!GetNymID()->empty());
    const Identifier& theSenderNymID = (GetNymID());
    OT_ASSERT(!GetMemo()->empty());
    const String& strMemo = (GetMemo());
    // Note: theSenderNymID is the originator of the Dividend Payout.
    // However, all the actual vouchers will be from "the server Nym" and
    // not from theSenderNymID. So then why is it even here? Because anytime
    // there's an error, the server will send to theSenderNymID instead of
    // RECIPIENT_ID (so the original sender can have his money back, instead of
    // just having it get lost in the ether.)
    bool bReturnValue = false;

    auto theVoucher{
        server_.API().Factory().Cheque(theNotaryID, Identifier::Factory())};

    OT_ASSERT(false != bool(theVoucher));

    // 10 minutes ==    600 Seconds
    // 1 hour    ==     3600 Seconds
    // 1 day    ==    86400 Seconds
    // 30 days    ==  2592000 Seconds
    // 3 months ==  7776000 Seconds
    // 6 months == 15552000 Seconds

    const time64_t VALID_FROM =
        OTTimeGetCurrentTime();  // This time is set to TODAY NOW
    const time64_t VALID_TO = OTTimeAddTimeInterval(
        VALID_FROM,
        OTTimeGetSecondsFromTime(OT_TIME_SIX_MONTHS_IN_SECONDS));  // This time
                                                                   // occurs in
    // 180 days (6 months).
    // Todo hardcoding.
    TransactionNumber lNewTransactionNumber = 0;
    auto context = server_.API().Wallet().mutable_ClientContext(
        theServerNym.ID(), theServerNym.ID());
    bool bGotNextTransNum =
        server_.GetTransactor().issueNextTransactionNumberToNym(
            context.It(), lNewTransactionNumber);  // We save the transaction
    // number on the server Nym (normally we'd discard it) because
    // when the cheque is deposited, the server nym, as the owner of
    // the voucher account, needs to verify the transaction # on the
    // cheque (to prevent double-spending of cheques.)
    if (bGotNextTransNum) {
        const bool bIssueVoucher = theVoucher->IssueCheque(
            lPayoutAmount,          // The amount of the cheque.
            lNewTransactionNumber,  // Requiring a transaction number prevents
                                    // double-spending of cheques.
            VALID_FROM,  // The expiration date (valid from/to dates) of the
                         // cheque
            VALID_TO,  // Vouchers are automatically starting today and lasting
                       // 6
                       // months.
            theVoucherAcctID,  // The asset account the cheque is drawn on.
            theServerNymID,    // Nym ID of the sender (in this case the server
                               // nym.)
            strMemo,  // Optional memo field. Includes item note and request
                      // memo.
            Identifier::Factory(RECIPIENT_ID));

        // All account crediting / debiting happens in the caller, in
        // server::Server.
        //    (AND it happens only ONCE, to cover ALL vouchers.)
        // Then in here, the voucher either gets send to the recipient, or if
        // error, sent back home to
        // the issuer Nym. (ALL the funds are removed, then the vouchers are
        // sent one way or the other.)
        // Any returned vouchers, obviously serve to notify the dividend payer
        // of where the errors were
        // (as well as give him the opportunity to get his money back.)
        //
        bool bSent = false;
        if (bIssueVoucher) {
            // All this does is set the voucher's internal contract string to
            // "VOUCHER" instead of "CHEQUE". We also set the server itself as
            // the remitter, which is unusual for vouchers, but necessary in the
            // case of dividends.
            //
            theVoucher->SetAsVoucher(theServerNymID, theVoucherAcctID);
            theVoucher->SignContract(theServerNym);
            theVoucher->SaveContract();

            // Send the voucher to the payments inbox of the recipient.
            //
            const auto strVoucher = String::Factory(*theVoucher);
            auto thePayment{server_.API().Factory().Payment(strVoucher)};

            OT_ASSERT(false != bool(thePayment));

            // calls DropMessageToNymbox
            bSent = server_.SendInstrumentToNym(
                theNotaryID,
                theServerNymID,  // sender nym
                RECIPIENT_ID,    // recipient nym
                *thePayment,
                "payDividend");    // todo: hardcoding.
            bReturnValue = bSent;  // <======= RETURN VALUE.
            if (bSent)
                m_lAmountPaidOut +=
                    lPayoutAmount;  // At the end of iterating all accounts, if
                                    // m_lAmountPaidOut is less than
            // lTotalPayoutAmount, then we return to rest
            // to the sender.
        } else {
            const auto strPayoutUnitTypeId = String::Factory(
                           Identifier::Factory(payoutUnitTypeId_)),
                       strRecipientNymID = String::Factory(RECIPIENT_ID);
            otErr << "PayDividendVisitor::Trigger: ERROR failed issuing "
                  << "voucher (to send to dividend payout recipient.) WAS "
                  << "TRYING TO PAY " << lPayoutAmount
                  << " of instrument definition " << strPayoutUnitTypeId
                  << " to Nym " << strRecipientNymID << ".\n";
        }
        // If we didn't send it, then we need to return the funds to where they
        // came from.
        //
        if (!bSent) {
            auto theReturnVoucher{server_.API().Factory().Cheque(
                theNotaryID, Identifier::Factory())};

            OT_ASSERT(false != bool(theReturnVoucher));

            const bool bIssueReturnVoucher = theReturnVoucher->IssueCheque(
                lPayoutAmount,          // The amount of the cheque.
                lNewTransactionNumber,  // Requiring a transaction number
                                        // prevents double-spending of cheques.
                VALID_FROM,  // The expiration date (valid from/to dates) of the
                             // cheque
                VALID_TO,    // Vouchers are automatically starting today and
                             // lasting 6 months.
                theVoucherAcctID,  // The asset account the cheque is drawn on.
                theServerNymID,    // Nym ID of the sender (in this case the
                                   // server nym.)
                strMemo,  // Optional memo field. Includes item note and request
                          // memo.
                Identifier::Factory(theSenderNymID));  // We're returning the
                                                       // money to its original
                                                       // sender.
            if (bIssueReturnVoucher) {
                // All this does is set the voucher's internal contract string
                // to
                // "VOUCHER" instead of "CHEQUE".
                //
                theReturnVoucher->SetAsVoucher(
                    theServerNymID, theVoucherAcctID);
                theReturnVoucher->SignContract(theServerNym);
                theReturnVoucher->SaveContract();

                // Return the voucher back to the payments inbox of the original
                // sender.
                //
                const auto strReturnVoucher =
                    String::Factory(*theReturnVoucher);
                auto theReturnPayment{
                    server_.API().Factory().Payment(strReturnVoucher)};

                OT_ASSERT(false != bool(theReturnPayment));

                // calls DropMessageToNymbox
                bSent = server_.SendInstrumentToNym(
                    theNotaryID,
                    theServerNymID,  // sender nym
                    theSenderNymID,  // recipient nym (original sender.)
                    *theReturnPayment,
                    "payDividend");  // todo: hardcoding.
                if (bSent)
                    m_lAmountReturned +=
                        lPayoutAmount;  // At the end of iterating all accounts,
                                        // if m_lAmountPaidOut+m_lAmountReturned
                                        // is less than lTotalPayoutAmount, then
                                        // we return the rest to the sender.
            } else {
                const auto strPayoutUnitTypeId =
                               String::Factory(payoutUnitTypeId_),
                           strSenderNymID = String::Factory(theSenderNymID);
                otErr << "PayDividendVisitor::Trigger: ERROR "
                         "failed issuing voucher (to return back to "
                         "the dividend payout initiator, after a failed "
                         "payment attempt to the originally intended "
                         "recipient.) WAS TRYING TO PAY "
                      << lPayoutAmount << " of instrument definition "
                      << strPayoutUnitTypeId << " to Nym " << strSenderNymID
                      << ".\n";
            }
        }   // if !bSent
    } else  // !bGotNextTransNum
    {
        const auto strPayoutUnitTypeId = String::Factory(payoutUnitTypeId_),
                   strRecipientNymID = String::Factory(RECIPIENT_ID);
        otErr << OT_METHOD << __FUNCTION__
              << ": ERROR!! Failed issuing next transaction number while "
              << "trying to send a voucher (while paying dividends.) "
              << "WAS TRYING TO PAY " << lPayoutAmount
              << " of instrument definition " << strPayoutUnitTypeId->Get()
              << " to Nym " << strRecipientNymID->Get() << ".\n";
    }

    return bReturnValue;
}