// 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; }