Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@
build/*
.DS_Store
.vscode
.idea
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The collection of system contracts consists of the following individual contract
+ An auction for bidding for premium account names.
* [multisig contract](contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp): A contract that enables proposing Antelope transactions on the blockchain, collecting authorization approvals for many accounts, and then executing the actions within the transaction after authorization requirements of the transaction have been reached. (Note: this contract must be deployed to a privileged account.)
* [wrap contract](contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp): A contract that wraps around any Antelope transaction and allows for executing its actions without needing to satisfy the authorization requirements of the transaction. If used, the permissions of the account hosting this contract should be configured to only allow highly trusted parties (e.g. the operators of the blockchain) to have the ability to execute its actions. (Note: this contract must be deployed to a privileged account.)
* [core.vaulta](contracts/core.vaulta/include/core.vaulta/core.vaulta.hpp): A contract for the Vaulta (`$A`) token and system forwarding actions that allows using the core contract with the `$A` token. (Note: This is currently a mock contract until the [full contract](https://github.com/VaultaFoundation/vaulta-system-contract) gets merged in.)

## Repository organization

Expand Down
9 changes: 7 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ function usage() {
printf "Usage: $0 OPTION...
-c DIR Path to CDT installation/build directory. (Optional if using CDT installled at standard system location.)
-l DIR Path to Spring build directory. Optional, but must be specified to build tests.
-p NUM Override the number of CPU cores used for building.
-h Print this help menu.
\\n" "$0" 1>&2
exit 1
}

BUILD_TESTS=OFF
CPU_OVERRIDE=""

if [ $# -ne 0 ]; then
while getopts "c:l:h" opt; do
while getopts "c:l:p:h" opt; do
case "${opt}" in
c )
CDT_INSTALL_DIR=$(realpath $OPTARG)
Expand All @@ -22,6 +24,9 @@ if [ $# -ne 0 ]; then
SPRING_BUILD_DIR=$(realpath $OPTARG)
BUILD_TESTS=ON
;;
p )
CPU_OVERRIDE="$OPTARG"
;;
h )
usage
;;
Expand Down Expand Up @@ -76,7 +81,7 @@ fi
printf "\t=========== Building system-contracts ===========\n\n"
RED='\033[0;31m'
NC='\033[0m'
CPU_CORES=$(getconf _NPROCESSORS_ONLN)
CPU_CORES=${CPU_OVERRIDE:-$(getconf _NPROCESSORS_ONLN)}
mkdir -p build
pushd build &> /dev/null
cmake -DBUILD_TESTS=${BUILD_TESTS} ${SPRING_DIR_CMAKE_OPTION} ${CDT_DIR_CMAKE_OPTION} ../
Expand Down
1 change: 1 addition & 0 deletions contracts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ add_subdirectory(eosio.token)
add_subdirectory(eosio.wrap)
add_subdirectory(eosio.fees)
add_subdirectory(eosio.bpay)
add_subdirectory(core.vaulta)

add_subdirectory(test_contracts)
13 changes: 13 additions & 0 deletions contracts/core.vaulta/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
add_contract(core.vaulta core.vaulta ${CMAKE_CURRENT_SOURCE_DIR}/src/core.vaulta.cpp)

target_include_directories(core.vaulta
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include)

set_target_properties(core.vaulta
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/core.vaulta.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/core.vaulta.contracts.md @ONLY )

target_compile_options( core.vaulta PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian )
63 changes: 63 additions & 0 deletions contracts/core.vaulta/include/core.vaulta/core.vaulta.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include <eosio/eosio.hpp>
#include <eosio/asset.hpp>
#include <eosio/singleton.hpp>

namespace eosio {
class [[eosio::contract("core.vaulta")]] core : public contract {
public:
using contract::contract;
using name = eosio::name;
using asset = eosio::asset;
using symbol = eosio::symbol;
static constexpr symbol EOS = symbol("EOS", 4);

struct [[eosio::table("accounts"), eosio::contract("core.vaulta")]] account {
asset balance;
bool released = false;
uint64_t primary_key()const { return balance.symbol.code().raw(); }
};

struct [[eosio::table("stat"), eosio::contract("core.vaulta")]] currency_stats {
asset supply;
asset max_supply;
name issuer;

uint64_t primary_key()const { return supply.symbol.code().raw(); }
};

typedef eosio::multi_index< "accounts"_n, account > accounts;
typedef eosio::multi_index< "stat"_n, currency_stats > stats;

struct [[eosio::table]] config {
symbol token_symbol;
};

typedef eosio::singleton<"config"_n, config> config_table;


[[eosio::action]] void init(asset maximum_supply);
[[eosio::action]] void transfer(const name& from, const name& to, const asset& quantity, const std::string& memo);
[[eosio::on_notify("eosio.token::transfer")]]
void on_transfer(const name& from, const name& to, const asset& quantity, const std::string& memo);

[[eosio::action]] void deposit(const name& owner, const asset& amount);
[[eosio::action]] void withdraw(const name& owner, const asset& amount);
[[eosio::action]] void unstaketorex(const name& owner, const name& receiver, const asset& from_net, const asset& from_cpu);
[[eosio::action]] void claimrewards(const name owner);

using init_action = eosio::action_wrapper<"init"_n, &core::init>;
using transfer_action = eosio::action_wrapper<"transfer"_n, &core::transfer>;
using deposit_action = eosio::action_wrapper<"deposit"_n, &core::deposit>;
using withdraw_action = eosio::action_wrapper<"withdraw"_n, &core::withdraw>;
using unstaketorex_action = eosio::action_wrapper<"unstaketorex"_n, &core::unstaketorex>;
using claimrewards_action = eosio::action_wrapper<"claimrewards"_n, &core::claimrewards>;

private:
void add_balance(const name& owner, const asset& value, const name& ram_payer);
void sub_balance(const name& owner, const asset& value);
symbol get_token_symbol();
void credit_eos_to(const name& account, const asset& quantity);
};
} /// namespace eosio
Empty file.
161 changes: 161 additions & 0 deletions contracts/core.vaulta/src/core.vaulta.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#include <core.vaulta/core.vaulta.hpp>

namespace eosio {

void core::init(asset maximum_supply) {
require_auth(get_self());
config_table _config(get_self(), get_self().value);
check(!_config.exists(), "This system contract is already initialized");

auto sym = maximum_supply.symbol;
check(maximum_supply.is_valid(), "invalid supply");
check(maximum_supply.amount > 0, "max-supply must be positive");

_config.set(config{.token_symbol = sym}, get_self());

stats statstable(get_self(), sym.code().raw());
statstable.emplace(get_self(), [&](auto& s) {
s.supply = maximum_supply;
s.max_supply = maximum_supply;
s.issuer = get_self();
});

add_balance(get_self(), maximum_supply, get_self());
}

void core::transfer(const name& from, const name& to, const asset& quantity, const std::string& memo) {
check(from != to, "cannot transfer to self");
require_auth(from);
check(is_account(to), "to account does not exist");

auto sym = quantity.symbol.code();
stats statstable(get_self(), sym.raw());
const auto& st = statstable.get(sym.raw());

check(quantity.is_valid(), "invalid quantity");
check(quantity.amount > 0, "must transfer positive quantity");
check(quantity.symbol == st.supply.symbol, "symbol precision mismatch");
check(memo.size() <= 256, "memo has more than 256 bytes");

auto payer = has_auth(to) ? to : from;

sub_balance(from, quantity);
add_balance(to, quantity, payer);

require_recipient(from);
require_recipient(to);

// If `from` is sending $A tokens to this contract
// they are swapping from $A to EOS
if (to == get_self()) {
check(quantity.symbol == get_token_symbol(), "Wrong token used");
credit_eos_to(from, quantity);
}
}

void core::add_balance(const name& owner, const asset& value, const name& ram_payer) {
accounts to_acnts(get_self(), owner.value);
auto to = to_acnts.find(value.symbol.code().raw());
if (to == to_acnts.end()) {
to_acnts.emplace(ram_payer == owner ? owner : get_self(), [&](auto& a) {
a.balance = value;
a.released = ram_payer == owner;
});
} else {
to_acnts.modify(to, same_payer, [&](auto& a) { a.balance += value; });
}
}

void core::sub_balance(const name& owner, const asset& value) {
accounts from_acnts(get_self(), owner.value);

const auto& from = from_acnts.get(value.symbol.code().raw(), "no balance object found");
check(from.balance.amount >= value.amount, "overdrawn balance");

if(!from.released){
auto balance = from.balance;
// This clears out the RAM consumed by the scope overhead.
from_acnts.erase( from );
from_acnts.emplace( owner, [&]( auto& a ){
a.balance = balance - value;
a.released = true;
});
} else {
from_acnts.modify( from, owner, [&]( auto& a ) {
a.balance -= value;
});
}
}

void core::on_transfer(const name& from, const name& to, const asset& quantity, const std::string& memo) {
if (from == get_self() || to != get_self())
return;
check(quantity.amount > 0, "Swap amount must be greater than 0");

// Ignore for system accounts, otherwise when unstaking or selling ram this will swap EOS for
// $A and credit them to the sending account which will lock those tokens.
if (from == "eosio.ram"_n)
return;
if (from == "eosio.stake"_n)
return;

check(quantity.symbol == EOS, "Invalid symbol");
asset swap_amount = asset(quantity.amount, get_token_symbol());
transfer_action(get_self(), {{get_self(), "active"_n}}).send(get_self(), from, swap_amount, std::string(""));
}

symbol core::get_token_symbol() {
config_table _config(get_self(), get_self().value);
check(_config.exists(), "Contract is not initialized");
config cfg = _config.get();
return cfg.token_symbol;
}

void core::credit_eos_to(const name& account, const asset& quantity) {
check(quantity.amount > 0, "Credit amount must be greater than 0");

asset swap_amount = asset(quantity.amount, EOS);
transfer_action("eosio.token"_n, {{get_self(), "active"_n}}).send(get_self(), account, swap_amount, std::string(""));
}

void core::deposit(const name& owner, const asset& amount) {
require_auth(owner);
action(
permission_level{ owner, "active"_n },
"eosio"_n,
"deposit"_n,
std::make_tuple(owner, amount)
).send();
}

void core::withdraw(const name& owner, const asset& amount) {
require_auth(owner);
action(
permission_level{ owner, "active"_n },
"eosio"_n,
"withdraw"_n,
std::make_tuple(owner, amount)
).send();
}

void core::unstaketorex(const name& owner, const name& receiver, const asset& from_net, const asset& from_cpu) {
require_auth(owner);
action(
permission_level{ owner, "active"_n },
"eosio"_n,
"unstaketorex"_n,
std::make_tuple(owner, receiver, from_net, from_cpu)
).send();
}

void core::claimrewards(const name owner) {
require_auth(owner);
action(
permission_level{ owner, "active"_n },
"eosio"_n,
"claimrewards"_n,
std::make_tuple(owner)
).send();
}

} /// namespace eosio
11 changes: 9 additions & 2 deletions contracts/eosio.bpay/src/eosio.bpay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@ void bpay::claimrewards( const name owner ) {

const auto& row = _rewards.get( owner.value, "no rewards to claim" );

eosio::token::transfer_action transfer( "eosio.token"_n, { get_self(), "active"_n });
transfer.send( get_self(), owner, row.quantity, "producer block pay" );
{ // swap to vaulta token
eosio::token::transfer_action transfer( "eosio.token"_n, { get_self(), "active"_n });
transfer.send( get_self(), "core.vaulta"_n, row.quantity, "producer block pay (swap)" );
}

{ // send vaulta tokens to claimer
eosio::token::transfer_action transfer( "core.vaulta"_n, { get_self(), "active"_n });
transfer.send( get_self(), owner, asset(row.quantity.amount, symbol("A", 4)), "producer block pay" );
}

_rewards.erase(row);
}
Expand Down
5 changes: 5 additions & 0 deletions contracts/eosio.system/src/producer_pay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ namespace eosiosystem {
}

void system_contract::claimrewards( const name& owner ) {
check(
eosio::get_sender() == "core.vaulta"_n,
"EOS has been rebranded to Vaulta. This action must now be called from the core.vaulta contract."
);

require_auth( owner );

execute_next_schedule();
Expand Down
15 changes: 15 additions & 0 deletions contracts/eosio.system/src/rex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ namespace eosiosystem {

void system_contract::deposit( const name& owner, const asset& amount )
{
check(
eosio::get_sender() == "core.vaulta"_n,
"EOS has been rebranded to Vaulta. This action must now be called from the core.vaulta contract."
);

require_auth( owner );

check( amount.symbol == core_symbol(), "must deposit core token" );
Expand All @@ -39,6 +44,11 @@ namespace eosiosystem {

void system_contract::withdraw( const name& owner, const asset& amount )
{
check(
eosio::get_sender() == "core.vaulta"_n,
"EOS has been rebranded to Vaulta. This action must now be called from the core.vaulta contract."
);

require_auth( owner );

check( amount.symbol == core_symbol(), "must withdraw core token" );
Expand Down Expand Up @@ -74,6 +84,11 @@ namespace eosiosystem {

void system_contract::unstaketorex( const name& owner, const name& receiver, const asset& from_net, const asset& from_cpu )
{
check(
eosio::get_sender() == "core.vaulta"_n,
"EOS has been rebranded to Vaulta. This action must now be called from the core.vaulta contract."
);

require_auth( owner );

check( from_net.symbol == core_symbol() && from_cpu.symbol == core_symbol(), "asset must be core token" );
Expand Down
2 changes: 2 additions & 0 deletions tests/contracts.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct contracts {
static std::vector<char> bios_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.bios/eosio.bios.abi"); }
static std::vector<uint8_t> bpay_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.bpay/eosio.bpay.wasm"); }
static std::vector<char> bpay_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.bpay/eosio.bpay.abi"); }
static std::vector<uint8_t> vaulta_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/core.vaulta/core.vaulta.wasm"); }
static std::vector<char> vaulta_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/core.vaulta/core.vaulta.abi"); }

struct util {
static std::vector<uint8_t> reject_all_wasm() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/reject_all.wasm"); }
Expand Down
Loading