예제 #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;
}
예제 #2
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 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;
}
예제 #3
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 & 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;
}
예제 #4
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;
}
예제 #5
0
// 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;
}
예제 #6
0
// 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;
}