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

Stake in a box #314 #315 #316

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_subdirectory(cyber.stake)
add_subdirectory(cyber.govern)
add_subdirectory(cyber.rejector)
add_subdirectory(cyber.incomereject)
add_subdirectory(cyber.box)

add_subdirectory(scripts/base-genesis)

Expand Down
1 change: 1 addition & 0 deletions common/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace cyber { namespace config {
static const auto token_name = "cyber.token"_n;
static const auto stake_name = "cyber.stake"_n;
static const auto govern_name = "cyber.govern"_n;
static const auto box_name = "cyber.box"_n;
static const auto worker_name = "cyber.worker"_n;
static const auto names_name = "cyber.names"_n;
static const auto producers_name = "cyber.prods"_n;
Expand Down
12 changes: 12 additions & 0 deletions cyber.box/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_contract(cyber.box cyber.box ${CMAKE_CURRENT_SOURCE_DIR}/src/cyber.box.cpp)
install_contract(cyber.box)

target_include_directories(cyber.box.wasm
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../cyber.token/include
${CMAKE_CURRENT_SOURCE_DIR}/..)

set_target_properties(cyber.box.wasm
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
40 changes: 40 additions & 0 deletions cyber.box/include/cyber.box/cyber.box.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once
#include <eosio/eosio.hpp>
#include <eosio/time.hpp>
#include <eosio/singleton.hpp>
#include <tuple>
#include <eosio/privileged.hpp>
#include <cyber.token/cyber.token.hpp>
#include <common/dispatchers.hpp>

namespace cyber {
using eosio::name;
class [[eosio::contract("cyber.box")]] box : public eosio::contract {
struct structures {
struct box {
uint64_t id;
name contract;
name treasurer;
name title;
name owner;
bool empty;
uint64_t primary_key()const { return id; }
using key_t = std::tuple<name, name, name>;
key_t by_key()const { return std::make_tuple(contract, treasurer, title); }
};
};
using box_key_index [[using eosio: order("contract"), order("treasurer"), order("title")]] =
eosio::indexed_by<"bykey"_n, eosio::const_mem_fun<structures::box, structures::box::key_t, &structures::box::by_key> >;
using boxes [[eosio::order("id")]] = eosio::multi_index<"box"_n, structures::box, box_key_index>;

void erase_box(name contract, name treasurer, name title, bool release);
public:
using contract::contract;
[[eosio::action]] void create(name contract, name treasurer, name title);
[[eosio::action]] void packup(name contract, name treasurer, name title);
[[eosio::action]] void unpack(name contract, name treasurer, name title);
[[eosio::action]] void burn(name contract, name treasurer, name title);
[[eosio::action]] void transfer(name contract, name treasurer, name title, name to, std::string memo);
//do we need to add the ability to put boxes in a box?
};
} /// namespace cyber
68 changes: 68 additions & 0 deletions cyber.box/src/cyber.box.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <cyber.box/cyber.box.hpp>
namespace cyber {

void box::create(name contract, name treasurer, name title) {
require_auth(treasurer);
zxcat marked this conversation as resolved.
Show resolved Hide resolved
boxes boxes_table(_self, _self.value);
auto boxes_idx = boxes_table.get_index<"bykey"_n>();
eosio::check(boxes_idx.find({contract, treasurer, title}) == boxes_idx.end(), "such a box already exists");
boxes_table.emplace(treasurer, [&](auto& b) { b = {
.id = boxes_table.available_primary_key(),
.contract = contract,
.treasurer = treasurer,
zxcat marked this conversation as resolved.
Show resolved Hide resolved
.title = title,
.owner = treasurer,
.empty = true
};});
}

void box::packup(name contract, name treasurer, name title) {
require_auth(contract);
boxes boxes_table(_self, _self.value);
auto boxes_idx = boxes_table.get_index<"bykey"_n>();
auto box_itr = boxes_idx.find({contract, treasurer, title});
eosio::check(box_itr != boxes_idx.end(), "box does not exist");
eosio::check(box_itr->empty, "the box is not empty");
eosio::check(box_itr->treasurer == box_itr->owner, "SYSTEM: invalid box owner");
boxes_idx.modify(box_itr, name(), [&](auto& b) { b.empty = false; });
}

void box::erase_box(name contract, name treasurer, name title, bool release) {
boxes boxes_table(_self, _self.value);
auto boxes_idx = boxes_table.get_index<"bykey"_n>();
auto box_itr = boxes_idx.find({contract, treasurer, title});
eosio::check(box_itr != boxes_idx.end(), "box does not exist");
require_auth(box_itr->owner);
if (!box_itr->empty && release) {

Choose a reason for hiding this comment

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

I think contract should prohibit unpack empty box.

eosio::action(
eosio::permission_level{_self, config::active_name},
contract, "release"_n,
std::make_tuple(treasurer, title, box_itr->owner)
).send();
}
boxes_idx.erase(box_itr);
}

void box::unpack(name contract, name treasurer, name title) {

Choose a reason for hiding this comment

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

unpack and burn can take owner as argument. In this case unpack can send notification to contract instead call contract's release action. These modification enable to use release` action to self-purposes for contract.

erase_box(contract, treasurer, title, true);
}

void box::burn(name contract, name treasurer, name title) {
erase_box(contract, treasurer, title, false);
}

void box::transfer(name contract, name treasurer, name title, name to, std::string memo) {
eosio::check(is_account(to), "to account does not exist");
boxes boxes_table(_self, _self.value);
auto boxes_idx = boxes_table.get_index<"bykey"_n>();
auto box_itr = boxes_idx.find({contract, treasurer, title});
eosio::check(box_itr != boxes_idx.end(), "box does not exist");
require_auth(box_itr->owner);
eosio::check(box_itr->owner != to, "cannot transfer to self");
eosio::check(!box_itr->empty, "cannot transfer an empty box");
require_recipient(box_itr->owner);
require_recipient(to);
zxcat marked this conversation as resolved.
Show resolved Hide resolved
boxes_idx.modify(box_itr, name(), [&](auto& b) { b.owner = to; });
}

} /// namespace cyber
2 changes: 2 additions & 0 deletions tests/contracts.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ struct contracts {
static std::vector<char> stake_abi() { return read_abi(cyberway_contracts + "/cyber.stake/cyber.stake.abi"); }
static std::vector<uint8_t> govern_wasm() { return read_wasm(cyberway_contracts + "/cyber.govern/cyber.govern.wasm"); }
static std::vector<char> govern_abi() { return read_abi(cyberway_contracts + "/cyber.govern/cyber.govern.abi"); }
static std::vector<uint8_t> box_wasm() { return read_wasm(cyberway_contracts + "/cyber.box/cyber.box.wasm"); }
static std::vector<char> box_abi() { return read_abi(cyberway_contracts + "/cyber.box/cyber.box.abi"); }

struct util {
static std::vector<uint8_t> test_api_wasm() { return read_wasm(cyberway_test_contracts + "/test_api.wasm"); }
Expand Down
48 changes: 48 additions & 0 deletions tests/cyber.box_test_api.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once
#include "test_api_helper.hpp"
#include "../common/config.hpp"

using eosio::chain::symbol_code;

namespace eosio { namespace testing {

struct cyber_box_api: base_contract_api {

public:
cyber_box_api(golos_tester* tester, name code)
: base_contract_api(tester, code){}

////actions
action_result create(name contract, name treasurer, name title, name signer = name()) {
return push(N(create), signer ? signer : treasurer,
args()("contract", contract)("treasurer", treasurer)("title", title));
}
action_result packup(name contract, name treasurer, name title, name signer = name()) {
return push(N(packup), signer ? signer : contract,
args()("contract", contract)("treasurer", treasurer)("title", title));
}
action_result unpack(name contract, name treasurer, name title, name signer) {
return push(N(unpack), signer,
args()("contract", contract)("treasurer", treasurer)("title", title));
}
action_result burn(name contract, name treasurer, name title, name signer) {
return push(N(burn), signer,
args()("contract", contract)("treasurer", treasurer)("title", title));
}
action_result transfer(name contract, name treasurer, name title, name to, std::string memo, name signer) {
return push(N(transfer), signer,
args()("contract", contract)("treasurer", treasurer)("title", title)("to", to)("memo", memo));
}

variant get_box(name contract, name treasurer, name title) {
auto all = _tester->get_all_chaindb_rows(_code, _code.value, N(box), false);
for(auto& v : all) {
if (v["contract"].as<name>() == contract && v["treasurer"].as<name>() == treasurer && v["title"].as<name>() == title) {
return v;
}
}
return variant();
}
};

}} // eosio::testing