Skip to content
Open
Show file tree
Hide file tree
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
7 changes: 4 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.5)

project(eosio_contracts)

set(VERSION_MAJOR 1)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 9)
set(VERSION_PATCH 1)
set(VERSION_PATCH 2)
#set(VERSION_SUFFIX rc4)

if (VERSION_SUFFIX)
Expand All @@ -16,6 +16,7 @@ endif()
include(ExternalProject)

find_package(eosio.cdt)
message(STATUS "Using eosio.cdt in ${EOSIO_CDT_ROOT}")

message(STATUS "Building eosio.contracts v${VERSION_FULL}")

Expand Down Expand Up @@ -82,7 +83,7 @@ if(BUILD_TESTS)
ExternalProject_Add(
contracts_unit_tests
LIST_SEPARATOR | # Use the alternate list separator
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_PREFIX_PATH=${TEST_PREFIX_PATH} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT}
CMAKE_ARGS -Deosio.cdt_DIR=${eosio.cdt_DIR} -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_PREFIX_PATH=${TEST_PREFIX_PATH} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT}
SOURCE_DIR ${CMAKE_SOURCE_DIR}/tests
BINARY_DIR ${CMAKE_BINARY_DIR}/tests
BUILD_ALWAYS 1
Expand Down
6 changes: 6 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ function usage() {
exit 1
}

EOSIO_MAX_VERSION_MAJOR=1
EOSIO_MAX_VERSION_MINOR=8
BUILD_TESTS=false

