Skip to content
This repository has been archived by the owner on May 25, 2024. It is now read-only.

Commit

Permalink
cosmwasm: Add simple token contract example
Browse files Browse the repository at this point in the history
  • Loading branch information
conr2d committed Jun 26, 2021
1 parent 0538263 commit 1c626e1
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 0 deletions.
17 changes: 17 additions & 0 deletions examples/cosmwasm_simple_token/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.16)

project(cosmwasm_simple_token)

find_package(blanc)

# TODO: Separate cosmwasm toolchain configuration
include(EosioWasmToolchain)

add_executable(token ${CMAKE_CURRENT_SOURCE_DIR}/src/token.cpp)

target_include_directories(token PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

# TODO: Add a convenient way to set build profile
target_compile_options(token PUBLIC --profile=cosmwasm)
target_link_options(token PUBLIC --profile=cosmwasm)

54 changes: 54 additions & 0 deletions examples/cosmwasm_simple_token/include/token.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once
#include <cosmwasm/serialize.hpp>

struct token {
std::string address;
uint128_t amount;

COSMWASM_SERIALIZE(token, (address)(amount))
};

struct instantiate_msg {
std::string name;
std::string symbol;
uint8_t decimals;
std::vector<token> initial_balances;

COSMWASM_SERIALIZE(instantiate_msg, (name)(symbol)(decimals)(initial_balances))
};

struct transfer_msg {
std::string recipient;
uint128_t amount;

COSMWASM_SERIALIZE2(transfer_msg, "transfer", (recipient)(amount))
};

using execute_msg = std::variant<transfer_msg>;

struct balance_msg {
std::string address;

COSMWASM_SERIALIZE2(balance_msg, "balance", (address))
};

struct token_info_msg {
COSMWASM_SERIALIZE2(token_info_msg, "token_info")
};

using query_msg = std::variant<balance_msg,token_info_msg>;

struct balance_response {
uint128_t balance;

COSMWASM_SERIALIZE(balance_response, (balance))
};

struct token_info_response {
std::string name;
std::string symbol;
uint8_t decimals;
uint128_t total_supply;

COSMWASM_SERIALIZE(token_info_response, (name)(symbol)(decimals)(total_supply))
};
140 changes: 140 additions & 0 deletions examples/cosmwasm_simple_token/src/token.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <cosmwasm/cosmwasm.hpp>
#include "token.hpp"

using namespace cosmwasm;

class token_contract : public contract {
public:
using contract::contract;

void instantiate(
const std::string& name,
const std::string& symbol,
uint8_t decimals,
std::vector<token> initial_balances
) {
auto total_supply = create_accounts(initial_balances);
_storage.set(
namespaces_with_key({}, to_bytes("token_info")),
token_info_response {
name, symbol, decimals, total_supply
}.as_bytes()
);
}

void transfer(const std::string& recipient, uint128_t amount) {
auto address = addr_validate(recipient);
sub_balance(_info.sender, amount);
add_balance(address, amount);
}

bytes get_balance(const std::string& address) {
balance_response bres = { 0 };

auto s = _storage.get(namespaces_with_key({to_bytes("balance")}, to_bytes(address)));
if (s) {
bres.balance = from_bytes<uint128_t>(*s);
}

return to_bytes(bres);
}

bytes get_token_info() {
return *_storage.get(namespaces_with_key({}, to_bytes("token_info")));
}


private:
void add_balance(const std::string& address, const uint128_t& amount) {
uint128_t balance = 0;

auto key = namespaces_with_key({to_bytes("balance")}, to_bytes(address));
auto s = _storage.get(key);
if (s) {
balance = from_bytes<uint128_t>(*s);
}

uint128_t new_balance = balance + amount;
check(new_balance > balance);
_storage.set(key, to_bytes(new_balance));
}

void sub_balance(const std::string& address, const uint128_t& amount) {
uint128_t balance = 0;

auto key = namespaces_with_key({to_bytes("balance")}, to_bytes(address));
auto s = _storage.get(key);
if (s) {
balance = from_bytes<uint128_t>(*s);
}

uint128_t new_balance = balance - amount;
check(new_balance < balance);
_storage.set(key, to_bytes(new_balance));
}

uint128_t create_accounts(const std::vector<token>& accounts) {
uint128_t total_supply = 0;
for (const auto& acc : accounts) {
total_supply += acc.amount;
auto address = addr_validate(acc.address);
add_balance(address, acc.amount);
}
return total_supply;
}
};


extern "C" {
[[clang::export_name("instantiate")]]
region* instantiate(region* env_ptr, region* info_ptr, region* msg_ptr) {
contract_result<response> res;

auto e = json::from_region<cosmwasm::env>(env_ptr);
auto i = json::from_region<cosmwasm::message_info>(info_ptr);
auto m = json::from_region<instantiate_msg>(msg_ptr);
auto c = token_contract(e, i);

c.instantiate(m.name, m.symbol, m.decimals, m.initial_balances);

return json::to_region(res).release();
}

[[clang::export_name("execute")]]
region* execute(region* env_ptr, region* info_ptr, region* msg_ptr) {
contract_result<response> res;

auto e = json::from_region<cosmwasm::env>(env_ptr);
auto i = json::from_region<cosmwasm::message_info>(info_ptr);
auto m = json::from_region<execute_msg>(msg_ptr);
auto c = token_contract(e, i);

std::visit(overloaded {
[&](const transfer_msg& msg) {
c.transfer(msg.recipient, msg.amount);
res.ok.attributes.push_back({"action", "transfer"});
res.ok.attributes.push_back({"from", i.sender});
res.ok.attributes.push_back({"to", msg.recipient});
res.ok.attributes.push_back({"amount", std::to_string(msg.amount)});
},
}, m);

return json::to_region(res).release();
}

[[clang::export_name("query")]]
region* query(region* env_ptr, region* msg_ptr) {
contract_result<bytes> res;

auto e = json::from_region<cosmwasm::env>(env_ptr);
auto m = json::from_region<query_msg>(msg_ptr);
auto c = token_contract(e, {});

std::visit(overloaded {
[&](balance_msg& msg) { res.ok = c.get_balance(msg.address); },
[&](token_info_msg& msg) { res.ok = c.get_token_info(); },
}, m);

return json::to_region(res).release();
}
}

0 comments on commit 1c626e1

Please sign in to comment.