// 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; }
int CALLBACK GetMemoData( LPVOID lp, int nGetType, LPVOID lpData, int nDataSize) { switch( nGetType) { case _GET_MEMO: return GetMemo( lp, lpData, nDataSize); case _GET_TITLE: return GetTitle( lp, lpData, nDataSize); case _GET_FONT: return GetFont( lp, lpData, nDataSize); case _GET_FORECOLOR: return GetForeColor( lp, lpData, nDataSize); case _GET_BACKCOLOR: return GetBackColor( lp, lpData, nDataSize); case _GET_ICON: return GetIconIndex( lp); case _GET_ZORDER: return GetZOrder( lp); case _GET_WINDOWTYPE: return GetWindowType( lp); case _GET_RECT_NORMAL: return GetNormalRect( lp, lpData, nDataSize); case _GET_POINT_TITLE: return GetTitlePoint( lp, lpData, nDataSize); case _GET_POINT_ICON: return GetIconPoint( lp, lpData, nDataSize); case _GET_RECT_TITLE: return GetTitleRect( lp, lpData, nDataSize); case _GET_RECT_ICON: return GetIconRect( lp, lpData, nDataSize); case _GET_TIMERENABLE: return IsTimerEnable( lp); case _GET_TIMER_TYPE: return GetTimerType( lp); case _GET_TIMER_MONTH: return GetTimerMonth( lp); case _GET_TIMER_DAY: return GetTimerDay( lp); case _GET_TIMER_HOUR: return GetTimerHour( lp); case _GET_TIMER_MIN: return GetTimerMin( lp); case _GET_TIMER_WEEK: return GetTimerWeek( lp); case _GET_TIMER_SOUND: return GetTimerSound( lp, lpData, nDataSize); case _GET_LINKENABLE: return IsLink( lp); case _GET_LINK_FILE: return GetLinkFile( lp, lpData, nDataSize); case _GET_LINK_PARAM: return GetLinkParam( lp, lpData, nDataSize); case _GET_CREATE_YEAR: return GetCreateYear( lp); case _GET_CREATE_MONTH: return GetCreateMonth( lp); case _GET_CREATE_DAY: return GetCreateDay( lp); case _GET_DEF_FONT: return GetDefFont( lpData, nDataSize); case _GET_DEF_FORECLR: return GetDefForeColor( lpData, nDataSize); case _GET_DEF_BACKCLR: return GetDefBackColor( lpData, nDataSize); case _GET_VERSION: return VERSION_CODE; } return 0; }