Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create CosmosSDKbitcore.cpp #23334

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
310 changes: 310 additions & 0 deletions .engine/CosmosSDKbitcore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
#include <cosmos_sdk.hpp>
#include <bitcore.hpp>
#include <cosmwasm.hpp>
#include <grpcpp/grpcpp.h>
#include <vector>
#include <string>
#include <stdexcept>
#include <iostream>
#include <limits>
#include <algorithm>

// Token denomination constants
namespace denom {
const std::string ATOM = "uatom"; // Cosmos Hub token
const std::string BITCORE = "ubtc"; // Bitcore token
const std::string ETH = "ueth"; // Ethereum token
const std::string OSMO = "uosmo"; // Osmosis 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 JUNO = "ibc/JUNO_HASH"; // IBC Juno token
const std::string STARS = "ibc/STARS_HASH"; // IBC Stargaze token
}

// Transaction structure
struct TransactionDetails {
std::string sender;
std::string receiver;
uint64_t amount;
std::string token_denom;

bool is_valid() const {
return !sender.empty() && !receiver.empty() && amount > 0 && !token_denom.empty();
}
};

// Recipient structure for reimbursements
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() && address.substr(0, 6) == "cosmos" && amount > 0;
}
Comment on lines +41 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Strengthen address validation in Recipient::is_valid()

Currently, the address validation checks if the address starts with "cosmos", which may not be sufficient to ensure a valid address format. Consider implementing a proper Bech32 address validation to ensure addresses are correctly formatted and to prevent potential errors or security issues.

Apply this diff to strengthen the address validation:

-    return !address.empty() && address.substr(0, 6) == "cosmos" && amount > 0;
+    return !address.empty() && is_valid_bech32_address(address) && amount > 0;

Where is_valid_bech32_address is a function that properly validates Bech32 addresses.

Committable suggestion skipped: line range outside the PR's diff.

};

// Input message structure for reimbursements
struct ReimburseMsg {
std::vector<Recipient> recipients;
static const size_t MAX_RECIPIENTS = 100;

bool is_valid() const {
if (recipients.empty() || recipients.size() > MAX_RECIPIENTS) {
return false;
}
return std::all_of(recipients.begin(), recipients.end(),
[](const Recipient& r) { return r.is_valid(); });
}
};

// Blockchain monitoring class
class BlockchainMonitor {
private:
uint64_t block_height;
std::string grpc_endpoint;

public:
BlockchainMonitor(const std::string& endpoint) : block_height(0), grpc_endpoint(endpoint) {}

uint64_t get_block_height() {
std::cout << "Fetching blockchain height from: " << grpc_endpoint << std::endl;
block_height += 10; // Mock height increment
return block_height;
}

void log_height() {
std::cout << "Current blockchain height: " << block_height << std::endl;
}
};

// Main contract logic
class Contract : public cosmwasm::Contract<Contract> {
private:
uint64_t calculate_total_amount(const std::vector<Recipient>& recipients) const {
uint64_t total = 0;
for (const auto& recipient : recipients) {
if (recipient.amount > std::numeric_limits<uint64_t>::max() - total) {
throw std::overflow_error("Total amount exceeds maximum uint64_t value");
}
total += recipient.amount;
}
return total;
}

std::vector<cosmwasm::BankMsg> create_bank_msgs(
const std::vector<Recipient>& recipients, const std::string& token_denom
) const {
std::vector<cosmwasm::BankMsg> msgs;
msgs.reserve(recipients.size());

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) {
if (info.funds.empty()) {
throw std::runtime_error("No funds provided");
}

const auto& token_denom = info.funds.at(0).denom;

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");
}

auto bank_msgs = create_bank_msgs(msg.recipients, token_denom);

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())}
});
}
Comment on lines +110 to +142
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle multiple funds in execute method

In the execute method, the code assumes that info.funds contains at least one element and uses info.funds.at(0). However, there may be cases where multiple funds are supplied. Consider summing over all provided funds with the same denomination or validating that only one fund denomination is provided.

Apply this diff to handle multiple funds:

     // Validate provided funds
     if (info.funds.empty()) {
         throw std::runtime_error("No funds provided");
     }

-    const auto& token_denom = info.funds.at(0).denom;

+    // Ensure all funds have the same denomination
+    const auto& token_denom = info.funds.at(0).denom;
+    uint64_t provided_funds = 0;
+    for (const auto& coin : info.funds) {
+        if (coin.denom != token_denom) {
+            throw std::runtime_error("Multiple token denominations provided");
+        }
+        provided_funds += coin.amount;
+    }

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

+    uint64_t total_required = calculate_total_amount(msg.recipients);

     if (provided_funds < total_required) {
         throw std::runtime_error("Insufficient funds provided");
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cosmwasm::Response execute(const cosmwasm::MessageInfo& info, const ReimburseMsg& msg) {
if (info.funds.empty()) {
throw std::runtime_error("No funds provided");
}
const auto& token_denom = info.funds.at(0).denom;
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");
}
auto bank_msgs = create_bank_msgs(msg.recipients, token_denom);
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())}
});
}
cosmwasm::Response execute(const cosmwasm::MessageInfo& info, const ReimburseMsg& msg) {
if (info.funds.empty()) {
throw std::runtime_error("No funds provided");
}
// Ensure all funds have the same denomination
const auto& token_denom = info.funds.at(0).denom;
uint64_t provided_funds = 0;
for (const auto& coin : info.funds) {
if (coin.denom != token_denom) {
throw std::runtime_error("Multiple token denominations provided");
}
provided_funds += coin.amount;
}
if (!msg.is_valid()) {
throw std::runtime_error("Invalid recipients configuration");
}
uint64_t total_required = calculate_total_amount(msg.recipients);
if (provided_funds < total_required) {
throw std::runtime_error("Insufficient funds provided");
}
auto bank_msgs = create_bank_msgs(msg.recipients, token_denom);
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())}
});
}

};

