// 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; }
// 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 theOffer's SenderUserID, 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 & theOffer) { // At this point, I have a working, loaded, model of the Offer. // Let's verify the thing. if (GetTransactionNum() != theOffer.GetTransactionNum()) { OTLog::Error("While verifying offer, failed matching transaction number.\n"); return false; } else if (GetServerID() != theOffer.GetServerID()) { OTLog::Error("While verifying offer, failed matching Server ID.\n"); return false; } else if (GetAssetID() != theOffer.GetAssetID()) { OTLog::Error("While verifying offer, failed matching asset type ID.\n"); return false; } else if (GetCurrencyID() != theOffer.GetCurrencyID()) { OTLog::Error("While verifying offer, failed matching currency type ID.\n"); return false; } // the Offer validates properly for this Trade. return true; }
// 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 & theOffer, char cStopSign/*=0*/, long lStopPrice/*=0*/) { // Make sure the Stop Sign is within parameters (0, '<', or '>') if ((cStopSign == 0 ) || (cStopSign == '<') || (cStopSign == '>')) m_cStopSign = cStopSign; else { OTLog::vError("Bad data in Stop Sign while issuing trade: %c\n", cStopSign); return false; } // Make sure, if this IS a Stop order, that the price is within parameters and set. if ((m_cStopSign == '<') || (m_cStopSign == '>')) { if (0 >= lStopPrice) { OTLog::Error("Expected Stop Price for trade.\n"); return false; } m_lStopPrice = lStopPrice; } m_nTradesAlreadyDone = 0; SetCreationDate(time(NULL)); // This time is set to TODAY NOW (OTCronItem) // ------------------------------------------------------------------------ // Validate the Server ID, Asset Type ID, Currency Type ID, and Date Range. if ((GetServerID() != theOffer.GetServerID()) || (GetCurrencyID() != theOffer.GetCurrencyID()) || (GetAssetID() != theOffer.GetAssetID()) || (theOffer.GetValidFrom() < 0) || (theOffer.GetValidTo() < theOffer.GetValidFrom()) ) { return false; } // m_CURRENCY_TYPE_ID // This is already set in the constructors of this and the offer. (And compared.) // m_CURRENCY_ACCT_ID // This is already set in the constructor of this. // Set the (now validated) date range as per the Offer. SetValidFrom(theOffer.GetValidFrom()); SetValidTo(theOffer.GetValidTo()); // Get the transaction number from the Offer. SetTransactionNum(theOffer.GetTransactionNum()); // Save a copy of the offer, in XML form, here on this Trade. OTString strOffer(theOffer); m_strOffer.Set(strOffer); return true; }
// 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; }
// Assuming the offer is ON the market, this will get the pointer to that offer. // Otherwise it will try to add it to the market. // Otherwise it will fail. (Perhaps it's a stop order, and not ready to activate // yet.) // OTOffer* OTTrade::GetOffer(Identifier* offerMarketId, OTMarket** market) { OT_ASSERT(GetCron() != nullptr); // See if the offer has already been instantiated onto a market... if (offer_ != nullptr) { offer_->SetTrade(*this); // Probably don't need this line. I'll remove // it someday while optimizing. // In fact since it should already be set, having this here would // basically // hide it from me if the memory was ever walked on from a bug // somewhere. // It loaded. Let's get the Market ID off of it so we can locate the // market. const Identifier OFFER_MARKET_ID(*offer_); if (market != nullptr) { OTMarket* pMarket = GetCron()->GetMarket(OFFER_MARKET_ID); // Sometimes the caller function would like a copy of this market // pointer, when available. // So I pass it back to him here, if he wants. That way he doesn't // have to do this work again // to look it up. if (pMarket != nullptr) *market = pMarket; // <================= else otErr << "OTTrade::" << __FUNCTION__ << ": offer_ already exists, yet unable to find the " "market it's supposed to be on.\n"; } if (offerMarketId != nullptr) { // Sometimes the caller function would like a copy of this ID. So I // give the option to pass in a pointer so I can give it here. offerMarketId->Assign(OFFER_MARKET_ID); } return offer_; } // if offer_ ALREADY EXISTS. // else (BELOW) offer_ IS nullptr, and thus it didn't exist yet... if (!marketOffer_.Exists()) { otErr << "OTTrade::GetOffer called with empty marketOffer_.\n"; return nullptr; } OTOffer* offer = new OTOffer(); OT_ASSERT(offer != nullptr); // Trying to load the offer from the trader's original signed request // (So I can use it to lookup the Market ID, so I can see the offer is // already there on the market.) if (!offer->LoadContractFromString(marketOffer_)) { otErr << "Error loading offer from string in OTTrade::GetOffer\n"; delete offer; offer = nullptr; return nullptr; } // No need to do any additional security verification here on the Offer, // since the Offer is already heavily verified in // OTServer::NotarizeMarketOffer(). // So as long as you feel safe about the Trade, then you can feel safe about // the Offer already, with no further checks. // *Also remember we saved a copy of the original in the cron folder. // It loaded. Let's get the Market ID off of it so we can locate the market. Identifier OFFER_MARKET_ID(*offer); if (offerMarketId != nullptr) { // Sometimes the caller function would like a copy of this ID. So I // give the option to pass in a pointer so I can give it here. offerMarketId->Assign(OFFER_MARKET_ID); } // Previously if a user tried to use a market that didn't exist, I'd just // return failure. // But now we will create any market that doesn't already exist. // (Remember, the server operator could just erase the market folder--it // wouldn't // affect anyone's balances!) Update: he probably couldn't just wipe the // markets folder, // actually, without making it impossible for certain Nyms to get rid of // certain issued #s. // // OTMarket * pMarket = m_cron->GetMarket(OFFER_MARKET_ID); OTMarket* pMarket = GetCron()->GetOrCreateMarket( GetInstrumentDefinitionID(), GetCurrencyID(), offer->GetScale()); // Couldn't find (or create) the market. if (pMarket == nullptr) { otOut << "OTTrade::" << __FUNCTION__ << ": Unable to find or create market within requested parameters."; delete offer; offer = nullptr; return nullptr; } // If the caller passed in the address of a market pointer (optional) if (market != nullptr) { // Sometimes the caller function would like a copy of this market // pointer, when available. // So I pass it back to him here, if he wants. That way he doesn't have // to do this work again // to look it up. *market = pMarket; } // At this point, I have heap-allocated the offer, used it to get the Market // ID, and successfully // used that to get a pointer to the market matching that ID. // // Let's see if the offer is ALREADY allocated and on this market! // If so, delete the one I just allocated. If not, add it to the market. OTOffer* marketOffer = pMarket->GetOffer(offer->GetTransactionNum()); // The Offer is already on the Market. // NOTE: It may just start out this way, without ever being added. // How is that possible? Because maybe it was in the market file when we // first loaded up, // and had been added on some previous run of the software. So since we // started running, // the pMarket->AddOffer() code below has literally never run for that // offer. Instead we // first find it here, and thus return the pointer before getting any // farther. // // IN ALL CASES, we make sure to call offer_->SetTrade() so that it has a // pointer BACK to // this Trade object! (When actually processing the offer, the market will // need the account // numbers and Nym IDs... which are stored here on the trade.) if (marketOffer != nullptr) { offer_ = marketOffer; // Since the Offer already exists on the market, no need anymore for the // one we allocated above (to get the market ID.) So we delete it now. delete offer; offer = nullptr; offer_->SetTrade(*this); return offer_; } // Okay so the offer ISN'T already on the market. If it's not a stop order, // let's ADD the one we // allocated to the market now! (Stop orders are activated through their own // logic, which is below // this, in the else block.) // if (!IsStopOrder()) { if (hasTradeActivated_) { // Error -- how has the trade already activated, yet not on the // market and null in my pointer? otErr << "How has the trade already activated, yet not on the " "market and null in my pointer?\n"; } else if (!pMarket->AddOffer(this, *offer, true)) // Since we're // actually adding // an offer to the // market (not just { // loading from disk) the we actually want to save the market. // bSaveFile=true. // Error adding the offer to the market! otErr << "Error adding the offer to the market! (Even though " "supposedly the right market.)\n"; } else { // SUCCESS! offer_ = offer; hasTradeActivated_ = true; // The Trade (stored on Cron) has a copy of the Original Offer, with // the User's signature on it. // A copy of that original Trade object (itself with the user's // signature) is already stored in // the cron folder (by transaction number.) This happens when the // Trade is FIRST added to cron, // so it's already safe before we even get here. // // So thus I am FREE to release the signatures on the offer, and // sign with the server instead. // The server-signed offer will be stored by the OTMarket. offer_->ReleaseSignatures(); offer_->SignContract(*(GetCron()->GetServerNym())); offer_->SaveContract(); pMarket->SaveMarket(); // Now when the market loads next time, it can verify this offer // using the server's signature, // instead of having to load the user. Because the server has // verified it and added it, and now // signs it, vouching for it. // The Trade itself (all its other variables) are now allowed to // change, since its signatures // are also released and it is now server-signed. (With a copy // stored of the original.) offer_->SetTrade(*this); return offer_; } } // It's a stop order, and not activated yet. // Should we activate it now? // else if (IsStopOrder() && !stopActivated_) { int64_t relevantPrice = 0; // If the stop order is trying to sell something, then it cares about // the highest bidder. if (offer->IsAsk()) relevantPrice = pMarket->GetHighestBidPrice(); else // But if the stop order is trying to buy something, then it cares // about the lowest ask price. relevantPrice = pMarket->GetLowestAskPrice(); // It's a stop order that hasn't activated yet. SHOULD IT ACTIVATE NOW? if ((IsGreaterThan() && (relevantPrice > GetStopPrice())) || (IsLessThan() && (relevantPrice < GetStopPrice()))) { // Activate the stop order! if (!pMarket->AddOffer(this, *offer, true)) // Since we're actually // adding an offer to // the market (not just { // loading from disk) the we actually want to save the market. // Error adding the offer to the market! // bSaveFile=true. otErr << "Error adding the stop order to the market! (Even " "though supposedly the right market.)\n"; } else { // SUCCESS! offer_ = offer; stopActivated_ = true; hasTradeActivated_ = true; // The Trade (stored on Cron) has a copy of the Original Offer, // with the User's signature on it. // A copy of that original Trade object (itself with the user's // signature) is already stored in // the cron folder (by transaction number.) This happens when // the Trade is FIRST added to cron, // so it's already safe before we even get here. // // So thus I am FREE to release the signatures on the offer, and // sign with the server instead. // The server-signed offer will be stored by the OTMarket. offer_->ReleaseSignatures(); offer_->SignContract(*(GetCron()->GetServerNym())); offer_->SaveContract(); pMarket->SaveMarket(); // Now when the market loads next time, it can verify this offer // using the server's signature, // instead of having to load the user. Because the server has // verified it and added it, and now // signs it, vouching for it. // The Trade itself (all its other variables) are now allowed to // change, since its signatures // are also released and it is now server-signed. (With a copy // stored of the original.) offer_->SetTrade(*this); return offer_; } } } delete offer; offer = nullptr; return nullptr; }
// Assuming the offer is ON the market, this will get the pointer to that offer. // Otherwise it will try to add it to the market. OTOffer * OTTrade::GetOffer(OTIdentifier * pOFFER_MARKET_ID/*=NULL*/, OTMarket ** ppMarket/*=NULL*/) { OT_ASSERT(NULL != GetCron()); // See if the offer has already been instantiated. if (NULL != m_pOffer) { m_pOffer->SetTrade(*this); // Probably don't need this one. I'll remove it someday while optimizing. return m_pOffer; // In fact since it should already be set, having this here would basically // hide it from me if the memory was ever walked on from a bug somewhere. } if (!m_strOffer.Exists()) { OTLog::Error("OTTrade::GetOffer called with empty m_strOffer.\n"); return NULL; } OTOffer * pOffer = new OTOffer(); OT_ASSERT(NULL != pOffer); // -------------------------------------------------- // Trying to load the offer from the trader's original signed request // (So I can use it to lookup the Market ID, so I can see the offer is // already there on the market.) if (!pOffer->LoadContractFromString(m_strOffer)) { OTLog::Error("Error loading offer from string in OTTrade::GetOffer\n"); delete pOffer; pOffer = NULL; return NULL; } // No need to do any additional security verification here on the Offer, // since the Offer is already heavily verified in OTServer::NotarizeMarketOffer(). // So as long as you feel safe about the Trade, then you can feel safe about // the Offer already, with no further checks. // *Also remember we saved a copy of the original in the cron folder. // It loaded. Let's get the Market ID off of it so we can locate the market. OTIdentifier OFFER_MARKET_ID(*pOffer); if (NULL != pOFFER_MARKET_ID) { // Sometimes the caller function would like a copy of this ID. So I // give the option to pass in a pointer so I can give it here. pOFFER_MARKET_ID->Assign(OFFER_MARKET_ID); } // Previously if a user tried to use a market that didn't exist, I'd just return failure. // But now we will create any market that doesn't already exist. // (Remember, the server operator could just erase the market folder--it wouldn't // affect anyone's balances!) // // OTMarket * pMarket = m_pCron->GetMarket(OFFER_MARKET_ID); OTMarket * pMarket = GetCron()->GetOrCreateMarket(GetAssetID(), GetCurrencyID(), pOffer->GetScale()); // Couldn't find (or create) the market. if (NULL == pMarket) { OTLog::Output(3, "Unable to find or create market within requested parameters in OTTrade::GetOffer."); delete pOffer; pOffer = NULL; return NULL; } // If the caller passed in the address of a market pointer (optional) if (NULL != ppMarket) { // Sometimes the caller function would like a copy of this market pointer, when available. // So I pass it back to him here, if he wants. That way he doesn't have to do this work again // to look it up. *ppMarket = pMarket; } // -------------------------------------------------- // At this point, I have heap-allocated the offer, used it to get the Market ID, and successfully // used that to get a pointer to the market matching that ID. // // Let's see if the offer is ALREADY allocated and on this market! // If so, delete the one I just allocated. If not, add it to the market. OTOffer * pMarketOffer = pMarket->GetOffer(pOffer->GetTransactionNum()); // The Offer is already on the Market. // NOTE: It may just start out this way, without ever being added. // How is that possible? Because maybe it was in the market file when we first loaded up, // and had been added on some previous run of the software. So since we started running, // the pMarket->AddOffer() code below has literally never run for that offer. Instead we // first find it here, and thus return the pointer before getting any farther. // // IN ALL CASES, we make sure to call m_pOffer->SetTrade() so that it has a pointer BACK to // this Trade object! (When actually processing the offer, the market will need the account // numbers and Nym IDs... which are stored here on the trade.) if (NULL != pMarketOffer) { m_pOffer = pMarketOffer; // Since the Offer already exists on the market, no need anymore for the // one we allocated above (to get the market ID.) So we delete it now. delete pOffer; pOffer = NULL; m_pOffer->SetTrade(*this); return m_pOffer; } // Okay so the offer ISN'T already on the market. If it's not a stop order, let's ADD the one we // allocated to the market now! (Stop orders are activated through their own logic, which is in the else.) if (!IsStopOrder()) { if (m_bHasTradeActivated) { // Error -- how has the trade already activated, yet not on the market and null in my pointer? OTLog::Error("How has the trade already activated, yet not on the market and null in my pointer?\n"); } else if (!pMarket->AddOffer(*pOffer, true)) // Since we're actually adding an offer to the market (not just { // loading from disk) the we actually want to save the market. bSaveFile=true. // Error adding the offer to the market! OTLog::Error("Error adding the offer to the market! (Even though supposedly the right market.)\n"); } else { // SUCCESS! m_pOffer = pOffer; m_bHasTradeActivated = true; // The Trade (stored on Cron) has a copy of the Original Offer, with the User's signature on it. // A copy of that original Trade object (itself with the user's signature) is already stored in // the cron folder (by transaction number.) This happens when the Trade is FIRST added to cron, // so it's already safe before we even get here. // // So thus I am FREE to release the signatures on the offer, and sign with the server instead. // The server-signed offer will be stored by the OTMarket. m_pOffer->ReleaseSignatures(); m_pOffer->SignContract(*(GetCron()->GetServerNym())); m_pOffer->SaveContract(); pMarket->SaveMarket(); // Now when the market loads next time, it can verify this offer using the server's signature, // instead of having to load the user. Because the server has verified it and added it, and now // signs it, vouching for it. // The Trade itself (all its other variables) are now allowed to change, since its signatures // are also released and it is now server-signed. (With a copy stored of the original.) m_pOffer->SetTrade(*this); return m_pOffer; } } else if(IsStopOrder() && !m_bHasStopActivated) // It's a stop order. Should we activate it now? { long lRelevantPrice = 0; // If the stop order is trying to sell something, then it cares about the highest bidder. if (pOffer->IsAsk()) lRelevantPrice = pMarket->GetHighestBidPrice(); else // But if the stop order is trying to buy something, then it cares about the lowest ask price. lRelevantPrice = pMarket->GetLowestAskPrice(); // It's a stop order that hasn't activated yet. SHOULD IT ACTIVATE NOW? if ((IsGreaterThan() && (lRelevantPrice > GetStopPrice())) || (IsLessThan() && (lRelevantPrice < GetStopPrice()))) { // Activate the stop order! if (!pMarket->AddOffer(*pOffer, true)) // Since we're actually adding an offer to the market (not just { // loading from disk) the we actually want to save the market. bSaveFile=true. // Error adding the offer to the market! OTLog::Error("Error adding the stop order to the market! (Even though supposedly the right market.)\n"); } else { // SUCCESS! m_pOffer = pOffer; m_bHasStopActivated = true; m_bHasTradeActivated = true; // The Trade (stored on Cron) has a copy of the Original Offer, with the User's signature on it. // A copy of that original Trade object (itself with the user's signature) is already stored in // the cron folder (by transaction number.) This happens when the Trade is FIRST added to cron, // so it's already safe before we even get here. // // So thus I am FREE to release the signatures on the offer, and sign with the server instead. // The server-signed offer will be stored by the OTMarket. m_pOffer->ReleaseSignatures(); m_pOffer->SignContract(*(GetCron()->GetServerNym())); m_pOffer->SaveContract(); pMarket->SaveMarket(); // Now when the market loads next time, it can verify this offer using the server's signature, // instead of having to load the user. Because the server has verified it and added it, and now // signs it, vouching for it. // The Trade itself (all its other variables) are now allowed to change, since its signatures // are also released and it is now server-signed. (With a copy stored of the original.) m_pOffer->SetTrade(*this); return m_pOffer; } } } delete pOffer; pOffer = NULL; return NULL; }