// 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; }
bool OTCron::GetMarketList (OTASCIIArmor & ascOutput, int & nMarketCount) { nMarketCount = 0; // This parameter is set to zero here, and incremented in the loop below. // ------------------------ OTMarket * pMarket = NULL; OTDB::MarketList * pMarketList = dynamic_cast<OTDB::MarketList*>(OTDB::CreateObject(OTDB::STORED_OBJ_MARKET_LIST)); OTCleanup<OTDB::MarketList> theListAngel(*pMarketList); // ----------------------------------------------------------- for (mapOfMarkets::iterator ii = m_mapMarkets.begin(); ii != m_mapMarkets.end(); ++ii) { pMarket = (*ii).second; OT_ASSERT(NULL != pMarket); OTDB::MarketData * pMarketData = dynamic_cast<OTDB::MarketData *>(OTDB::CreateObject(OTDB::STORED_OBJ_MARKET_DATA)); OTCleanup<OTDB::MarketData> theDataAngel(*pMarketData); // -------------------------------------------- const OTIdentifier MARKET_ID(*pMarket); const OTString str_MARKET_ID(MARKET_ID); const OTString str_ServerID(pMarket->GetServerID()); const OTString str_ASSET_ID(pMarket->GetAssetID()); const OTString str_CURRENCY_ID(pMarket->GetCurrencyID()); pMarketData->server_id = str_ServerID.Get(); pMarketData->market_id = str_MARKET_ID.Get(); pMarketData->asset_type_id = str_ASSET_ID.Get(); pMarketData->currency_type_id = str_CURRENCY_ID.Get(); // -------------------------------------------- const long & lScale = pMarket->GetScale(); pMarketData->scale = to_string<long>(lScale); // -------------------------------------------- const uint64_t theCurrentBid = pMarket->GetHighestBidPrice(); const uint64_t theCurrentAsk = pMarket->GetLowestAskPrice(); pMarketData->current_bid = to_string<uint64_t>(theCurrentBid); pMarketData->current_ask = to_string<uint64_t>(theCurrentAsk); // --------------------------------------------- const long & lLastSalePrice = pMarket->GetLastSalePrice(); const long & lTotalAvailableAssets = pMarket->GetTotalAvailableAssets(); pMarketData->total_assets = to_string<long>(lTotalAvailableAssets); pMarketData->last_sale_price = to_string<long>(lLastSalePrice); // --------------------------------------------- const mapOfOffers::size_type theBidCount = pMarket->GetBidCount(); const mapOfOffers::size_type theAskCount = pMarket->GetAskCount(); pMarketData->number_bids = to_string<mapOfOffers::size_type>(theBidCount); pMarketData->number_asks = to_string<mapOfOffers::size_type>(theAskCount); // --------------------------------------------- // In the past 24 hours. // (I'm not collecting this data yet, (maybe never), so these values aren't set at all.) // // pMarketData->volume_trades = ???; // pMarketData->volume_assets = ???; // pMarketData->volume_currency = ???; // // pMarketData->recent_highest_bid = ???; // pMarketData->recent_lowest_ask = ???; // --------------------------------------------- // *pMarketData is CLONED at this time (I'm still responsible to delete.) // That's also why I add it here, below: So the data is set right before the cloning occurs. // pMarketList->AddMarketData(*pMarketData); nMarketCount++; } // ------------------------------------------------------------- // Now pack the list into strOutput... if (nMarketCount == 0) return true; // Success, but the list contains 0 markets. else if (nMarketCount > 0) { OTDB::Storage * pStorage = OTDB::GetDefaultStorage(); OT_ASSERT(NULL != pStorage); OTDB::OTPacker * pPacker = pStorage->GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either. // ----------------------------- OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pMarketList); // Now we PACK our market list. if (NULL == pBuffer) { OTLog::Error("Failed packing pMarketList in OTCron::GetMarketList. \n"); return false; } OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up. // -------------------------------------------------------- // Now we need to translate pBuffer into strOutput. const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData()); const size_t theSize = pBuffer->GetSize(); if ((theSize > 0) && (NULL != pUint)) { OTData theData(pUint, theSize); // This function will base64 ENCODE theData, // and then Set() that as the string contents. ascOutput.SetData(theData); // bool bSuccessSetData = false; // bSuccessSetData = ascOutput.SetData(theData); return true; } else OTLog::Error("OTCron::GetMarketList: 0 size, or null return value, while getting raw data from packed buffer.\n"); } else OTLog::vError("OTCron::GetMarketList: nMarketCount is less than zero: %d.\n", nMarketCount); return false; }
// 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; }