667 lines
26 KiB
C++
667 lines
26 KiB
C++
/*++
|
|
|
|
Program name:
|
|
|
|
BitDeals
|
|
|
|
Module Name:
|
|
|
|
Deal.cpp
|
|
|
|
Notices:
|
|
|
|
Apostol Core (Deal)
|
|
|
|
Author:
|
|
|
|
Copyright (c) Prepodobny Alen
|
|
|
|
mailto: alienufo@inbox.ru
|
|
mailto: ufocomp@gmail.com
|
|
|
|
--*/
|
|
|
|
#include "Core.hpp"
|
|
#include "Deal.hpp"
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
#ifdef __cplusplus
|
|
extern "C++" {
|
|
#endif // __cplusplus
|
|
|
|
namespace Apostol {
|
|
|
|
namespace Deal {
|
|
|
|
CString UTCFormat(const CString& Value) {
|
|
return Value.SubString(0, 19) << " UTC";
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString BTCFormat(const CString& Value) {
|
|
if (Value.Find(BitcoinConfig.Symbol) == CString::npos)
|
|
return Value.TrimRight('0') << " " << BitcoinConfig.Symbol;
|
|
return Value.TrimRight('0');
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
double BTCToDouble(const CString &Value) {
|
|
const size_t Pos = Value.Find(BitcoinConfig.Symbol);
|
|
if (Pos == CString::npos)
|
|
return StrToDouble(Value.c_str());
|
|
return StrToDouble(Value.SubString(0, Pos).TrimRight().c_str());
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DoubleToBTC(const double &Value, const CString &Format) {
|
|
TCHAR Buffer[25] = {0};
|
|
FloatToStr(Value, Buffer, sizeof(Buffer), Format.c_str());
|
|
return Buffer;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
int CheckSum(const CString &Sum) {
|
|
if (Sum.IsEmpty())
|
|
return 0;
|
|
|
|
size_t whole = 0, fractional = 0, delimiter = 0;
|
|
|
|
size_t pos = 0;
|
|
TCHAR ch;
|
|
|
|
ch = Sum.at(pos);
|
|
while (ch != 0) {
|
|
if (IsNumeral(ch)) {
|
|
if (delimiter == 0)
|
|
whole++;
|
|
else
|
|
fractional++;
|
|
} else if (ch == '.') {
|
|
delimiter++;
|
|
} else if (ch == ' ') {
|
|
break;
|
|
} else {
|
|
return -1;
|
|
}
|
|
ch = Sum.at(++pos);
|
|
}
|
|
|
|
if (whole == 0 || delimiter > 1 || fractional > 8)
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
int VerifyDate(const CString &Date, CDateTime &Result) {
|
|
if (!Date.IsEmpty()) {
|
|
|
|
if (Date.Length() < 10)
|
|
return 0;
|
|
|
|
CString StrDate(Date);
|
|
|
|
int pos = 0;
|
|
TCHAR ch = StrDate.at(pos);
|
|
while (ch != 0 && (IsNumeral(ch) || ((pos == 4 || pos == 7) && (ch == '-' || ch == '/')) ||
|
|
(pos == 10 && ch == ' ') || ((pos == 13 || pos == 16) && ch == ':'))) {
|
|
ch = StrDate.at(++pos);
|
|
}
|
|
|
|
if (pos == 10)
|
|
StrDate << " 00:00:00";
|
|
|
|
if (StrDate.Length() != 19 && StrDate.Length() != 23) {
|
|
return 0;
|
|
}
|
|
|
|
try {
|
|
if ((Result = StrToDateTimeDef(StrDate.c_str(), 0, "%04d-%02d-%02d %02d:%02d:%02d")) == 0)
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
catch (...) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CDateTime StringToDate(const CString &Value, const CString &Format) {
|
|
return StrToDateTimeDef(Value.c_str(), 0, Format.c_str());
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DateToString(CDateTime Value, const CString &Format) {
|
|
TCHAR Buffer[25] = {0};
|
|
DateTimeToStr(Value, Buffer, sizeof(Buffer), Format.c_str());
|
|
return Buffer;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
//-- DealData --------------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CDealOrder DealData::StringToOrder(const CString &Value) {
|
|
const CString &S = Value.Lower();
|
|
|
|
if (S == "create") {
|
|
return doCreate;
|
|
} else if (S == "created") {
|
|
return doCreated;
|
|
} else if (S == "submit") {
|
|
return doSubmit;
|
|
} else if (S == "submitted") {
|
|
return doSubmitted;
|
|
} else if (S == "confirm") {
|
|
return doConfirm;
|
|
} else if (S == "confirmed") {
|
|
return doConfirmed;
|
|
} else if (S == "pay") {
|
|
return doPay;
|
|
} else if (S == "paid") {
|
|
return doPaid;
|
|
} else if (S == "complete") {
|
|
return doComplete;
|
|
} else if (S == "completed") {
|
|
return doCompleted;
|
|
} else if (S == "cancel") {
|
|
return doCancel;
|
|
} else if (S == "canceled") {
|
|
return doCanceled;
|
|
} else if (S == "execute") {
|
|
return doExecute;
|
|
} else if (S == "executed") {
|
|
return doExecuted;
|
|
} else if (S == "delete") {
|
|
return doDelete;
|
|
} else if (S == "deleted") {
|
|
return doDeleted;
|
|
} else if (S == "fail") {
|
|
return doFail;
|
|
} else if (S == "failed") {
|
|
return doFailed;
|
|
} else if (S == "feedback") {
|
|
return doFeedback;
|
|
} else {
|
|
throw ExceptionFrm("Invalid deal order value: \"%s\".", Value.c_str());
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DealData::OrderToString(CDealOrder Order) {
|
|
switch (Order) {
|
|
case doCreate:
|
|
return "Create";
|
|
case doCreated:
|
|
return "Created";
|
|
case doSubmit:
|
|
return "Submit";
|
|
case doSubmitted:
|
|
return "Submitted";
|
|
case doConfirm:
|
|
return "Confirm";
|
|
case doConfirmed:
|
|
return "Confirmed";
|
|
case doPay:
|
|
return "Pay";
|
|
case doPaid:
|
|
return "Paid";
|
|
case doComplete:
|
|
return "Complete";
|
|
case doCompleted:
|
|
return "Completed";
|
|
case doCancel:
|
|
return "Cancel";
|
|
case doCanceled:
|
|
return "Canceled";
|
|
case doExecute:
|
|
return "Execute";
|
|
case doExecuted:
|
|
return "Executed";
|
|
case doDelete:
|
|
return "Delete";
|
|
case doDeleted:
|
|
return "Deleted";
|
|
case doFail:
|
|
return "Fail";
|
|
case doFailed:
|
|
return "Failed";
|
|
case doFeedback:
|
|
return "Feedback";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CDealType DealData::StringToType(const CString &Value) {
|
|
const auto &status = Value.Lower();
|
|
|
|
if (status.Find("prepayment") != CString::npos) {
|
|
return dtPrepayment;
|
|
} else if (status.Find("postpayment") != CString::npos) {
|
|
return dtPostpayment;
|
|
} else {
|
|
throw ExceptionFrm(R"(Invalid order type value: "%s".)", status.c_str());
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DealData::TypeToString(CDealType Type) {
|
|
switch (Type) {
|
|
case dtPrepayment:
|
|
return "Prepayment";
|
|
case dtPostpayment:
|
|
return "Postpayment";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DealData::TypeCodeToString(const CString &Code) {
|
|
if (Code == "prepayment.deal") {
|
|
return {"Prepayment"};
|
|
} else if (Code == "postpayment.deal") {
|
|
return {"Postpayment"};
|
|
} else {
|
|
throw ExceptionFrm(R"(Invalid type code value: "%s".)", Code.c_str());
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CFeedBackStatus DealData::StringToFeedBackStatus(const CString &Value) {
|
|
const CString &Status = Value.Lower();
|
|
|
|
if (Status == "negative") {
|
|
return fsNegative;
|
|
} else if (Status == "neutral") {
|
|
return fsNeutral;
|
|
} else if (Status == "positive") {
|
|
return fsPositive;
|
|
} else {
|
|
throw ExceptionFrm(R"(Invalid feedback status value: "%s".)", Status.c_str());
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DealData::FeedBackStatusToString(CFeedBackStatus Status) {
|
|
switch (Status) {
|
|
case fsNegative:
|
|
return "Negative";
|
|
case fsNeutral:
|
|
return "Neutral";
|
|
case fsPositive:
|
|
return "Positive";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString DealData::GetStringData() const {
|
|
CString Data;
|
|
CString S;
|
|
|
|
Data = S.Format("Type: %d;", (int) Type);
|
|
Data += S.Format("URL: %s;", At.c_str());
|
|
Data += S.Format("Date: %s;", Date.c_str());
|
|
Data += S.Format("Seller: %s;", Seller.Address.c_str());
|
|
Data += S.Format("Customer: %s;", Customer.Address.c_str());
|
|
Data += S.Format("Until: %s;", Payment.Until.c_str());
|
|
Data += S.Format("Sum: %s;", Payment.Sum.c_str());
|
|
Data += S.Format("LeaveBefore: %s", FeedBack.LeaveBefore.c_str());
|
|
|
|
return Data;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
//-- CRating ---------------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
void CRating::Parse(const CString &Value) {
|
|
size_t Pos = 0;
|
|
|
|
TCHAR ch = Value.at(Pos++);
|
|
if (Value.Size() < 4 || !IsNumeral(ch))
|
|
throw ExceptionFrm("Invalid rating value.");
|
|
|
|
CString Item;
|
|
while (!IsCtl(ch)) {
|
|
if (ch == '+' && !Item.IsEmpty()) {
|
|
Count = StrToIntDef(Item.c_str(), 0);
|
|
Count++;
|
|
Item.Clear();
|
|
} else if (ch == ',' && !Item.IsEmpty()) {
|
|
Count = StrToIntDef(Item.c_str(), 0);
|
|
Item.Clear();
|
|
} else if (ch == '%' && !Item.IsEmpty()) {
|
|
Positive = StrToIntDef(Item.c_str(), 0);
|
|
Item.Clear();
|
|
} else {
|
|
if (!(ch == ' ' || ch == ',')) {
|
|
if (!IsNumeral(ch))
|
|
throw ExceptionFrm("Invalid rating value.");
|
|
Item << ch;
|
|
}
|
|
}
|
|
|
|
ch = Value.at(Pos++);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
//-- CDeal -----------------------------------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CDeal::CDeal() {
|
|
m_Data.Order = doCreate;
|
|
m_Data.FeedBack.Status = fsPositive;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CDeal::CDeal(const YAML::Node &node) : CDeal() {
|
|
Parse(node);
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString CDeal::GetHashData() {
|
|
return m_Data.GetStringData();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string CDeal::get_hash() {
|
|
const std::string str(GetHashData().c_str());
|
|
return sha256(str);
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string CDeal::get_code() {
|
|
const std::string value(GetHashData().c_str());
|
|
const auto& hex = string_to_hex(value);
|
|
const config::base16 data(hex);
|
|
const auto& hash = ripemd160_hash(sha256_hash(data));
|
|
return encode_base16(hash);
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString CDeal::GetCode() {
|
|
return get_code();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString CDeal::GetHash() {
|
|
return sha256(GetHashData());
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
wallet::ec_public CDeal::to_public_ek(uint8_t version) {
|
|
const auto& hash = get_hash();
|
|
const std::string seed(hash.substr(0, 48));
|
|
const std::string salt(hash.substr(48, 16));
|
|
const auto& token = Bitcoin::token_new(hash, base16(salt));
|
|
const auto& key = Bitcoin::ek_public(token, base16(seed), version);
|
|
return ek_public_to_ec(hash, key);
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
wallet::payment_address CDeal::to_address_ek(uint8_t version) {
|
|
const auto& hash = get_hash();
|
|
const std::string seed(hash.substr(0, 48));
|
|
const std::string salt(hash.substr(48, 16));
|
|
const auto& token = Bitcoin::token_new(hash, base16(salt));
|
|
return Bitcoin::ek_address(token, base16(seed), version);
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
wallet::ec_public CDeal::to_public_hd(uint64_t prefixes) {
|
|
const auto& hash = get_hash();
|
|
const auto& key = hd_new(base16(hash), prefixes);
|
|
const auto& public_key = key.to_public();
|
|
return public_key.point();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
wallet::payment_address CDeal::to_address_hd(uint64_t prefixes) {
|
|
const auto& key = to_public_hd(prefixes);
|
|
return key.to_payment_address();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string CDeal::get_payment_ek(const std::string &key1, const std::string &key2, std::string &key3,
|
|
uint8_t version_key, uint8_t version_script) {
|
|
|
|
CWitness Witness(ec_public(key1), ec_public(key2), key3.empty() ? to_public_ek(version_key) : ec_public(key3));
|
|
|
|
if (key3.empty())
|
|
key3 = Witness.keys()[2].encoded();
|
|
|
|
const auto& address = Witness.to_address(version_script);
|
|
|
|
return address.encoded();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string CDeal::get_payment_hd(const std::string &key1, const std::string &key2, std::string &key3,
|
|
uint64_t prefixes, uint8_t version_script) {
|
|
|
|
CWitness Witness(ec_public(key1), ec_public(key2), key3.empty() ? to_public_hd(prefixes) : ec_public(key3));
|
|
|
|
if (key3.empty())
|
|
key3 = Witness.keys()[2].encoded();
|
|
|
|
const auto& address = Witness.to_address(version_script);
|
|
|
|
return address.encoded();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
std::string CDeal::get_payment_witness(const std::string &key1, const std::string &key2, std::string &key3,
|
|
uint64_t prefixes) {
|
|
|
|
CWitness Witness(ec_public(key1), ec_public(key2), key3.empty() ? to_public_hd(prefixes) : ec_public(key3));
|
|
|
|
if (key3.empty())
|
|
key3 = Witness.keys()[2].encoded();
|
|
|
|
return Witness.to_witness(prefixes == hd_private::mainnet ? "bc" : "tb");
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString CDeal::GetPaymentEK(const CString &Key1, const CString &Key2, CString &Key3,
|
|
uint8_t version_key, uint8_t version_script) {
|
|
|
|
std::string key3(Key3);
|
|
|
|
const auto& payment = get_payment_ek(Key1.c_str(), Key2.c_str(), key3, version_key, version_script);
|
|
|
|
Key3 = key3;
|
|
|
|
return payment;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString CDeal::GetPaymentHD(const CString &Key1, const CString &Key2, CString &Key3,
|
|
uint64_t prefixes, uint8_t version_script) {
|
|
|
|
std::string key3(Key3);
|
|
|
|
const auto& payment = get_payment_hd(Key1.c_str(), Key2.c_str(), key3, prefixes, version_script);
|
|
|
|
Key3 = key3;
|
|
|
|
return payment;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
CString CDeal::GetPaymentSW(const CString &Key1, const CString &Key2, CString &Key3, uint64_t prefixes) {
|
|
|
|
std::string key3(Key3);
|
|
|
|
const auto& payment = get_payment_witness(Key1.c_str(), Key2.c_str(), key3, prefixes);
|
|
|
|
Key3 = key3;
|
|
|
|
return payment;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
void CDeal::Parse(const YAML::Node &node) {
|
|
|
|
const auto& deal = node["deal"];
|
|
|
|
if (deal) {
|
|
m_Data.Order = CDealData::StringToOrder(deal["order"].as<std::string>());
|
|
m_Data.Type = CDealData::StringToType(deal["type"].as<std::string>());
|
|
|
|
m_Data.At = deal["at"].as<std::string>();
|
|
|
|
const auto &date = deal["date"].as<std::string>();
|
|
|
|
CDateTime Date;
|
|
if (VerifyDate(date, Date) != 1)
|
|
throw ExceptionFrm("Invalid deal date format: %s.", date.c_str());
|
|
|
|
m_Data.Date = DateToString(Date);
|
|
|
|
const auto& seller = deal["seller"];
|
|
m_Data.Seller.Address = seller["address"].as<std::string>();
|
|
|
|
if (!valid_address(m_Data.Seller.Address))
|
|
throw ExceptionFrm("Invalid seller address: %s.", m_Data.Seller.Address.c_str());
|
|
|
|
if (seller["rating"])
|
|
m_Data.Seller.Rating = seller["rating"].as<std::string>();
|
|
|
|
if (seller["signature"])
|
|
m_Data.Seller.Signature = seller["signature"].as<std::string>();
|
|
|
|
const auto& customer = deal["customer"];
|
|
m_Data.Customer.Address = customer["address"].as<std::string>();
|
|
|
|
if (!valid_address(m_Data.Customer.Address))
|
|
throw ExceptionFrm("Invalid customer address: %s.", m_Data.Customer.Address.c_str());
|
|
|
|
if (customer["rating"])
|
|
m_Data.Customer.Rating = customer["rating"].as<std::string>();
|
|
|
|
if (customer["signature"])
|
|
m_Data.Customer.Signature = customer["signature"].as<std::string>();
|
|
|
|
const auto& payment = deal["payment"];
|
|
if (payment) {
|
|
if (payment["address"])
|
|
m_Data.Payment.Address = payment["address"].as<std::string>();
|
|
|
|
if (payment["until"]) {
|
|
const auto &until = payment["until"].as<std::string>();
|
|
|
|
CDateTime Until;
|
|
if (VerifyDate(until, Until) != 1)
|
|
throw ExceptionFrm("Invalid until date format: %s.", until.c_str());
|
|
|
|
m_Data.Payment.Until = DateToString(Until);
|
|
}
|
|
|
|
const auto &sum = payment["sum"].as<std::string>();
|
|
|
|
if (CheckSum(sum) != 1)
|
|
throw ExceptionFrm("Invalid format sum: %s.", sum.c_str());
|
|
|
|
m_Data.Payment.Sum = BTCFormat(sum);
|
|
}
|
|
|
|
const auto& feedback = deal["feedback"];
|
|
if (feedback) {
|
|
if (feedback["leave-before"]) {
|
|
const auto &leave_before = feedback["leave-before"].as<std::string>();
|
|
|
|
CDateTime LeaveBefore;
|
|
if (VerifyDate(leave_before, LeaveBefore) != 1)
|
|
throw ExceptionFrm("Invalid leave before date format: %s.", leave_before.c_str());
|
|
|
|
m_Data.FeedBack.LeaveBefore = DateToString(LeaveBefore);
|
|
}
|
|
|
|
if (feedback["status"])
|
|
m_Data.FeedBack.Status = CDealData::StringToFeedBackStatus(feedback["status"].as<std::string>());
|
|
|
|
if (feedback["refund"])
|
|
m_Data.FeedBack.Refund = feedback["refund"].as<std::string>();
|
|
|
|
if (feedback["comments"])
|
|
m_Data.FeedBack.Comments = feedback["comments"].as<std::string>();
|
|
}
|
|
|
|
const auto& transaction = deal["transaction"];
|
|
if (transaction) {
|
|
m_Data.Transaction.Hex = transaction["hex"].as<std::string>();
|
|
}
|
|
|
|
const auto& error = deal["error"];
|
|
if (error) {
|
|
m_Data.Error.Message = error["message"].as<std::string>();
|
|
}
|
|
|
|
if (m_Data.Payment.Until.IsEmpty())
|
|
m_Data.Payment.Until = DateToString(Date + 1); // 1 day
|
|
|
|
if (m_Data.FeedBack.LeaveBefore.IsEmpty())
|
|
m_Data.FeedBack.LeaveBefore = DateToString(Date + 14); // 14 day
|
|
|
|
m_Data.Code = GetCode();
|
|
} else
|
|
throw ExceptionFrm("Invalid YAML format: Need node \"deal\".");
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
void CDeal::SetOrder(YAML::Node &Node, CDealOrder Order) {
|
|
Node["deal"]["order"] = CDealData::OrderToString(Order).c_str();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
void CDeal::AddFeedback(YAML::Node &Node, CFeedBackStatus Status, const CString &Comments) {
|
|
YAML::Node Deal = Node["deal"];
|
|
YAML::Node Feedback = Deal["feedback"];
|
|
Feedback["status"] = CDealData::FeedBackStatusToString(Status).c_str();
|
|
if (!Comments.IsEmpty())
|
|
Feedback["comments"] = Comments.c_str();
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
void CDeal::AddTransaction(YAML::Node &Node, const transaction &tx) {
|
|
|
|
YAML::Node Deal = Node["deal"];
|
|
YAML::Node Transaction = Deal["transaction"];
|
|
|
|
const auto& hex = encode_base16(tx.to_data(true, true));
|
|
|
|
Transaction["hex"] = hex;
|
|
|
|
DebugMessage("tx: %s\n", hex.c_str());
|
|
}
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
|
|
void CDeal::AddError(YAML::Node &Node, const CString &Message) {
|
|
YAML::Node Deal = Node["deal"];
|
|
YAML::Node Error = Deal["error"];
|
|
Error["message"] = Message.c_str();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif // __cplusplus
|