// --------------------------------------- void MTRecord::SetContents (const std::string & str_contents) { m_str_contents = str_contents; if (!m_str_contents.empty() && (MTRecord::Instrument == this->GetRecordType())) { OTString strPayment(m_str_contents); OTPayment thePayment(strPayment); if (thePayment.IsValid() && thePayment.SetTempValues()) { switch (thePayment.GetType()) { case OTPayment::PURSE: m_bIsCash = true; break; case OTPayment::CHEQUE: m_bIsCheque = true; break; case OTPayment::VOUCHER: m_bIsVoucher = true; break; case OTPayment::INVOICE: m_bIsInvoice = true; break; case OTPayment::PAYMENT_PLAN: m_bIsPaymentPlan = true; break; case OTPayment::SMART_CONTRACT: m_bIsSmartContract = true; break; default: break; } } } }
// --------------------------------------- // For outgoing, pending (not-yet-accepted) instruments. // bool MTRecord::CancelOutgoing(const std::string str_via_acct) // This can be blank if it's a cheque. { if (!this->CanCancelOutgoing()) return false; switch (this->GetRecordType()) { case MTRecord::Instrument: { if (m_str_nym_id.empty()) { OTLog::vError("%s: Error: missing nym id (%s)\n", __FUNCTION__, m_str_nym_id.c_str()); return false; } const OTIdentifier theNymID(m_str_nym_id); // ------------------------------ std::string str_using_acct; if (this->IsCheque()) { str_using_acct = m_str_account_id; } else { str_using_acct = str_via_acct; } // --------------------------------------- if (str_using_acct.empty()) { OTLog::vError("%s: Error: Missing account ID (FAILURE)\n", __FUNCTION__); return false; } // ------------------------------ if (0 == m_lTransactionNum) { if (IsCash()) { // Maybe it's cash... std::string strOutpayment(OTAPI_Wrap::GetNym_OutpaymentsContentsByIndex(m_str_nym_id, GetBoxIndex())); if (strOutpayment.empty()) { long lIndex = static_cast<long>(GetBoxIndex()); OTLog::vError("%s: Error: Blank outpayment at index %ld\n", __FUNCTION__, lIndex); return false; } // ------------------------ OTString strPayment(strOutpayment); OTPayment thePayment(strPayment); if (!thePayment.IsValid() || !thePayment.SetTempValues()) { long lIndex = static_cast<long>(GetBoxIndex()); OTLog::vError("%s: Error: Invalid outpayment at index %ld\n", __FUNCTION__, lIndex); return false; } // ------------------------ long lTransNum = 0; thePayment.GetOpeningNum(lTransNum, theNymID); // ------------------------ if (0 == lTransNum) // Found it. { long lIndex = static_cast<long>(GetBoxIndex()); OTString strIndices; strIndices.Format("%ld", lIndex); const std::string str_indices(strIndices.Get()); // --------------------------------- OT_ME madeEasy; return madeEasy.cancel_outgoing_payments(m_str_nym_id, str_using_acct, str_indices); } else { OTLog::vError("%s: Error: Transaction number is non-zero (%ld), for cash outgoing payment for nym id (%s)\n", __FUNCTION__, lTransNum, m_str_nym_id.c_str()); return false; } } // IsCash() else { OTLog::vError("%s: Error: Transaction number is 0, for non-cash outgoing payment for nym id (%s)\n", __FUNCTION__, m_str_nym_id.c_str()); return false; } } // --------------------------------------- // Find the payment in the Nym's outpayments box that correlates to this MTRecord. // int32_t nCount = OTAPI_Wrap::GetNym_OutpaymentsCount(m_str_nym_id); for (int32_t nIndex = 0; nIndex < nCount; ++nIndex) { std::string strOutpayment(OTAPI_Wrap::GetNym_OutpaymentsContentsByIndex(m_str_nym_id, nIndex)); if (strOutpayment.empty()) { long lIndex = nIndex; OTLog::vError("%s: Error: Blank outpayment at index %ld\n", __FUNCTION__, lIndex); return false; } // ------------------------ OTString strPayment(strOutpayment); OTPayment thePayment(strPayment); if (!thePayment.IsValid() || !thePayment.SetTempValues()) { long lIndex = nIndex; OTLog::vError("%s: Error: Invalid outpayment at index %ld\n", __FUNCTION__, lIndex); return false; } // ------------------------ long lTransNum = 0; thePayment.GetOpeningNum(lTransNum, theNymID); // ------------------------ if (lTransNum == m_lTransactionNum) // Found it. { long lIndex = nIndex; OTString strIndices; strIndices.Format("%ld", lIndex); const std::string str_indices(strIndices.Get()); // --------------------------------- OT_ME madeEasy; return madeEasy.cancel_outgoing_payments(m_str_nym_id, str_using_acct, str_indices); } } // for // --------------------------------------------------- } break; // ----------------------------- default: OTLog::vError("%s: Unexpected type: %s\n", __FUNCTION__, this->GetInstrumentType().c_str()); return false; } return true; }
// PayDividendVisitor::Trigger() is used in // OTUnitDefinition::VisitAccountRecords() // cppcheck-suppress unusedFunction bool PayDividendVisitor::Trigger(Account& theSharesAccount) // theSharesAccount // is, say, a Pepsi // shares // account. Here, we'll send a dollars voucher // to its owner. { const int64_t lPayoutAmount = (theSharesAccount.GetBalance() * GetPayoutPerShare()); if (lPayoutAmount <= 0) { Log::Output(0, "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(nullptr != GetNotaryID()); const Identifier& theNotaryID = *(GetNotaryID()); OT_ASSERT(nullptr != GetPayoutInstrumentDefinitionID()); const Identifier& thePayoutInstrumentDefinitionID = *(GetPayoutInstrumentDefinitionID()); OT_ASSERT(nullptr != GetVoucherAcctID()); const Identifier& theVoucherAcctID = *(GetVoucherAcctID()); OT_ASSERT(nullptr != GetServer()); OTServer& theServer = *(GetServer()); Nym& theServerNym = const_cast<Nym&>(theServer.GetServerNym()); const Identifier theServerNymID(theServerNym); const Identifier& RECIPIENT_ID = theSharesAccount.GetNymID(); OT_ASSERT(nullptr != GetNymID()); const Identifier& theSenderNymID = *(GetNymID()); OT_ASSERT(nullptr != GetMemo()); 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; Cheque theVoucher(theNotaryID, thePayoutInstrumentDefinitionID); // 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. int64_t lNewTransactionNumber = 0; bool bGotNextTransNum = theServer.transactor_.issueNextTransactionNumberToNym( theServerNym, 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. &RECIPIENT_ID); // All account crediting / debiting happens in the caller, in OTServer. // (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 String strVoucher(theVoucher); OTPayment thePayment(strVoucher); // calls DropMessageToNymbox bSent = theServer.SendInstrumentToNym( theNotaryID, theServerNymID, // sender nym RECIPIENT_ID, // recipient nym nullptr, &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 String strPayoutInstrumentDefinitionID( thePayoutInstrumentDefinitionID), strRecipientNymID(RECIPIENT_ID); Log::vError("PayDividendVisitor::Trigger: ERROR failed " "issuing voucher (to send to dividend payout " "recipient.) " "WAS TRYING TO PAY %" PRId64 " of instrument definition %s to Nym %s.\n", lPayoutAmount, strPayoutInstrumentDefinitionID.Get(), strRecipientNymID.Get()); } // If we didn't send it, then we need to return the funds to where they // came from. // if (!bSent) { Cheque theReturnVoucher(theNotaryID, thePayoutInstrumentDefinitionID); 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. &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 String strReturnVoucher(theReturnVoucher); OTPayment theReturnPayment(strReturnVoucher); // calls DropMessageToNymbox bSent = theServer.SendInstrumentToNym( theNotaryID, theServerNymID, // sender nym theSenderNymID, // recipient nym (original sender.) nullptr, &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 String strPayoutInstrumentDefinitionID( thePayoutInstrumentDefinitionID), strSenderNymID(theSenderNymID); Log::vError("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 %" PRId64 " of instrument definition " "%s to Nym %s.\n", lPayoutAmount, strPayoutInstrumentDefinitionID.Get(), strSenderNymID.Get()); } } // if !bSent } else // !bGotNextTransNum { const String strPayoutInstrumentDefinitionID( thePayoutInstrumentDefinitionID), strRecipientNymID(RECIPIENT_ID); Log::vError( "PayDividendVisitor::Trigger: ERROR!! Failed issuing next " "transaction " "number while trying to send a voucher (while paying dividends.) " "WAS TRYING TO PAY %" PRId64 " of instrument definition %s to Nym %s.\n", lPayoutAmount, strPayoutInstrumentDefinitionID.Get(), strRecipientNymID.Get()); } return bReturnValue; }