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