From 88baaf6fa8da0c7a7a5bb6e6c55bdd74ba138219 Mon Sep 17 00:00:00 2001 From: "J. K. Edwards" Date: Fri, 10 Jan 2025 19:56:56 -0500 Subject: [PATCH 1/5] Create cosmosSDK.cpp creating an engine subdirectory for potential future .cpp engines such as the engineer for the SDK itself. --- .engine/cosmosSDK.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .engine/cosmosSDK.cpp diff --git a/.engine/cosmosSDK.cpp b/.engine/cosmosSDK.cpp new file mode 100644 index 000000000000..610e2bc4e501 --- /dev/null +++ b/.engine/cosmosSDK.cpp @@ -0,0 +1,48 @@ +#include +#include +#include + +// Recipient structure +struct Recipient { + std::string address; + uint64_t amount; // Amount in microATOM +}; + +// Input message +struct ReimburseMsg { + std::vector recipients; +}; + +// Main contract logic +class Contract : public cosmwasm::Contract { +public: + // Execute function + cosmwasm::Response execute(const cosmwasm::MessageInfo& info, const ReimburseMsg& msg) { + // Verify sender funds + uint64_t total_amount = 0; + for (const auto& recipient : msg.recipients) { + total_amount += recipient.amount; + } + + uint64_t sent_amount = info.funds.at(0).amount; + + if (sent_amount < total_amount) { + throw std::runtime_error("Insufficient funds provided"); + } + + // Generate bank send messages + std::vector bank_msgs; + for (const auto& recipient : msg.recipients) { + bank_msgs.emplace_back(cosmwasm::BankMsg::Send{ + recipient.address, + {{ "uatom", recipient.amount }} + }); + } + + // Create response with messages + return cosmwasm::Response() + .add_messages(bank_msgs) + .add_attribute("action", "reimburse") + .add_attribute("sender", info.sender); + } +}; From 394448ba80d088ab16dcb452d95d8148dfe1967f Mon Sep 17 00:00:00 2001 From: "J. K. Edwards" Date: Fri, 10 Jan 2025 20:06:16 -0500 Subject: [PATCH 2/5] Update cosmosSDK.cpp adding in enhancements that were suggested --- .engine/cosmosSDK.cpp | 66 ++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/.engine/cosmosSDK.cpp b/.engine/cosmosSDK.cpp index 610e2bc4e501..b43a12218a59 100644 --- a/.engine/cosmosSDK.cpp +++ b/.engine/cosmosSDK.cpp @@ -2,47 +2,73 @@ #include #include +// Token denomination constants +namespace denom { + const std::string ATOM = "uatom"; // Cosmos Hub token + const std::string IBC_BTC = "ibc/BTC_HASH"; // IBC Bitcoin token + const std::string IBC_ETH = "ibc/ETH_HASH"; // IBC Ethereum token + const std::string OSMO = "ibc/OSMO_HASH"; // IBC Osmosis token + const std::string JUNO = "ibc/JUNO_HASH"; // IBC Juno token + const std::string STARS = "ibc/STARS_HASH"; // IBC Stargaze token +} + // Recipient structure struct Recipient { - std::string address; - uint64_t amount; // Amount in microATOM + std::string address; // Recipient's wallet address + uint64_t amount; // Amount to send (in microATOM or token denomination) }; -// Input message +// Input message structure struct ReimburseMsg { - std::vector recipients; + std::vector recipients; // List of recipients with amounts }; // Main contract logic class Contract : public cosmwasm::Contract { public: - // Execute function cosmwasm::Response execute(const cosmwasm::MessageInfo& info, const ReimburseMsg& msg) { - // Verify sender funds - uint64_t total_amount = 0; - for (const auto& recipient : msg.recipients) { - total_amount += recipient.amount; + // Validate provided funds + if (info.funds.empty()) { + throw std::runtime_error("No funds provided"); } - uint64_t sent_amount = info.funds.at(0).amount; + uint64_t total_required = calculate_total_amount(msg.recipients); + uint64_t provided_funds = info.funds.at(0).amount; - if (sent_amount < total_amount) { + if (provided_funds < total_required) { throw std::runtime_error("Insufficient funds provided"); } - // Generate bank send messages - std::vector bank_msgs; - for (const auto& recipient : msg.recipients) { - bank_msgs.emplace_back(cosmwasm::BankMsg::Send{ - recipient.address, - {{ "uatom", recipient.amount }} - }); - } + // Generate BankMsg::Send messages for recipients + auto bank_msgs = create_bank_msgs(msg.recipients); - // Create response with messages + // Create response with messages and attributes return cosmwasm::Response() .add_messages(bank_msgs) .add_attribute("action", "reimburse") .add_attribute("sender", info.sender); } + +private: + // Helper function to calculate the total amount needed + uint64_t calculate_total_amount(const std::vector& recipients) { + uint64_t total = 0; + for (const auto& recipient : recipients) { + total += recipient.amount; + } + return total; + } + + // Helper function to create BankMsg::Send messages + std::vector create_bank_msgs(const std::vector& recipients) { + std::vector messages; + for (const auto& recipient : recipients) { + messages.emplace_back(cosmwasm::BankMsg::Send{ + recipient.address, + {{ denom::ATOM, recipient.amount }} // Currently defaulting to ATOM + }); + } + return messages; + } }; + From 6af6d0bcbcfca3a0878fc1054c8d0fe632c391ab Mon Sep 17 00:00:00 2001 From: "J. K. Edwards" Date: Fri, 10 Jan 2025 20:15:14 -0500 Subject: [PATCH 3/5] Update cosmosSDK.cpp #include #include #include #include // Token denomination constants namespace denom { const std::string ATOM = "uatom"; // Cosmos Hub token const std::string IBC_BTC = "ibc/BTC_HASH"; // IBC Bitcoin token const std::string IBC_ETH = "ibc/ETH_HASH"; // IBC Ethereum token const std::string OSMO = "ibc/OSMO_HASH"; // IBC Osmosis token const std::string JUNO = "ibc/JUNO_HASH"; // IBC Juno token const std::string STARS = "ibc/STARS_HASH"; // IBC Stargaze token } // Recipient structure struct Recipient { std::string address; // Recipient's wallet address uint64_t amount; // Amount to send (in microATOM or token denomination) bool is_valid() const { return !address.empty() && amount > 0; } }; // Input message structure struct ReimburseMsg { std::vector recipients; // List of recipients with amounts bool is_valid() const { if (recipients.empty()) { return false; } for (const auto& recipient : recipients) { if (!recipient.is_valid()) { return false; } } return true; } }; // Main contract logic class Contract : public cosmwasm::Contract { private: // Helper to calculate the total amount required, with overflow protection uint64_t calculate_total_amount(const std::vector& recipients) const { uint64_t total = 0; for (const auto& recipient : recipients) { if (recipient.amount > std::numeric_limits::max() - total) { throw std::overflow_error("Total amount exceeds maximum uint64_t value"); } total += recipient.amount; } return total; } // Helper to create bank messages for recipients std::vector create_bank_msgs( const std::vector& recipients, const std::string& token_denom ) const { std::vector msgs; msgs.reserve(recipients.size()); // Optimize vector growth for (const auto& recipient : recipients) { msgs.emplace_back(cosmwasm::BankMsg::Send{ recipient.address, {{token_denom, recipient.amount}} }); } return msgs; } public: cosmwasm::Response execute(const cosmwasm::MessageInfo& info, const ReimburseMsg& msg) { // Validate provided funds if (info.funds.empty()) { throw std::runtime_error("No funds provided"); } const auto& token_denom = info.funds.at(0).denom; // Validate token denomination (defaults to ATOM for now) if (token_denom != denom::ATOM) { throw std::runtime_error("Invalid token denomination: expected " + denom::ATOM); } // Validate message structure if (!msg.is_valid()) { throw std::runtime_error("Invalid recipients configuration"); } uint64_t total_required = calculate_total_amount(msg.recipients); uint64_t provided_funds = info.funds.at(0).amount; if (provided_funds < total_required) { throw std::runtime_error("Insufficient funds provided: required " + std::to_string(total_required) + ", got " + std::to_string(provided_funds)); } // Generate BankMsg::Send messages for recipients auto bank_msgs = create_bank_msgs(msg.recipients, token_denom); // Create response with messages, attributes, and events return cosmwasm::Response() .add_messages(bank_msgs) .add_attribute("action", "reimburse") .add_attribute("sender", info.sender) .add_attribute("total_amount", std::to_string(total_required)) .add_attribute("recipient_count", std::to_string(msg.recipients.size())) .add_event("reimburse", { {"sender", info.sender}, {"total_amount", std::to_string(total_required)}, {"denom", token_denom}, {"recipients", std::to_string(msg.recipients.size())} }); } }; --- .engine/cosmosSDK.cpp | 97 +++++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 26 deletions(-) diff --git a/.engine/cosmosSDK.cpp b/.engine/cosmosSDK.cpp index b43a12218a59..f4d35a5f2973 100644 --- a/.engine/cosmosSDK.cpp +++ b/.engine/cosmosSDK.cpp @@ -1,6 +1,7 @@ #include #include #include +#include // Token denomination constants namespace denom { @@ -16,15 +17,61 @@ namespace denom { struct Recipient { std::string address; // Recipient's wallet address uint64_t amount; // Amount to send (in microATOM or token denomination) + + bool is_valid() const { + return !address.empty() && amount > 0; + } }; // Input message structure struct ReimburseMsg { std::vector recipients; // List of recipients with amounts + + bool is_valid() const { + if (recipients.empty()) { + return false; + } + for (const auto& recipient : recipients) { + if (!recipient.is_valid()) { + return false; + } + } + return true; + } }; // Main contract logic class Contract : public cosmwasm::Contract { +private: + // Helper to calculate the total amount required, with overflow protection + uint64_t calculate_total_amount(const std::vector& recipients) const { + uint64_t total = 0; + for (const auto& recipient : recipients) { + if (recipient.amount > std::numeric_limits::max() - total) { + throw std::overflow_error("Total amount exceeds maximum uint64_t value"); + } + total += recipient.amount; + } + return total; + } + + // Helper to create bank messages for recipients + std::vector create_bank_msgs( + const std::vector& recipients, + const std::string& token_denom + ) const { + std::vector msgs; + msgs.reserve(recipients.size()); // Optimize vector growth + + for (const auto& recipient : recipients) { + msgs.emplace_back(cosmwasm::BankMsg::Send{ + recipient.address, + {{token_denom, recipient.amount}} + }); + } + return msgs; + } + public: cosmwasm::Response execute(const cosmwasm::MessageInfo& info, const ReimburseMsg& msg) { // Validate provided funds @@ -32,43 +79,41 @@ class Contract : public cosmwasm::Contract { throw std::runtime_error("No funds provided"); } + const auto& token_denom = info.funds.at(0).denom; + + // Validate token denomination (defaults to ATOM for now) + if (token_denom != denom::ATOM) { + throw std::runtime_error("Invalid token denomination: expected " + denom::ATOM); + } + + // Validate message structure + if (!msg.is_valid()) { + throw std::runtime_error("Invalid recipients configuration"); + } + uint64_t total_required = calculate_total_amount(msg.recipients); uint64_t provided_funds = info.funds.at(0).amount; if (provided_funds < total_required) { - throw std::runtime_error("Insufficient funds provided"); + throw std::runtime_error("Insufficient funds provided: required " + + std::to_string(total_required) + ", got " + std::to_string(provided_funds)); } // Generate BankMsg::Send messages for recipients - auto bank_msgs = create_bank_msgs(msg.recipients); + auto bank_msgs = create_bank_msgs(msg.recipients, token_denom); - // Create response with messages and attributes + // Create response with messages, attributes, and events return cosmwasm::Response() .add_messages(bank_msgs) .add_attribute("action", "reimburse") - .add_attribute("sender", info.sender); - } - -private: - // Helper function to calculate the total amount needed - uint64_t calculate_total_amount(const std::vector& recipients) { - uint64_t total = 0; - for (const auto& recipient : recipients) { - total += recipient.amount; - } - return total; - } - - // Helper function to create BankMsg::Send messages - std::vector create_bank_msgs(const std::vector& recipients) { - std::vector messages; - for (const auto& recipient : recipients) { - messages.emplace_back(cosmwasm::BankMsg::Send{ - recipient.address, - {{ denom::ATOM, recipient.amount }} // Currently defaulting to ATOM + .add_attribute("sender", info.sender) + .add_attribute("total_amount", std::to_string(total_required)) + .add_attribute("recipient_count", std::to_string(msg.recipients.size())) + .add_event("reimburse", { + {"sender", info.sender}, + {"total_amount", std::to_string(total_required)}, + {"denom", token_denom}, + {"recipients", std::to_string(msg.recipients.size())} }); - } - return messages; } }; - From 2a4701691af8cba2da875435d33f675d020b98ac Mon Sep 17 00:00:00 2001 From: "J. K. Edwards" Date: Fri, 10 Jan 2025 20:17:26 -0500 Subject: [PATCH 4/5] Update cosmosSDK.cpp hopefully this is the final iteration of this... --- .engine/cosmosSDK.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.engine/cosmosSDK.cpp b/.engine/cosmosSDK.cpp index f4d35a5f2973..2244b4c02c8f 100644 --- a/.engine/cosmosSDK.cpp +++ b/.engine/cosmosSDK.cpp @@ -2,6 +2,7 @@ #include #include #include +#include // For std::all_of // Token denomination constants namespace denom { @@ -19,24 +20,21 @@ struct Recipient { uint64_t amount; // Amount to send (in microATOM or token denomination) bool is_valid() const { - return !address.empty() && amount > 0; + // Validate bech32 address format (simple validation for Cosmos address) + return address.substr(0, 6) == "cosmos" && address.length() == 45 && amount > 0; } }; // Input message structure struct ReimburseMsg { - std::vector recipients; // List of recipients with amounts + std::vector recipients; // List of recipients with amounts + static const size_t MAX_RECIPIENTS = 100; // Prevent excessive gas usage bool is_valid() const { - if (recipients.empty()) { - return false; - } - for (const auto& recipient : recipients) { - if (!recipient.is_valid()) { - return false; - } - } - return true; + // Validate recipient count and individual recipient validity + return recipients.size() <= MAX_RECIPIENTS && + std::all_of(recipients.begin(), recipients.end(), + [](const Recipient& r) { return r.is_valid(); }); } }; From 220122274ae839d2c0ef88809d86f68a27c4b84e Mon Sep 17 00:00:00 2001 From: "J. K. Edwards" Date: Fri, 10 Jan 2025 20:21:41 -0500 Subject: [PATCH 5/5] Update cosmosSDK.cpp best practices --- .engine/cosmosSDK.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.engine/cosmosSDK.cpp b/.engine/cosmosSDK.cpp index 2244b4c02c8f..9fd8a037f83b 100644 --- a/.engine/cosmosSDK.cpp +++ b/.engine/cosmosSDK.cpp @@ -2,16 +2,16 @@ #include #include #include -#include // For std::all_of +#include // Token denomination constants namespace denom { const std::string ATOM = "uatom"; // Cosmos Hub token - const std::string IBC_BTC = "ibc/BTC_HASH"; // IBC Bitcoin token - const std::string IBC_ETH = "ibc/ETH_HASH"; // IBC Ethereum token - const std::string OSMO = "ibc/OSMO_HASH"; // IBC Osmosis token - const std::string JUNO = "ibc/JUNO_HASH"; // IBC Juno token - const std::string STARS = "ibc/STARS_HASH"; // IBC Stargaze token + const std::string IBC_BTC = "ibc/BTC_HASH"; // IBC Bitcoin token + const std::string IBC_ETH = "ibc/ETH_HASH"; // IBC Ethereum token + const std::string OSMO = "ibc/OSMO_HASH"; // IBC Osmosis token + const std::string JUNO = "ibc/JUNO_HASH"; // IBC Juno token + const std::string STARS = "ibc/STARS_HASH"; // IBC Stargaze token } // Recipient structure @@ -20,21 +20,22 @@ struct Recipient { uint64_t amount; // Amount to send (in microATOM or token denomination) bool is_valid() const { - // Validate bech32 address format (simple validation for Cosmos address) - return address.substr(0, 6) == "cosmos" && address.length() == 45 && amount > 0; + // Validate bech32 address format (basic check) + return !address.empty() && address.substr(0, 6) == "cosmos" && amount > 0; } }; // Input message structure struct ReimburseMsg { - std::vector recipients; // List of recipients with amounts - static const size_t MAX_RECIPIENTS = 100; // Prevent excessive gas usage + std::vector recipients; // List of recipients with amounts + static const size_t MAX_RECIPIENTS = 100; // Prevent excessive gas usage bool is_valid() const { - // Validate recipient count and individual recipient validity - return recipients.size() <= MAX_RECIPIENTS && - std::all_of(recipients.begin(), recipients.end(), - [](const Recipient& r) { return r.is_valid(); }); + if (recipients.empty() || recipients.size() > MAX_RECIPIENTS) { + return false; + } + return std::all_of(recipients.begin(), recipients.end(), + [](const Recipient& r) { return r.is_valid(); }); } }; @@ -115,3 +116,4 @@ class Contract : public cosmwasm::Contract { }); } }; +