if [ $# -ne 0 ]; then
Expand Down Expand Up @@ -55,6 +57,9 @@ fi
if [[ ${BUILD_TESTS} == true ]]; then
# Prompt user for location of eosio.
eosio-directory-prompt

default-boost-directories;
echo "Using Boost installation at: ${BOOST_INSTALL_DIR}"
fi

# Prompt user for location of eosio.cdt.
Expand All @@ -71,6 +76,7 @@ if [[ ${BUILD_TESTS} == true ]]; then
# Include EOSIO_INSTALL_DIR in CMAKE_FRAMEWORK_PATH
echo "Using EOSIO installation at: $EOSIO_INSTALL_DIR"
export CMAKE_FRAMEWORK_PATH="${EOSIO_INSTALL_DIR}:${CMAKE_FRAMEWORK_PATH}"
export CMAKE_PREFIX_PATH="${BOOST_INSTALL_DIR}"
fi

printf "\t=========== Building eosio.contracts ===========\n\n"
Expand Down
123 changes: 55 additions & 68 deletions contracts/rem.msig/include/rem.msig/rem.msig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,46 @@
#include <eosio/transaction.hpp>

namespace eosio {
/// @cond IMPLEMENTATIONS

/**
* @defgroup eosiomsig rem.msig
* @ingroup eosiocontracts
* rem.msig contract defines the structures and actions needed to manage the proposals and approvals on blockchain.
* @{
* The `rem.msig` system contract allows for creation of proposed transactions which require authorization from a list of accounts, approval of the proposed transactions by those accounts required to approve it, and finally, it also allows the execution of the approved transactions on the blockchain.
*
* In short, the workflow to propose, review, approve and then executed a transaction it can be described by the following:
* - first you create a transaction json file,
* - then you submit this proposal to the `rem.msig` contract, and you also insert the account permissions required to approve this proposal into the command that submits the proposal to the blockchain,
* - the proposal then gets stored on the blockchain by the `rem.msig` contract, and is accessible for review and approval to those accounts required to approve it,
* - after each of the appointed accounts required to approve the proposed transactions reviews and approves it, you can execute the proposed transaction. The `rem.msig` contract will execute it automatically, but not before validating that the transaction has not expired, it is not cancelled, and it has been signed by all the permissions in the initial proposal's required permission list.
*/
class [[eosio::contract("rem.msig")]] multisig : public contract {
public:
using contract::contract;

/**
* Create proposal
*
* @details Creates a proposal containing one transaction.
* Propose action, creates a proposal containing one transaction.
* Allows an account `proposer` to make a proposal `proposal_name` which has `requested`
* permission levels expected to approve the proposal, and if approved by all expected
* permission levels then `trx` transaction can we executed by this proposal.
* The `proposer` account is authorized and the `trx` transaction is verified if it was
* authorized by the provided keys and permissions, and if the proposal name doesn’t
* already exist; if all validations pass the `proposal_name` and `trx` trasanction are
* saved in the proposals table and the `requested` permission levels to the
* approvals table (for the `proposer` context).
* Storage changes are billed to `proposer`.
* approvals table (for the `proposer` context). Storage changes are billed to `proposer`.
*
* @param proposer - The account proposing a transaction
* @param proposal_name - The name of the proposal (should be unique for proposer)
* @param requested - Permission levels expected to approve the proposal
* @param trx - Proposed transaction
*/
[[eosio::action]]
void propose(ignore<name> proposer, ignore<name> proposal_name,
ignore<std::vector<permission_level>> requested, ignore<transaction> trx);
void propose(name proposer, name proposal_name,
std::vector<permission_level> requested, ignore<transaction> trx);
/**
* Approve proposal
*
* @details Approves an existing proposal
* Allows an account, the owner of `level` permission, to approve a proposal `proposal_name`
* Approve action approves an existing proposal. Allows an account, the owner of `level` permission, to approve a proposal `proposal_name`
* proposed by `proposer`. If the proposal's requested approval list contains the `level`
* permission then the `level` permission is moved from internal `requested_approvals` list to
* internal `provided_approvals` list of the proposal, thus persisting the approval for
* the `proposal_name` proposal.
* Storage changes are billed to `proposer`.
* the `proposal_name` proposal. Storage changes are billed to `proposer`.
*
* @param proposer - The account proposing a transaction
* @param proposal_name - The name of the proposal (should be unique for proposer)
Expand All @@ -58,10 +56,7 @@ namespace eosio {
void approve( name proposer, name proposal_name, permission_level level,
const eosio::binary_extension<eosio::checksum256>& proposal_hash );
/**
* Revoke proposal
*
* @details Revokes an existing proposal
* This action is the reverse of the `approve` action: if all validations pass
* Unapprove action revokes an existing proposal. This action is the reverse of the `approve` action: if all validations pass
* the `level` permission is erased from internal `provided_approvals` and added to the internal
* `requested_approvals` list, and thus un-approve or revoke the proposal.
*
Expand All @@ -72,9 +67,7 @@ namespace eosio {
[[eosio::action]]
void unapprove( name proposer, name proposal_name, permission_level level );
/**
* Cancel proposal
*
* @details Cancels an existing proposal
* Cancel action cancels an existing proposal.
*
* @param proposer - The account proposing a transaction
* @param proposal_name - The name of the proposal (should be an existing proposal)
Expand All @@ -87,9 +80,7 @@ namespace eosio {
[[eosio::action]]
void cancel( name proposer, name proposal_name, name canceler );
/**
* Execute proposal
*
* @details Allows an `executer` account to execute a proposal.
* Exec action allows an `executer` account to execute a proposal.
*
* Preconditions:
* - `executer` has authorization,
Expand All @@ -108,9 +99,7 @@ namespace eosio {
[[eosio::action]]
void exec( name proposer, name proposal_name, name executer );
/**
* Invalidate proposal
*
* @details Allows an `account` to invalidate itself, that is, its name is added to
* Invalidate action allows an `account` to invalidate itself, that is, its name is added to
* the invalidations table and this table will be cross referenced when exec is performed.
*
* @param account - The account invalidating the transaction
Expand All @@ -124,52 +113,50 @@ namespace eosio {
using cancel_action = eosio::action_wrapper<"cancel"_n, &multisig::cancel>;
using exec_action = eosio::action_wrapper<"exec"_n, &multisig::exec>;
using invalidate_action = eosio::action_wrapper<"invalidate"_n, &multisig::invalidate>;
};

private:
struct [[eosio::table]] proposal {
name proposal_name;
std::vector<char> packed_transaction;

uint64_t primary_key()const { return proposal_name.value; }
};

typedef eosio::multi_index< "proposal"_n, proposal > proposals;
struct [[eosio::table, eosio::contract("rem.msig")]] proposal {
name proposal_name;
std::vector<char> packed_transaction;
eosio::binary_extension< std::optional<time_point> > earliest_exec_time;

struct [[eosio::table]] old_approvals_info {
name proposal_name;
std::vector<permission_level> requested_approvals;
std::vector<permission_level> provided_approvals;
uint64_t primary_key()const { return proposal_name.value; }
};
typedef eosio::multi_index< "proposal"_n, proposal > proposals;

uint64_t primary_key()const { return proposal_name.value; }
};
typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals;
struct [[eosio::table, eosio::contract("rem.msig")]] old_approvals_info {
name proposal_name;
std::vector<permission_level> requested_approvals;
std::vector<permission_level> provided_approvals;

struct approval {
permission_level level;
time_point time;
};
uint64_t primary_key()const { return proposal_name.value; }
};
typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals;

struct [[eosio::table]] approvals_info {
uint8_t version = 1;
name proposal_name;
//requested approval doesn't need to cointain time, but we want requested approval
//to be of exact the same size ad provided approval, in this case approve/unapprove
//doesn't change serialized data size. So, we use the same type.
std::vector<approval> requested_approvals;
std::vector<approval> provided_approvals;
struct approval {
permission_level level;
time_point time;
};

uint64_t primary_key()const { return proposal_name.value; }
};
typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals;
struct [[eosio::table, eosio::contract("rem.msig")]] approvals_info {
uint8_t version = 1;
name proposal_name;
//requested approval doesn't need to contain time, but we want requested approval
//to be of exactly the same size as provided approval, in this case approve/unapprove
//doesn't change serialized data size. So, we use the same type.
std::vector<approval> requested_approvals;
std::vector<approval> provided_approvals;

struct [[eosio::table]] invalidation {
name account;
time_point last_invalidation_time;
uint64_t primary_key()const { return proposal_name.value; }
};
typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals;

uint64_t primary_key() const { return account.value; }
};
struct [[eosio::table, eosio::contract("rem.msig")]] invalidation {
name account;
time_point last_invalidation_time;

typedef eosio::multi_index< "invals"_n, invalidation > invalidations;
uint64_t primary_key() const { return account.value; }
};
/** @}*/ // end of @defgroup eosiomsig rem.msig
typedef eosio::multi_index< "invals"_n, invalidation > invalidations;

} /// namespace eosio
Loading