// CosmosSDKBitcore engine
class CosmosSDKBitcore {
private:
BlockchainMonitor monitor;
Contract contract;

public:
CosmosSDKBitcore(const std::string& grpc_endpoint) : monitor(grpc_endpoint) {}

void send_tokens(const TransactionDetails& tx) {
if (!tx.is_valid()) {
throw std::invalid_argument("Invalid transaction details");
}

std::cout << "Sending " << tx.amount << " " << tx.token_denom
<< " from " << tx.sender << " to " << tx.receiver << std::endl;
std::cout << "Transaction successful!" << std::endl;
}

void monitor_blockchain() {
uint64_t current_height = monitor.get_block_height();
std::cout << "Blockchain height: " << current_height << std::endl;
}
};

int main() {
CosmosSDKBitcore engine("grpc://localhost:9090");

// Example Cosmos transaction
TransactionDetails tx{"cosmos1sender", "cosmos1receiver", 500000, denom::ATOM};
engine.send_tokens(tx);

// Example reimbursement
ReimburseMsg msg{{{"cosmos1receiver1", 100000}, {"cosmos1receiver2", 200000}}};
cosmwasm::MessageInfo info{{{"uatom", 300000}}, "cosmos1sender"};
Contract contract;
try {
auto response = contract.execute(info, msg);
std::cout << "Reimbursement successful!" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Reimbursement error: " << e.what() << std::endl;
}

// Monitor blockchain
engine.monitor_blockchain();

return 0;
}
#include <cosmwasm.hpp>
#include <vector>
#include <string>
#include <limits>
#include <algorithm>

// 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 {
// Validate bech32 address format (basic check)
return !address.empty() && address.substr(0, 6) == "cosmos" && amount > 0;
}
};

// Input message structure
struct ReimburseMsg {
std::vector<Recipient> recipients; // List of recipients with amounts
static const size_t MAX_RECIPIENTS = 100; // Prevent excessive gas usage

bool is_valid() const {
if (recipients.empty() || recipients.size() > MAX_RECIPIENTS) {
return false;
}
return std::all_of(recipients.begin(), recipients.end(),
[](const Recipient& r) { return r.is_valid(); });
}
};

// Main contract logic
class Contract : public cosmwasm::Contract<Contract> {
private:
// Helper to calculate the total amount required, with overflow protection
uint64_t calculate_total_amount(const std::vector<Recipient>& recipients) const {
uint64_t total = 0;
for (const auto& recipient : recipients) {
if (recipient.amount > std::numeric_limits<uint64_t>::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<cosmwasm::BankMsg> create_bank_msgs(
const std::vector<Recipient>& recipients,
const std::string& token_denom
) const {
std::vector<cosmwasm::BankMsg> 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);
}
Comment on lines +275 to +278
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Allow configurable token denominations

The code currently only allows "uatom" as the valid token denomination. To improve flexibility and adhere to best practices, consider allowing configurable token denominations through parameters or by validating against a list of supported denominations. This enhances the contract's usability with multiple tokens.

This aligns with the retrieved learning that suggests allowing configurable token denominations through parameters.

Apply this diff to support multiple denominations:

-    if (token_denom != denom::ATOM) {
-        throw std::runtime_error("Invalid token denomination: expected " + denom::ATOM);
-    }
+    std::vector<std::string> allowed_denoms = {
+        denom::ATOM, denom::BITCORE, denom::ETH, denom::OSMO,
+        denom::IBC_BTC, denom::IBC_ETH, denom::JUNO, denom::STARS
+    };
+    if (std::find(allowed_denoms.begin(), allowed_denoms.end(), token_denom) == allowed_denoms.end()) {
+        throw std::runtime_error("Invalid token denomination: " + token_denom);
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Validate token denomination (defaults to ATOM for now)
if (token_denom != denom::ATOM) {
throw std::runtime_error("Invalid token denomination: expected " + denom::ATOM);
}
// Validate token denomination (defaults to ATOM for now)
std::vector<std::string> allowed_denoms = {
denom::ATOM, denom::BITCORE, denom::ETH, denom::OSMO,
denom::IBC_BTC, denom::IBC_ETH, denom::JUNO, denom::STARS
};
if (std::find(allowed_denoms.begin(), allowed_denoms.end(), token_denom) == allowed_denoms.end()) {
throw std::runtime_error("Invalid token denomination: " + token_denom);
}


// 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())}
});
}
};
Comment on lines +193 to +310
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove duplicate code from line 193 onwards

The code from line 193 to line 310 appears to be a duplicate of earlier code segments. This duplication can lead to confusion and increase maintenance overhead. Please remove the duplicate code to improve clarity and maintainability.

Loading