35 |
36 | ---
37 | spec_version: "0.2.0"
38 | title: Link Action to Permission
39 | summary: '{{nowrap account}} sets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract to {{nowrap requirement}}'
40 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
41 | ---
42 |
43 | {{account}} sets the minimum required permission for the {{#if type}}{{type}} action of the{{/if}} {{code}} contract to {{requirement}}.
44 |
45 | {{#if type}}{{else}}Any links explicitly associated to specific actions of {{code}} will take precedence.{{/if}}
46 |
47 |
newaccount
48 |
49 | ---
50 | spec_version: "0.2.0"
51 | title: Create New Account
52 | summary: '{{nowrap creator}} creates a new account with the name {{nowrap name}}'
53 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
54 | ---
55 |
56 | {{creator}} creates a new account with the name {{name}} and the following permissions:
57 |
58 | owner permission with authority:
59 | {{to_json owner}}
60 |
61 | active permission with authority:
62 | {{to_json active}}
63 |
64 |
reqactivated
65 |
66 | ---
67 | spec_version: "0.2.0"
68 | title: Assert Protocol Feature Activation
69 | summary: 'Assert that protocol feature {{nowrap feature_digest}} has been activated'
70 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
71 | ---
72 |
73 | Assert that the protocol feature with a digest of {{feature_digest}} has been activated.
74 |
75 |
reqauth
76 |
77 | ---
78 | spec_version: "0.2.0"
79 | title: Assert Authorization
80 | summary: 'Assert that authorization by {{nowrap from}} is provided'
81 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
82 | ---
83 |
84 | Assert that authorization by {{from}} is provided.
85 |
86 |
setabi
87 |
88 | ---
89 | spec_version: "0.2.0"
90 | title: Deploy Contract ABI
91 | summary: 'Deploy contract ABI on account {{nowrap account}}'
92 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
93 | ---
94 |
95 | Deploy the ABI file associated with the contract on account {{account}}.
96 |
97 |
setalimits
98 |
99 | ---
100 | spec_version: "0.2.0"
101 | title: Adjust Resource Limits of Account
102 | summary: 'Adjust resource limits of account {{nowrap account}}'
103 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
104 | ---
105 |
106 | {{$action.account}} updates {{account}}’s resource limits to have a RAM quota of {{ram_bytes}} bytes, a NET bandwidth quota of {{net_weight}} and a CPU bandwidth quota of {{cpu_weight}}.
107 |
108 |
120 |
121 | ---
122 | spec_version: "0.2.0"
123 | title: Set System Parameters
124 | summary: 'Set system parameters'
125 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
126 | ---
127 |
128 | {{$action.account}} sets system parameters to:
129 | {{to_json params}}
130 |
131 |
setpriv
132 |
133 | ---
134 | spec_version: "0.2.0"
135 | title: Make an Account Privileged or Unprivileged
136 | summary: '{{#if is_priv}}Make {{nowrap account}} privileged{{else}}Remove privileged status of {{nowrap account}}{{/if}}'
137 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
138 | ---
139 |
140 | {{#if is_priv}}
141 | {{$action.account}} makes {{account}} privileged.
142 | {{else}}
143 | {{$action.account}} removes privileged status of {{account}}.
144 | {{/if}}
145 |
146 |
setprods
147 |
148 | ---
149 | spec_version: "0.2.0"
150 | title: Set Block Producers
151 | summary: 'Set block producer schedule'
152 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
153 | ---
154 |
155 | {{$action.account}} proposes a block producer schedule of:
156 | {{#each schedule}}
157 | 1. {{this.producer_name}}
158 | {{/each}}
159 |
160 | The block signing authorities of each of the producers in the above schedule are listed below:
161 | {{#each schedule}}
162 | ### {{this.producer_name}}
163 | {{to_json this.authority}}
164 | {{/each}}
165 |
166 |
unlinkauth
167 |
168 | ---
169 | spec_version: "0.2.0"
170 | title: Unlink Action from Permission
171 | summary: '{{nowrap account}} unsets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract'
172 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
173 | ---
174 |
175 | {{account}} removes the association between the {{#if type}}{{type}} action of the{{/if}} {{code}} contract and its minimum required permission.
176 |
177 | {{#if type}}{{else}}This will not remove any links explicitly associated to specific actions of {{code}}.{{/if}}
178 |
179 |
updateauth
180 |
181 | ---
182 | spec_version: "0.2.0"
183 | title: Modify Account Permission
184 | summary: 'Add or update the {{nowrap permission}} permission of {{nowrap account}}'
185 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
186 | ---
187 |
188 | Modify, and create if necessary, the {{permission}} permission of {{account}} to have a parent permission of {{parent}} and the following authority:
189 | {{to_json auth}}
190 |
--------------------------------------------------------------------------------
/contracts/eosio.bios/src/eosio.bios.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | namespace eosiobios {
7 |
8 | void bios::setabi( name account, const std::vector& abi ) {
9 | abi_hash_table table(get_self(), get_self().value);
10 | auto itr = table.find( account.value );
11 | if( itr == table.end() ) {
12 | table.emplace( account, [&]( auto& row ) {
13 | row.owner = account;
14 | row.hash = eosio::sha256(const_cast(abi.data()), abi.size());
15 | });
16 | } else {
17 | table.modify( itr, eosio::same_payer, [&]( auto& row ) {
18 | row.hash = eosio::sha256(const_cast(abi.data()), abi.size());
19 | });
20 | }
21 | }
22 |
23 | void bios::setfinalizer( const finalizer_policy& finalizer_policy ) {
24 | // exensive checks are performed to make sure setfinalizer host function
25 | // will never fail
26 |
27 | require_auth( get_self() );
28 |
29 | check(finalizer_policy.finalizers.size() <= max_finalizers, "number of finalizers exceeds the maximum allowed");
30 | check(finalizer_policy.finalizers.size() > 0, "require at least one finalizer");
31 |
32 | eosio::finalizer_policy fin_policy;
33 | fin_policy.threshold = finalizer_policy.threshold;
34 | fin_policy.finalizers.reserve(finalizer_policy.finalizers.size());
35 |
36 | const std::string pk_prefix = "PUB_BLS";
37 | const std::string sig_prefix = "SIG_BLS";
38 |
39 | // use raw affine format (bls_g1 is std::array) for uniqueness check
40 | struct g1_hash {
41 | std::size_t operator()(const eosio::bls_g1& g1) const {
42 | std::hash hash_func;
43 | return hash_func(g1.data());
44 | }
45 | };
46 | struct g1_equal {
47 | bool operator()(const eosio::bls_g1& lhs, const eosio::bls_g1& rhs) const {
48 | return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
49 | }
50 | };
51 | std::unordered_set unique_finalizer_keys;
52 |
53 | uint64_t weight_sum = 0;
54 |
55 | for (const auto& f: finalizer_policy.finalizers) {
56 | check(f.description.size() <= max_finalizer_description_size, "Finalizer description greater than max allowed size");
57 |
58 | // basic key format checks
59 | check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key shoud start with PUB_BLS");
60 | check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature should start with SIG_BLS");
61 |
62 | // check overflow
63 | check(std::numeric_limits::max() - weight_sum >= f.weight, "sum of weights causes uint64_t overflow");
64 | weight_sum += f.weight;
65 |
66 | // decode_bls_public_key_to_g1 will fail ("check" function fails)
67 | // if the key is invalid
68 | const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key);
69 | // duplicate key check
70 | check(unique_finalizer_keys.insert(pk).second, "duplicate public key");
71 |
72 | const auto signature = eosio::decode_bls_signature_to_g2(f.pop);
73 |
74 | // proof of possession of private key check
75 | check(eosio::bls_pop_verify(pk, signature), "proof of possession failed");
76 |
77 | std::vector pk_vector(pk.begin(), pk.end());
78 | fin_policy.finalizers.emplace_back(eosio::finalizer_authority{f.description, f.weight, std::move(pk_vector)});
79 | }
80 |
81 | check( weight_sum >= finalizer_policy.threshold && finalizer_policy.threshold > weight_sum / 2,
82 | "Finalizer policy threshold must be greater than half of the sum of the weights, and less than or equal to the sum of the weights");
83 |
84 | set_finalizers(std::move(fin_policy));
85 | }
86 |
87 | void bios::onerror( ignore, ignore> ) {
88 | check( false, "the onerror action cannot be called directly" );
89 | }
90 |
91 | void bios::setpriv( name account, uint8_t is_priv ) {
92 | require_auth( get_self() );
93 | set_privileged( account, is_priv );
94 | }
95 |
96 | void bios::setalimits( name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) {
97 | require_auth( get_self() );
98 | set_resource_limits( account, ram_bytes, net_weight, cpu_weight );
99 | }
100 |
101 | void bios::setprods( const std::vector& schedule ) {
102 | require_auth( get_self() );
103 | set_proposed_producers( schedule );
104 | }
105 |
106 | void bios::setparams( const eosio::blockchain_parameters& params ) {
107 | require_auth( get_self() );
108 | set_blockchain_parameters( params );
109 | }
110 |
111 | void bios::reqauth( name from ) {
112 | require_auth( from );
113 | }
114 |
115 | void bios::activate( const eosio::checksum256& feature_digest ) {
116 | require_auth( get_self() );
117 | preactivate_feature( feature_digest );
118 | }
119 |
120 | void bios::reqactivated( const eosio::checksum256& feature_digest ) {
121 | check( is_feature_activated( feature_digest ), "protocol feature is not activated" );
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/contracts/eosio.boot/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(eosio.boot eosio.boot ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.boot.cpp)
2 |
3 | target_include_directories(eosio.boot
4 | PUBLIC
5 | ${CMAKE_CURRENT_SOURCE_DIR}/include)
6 |
7 | set_target_properties(eosio.boot
8 | PROPERTIES
9 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
10 |
11 | configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.boot.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.boot.contracts.md @ONLY )
12 |
13 | target_compile_options( eosio.boot PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian )
14 |
--------------------------------------------------------------------------------
/contracts/eosio.boot/ricardian/eosio.boot.contracts.md.in:
--------------------------------------------------------------------------------
1 |
35 |
36 | ---
37 | spec_version: "0.2.0"
38 | title: Link Action to Permission
39 | summary: '{{nowrap account}} sets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract to {{nowrap requirement}}'
40 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
41 | ---
42 |
43 | {{account}} sets the minimum required permission for the {{#if type}}{{type}} action of the{{/if}} {{code}} contract to {{requirement}}.
44 |
45 | {{#if type}}{{else}}Any links explicitly associated to specific actions of {{code}} will take precedence.{{/if}}
46 |
47 |
newaccount
48 |
49 | ---
50 | spec_version: "0.2.0"
51 | title: Create New Account
52 | summary: '{{nowrap creator}} creates a new account with the name {{nowrap name}}'
53 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
54 | ---
55 |
56 | {{creator}} creates a new account with the name {{name}} and the following permissions:
57 |
58 | owner permission with authority:
59 | {{to_json owner}}
60 |
61 | active permission with authority:
62 | {{to_json active}}
63 |
64 |
reqactivated
65 |
66 | ---
67 | spec_version: "0.2.0"
68 | title: Assert Protocol Feature Activation
69 | summary: 'Assert that protocol feature {{nowrap feature_digest}} has been activated'
70 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
71 | ---
72 |
73 | Assert that the protocol feature with a digest of {{feature_digest}} has been activated.
74 |
75 |
setabi
76 |
77 | ---
78 | spec_version: "0.2.0"
79 | title: Deploy Contract ABI
80 | summary: 'Deploy contract ABI on account {{nowrap account}}'
81 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
82 | ---
83 |
84 | Deploy the ABI file associated with the contract on account {{account}}.
85 |
86 |
98 |
99 | ---
100 | spec_version: "0.2.0"
101 | title: Unlink Action from Permission
102 | summary: '{{nowrap account}} unsets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract'
103 | icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@
104 | ---
105 |
106 | {{account}} removes the association between the {{#if type}}{{type}} action of the{{/if}} {{code}} contract and its minimum required permission.
107 |
108 | {{#if type}}{{else}}This will not remove any links explicitly associated to specific actions of {{code}}.{{/if}}
109 |
110 |
2 |
3 | ---
4 | spec_version: "0.2.0"
5 | title: Claim Rewards
6 | summary: '{{nowrap owner}} claims block production rewards'
7 | icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@
8 | ---
9 |
10 | {{owner}} claims block production rewards accumulated through network fees.
11 |
--------------------------------------------------------------------------------
/contracts/eosio.bpay/src/eosio.bpay.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace eosio {
4 |
5 | void bpay::claimrewards( const name owner ) {
6 | require_auth( owner );
7 |
8 | rewards_table _rewards( get_self(), get_self().value );
9 |
10 | const auto& row = _rewards.get( owner.value, "no rewards to claim" );
11 |
12 | eosio::token::transfer_action transfer( "eosio.token"_n, { get_self(), "active"_n });
13 | transfer.send( get_self(), owner, row.quantity, "producer block pay" );
14 |
15 | _rewards.erase(row);
16 | }
17 |
18 | void bpay::on_transfer( const name from, const name to, const asset quantity, const string memo ) {
19 | if (from == get_self() || to != get_self()) {
20 | return;
21 | }
22 |
23 | // ignore eosio system incoming transfers (caused by bpay income transfers eosio => eosio.bpay => producer)
24 | if ( from == "eosio"_n) return;
25 |
26 | symbol system_symbol = eosiosystem::system_contract::get_core_symbol();
27 |
28 | check( quantity.symbol == system_symbol, "only core token allowed" );
29 |
30 | rewards_table _rewards( get_self(), get_self().value );
31 | eosiosystem::producers_table _producers( "eosio"_n, "eosio"_n.value );
32 |
33 | eosiosystem::global_state_singleton _global("eosio"_n, "eosio"_n.value);
34 | check( _global.exists(), "global state does not exist");
35 | uint16_t producer_count = _global.get().last_producer_schedule_size;
36 |
37 | // get producer with the most votes
38 | // using `by_votes` secondary index
39 | auto idx = _producers.get_index<"prototalvote"_n>();
40 | auto prod = idx.begin();
41 |
42 | // get top n producers by vote, excluding inactive
43 | std::vector top_producers;
44 | while (true) {
45 | if (prod == idx.end()) break;
46 | if (prod->is_active == false) continue;
47 |
48 | top_producers.push_back(prod->owner);
49 |
50 | if (top_producers.size() == producer_count) break;
51 |
52 | prod++;
53 | }
54 |
55 | asset reward = quantity / top_producers.size();
56 |
57 | // distribute rewards to top producers
58 | for (auto producer : top_producers) {
59 | auto row = _rewards.find( producer.value );
60 | if (row == _rewards.end()) {
61 | _rewards.emplace( get_self(), [&](auto& row) {
62 | row.owner = producer;
63 | row.quantity = reward;
64 | });
65 | } else {
66 | _rewards.modify(row, get_self(), [&](auto& row) {
67 | row.quantity += reward;
68 | });
69 | }
70 | }
71 | }
72 |
73 | } /// namespace eosio
74 |
--------------------------------------------------------------------------------
/contracts/eosio.fees/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(eosio.fees eosio.fees ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.fees.cpp)
2 |
3 | target_include_directories(eosio.fees PUBLIC
4 | ${CMAKE_CURRENT_SOURCE_DIR}/include
5 | ${CMAKE_CURRENT_SOURCE_DIR}/../eosio.system/include)
6 |
7 | set_target_properties(eosio.fees
8 | PROPERTIES
9 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
10 |
11 | target_compile_options( eosio.fees PUBLIC )
12 |
--------------------------------------------------------------------------------
/contracts/eosio.fees/include/eosio.fees/eosio.fees.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | namespace eosiosystem {
10 | class system_contract;
11 | }
12 |
13 | namespace eosio {
14 |
15 | using std::string;
16 | /**
17 | * The eosio.fees smart contract facilitates the collection of transaction fees from system accounts and their subsequent distribution to the Resource Exchange (REX) pool.
18 | *
19 | * This contract serves as an essential component for inclusion in system-level unit tests.
20 | *
21 | * A comprehensive implementation of the eosio.fees contract can be accessed at Vaulta Foundation GitHub repository.
22 | * https://github.com/VaultaFoundation/eosio.fees
23 | */
24 | class [[eosio::contract("eosio.fees")]] fees : public contract {
25 | public:
26 | using contract::contract;
27 |
28 | [[eosio::on_notify("eosio.token::transfer")]]
29 | void on_transfer( const name from, const name to, const asset quantity, const string memo );
30 |
31 | [[eosio::action]]
32 | void noop();
33 | };
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/contracts/eosio.fees/src/eosio.fees.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace eosio {
4 |
5 | void fees::on_transfer( const name from, const name to, const asset quantity, const string memo )
6 | {
7 | if ( to != get_self() ) {
8 | return;
9 | }
10 | if (eosiosystem::system_contract::rex_available()) {
11 | eosiosystem::system_contract::donatetorex_action donatetorex( "eosio"_n, { get_self(), "active"_n });
12 | donatetorex.send(get_self(), quantity, memo);
13 | }
14 | }
15 |
16 | void fees::noop()
17 | {
18 | require_auth( get_self() );
19 | }
20 |
21 | } /// namespace eosio
22 |
--------------------------------------------------------------------------------
/contracts/eosio.msig/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(eosio.msig eosio.msig ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.msig.cpp)
2 |
3 | target_include_directories(eosio.msig
4 | PUBLIC
5 | ${CMAKE_CURRENT_SOURCE_DIR}/include)
6 |
7 | set_target_properties(eosio.msig
8 | PROPERTIES
9 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
10 |
11 | configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.msig.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.msig.contracts.md @ONLY )
12 |
13 | target_compile_options( eosio.msig PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian )
14 |
--------------------------------------------------------------------------------
/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace eosio {
9 | /**
10 | * The `eosio.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.
11 | *
12 | * In short, the workflow to propose, review, approve and then executed a transaction it can be described by the following:
13 | * - first you create a transaction json file,
14 | * - then you submit this proposal to the `eosio.msig` contract, and you also insert the account permissions required to approve this proposal into the command that submits the proposal to the blockchain,
15 | * - the proposal then gets stored on the blockchain by the `eosio.msig` contract, and is accessible for review and approval to those accounts required to approve it,
16 | * - after each of the appointed accounts required to approve the proposed transactions reviews and approves it, you can execute the proposed transaction. The `eosio.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.
17 | */
18 | class [[eosio::contract("eosio.msig")]] multisig : public contract {
19 | public:
20 | using contract::contract;
21 |
22 | /**
23 | * Propose action, creates a proposal containing one transaction.
24 | * Allows an account `proposer` to make a proposal `proposal_name` which has `requested`
25 | * permission levels expected to approve the proposal, and if approved by all expected
26 | * permission levels then `trx` transaction can we executed by this proposal.
27 | * The `proposer` account is authorized and the `trx` transaction is verified if it was
28 | * authorized by the provided keys and permissions, and if the proposal name doesn’t
29 | * already exist; if all validations pass the `proposal_name` and `trx` trasanction are
30 | * saved in the proposals table and the `requested` permission levels to the
31 | * approvals table (for the `proposer` context). Storage changes are billed to `proposer`.
32 | *
33 | * @param proposer - The account proposing a transaction
34 | * @param proposal_name - The name of the proposal (should be unique for proposer)
35 | * @param requested - Permission levels expected to approve the proposal
36 | * @param trx - Proposed transaction
37 | */
38 | [[eosio::action]]
39 | void propose(name proposer, name proposal_name,
40 | std::vector requested, ignore trx);
41 | /**
42 | * Approve action approves an existing proposal. Allows an account, the owner of `level` permission, to approve a proposal `proposal_name`
43 | * proposed by `proposer`. If the proposal's requested approval list contains the `level`
44 | * permission then the `level` permission is moved from internal `requested_approvals` list to
45 | * internal `provided_approvals` list of the proposal, thus persisting the approval for
46 | * the `proposal_name` proposal. Storage changes are billed to `proposer`.
47 | *
48 | * @param proposer - The account proposing a transaction
49 | * @param proposal_name - The name of the proposal (should be unique for proposer)
50 | * @param level - Permission level approving the transaction
51 | * @param proposal_hash - Transaction's checksum
52 | */
53 | [[eosio::action]]
54 | void approve( name proposer, name proposal_name, permission_level level,
55 | const eosio::binary_extension& proposal_hash );
56 | /**
57 | * Unapprove action revokes an existing proposal. This action is the reverse of the `approve` action: if all validations pass
58 | * the `level` permission is erased from internal `provided_approvals` and added to the internal
59 | * `requested_approvals` list, and thus un-approve or revoke the proposal.
60 | *
61 | * @param proposer - The account proposing a transaction
62 | * @param proposal_name - The name of the proposal (should be an existing proposal)
63 | * @param level - Permission level revoking approval for proposal
64 | */
65 | [[eosio::action]]
66 | void unapprove( name proposer, name proposal_name, permission_level level );
67 | /**
68 | * Cancel action cancels an existing proposal.
69 | *
70 | * @param proposer - The account proposing a transaction
71 | * @param proposal_name - The name of the proposal (should be an existing proposal)
72 | * @param canceler - The account cancelling the proposal (only the proposer can cancel an unexpired transaction, and the canceler has to be different than the proposer)
73 | *
74 | * Allows the `canceler` account to cancel the `proposal_name` proposal, created by a `proposer`,
75 | * only after time has expired on the proposed transaction. It removes corresponding entries from
76 | * internal proptable and from approval (or old approvals) tables as well.
77 | */
78 | [[eosio::action]]
79 | void cancel( name proposer, name proposal_name, name canceler );
80 | /**
81 | * Exec action allows an `executer` account to execute a proposal.
82 | *
83 | * Preconditions:
84 | * - `executer` has authorization,
85 | * - `proposal_name` is found in the proposals table,
86 | * - all requested approvals are received,
87 | * - proposed transaction is not expired,
88 | * - and approval accounts are not found in invalidations table.
89 | *
90 | * If all preconditions are met the transaction is executed as a deferred transaction,
91 | * and the proposal is erased from the proposals table.
92 | *
93 | * @param proposer - The account proposing a transaction
94 | * @param proposal_name - The name of the proposal (should be an existing proposal)
95 | * @param executer - The account executing the transaction
96 | */
97 | [[eosio::action]]
98 | void exec( name proposer, name proposal_name, name executer );
99 | /**
100 | * Invalidate action allows an `account` to invalidate itself, that is, its name is added to
101 | * the invalidations table and this table will be cross referenced when exec is performed.
102 | *
103 | * @param account - The account invalidating the transaction
104 | */
105 | [[eosio::action]]
106 | void invalidate( name account );
107 |
108 | using propose_action = eosio::action_wrapper<"propose"_n, &multisig::propose>;
109 | using approve_action = eosio::action_wrapper<"approve"_n, &multisig::approve>;
110 | using unapprove_action = eosio::action_wrapper<"unapprove"_n, &multisig::unapprove>;
111 | using cancel_action = eosio::action_wrapper<"cancel"_n, &multisig::cancel>;
112 | using exec_action = eosio::action_wrapper<"exec"_n, &multisig::exec>;
113 | using invalidate_action = eosio::action_wrapper<"invalidate"_n, &multisig::invalidate>;
114 |
115 | struct [[eosio::table, eosio::contract("eosio.msig")]] proposal {
116 | name proposal_name;
117 | std::vector packed_transaction;
118 | eosio::binary_extension< std::optional > earliest_exec_time;
119 |
120 | uint64_t primary_key()const { return proposal_name.value; }
121 | };
122 | typedef eosio::multi_index< "proposal"_n, proposal > proposals;
123 |
124 | struct [[eosio::table, eosio::contract("eosio.msig")]] old_approvals_info {
125 | name proposal_name;
126 | std::vector requested_approvals;
127 | std::vector provided_approvals;
128 | uint64_t primary_key()const { return proposal_name.value; }
129 | };
130 | typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals;
131 | struct approval {
132 | permission_level level;
133 | time_point time;
134 | };
135 |
136 | struct [[eosio::table, eosio::contract("eosio.msig")]] approvals_info {
137 | uint8_t version = 1;
138 | name proposal_name;
139 | //requested approval doesn't need to contain time, but we want requested approval
140 | //to be of exactly the same size as provided approval, in this case approve/unapprove
141 | //doesn't change serialized data size. So, we use the same type.
142 | std::vector requested_approvals;
143 | std::vector provided_approvals;
144 | uint64_t primary_key()const { return proposal_name.value; }
145 | };
146 | typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals;
147 |
148 | struct [[eosio::table, eosio::contract("eosio.msig")]] invalidation {
149 | name account;
150 | time_point last_invalidation_time;
151 |
152 | uint64_t primary_key() const { return account.value; }
153 | };
154 |
155 | typedef eosio::multi_index< "invals"_n, invalidation > invalidations;
156 | };
157 | } /// namespace eosio
158 |
--------------------------------------------------------------------------------
/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in:
--------------------------------------------------------------------------------
1 |
approve
2 |
3 | ---
4 | spec_version: "0.2.0"
5 | title: Approve Proposed Transaction
6 | summary: '{{nowrap level.actor}} approves the {{nowrap proposal_name}} proposal'
7 | icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@
8 | ---
9 |
10 | {{level.actor}} approves the {{proposal_name}} proposal proposed by {{proposer}} with the {{level.permission}} permission of {{level.actor}}.
11 |
12 |
24 |
25 | ---
26 | spec_version: "0.2.0"
27 | title: Execute Proposed Transaction
28 | summary: '{{nowrap executer}} executes the {{nowrap proposal_name}} proposal'
29 | icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@
30 | ---
31 |
32 | {{executer}} executes the {{proposal_name}} proposal submitted by {{proposer}} if the minimum required approvals for the proposal have been secured.
33 |
34 |
invalidate
35 |
36 | ---
37 | spec_version: "0.2.0"
38 | title: Invalidate All Approvals
39 | summary: '{{nowrap account}} invalidates approvals on outstanding proposals'
40 | icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@
41 | ---
42 |
43 | {{account}} invalidates all approvals on proposals which have not yet executed.
44 |
45 |
propose
46 |
47 | ---
48 | spec_version: "0.2.0"
49 | title: Propose Transaction
50 | summary: '{{nowrap proposer}} creates the {{nowrap proposal_name}}'
51 | icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@
52 | ---
53 |
54 | {{proposer}} creates the {{proposal_name}} proposal for the following transaction:
55 | {{to_json trx}}
56 |
57 | The proposal requests approvals from the following accounts at the specified permission levels:
58 | {{#each requested}}
59 | + {{this.permission}} permission of {{this.actor}}
60 | {{/each}}
61 |
62 | If the proposed transaction is not executed prior to {{trx.expiration}}, the proposal will automatically expire.
63 |
64 |
unapprove
65 |
66 | ---
67 | spec_version: "0.2.0"
68 | title: Unapprove Proposed Transaction
69 | summary: '{{nowrap level.actor}} revokes the approval previously provided to {{nowrap proposal_name}} proposal'
70 | icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@
71 | ---
72 |
73 | {{level.actor}} revokes the approval previously provided at their {{level.permission}} permission level from the {{proposal_name}} proposal proposed by {{proposer}}.
74 |
--------------------------------------------------------------------------------
/contracts/eosio.system/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(
2 | eosio.system
3 | eosio.system
4 | ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.system.cpp
5 | ${CMAKE_CURRENT_SOURCE_DIR}/src/delegate_bandwidth.cpp
6 | ${CMAKE_CURRENT_SOURCE_DIR}/src/exchange_state.cpp
7 | ${CMAKE_CURRENT_SOURCE_DIR}/src/finalizer_key.cpp
8 | ${CMAKE_CURRENT_SOURCE_DIR}/src/name_bidding.cpp
9 | ${CMAKE_CURRENT_SOURCE_DIR}/src/native.cpp
10 | ${CMAKE_CURRENT_SOURCE_DIR}/src/peer_keys.cpp
11 | ${CMAKE_CURRENT_SOURCE_DIR}/src/producer_pay.cpp
12 | ${CMAKE_CURRENT_SOURCE_DIR}/src/powerup.cpp
13 | ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp
14 | ${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp
15 | ${CMAKE_CURRENT_SOURCE_DIR}/src/limit_auth_changes.cpp
16 | ${CMAKE_CURRENT_SOURCE_DIR}/src/block_info.cpp)
17 |
18 | if(SYSTEM_CONFIGURABLE_WASM_LIMITS)
19 | target_compile_definitions(eosio.system PUBLIC SYSTEM_CONFIGURABLE_WASM_LIMITS)
20 | endif()
21 |
22 | if(SYSTEM_BLOCKCHAIN_PARAMETERS)
23 | target_compile_definitions(eosio.system PUBLIC SYSTEM_BLOCKCHAIN_PARAMETERS)
24 | endif()
25 |
26 | target_include_directories(eosio.system PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
27 | ${CMAKE_CURRENT_SOURCE_DIR}/../eosio.token/include)
28 |
29 | set_target_properties(eosio.system PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
30 |
31 | add_contract(rex.results rex.results ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.results.cpp)
32 | add_contract(powup.results powup.results ${CMAKE_CURRENT_SOURCE_DIR}/src/powerup.results.cpp)
33 |
34 | target_include_directories(rex.results PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
35 |
36 | target_include_directories(powup.results PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
37 |
38 | set_target_properties(rex.results PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.rex")
39 |
40 | set_target_properties(powup.results PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.powerup")
41 |
42 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.system.contracts.md.in
43 | ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.system.contracts.md @ONLY)
44 |
45 | target_compile_options(eosio.system PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian
46 | -R${CMAKE_CURRENT_BINARY_DIR}/ricardian)
47 |
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/block_info.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | namespace eosiosystem::block_info {
11 |
12 | static constexpr uint32_t rolling_window_size = 10;
13 |
14 | /**
15 | * The blockinfo table holds a rolling window of records containing information for recent blocks.
16 | *
17 | * Each record stores the height and timestamp of the correspond block.
18 | * A record is added for a new block through the onblock action.
19 | * The onblock action also erases up to two old records at a time in an attempt to keep the table consisting of only
20 | * records for blocks going back a particular block height difference backward from the most recent block.
21 | * Currently that block height difference is hardcoded to 10.
22 | */
23 | struct [[eosio::table, eosio::contract("eosio.system")]] block_info_record
24 | {
25 | uint8_t version = 0;
26 | uint32_t block_height;
27 | eosio::time_point block_timestamp;
28 |
29 | uint64_t primary_key() const { return block_height; }
30 |
31 | EOSLIB_SERIALIZE(block_info_record, (version)(block_height)(block_timestamp))
32 | };
33 |
34 | using block_info_table = eosio::multi_index<"blockinfo"_n, block_info_record>;
35 |
36 | struct block_batch_info
37 | {
38 | uint32_t batch_start_height;
39 | eosio::time_point batch_start_timestamp;
40 | uint32_t batch_current_end_height;
41 | eosio::time_point batch_current_end_timestamp;
42 | };
43 |
44 | struct latest_block_batch_info_result
45 | {
46 | enum error_code_enum : uint32_t
47 | {
48 | no_error,
49 | invalid_input,
50 | unsupported_version,
51 | insufficient_data
52 | };
53 |
54 | std::optional result;
55 | error_code_enum error_code = no_error;
56 | };
57 |
58 | /**
59 | * Get information on the latest block batch.
60 | *
61 | * A block batch is a contiguous range of blocks of a particular size.
62 | * A sequence of blocks can be partitioned into a sequence of block batches, where all except for perhaps the last batch
63 | * in the sequence have the same size. The last batch in the sequence can have a smaller size if the
64 | * blocks of the blockchain that would complete that batch have not yet been generated or recorded.
65 | *
66 | * This function enables the caller to specify a particular partitioning of the sequence of blocks into a sequence of
67 | * block batches of a particular non-zero size (`batch_size`) and then isolates the last block batch in that sequence
68 | * and returns the information about that latest block batch if possible. The partitioning will ensure that
69 | * `batch_start_height_offset` will be equal to the starting block height of exactly one of block batches in the
70 | * sequence.
71 | *
72 | * The information about the latest block batch is the same data captured in `block_batch_info`.
73 | * Particularly, it returns the height and timestamp of starting and ending blocks within that latest block batch.
74 | * Note that the range spanning from the start to end block of the latest block batch may be less than batch_size
75 | * because latest block batch may be incomplete.
76 | * Also, it is possible for the record capturing info for the starting block to not exist in the blockinfo table. This
77 | * can either be due to the records being erased as they fall out of the rolling window or, in rare cases, due to gaps
78 | * in block info records due to failures of the onblock action. In such a case, this function will be unable to return a
79 | * `block_batch_info` and will instead be forced to return the `insufficient_data` error code.
80 | * Furthermore, if `batch_start_height_offset` is greater than the height of the latest block for which
81 | * information is recorded in the blockinfo table, there will be no latest block batch identified for the function to
82 | * return information about and so it will again be forced to return the `insufficient_data` error code instead.
83 | */
84 | latest_block_batch_info_result get_latest_block_batch_info(uint32_t batch_start_height_offset,
85 | uint32_t batch_size,
86 | eosio::name system_account_name = "eosio"_n)
87 | {
88 | latest_block_batch_info_result result;
89 |
90 | if (batch_size == 0) {
91 | result.error_code = latest_block_batch_info_result::invalid_input;
92 | return result;
93 | }
94 |
95 | block_info_table t(system_account_name, 0);
96 |
97 | // Find information on latest block recorded in the blockinfo table.
98 |
99 | if (t.cbegin() == t.cend()) {
100 | // The blockinfo table is empty.
101 | result.error_code = latest_block_batch_info_result::insufficient_data;
102 | return result;
103 | }
104 |
105 | auto latest_block_info_itr = --t.cend();
106 |
107 | if (latest_block_info_itr->version != 0) {
108 | // Compiled code for this function within the calling contract has not been updated to support new version of
109 | // the blockinfo table.
110 | result.error_code = latest_block_batch_info_result::unsupported_version;
111 | return result;
112 | }
113 |
114 | uint32_t latest_block_batch_end_height = latest_block_info_itr->block_height;
115 |
116 | if (latest_block_batch_end_height < batch_start_height_offset) {
117 | // Caller asking for a block batch that has not even begun to be recorded yet.
118 | result.error_code = latest_block_batch_info_result::insufficient_data;
119 | return result;
120 | }
121 |
122 | // Calculate height for the starting block of the latest block batch.
123 |
124 | uint32_t latest_block_batch_start_height =
125 | latest_block_batch_end_height - ((latest_block_batch_end_height - batch_start_height_offset) % batch_size);
126 |
127 | // Note: 1 <= (latest_block_batch_end_height - latest_block_batch_start_height + 1) <= batch_size
128 |
129 | if (latest_block_batch_start_height == latest_block_batch_end_height) {
130 | // When batch_size == 1, this function effectively simplifies to just returning the info of the latest recorded
131 | // block. In that case, the start block and the end block of the batch are the same and there is no need for
132 | // another lookup. So shortcut the rest of the process and return a successful result immediately.
133 | result.result.emplace(block_batch_info{
134 | .batch_start_height = latest_block_batch_start_height,
135 | .batch_start_timestamp = latest_block_info_itr->block_timestamp,
136 | .batch_current_end_height = latest_block_batch_end_height,
137 | .batch_current_end_timestamp = latest_block_info_itr->block_timestamp,
138 | });
139 | return result;
140 | }
141 |
142 | // Find information on start block of the latest block batch recorded in the blockinfo table.
143 |
144 | auto start_block_info_itr = t.find(latest_block_batch_start_height);
145 | if (start_block_info_itr == t.cend() || start_block_info_itr->block_height != latest_block_batch_start_height) {
146 | // Record for information on start block of the latest block batch could not be found in blockinfo table.
147 | // This is either because of:
148 | // * a gap in recording info due to a failed onblock action;
149 | // * a requested start block that was processed by onblock prior to deployment of the system contract code
150 | // introducing the blockinfo table;
151 | // * or, most likely, because the record for the requested start block was pruned from the blockinfo table as
152 | // it fell out of the rolling window.
153 | result.error_code = latest_block_batch_info_result::insufficient_data;
154 | return result;
155 | }
156 |
157 | if (start_block_info_itr->version != 0) {
158 | // Compiled code for this function within the calling contract has not been updated to support new version of
159 | // the blockinfo table.
160 | result.error_code = latest_block_batch_info_result::unsupported_version;
161 | return result;
162 | }
163 |
164 | // Successfully return block_batch_info for the found latest block batch in its current state.
165 |
166 | result.result.emplace(block_batch_info{
167 | .batch_start_height = latest_block_batch_start_height,
168 | .batch_start_timestamp = start_block_info_itr->block_timestamp,
169 | .batch_current_end_height = latest_block_batch_end_height,
170 | .batch_current_end_timestamp = latest_block_info_itr->block_timestamp,
171 | });
172 | return result;
173 | }
174 |
175 | } // namespace eosiosystem::block_info
176 |
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/canon_name.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace eosiosystem {
5 |
6 | // -------------------------------------------------------------------------------------------
7 | struct canon_name_t
8 | {
9 | uint64_t _value; // all significant characters are shifted to the least significant position
10 | uint64_t _size; // number of significant characters
11 |
12 | uint64_t mask() const { return (1ull << (_size * 5)) - 1; }
13 | uint64_t size() const { return _size; }
14 | bool valid() const { return _size != 0; }
15 |
16 | // starts from the end, so n[0] is the last significant character of the name
17 | uint64_t operator[](uint64_t i) const { return (_value >> (5 * i)) & 0x1F; }
18 |
19 | canon_name_t(name n) {
20 | uint64_t v = n.value;
21 | auto num_zeros = std::countr_zero(v);
22 | if ((num_zeros < 4) || (num_zeros == 64)) { // 13th char must be zero, and pattern should not be empty
23 | _size = 0; // zero size denotes an invalid pattern
24 | } else {
25 | uint64_t shift = 4 + ((num_zeros - 4) / 5) * 5;
26 | _value = v >> shift;
27 | auto sig_bits = 64 - shift;
28 | _size = sig_bits / 5;
29 | }
30 | }
31 |
32 | // returns true if account_name ends with the same characters as `this`, preceded by a `.` (zero) character
33 | bool is_suffix_of(canon_name_t account_name) const {
34 | assert(valid());
35 | if (size() > account_name.size())
36 | return false;
37 |
38 | if (((_value ^ account_name._value) & mask()) != 0)
39 | return false;
40 |
41 | // pattern matches the end of account_name. To be a suffix it has to either be the same length (i.e. exact match),
42 | // or be preceded by a dot in account_name
43 | return (size() == account_name.size()) || (account_name[size()] == 0);
44 | }
45 |
46 | bool found_in(canon_name_t account_name) const {
47 | assert(valid());
48 | if (size() > account_name.size())
49 | return false;
50 |
51 | auto sz = size();
52 | size_t diff = account_name.size() - sz + 1;
53 | for (size_t i = 0; i < diff; ++i)
54 | if (((_value ^ (account_name._value >> (5 * i))) & mask()) == 0)
55 | return true;
56 | return false;
57 | }
58 | };
59 |
60 | // -------------------------------------------------------------------------------------------
61 | static inline bool name_allowed(name account, name patt)
62 | {
63 | canon_name_t pattern(patt);
64 | canon_name_t account_name(account);
65 |
66 | if (!pattern.valid())
67 | return true; // ignore invalid patterns
68 |
69 | if (pattern.is_suffix_of(account_name))
70 | return true;
71 | if (pattern.found_in(account_name))
72 | return false;
73 | return true;
74 | }
75 |
76 | } // namespace eosiosystem
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/exchange_state.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | namespace eosiosystem {
7 |
8 | using eosio::asset;
9 | using eosio::symbol;
10 |
11 | /**
12 | * Uses Bancor math to create a 50/50 relay between two asset types.
13 | *
14 | * The state of the bancor exchange is entirely contained within this struct.
15 | * There are no external side effects associated with using this API.
16 | */
17 | struct [[eosio::table, eosio::contract("eosio.system")]] exchange_state {
18 | asset supply;
19 |
20 | struct connector {
21 | asset balance;
22 | double weight = .5;
23 |
24 | EOSLIB_SERIALIZE( connector, (balance)(weight) )
25 | };
26 |
27 | connector base;
28 | connector quote;
29 |
30 | uint64_t primary_key()const { return supply.symbol.raw(); }
31 |
32 | asset convert_to_exchange( connector& reserve, const asset& payment );
33 | asset convert_from_exchange( connector& reserve, const asset& tokens );
34 | asset convert( const asset& from, const symbol& to );
35 | asset direct_convert( const asset& from, const symbol& to );
36 |
37 | static int64_t get_bancor_output( int64_t inp_reserve,
38 | int64_t out_reserve,
39 | int64_t inp );
40 | static int64_t get_bancor_input( int64_t out_reserve,
41 | int64_t inp_reserve,
42 | int64_t out );
43 |
44 | EOSLIB_SERIALIZE( exchange_state, (supply)(base)(quote) )
45 | };
46 |
47 | typedef eosio::multi_index< "rammarket"_n, exchange_state > rammarket;
48 | } /// namespace eosiosystem
49 |
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/limit_auth_changes.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | namespace eosiosystem {
6 | using eosio::name;
7 |
8 | struct [[eosio::table("limitauthchg"),eosio::contract("eosio.system")]] limit_auth_change {
9 | uint8_t version = 0;
10 | name account;
11 | std::vector allow_perms;
12 | std::vector disallow_perms;
13 |
14 | uint64_t primary_key() const { return account.value; }
15 |
16 | EOSLIB_SERIALIZE(limit_auth_change, (version)(account)(allow_perms)(disallow_perms))
17 | };
18 |
19 | typedef eosio::multi_index<"limitauthchg"_n, limit_auth_change> limit_auth_change_table;
20 | } // namespace eosiosystem
21 |
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/peer_keys.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | namespace eosiosystem {
11 |
12 | using eosio::name;
13 | using eosio::public_key;
14 |
15 | // -------------------------------------------------------------------------------------------------
16 | // -------------------------------------------------------------------------------------------------
17 | struct [[eosio::table("peerkeys"), eosio::contract("eosio.system")]] peer_key {
18 | struct v0_data {
19 | std::optional pubkey; // peer key for network message authentication
20 | EOSLIB_SERIALIZE(v0_data, (pubkey))
21 | };
22 |
23 | name account;
24 | std::variant data;
25 |
26 | uint64_t primary_key() const { return account.value; }
27 |
28 | void set_public_key(const public_key& key) { data = v0_data{key}; }
29 | const std::optional& get_public_key() const {
30 | return std::visit([](auto& v) -> const std::optional& { return v.pubkey; }, data);
31 | }
32 | void update_row() {}
33 | void init_row(name n) { *this = peer_key{n, v0_data{}}; }
34 | };
35 |
36 | // -------------------------------------------------------------------------------------------------
37 | // -------------------------------------------------------------------------------------------------
38 | typedef eosio::multi_index<"peerkeys"_n, peer_key> peer_keys_table;
39 |
40 | // -------------------------------------------------------------------------------------------------
41 | // -------------------------------------------------------------------------------------------------
42 | struct [[eosio::contract("eosio.system")]] peer_keys : public eosio::contract {
43 |
44 | peer_keys(name s, name code, eosio::datastream ds)
45 | : eosio::contract(s, code, ds) {}
46 |
47 | struct peerkeys_t {
48 | name producer_name;
49 | std::optional peer_key;
50 |
51 | EOSLIB_SERIALIZE(peerkeys_t, (producer_name)(peer_key))
52 | };
53 |
54 | using getpeerkeys_res_t = std::vector;
55 |
56 | /**
57 | * Action to register a public key for a proposer or finalizer name.
58 | * This key will be used to validate a network peer's identity.
59 | * A proposer or finalizer can only have have one public key registered at a time.
60 | * If a key is already registered for `proposer_finalizer_name`, and `regpeerkey` is
61 | * called with a different key, the new key replaces the previous one in `peer_keys_table`
62 | */
63 | [[eosio::action]]
64 | void regpeerkey(const name& proposer_finalizer_name, const public_key& key);
65 |
66 | /**
67 | * Action to delete a public key for a proposer or finalizer name.
68 | *
69 | * An existing public key for a given account can be changed by calling `regpeerkey` again.
70 | */
71 | [[eosio::action]]
72 | void delpeerkey(const name& proposer_finalizer_name, const public_key& key);
73 |
74 | /**
75 | * Returns a list of up to 50 top producers (active *and* non-active, in votes rank order),
76 | * along with their peer public key if it was registered via the regpeerkey action.
77 | */
78 | [[eosio::action]]
79 | getpeerkeys_res_t getpeerkeys();
80 |
81 | };
82 |
83 | } // namespace eosiosystem
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/powerup.results.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | using eosio::action_wrapper;
8 | using eosio::asset;
9 | using eosio::name;
10 |
11 | /**
12 | * The action `powupresult` is a no-op.
13 | * It is added as an inline convenience action to `powerup` reservation.
14 | * This inline convenience action does not have any effect, however,
15 | * its data includes the result of the parent action and appears in its trace.
16 | */
17 | class [[eosio::contract("powup.results")]] powup_results : eosio::contract {
18 | public:
19 |
20 | using eosio::contract::contract;
21 |
22 | /**
23 | * powupresult action.
24 | *
25 | * @param fee - powerup fee amount
26 | * @param powup_net - amount of powup NET tokens
27 | * @param powup_cpu - amount of powup CPU tokens
28 | */
29 | [[eosio::action]]
30 | void powupresult( const asset& fee, const int64_t powup_net, const int64_t powup_cpu );
31 |
32 | using powupresult_action = action_wrapper<"powupresult"_n, &powup_results::powupresult>;
33 | };
34 |
--------------------------------------------------------------------------------
/contracts/eosio.system/include/eosio.system/rex.results.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | using eosio::action_wrapper;
8 | using eosio::asset;
9 | using eosio::name;
10 |
11 | /**
12 | * The actions `buyresult`, `sellresult`, `rentresult`, and `orderresult` of `rex.results` are all no-ops.
13 | * They are added as inline convenience actions to `rentnet`, `rentcpu`, `buyrex`, `unstaketorex`, and `sellrex`.
14 | * An inline convenience action does not have any effect, however,
15 | * its data includes the result of the parent action and appears in its trace.
16 | */
17 | class [[eosio::contract("rex.results")]] rex_results : eosio::contract {
18 | public:
19 |
20 | using eosio::contract::contract;
21 |
22 | /**
23 | * Buyresult action.
24 | *
25 | * @param rex_received - amount of tokens used in buy order
26 | */
27 | [[eosio::action]]
28 | void buyresult( const asset& rex_received );
29 |
30 | /**
31 | * Sellresult action.
32 | *
33 | * @param proceeds - amount of tokens used in sell order
34 | */
35 | [[eosio::action]]
36 | void sellresult( const asset& proceeds );
37 |
38 | /**
39 | * Orderresult action.
40 | *
41 | * @param owner - the owner of the order
42 | * @param proceeds - amount of tokens used in order
43 | */
44 | [[eosio::action]]
45 | void orderresult( const name& owner, const asset& proceeds );
46 |
47 | /**
48 | * Rentresult action.
49 | *
50 | * @param rented_tokens - amount of rented tokens
51 | */
52 | [[eosio::action]]
53 | void rentresult( const asset& rented_tokens );
54 |
55 | using buyresult_action = action_wrapper<"buyresult"_n, &rex_results::buyresult>;
56 | using sellresult_action = action_wrapper<"sellresult"_n, &rex_results::sellresult>;
57 | using orderresult_action = action_wrapper<"orderresult"_n, &rex_results::orderresult>;
58 | using rentresult_action = action_wrapper<"rentresult"_n, &rex_results::rentresult>;
59 | };
60 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/block_info.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace {
5 |
6 | inline uint32_t block_height_from_id(const eosio::checksum256& block_id)
7 | {
8 | auto arr = block_id.extract_as_byte_array();
9 | // 32-bit block height is encoded in big endian as the sequence of bytes: arr[0], arr[1], arr[2], arr[3]
10 | return ((arr[0] << 0x18) | (arr[1] << 0x10) | (arr[2] << 0x08) | arr[3]);
11 | }
12 |
13 | } // namespace
14 |
15 | namespace eosiosystem {
16 |
17 | void system_contract::add_to_blockinfo_table(const eosio::checksum256& previous_block_id,
18 | const eosio::block_timestamp timestamp) const
19 | {
20 | const uint32_t new_block_height = block_height_from_id(previous_block_id) + 1;
21 | const auto new_block_timestamp = static_cast(timestamp);
22 |
23 | block_info::block_info_table t(get_self(), 0);
24 |
25 | if (block_info::rolling_window_size > 0) {
26 | // Add new entry to blockinfo table for the new block.
27 | t.emplace(get_self(), [&](block_info::block_info_record& r) {
28 | r.block_height = new_block_height;
29 | r.block_timestamp = new_block_timestamp;
30 | });
31 | }
32 |
33 | // Erase up to two entries that have fallen out of the rolling window.
34 |
35 | const uint32_t last_prunable_block_height =
36 | std::max(new_block_height, block_info::rolling_window_size) - block_info::rolling_window_size;
37 |
38 | int count = 2;
39 | for (auto itr = t.begin(), end = t.end(); //
40 | itr != end && itr->block_height <= last_prunable_block_height && 0 < count; //
41 | --count) //
42 | {
43 | itr = t.erase(itr);
44 | }
45 | }
46 |
47 | } // namespace eosiosystem
--------------------------------------------------------------------------------
/contracts/eosio.system/src/exchange_state.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include
6 |
7 | namespace eosiosystem {
8 |
9 | using eosio::check;
10 |
11 | asset exchange_state::convert_to_exchange( connector& reserve, const asset& payment )
12 | {
13 | const double S0 = supply.amount;
14 | const double R0 = reserve.balance.amount;
15 | const double dR = payment.amount;
16 | const double F = reserve.weight;
17 |
18 | double dS = S0 * ( std::pow(1. + dR / R0, F) - 1. );
19 | if ( dS < 0 ) dS = 0; // rounding errors
20 | reserve.balance += payment;
21 | supply.amount += int64_t(dS);
22 | return asset( int64_t(dS), supply.symbol );
23 | }
24 |
25 | asset exchange_state::convert_from_exchange( connector& reserve, const asset& tokens )
26 | {
27 | const double R0 = reserve.balance.amount;
28 | const double S0 = supply.amount;
29 | const double dS = -tokens.amount; // dS < 0, tokens are subtracted from supply
30 | const double Fi = double(1) / reserve.weight;
31 |
32 | double dR = R0 * ( std::pow(1. + dS / S0, Fi) - 1. ); // dR < 0 since dS < 0
33 | if ( dR > 0 ) dR = 0; // rounding errors
34 | reserve.balance.amount -= int64_t(-dR);
35 | supply -= tokens;
36 | return asset( int64_t(-dR), reserve.balance.symbol );
37 | }
38 |
39 | asset exchange_state::convert( const asset& from, const symbol& to )
40 | {
41 | const auto& sell_symbol = from.symbol;
42 | const auto& base_symbol = base.balance.symbol;
43 | const auto& quote_symbol = quote.balance.symbol;
44 | check( sell_symbol != to, "cannot convert to the same symbol" );
45 |
46 | asset out( 0, to );
47 | if ( sell_symbol == base_symbol && to == quote_symbol ) {
48 | const asset tmp = convert_to_exchange( base, from );
49 | out = convert_from_exchange( quote, tmp );
50 | } else if ( sell_symbol == quote_symbol && to == base_symbol ) {
51 | const asset tmp = convert_to_exchange( quote, from );
52 | out = convert_from_exchange( base, tmp );
53 | } else {
54 | check( false, "invalid conversion" );
55 | }
56 | return out;
57 | }
58 |
59 | asset exchange_state::direct_convert( const asset& from, const symbol& to )
60 | {
61 | const auto& sell_symbol = from.symbol;
62 | const auto& base_symbol = base.balance.symbol;
63 | const auto& quote_symbol = quote.balance.symbol;
64 | check( sell_symbol != to, "cannot convert to the same symbol" );
65 |
66 | asset out( 0, to );
67 | if ( sell_symbol == base_symbol && to == quote_symbol ) {
68 | out.amount = get_bancor_output( base.balance.amount, quote.balance.amount, from.amount );
69 | base.balance += from;
70 | quote.balance -= out;
71 | } else if ( sell_symbol == quote_symbol && to == base_symbol ) {
72 | out.amount = get_bancor_output( quote.balance.amount, base.balance.amount, from.amount );
73 | quote.balance += from;
74 | base.balance -= out;
75 | } else {
76 | check( false, "invalid conversion" );
77 | }
78 | return out;
79 | }
80 |
81 | int64_t exchange_state::get_bancor_output( int64_t inp_reserve,
82 | int64_t out_reserve,
83 | int64_t inp )
84 | {
85 | const double ib = inp_reserve;
86 | const double ob = out_reserve;
87 | const double in = inp;
88 |
89 | int64_t out = int64_t( (in * ob) / (ib + in) );
90 |
91 | if ( out < 0 ) out = 0;
92 |
93 | return out;
94 | }
95 |
96 | int64_t exchange_state::get_bancor_input( int64_t out_reserve,
97 | int64_t inp_reserve,
98 | int64_t out )
99 | {
100 | const double ob = out_reserve;
101 | const double ib = inp_reserve;
102 |
103 | int64_t inp = (ib * out) / (ob - out);
104 |
105 | if ( inp < 0 ) inp = 0;
106 |
107 | return inp;
108 | }
109 |
110 | } /// namespace eosiosystem
111 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/limit_auth_changes.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace eosiosystem {
5 |
6 | void system_contract::limitauthchg(const name& account, const std::vector& allow_perms,
7 | const std::vector& disallow_perms) {
8 | limit_auth_change_table table(get_self(), get_self().value);
9 | require_auth(account);
10 | eosio::check(allow_perms.empty() || disallow_perms.empty(), "either allow_perms or disallow_perms must be empty");
11 | eosio::check(allow_perms.empty() ||
12 | std::find(allow_perms.begin(), allow_perms.end(), "owner"_n) != allow_perms.end(),
13 | "allow_perms does not contain owner");
14 | eosio::check(disallow_perms.empty() ||
15 | std::find(disallow_perms.begin(), disallow_perms.end(), "owner"_n) == disallow_perms.end(),
16 | "disallow_perms contains owner");
17 | auto it = table.find(account.value);
18 | if(!allow_perms.empty() || !disallow_perms.empty()) {
19 | if(it == table.end()) {
20 | table.emplace(account, [&](auto& row){
21 | row.account = account;
22 | row.allow_perms = allow_perms;
23 | row.disallow_perms = disallow_perms;
24 | });
25 | } else {
26 | table.modify(it, account, [&](auto& row){
27 | row.allow_perms = allow_perms;
28 | row.disallow_perms = disallow_perms;
29 | });
30 | }
31 | } else {
32 | if(it != table.end())
33 | table.erase(it);
34 | }
35 | }
36 |
37 | void check_auth_change(name contract, name account, const binary_extension& authorized_by) {
38 | name by(authorized_by.has_value() ? authorized_by.value().value : 0);
39 | if(by.value)
40 | eosio::require_auth({account, by});
41 | limit_auth_change_table table(contract, contract.value);
42 | auto it = table.find(account.value);
43 | if(it == table.end())
44 | return;
45 | eosio::check(by.value, "authorized_by is required for this account");
46 | if(!it->allow_perms.empty())
47 | eosio::check(
48 | std::find(it->allow_perms.begin(), it->allow_perms.end(), by) != it->allow_perms.end(),
49 | "authorized_by does not appear in allow_perms");
50 | else
51 | eosio::check(
52 | std::find(it->disallow_perms.begin(), it->disallow_perms.end(), by) == it->disallow_perms.end(),
53 | "authorized_by appears in disallow_perms");
54 | }
55 |
56 | } // namespace eosiosystem
57 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/name_bidding.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | namespace eosiosystem {
7 |
8 | using eosio::current_time_point;
9 | using eosio::token;
10 |
11 | void system_contract::bidname( const name& bidder, const name& newname, const asset& bid ) {
12 | require_auth( bidder );
13 | check( newname.suffix() == newname, "you can only bid on top-level suffix" );
14 |
15 | check( (bool)newname, "the empty name is not a valid account name to bid on" );
16 | check( (newname.value & 0xFull) == 0, "13 character names are not valid account names to bid on" );
17 | check( (newname.value & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" );
18 | check( !is_account( newname ), "account already exists" );
19 | check( bid.symbol == core_symbol(), "asset must be system token" );
20 | check( bid.amount > 0, "insufficient bid" );
21 | token::transfer_action transfer_act{ token_account, { {bidder, active_permission} } };
22 | transfer_act.send( bidder, names_account, bid, std::string("bid name ")+ newname.to_string() );
23 | name_bid_table bids(get_self(), get_self().value);
24 | print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" );
25 | auto current = bids.find( newname.value );
26 | if( current == bids.end() ) {
27 | bids.emplace( bidder, [&]( auto& b ) {
28 | b.newname = newname;
29 | b.high_bidder = bidder;
30 | b.high_bid = bid.amount;
31 | b.last_bid_time = current_time_point();
32 | });
33 | } else {
34 | check( current->high_bid > 0, "this auction has already closed" );
35 | check( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" );
36 | check( current->high_bidder != bidder, "account is already highest bidder" );
37 |
38 | bid_refund_table refunds_table(get_self(), newname.value);
39 |
40 | auto it = refunds_table.find( current->high_bidder.value );
41 | if ( it != refunds_table.end() ) {
42 | refunds_table.modify( it, same_payer, [&](auto& r) {
43 | r.amount += asset( current->high_bid, core_symbol() );
44 | });
45 | } else {
46 | refunds_table.emplace( bidder, [&](auto& r) {
47 | r.bidder = current->high_bidder;
48 | r.amount = asset( current->high_bid, core_symbol() );
49 | });
50 | }
51 |
52 | bids.modify( current, bidder, [&]( auto& b ) {
53 | b.high_bidder = bidder;
54 | b.high_bid = bid.amount;
55 | b.last_bid_time = current_time_point();
56 | });
57 | }
58 | }
59 |
60 | void system_contract::bidrefund( const name& bidder, const name& newname ) {
61 | bid_refund_table refunds_table(get_self(), newname.value);
62 | auto it = refunds_table.find( bidder.value );
63 | check( it != refunds_table.end(), "refund not found" );
64 |
65 | token::transfer_action transfer_act{ token_account, { {names_account, active_permission}, {bidder, active_permission} } };
66 | transfer_act.send( names_account, bidder, asset(it->amount), std::string("refund bid on name ")+(name{newname}).to_string() );
67 | refunds_table.erase( it );
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/native.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | namespace eosiosystem {
6 |
7 | void native::onerror( ignore, ignore> ) {
8 | eosio::check( false, "the onerror action cannot be called directly" );
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/peer_keys.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | namespace eosiosystem {
8 |
9 | void peer_keys::regpeerkey(const name& proposer_finalizer_name, const public_key& key) {
10 | require_auth(proposer_finalizer_name);
11 | peer_keys_table peer_keys_table(get_self(), get_self().value);
12 | check(!std::holds_alternative(key), "webauthn keys not allowed in regpeerkey action");
13 |
14 | auto peers_itr = peer_keys_table.find(proposer_finalizer_name.value);
15 | if (peers_itr == peer_keys_table.end()) {
16 | peer_keys_table.emplace(proposer_finalizer_name, [&](auto& row) {
17 | row.init_row(proposer_finalizer_name);
18 | row.set_public_key(key);
19 | });
20 | } else {
21 | const auto& prev_key = peers_itr->get_public_key();
22 | check(!prev_key || *prev_key != key, "Provided key is the same as currently stored one");
23 | peer_keys_table.modify(peers_itr, same_payer, [&](auto& row) {
24 | row.update_row();
25 | row.set_public_key(key);
26 | });
27 | }
28 | }
29 |
30 | void peer_keys::delpeerkey(const name& proposer_finalizer_name, const public_key& key) {
31 | require_auth(proposer_finalizer_name);
32 | peer_keys_table peer_keys_table(get_self(), get_self().value);
33 |
34 | auto peers_itr = peer_keys_table.find(proposer_finalizer_name.value);
35 | check(peers_itr != peer_keys_table.end(), "Key not present for name: " + proposer_finalizer_name.to_string());
36 | const auto& prev_key = peers_itr->get_public_key();
37 | check(prev_key && *prev_key == key, "Current key does not match the provided one");
38 | peer_keys_table.erase(peers_itr);
39 | }
40 |
41 | peer_keys::getpeerkeys_res_t peer_keys::getpeerkeys() {
42 | peer_keys_table peer_keys_table(get_self(), get_self().value);
43 | producers_table producers(get_self(), get_self().value);
44 | constexpr size_t max_return = 50;
45 |
46 | getpeerkeys_res_t resp;
47 | resp.reserve(max_return);
48 |
49 | double vote_threshold = 0; // vote_threshold will always be >= 0
50 |
51 | auto add_peer = [&](auto it) {
52 | auto peers_itr = peer_keys_table.find(it->owner.value);
53 | if (peers_itr == peer_keys_table.end())
54 | resp.push_back(peerkeys_t{it->owner, {}});
55 | else
56 | resp.push_back(peerkeys_t{it->owner, peers_itr->get_public_key()});
57 |
58 | // once 21 producers have been selected, we will only consider producers
59 | // that have more than 50% of the votes of the 21st selected producer.
60 | // ---------------------------------------------------------------------
61 | if (resp.size() == 21)
62 | vote_threshold = it->total_votes * 0.5;
63 | };
64 |
65 | auto idx = producers.get_index<"prototalvote"_n>();
66 |
67 | auto it = idx.cbegin();
68 | auto rit = idx.cend();
69 | if (it == rit)
70 | return resp;
71 | else
72 | --rit;
73 |
74 | // 1. Consider both active and non-active producers. as a non-active producer can be
75 | // reactivated at any time.
76 | // 2. Once we have selected 21 producers, the threshold of votes required to be selected
77 | // increases from `> 0` to `> 50% of the votes that the 21st selected producer has`.
78 | // 3. We iterate from both ends, as non-active producers are indexed at the end (their
79 | // vote total is negated for the index computation). As a consequence, the highest
80 | // voted non-active producer will be the last entry of our index.
81 | // --------------------------------------------------------------------------------------
82 | bool last_one = false;
83 | do {
84 | // at this point, `it` and `rit` both point to a valid `producer_info` (possibly the same)
85 | assert(it <= rit);
86 | assert(vote_threshold >= 0);
87 | assert(it->total_votes >= 0 && rit->total_votes >= 0);
88 | last_one = (it == rit);
89 | if (rit->total_votes > std::max(vote_threshold, it->total_votes)) {
90 | add_peer(rit);
91 | assert(it != rit); // Should always be satisfied since `rit->total_votes > it->total_votes`
92 | --rit; // safe because `rit` cannot point to the first entry of the index.
93 | } else if (it->total_votes > vote_threshold) {
94 | add_peer(it);
95 | ++it;
96 | } else {
97 | // `total_votes <= threshold` on both ends of the index, exit the loop.
98 | break;
99 | }
100 | } while (!last_one && resp.size() < max_return);
101 |
102 | return resp;
103 | }
104 |
105 | } // namespace eosiosystem
106 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/powerup.results.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void powup_results::powupresult( const asset& fee, const int64_t powup_net_weight, const int64_t powup_cpu_weight ) { }
4 |
5 | extern "C" void apply( uint64_t, uint64_t, uint64_t ) { }
6 |
--------------------------------------------------------------------------------
/contracts/eosio.system/src/rex.results.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void rex_results::buyresult( const asset& rex_received ) { }
4 |
5 | void rex_results::sellresult( const asset& proceeds ) { }
6 |
7 | void rex_results::orderresult( const name& owner, const asset& proceeds ) { }
8 |
9 | void rex_results::rentresult( const asset& rented_tokens ) { }
10 |
11 | extern "C" void apply( uint64_t, uint64_t, uint64_t ) { }
12 |
--------------------------------------------------------------------------------
/contracts/eosio.token/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(eosio.token eosio.token ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.token.cpp)
2 |
3 | target_include_directories(eosio.token
4 | PUBLIC
5 | ${CMAKE_CURRENT_SOURCE_DIR}/include)
6 |
7 | set_target_properties(eosio.token
8 | PROPERTIES
9 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
10 |
11 | configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.token.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.token.contracts.md @ONLY )
12 |
13 | target_compile_options( eosio.token PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian )
14 |
--------------------------------------------------------------------------------
/contracts/eosio.token/ricardian/eosio.token.contracts.md.in:
--------------------------------------------------------------------------------
1 |
close
2 |
3 | ---
4 | spec_version: "0.2.0"
5 | title: Close Token Balance
6 | summary: 'Close {{nowrap owner}}’s zero quantity balance'
7 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
8 | ---
9 |
10 | {{owner}} agrees to close their zero quantity balance for the {{symbol_to_symbol_code symbol}} token.
11 |
12 | RAM will be refunded to the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}.
13 |
14 |
create
15 |
16 | ---
17 | spec_version: "0.2.0"
18 | title: Create New Token
19 | summary: 'Create a new token'
20 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
21 | ---
22 |
23 | {{$action.account}} agrees to create a new token with symbol {{asset_to_symbol_code maximum_supply}} to be managed by {{issuer}}.
24 |
25 | This action will not result any any tokens being issued into circulation.
26 |
27 | {{issuer}} will be allowed to issue tokens into circulation, up to a maximum supply of {{maximum_supply}}.
28 |
29 | RAM will deducted from {{$action.account}}’s resources to create the necessary records.
30 |
31 |
setmaxsupply
32 |
33 | ---
34 | spec_version: "0.2.0"
35 | title: Set Max Supply
36 | summary: 'Set max supply for token'
37 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
38 | ---
39 |
40 | {{issuer}} will be allowed to issue tokens into circulation, up to a maximum supply of {{maximum_supply}}.
41 |
42 | This action will not result any any tokens being issued into circulation.
43 |
44 |
issue
45 |
46 | ---
47 | spec_version: "0.2.0"
48 | title: Issue Tokens into Circulation
49 | summary: 'Issue {{nowrap quantity}} into circulation and transfer into {{nowrap to}}’s account'
50 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
51 | ---
52 |
53 | The token manager agrees to issue {{quantity}} into circulation, and transfer it into {{to}}’s account.
54 |
55 | {{#if memo}}There is a memo attached to the transfer stating:
56 | {{memo}}
57 | {{/if}}
58 |
59 | If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, or the token manager does not have a balance for {{asset_to_symbol_code quantity}}, the token manager will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from the token manager’s resources to create the necessary records.
60 |
61 | This action does not allow the total quantity to exceed the max allowed supply of the token.
62 |
63 |
issuefixed
64 |
65 | ---
66 | spec_version: "0.2.0"
67 | title: Issue Fixed Supply of Tokens into Circulation
68 | summary: 'Issue up to {{nowrap supply}} supply into circulation and transfer into {{nowrap to}}’s account'
69 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
70 | ---
71 |
72 | The token manager agrees to issue tokens up to {{supply}} fixed supply into circulation, and transfer it into {{to}}’s account.
73 |
74 | {{#if memo}}There is a memo attached to the transfer stating:
75 | {{memo}}
76 | {{/if}}
77 |
78 | If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, or the token manager does not have a balance for {{asset_to_symbol_code quantity}}, the token manager will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from the token manager’s resources to create the necessary records.
79 |
80 | This action does not allow the total quantity to exceed the max allowed supply of the token.
81 |
82 |
open
83 |
84 | ---
85 | spec_version: "0.2.0"
86 | title: Open Token Balance
87 | summary: 'Open a zero quantity balance for {{nowrap owner}}'
88 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
89 | ---
90 |
91 | {{ram_payer}} agrees to establish a zero quantity balance for {{owner}} for the {{symbol_to_symbol_code symbol}} token.
92 |
93 | If {{owner}} does not have a balance for {{symbol_to_symbol_code symbol}}, {{ram_payer}} will be designated as the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}. As a result, RAM will be deducted from {{ram_payer}}’s resources to create the necessary records.
94 |
95 |
retire
96 |
97 | ---
98 | spec_version: "0.2.0"
99 | title: Remove Tokens from Circulation
100 | summary: 'Remove {{nowrap quantity}} from circulation'
101 | icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@
102 | ---
103 |
104 | The token manager agrees to remove {{quantity}} from circulation, taken from their own account.
105 |
106 | {{#if memo}} There is a memo attached to the action stating:
107 | {{memo}}
108 | {{/if}}
109 |
110 |
transfer
111 |
112 | ---
113 | spec_version: "0.2.0"
114 | title: Transfer Tokens
115 | summary: 'Send {{nowrap quantity}} from {{nowrap from}} to {{nowrap to}}'
116 | icon: @ICON_BASE_URL@/@TRANSFER_ICON_URI@
117 | ---
118 |
119 | {{from}} agrees to send {{quantity}} to {{to}}.
120 |
121 | {{#if memo}}There is a memo attached to the transfer stating:
122 | {{memo}}
123 | {{/if}}
124 |
125 | If {{from}} is not already the RAM payer of their {{asset_to_symbol_code quantity}} token balance, {{from}} will be designated as such. As a result, RAM will be deducted from {{from}}’s resources to refund the original RAM payer.
126 |
127 | If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, {{from}} will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from {{from}}’s resources to create the necessary records.
--------------------------------------------------------------------------------
/contracts/eosio.token/src/eosio.token.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace eosio {
4 |
5 | void token::create( const name& issuer,
6 | const asset& maximum_supply )
7 | {
8 | require_auth( get_self() );
9 |
10 | auto sym = maximum_supply.symbol;
11 | check( maximum_supply.is_valid(), "invalid supply");
12 | check( maximum_supply.amount > 0, "max-supply must be positive");
13 |
14 | stats statstable( get_self(), sym.code().raw() );
15 | auto existing = statstable.find( sym.code().raw() );
16 | check( existing == statstable.end(), "token with symbol already exists" );
17 |
18 | statstable.emplace( get_self(), [&]( auto& s ) {
19 | s.supply.symbol = maximum_supply.symbol;
20 | s.max_supply = maximum_supply;
21 | s.issuer = issuer;
22 | });
23 | }
24 |
25 |
26 | void token::issue( const name& to, const asset& quantity, const string& memo )
27 | {
28 | auto sym = quantity.symbol;
29 | check( sym.is_valid(), "invalid symbol name" );
30 | check( memo.size() <= 256, "memo has more than 256 bytes" );
31 |
32 | stats statstable( get_self(), sym.code().raw() );
33 | auto existing = statstable.find( sym.code().raw() );
34 | check( existing != statstable.end(), "token with symbol does not exist, create token before issue" );
35 | const auto& st = *existing;
36 | check( to == st.issuer, "tokens can only be issued to issuer account" );
37 |
38 | require_auth( st.issuer );
39 | check( quantity.is_valid(), "invalid quantity" );
40 | check( quantity.amount > 0, "must issue positive quantity" );
41 |
42 | check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
43 | check( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply");
44 |
45 | statstable.modify( st, same_payer, [&]( auto& s ) {
46 | s.supply += quantity;
47 | });
48 |
49 | add_balance( st.issuer, quantity, st.issuer );
50 | }
51 |
52 | void token::issuefixed( const name& to, const asset& supply, const string& memo )
53 | {
54 | const asset circulating_supply = get_supply( get_self(), supply.symbol.code() );
55 | check( circulating_supply.symbol == supply.symbol, "symbol precision mismatch" );
56 | const asset quantity = supply - circulating_supply;
57 | issue( to, quantity, memo );
58 | }
59 |
60 | void token::setmaxsupply( const name& issuer, const asset& maximum_supply )
61 | {
62 | auto sym = maximum_supply.symbol;
63 | check( maximum_supply.is_valid(), "invalid supply");
64 | check( maximum_supply.amount > 0, "max-supply must be positive");
65 |
66 | stats statstable( get_self(), sym.code().raw() );
67 | auto & st = statstable.get( sym.code().raw(), "token supply does not exist" );
68 | check( issuer == st.issuer, "only issuer can set token maximum supply" );
69 | require_auth( st.issuer );
70 |
71 | check( maximum_supply.symbol == st.supply.symbol, "symbol precision mismatch" );
72 | check( maximum_supply.amount >= st.supply.amount, "max supply is less than available supply");
73 |
74 | statstable.modify( st, same_payer, [&]( auto& s ) {
75 | s.max_supply = maximum_supply;
76 | });
77 | }
78 |
79 | void token::retire( const asset& quantity, const string& memo )
80 | {
81 | auto sym = quantity.symbol;
82 | check( sym.is_valid(), "invalid symbol name" );
83 | check( memo.size() <= 256, "memo has more than 256 bytes" );
84 |
85 | stats statstable( get_self(), sym.code().raw() );
86 | auto existing = statstable.find( sym.code().raw() );
87 | check( existing != statstable.end(), "token with symbol does not exist" );
88 | const auto& st = *existing;
89 |
90 | require_auth( st.issuer );
91 | check( quantity.is_valid(), "invalid quantity" );
92 | check( quantity.amount > 0, "must retire positive quantity" );
93 |
94 | check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
95 |
96 | statstable.modify( st, same_payer, [&]( auto& s ) {
97 | s.supply -= quantity;
98 | });
99 |
100 | sub_balance( st.issuer, quantity );
101 | }
102 |
103 | void token::transfer( const name& from,
104 | const name& to,
105 | const asset& quantity,
106 | const string& memo )
107 | {
108 | check( from != to, "cannot transfer to self" );
109 | require_auth( from );
110 | check( is_account( to ), "to account does not exist");
111 | auto sym = quantity.symbol.code();
112 | stats statstable( get_self(), sym.raw() );
113 | const auto& st = statstable.get( sym.raw() );
114 |
115 | require_recipient( from );
116 | require_recipient( to );
117 |
118 | check( quantity.is_valid(), "invalid quantity" );
119 | check( quantity.amount > 0, "must transfer positive quantity" );
120 | check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
121 | check( memo.size() <= 256, "memo has more than 256 bytes" );
122 |
123 | auto payer = has_auth( to ) ? to : from;
124 |
125 | sub_balance( from, quantity );
126 | add_balance( to, quantity, payer );
127 | }
128 |
129 | void token::sub_balance( const name& owner, const asset& value ) {
130 | accounts from_acnts( get_self(), owner.value );
131 |
132 | const auto& from = from_acnts.get( value.symbol.code().raw(), "no balance object found" );
133 | check( from.balance.amount >= value.amount, "overdrawn balance" );
134 |
135 | from_acnts.modify( from, owner, [&]( auto& a ) {
136 | a.balance -= value;
137 | });
138 | }
139 |
140 | void token::add_balance( const name& owner, const asset& value, const name& ram_payer )
141 | {
142 | accounts to_acnts( get_self(), owner.value );
143 | auto to = to_acnts.find( value.symbol.code().raw() );
144 | if( to == to_acnts.end() ) {
145 | to_acnts.emplace( ram_payer, [&]( auto& a ){
146 | a.balance = value;
147 | });
148 | } else {
149 | to_acnts.modify( to, same_payer, [&]( auto& a ) {
150 | a.balance += value;
151 | });
152 | }
153 | }
154 |
155 | void token::open( const name& owner, const symbol& symbol, const name& ram_payer )
156 | {
157 | require_auth( ram_payer );
158 |
159 | check( is_account( owner ), "owner account does not exist" );
160 |
161 | auto sym_code_raw = symbol.code().raw();
162 | stats statstable( get_self(), sym_code_raw );
163 | const auto& st = statstable.get( sym_code_raw, "symbol does not exist" );
164 | check( st.supply.symbol == symbol, "symbol precision mismatch" );
165 |
166 | accounts acnts( get_self(), owner.value );
167 | auto it = acnts.find( sym_code_raw );
168 | if( it == acnts.end() ) {
169 | acnts.emplace( ram_payer, [&]( auto& a ){
170 | a.balance = asset{0, symbol};
171 | });
172 | }
173 | }
174 |
175 | void token::close( const name& owner, const symbol& symbol )
176 | {
177 | require_auth( owner );
178 | accounts acnts( get_self(), owner.value );
179 | auto it = acnts.find( symbol.code().raw() );
180 | check( it != acnts.end(), "Balance row already deleted or never existed. Action won't have any effect." );
181 | check( it->balance.amount == 0, "Cannot close because the balance is not zero." );
182 | acnts.erase( it );
183 | }
184 |
185 | } /// namespace eosio
--------------------------------------------------------------------------------
/contracts/eosio.wrap/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(eosio.wrap eosio.wrap ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.wrap.cpp)
2 |
3 | target_include_directories(eosio.wrap
4 | PUBLIC
5 | ${CMAKE_CURRENT_SOURCE_DIR}/include)
6 |
7 | set_target_properties(eosio.wrap
8 | PROPERTIES
9 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
10 |
11 | configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.wrap.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.wrap.contracts.md @ONLY )
12 |
13 | target_compile_options( eosio.wrap PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian )
14 |
--------------------------------------------------------------------------------
/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | namespace eosio {
8 | /**
9 | * The `eosio.wrap` system contract allows block producers to bypass authorization checks or run privileged actions with 15/21 producer approval and thus simplifies block producers superuser actions. It also makes these actions easier to audit.
10 | *
11 | * It does not give block producers any additional powers or privileges that do not already exist within the EOSIO based blockchains. As it is implemented, in an EOSIO based blockchain, 15/21 block producers can change an account's permissions or modify an account's contract code if they decided it is beneficial for the blockchain and community. However, the current method is opaque and leaves undesirable side effects on specific system accounts, and thus the `eosio.wrap `contract solves this matter by providing an easier method of executing important governance actions.
12 | *
13 | * The only action implemented by the `eosio.wrap` system contract is the `exec` action. This action allows for execution of a transaction, which is passed to the `exec` method in the form of a packed transaction in json format via the 'trx' parameter and the `executer` account that executes the transaction. The same `executer` account will also be used to pay the RAM and CPU fees needed to execute the transaction.
14 | */
15 | class [[eosio::contract("eosio.wrap")]] wrap : public contract {
16 | public:
17 | using contract::contract;
18 |
19 | /**
20 | * Execute action.
21 | *
22 | * Execute a transaction while bypassing regular authorization checks.
23 | *
24 | * Preconditions:
25 | * - Requires authorization of eosio.wrap which needs to be a privileged account.
26 | *
27 | * Postconditions:
28 | * - Deferred transaction RAM usage is billed to 'executer' *
29 | *
30 | * @param executer - account executing the transaction,
31 | * @param trx - the transaction to be executed.
32 | */
33 | [[eosio::action]]
34 | void exec( ignore executer, ignore trx );
35 |
36 | using exec_action = eosio::action_wrapper<"exec"_n, &wrap::exec>;
37 | };
38 | } /// namespace eosio
39 |
--------------------------------------------------------------------------------
/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in:
--------------------------------------------------------------------------------
1 |
exec
2 |
3 | ---
4 | spec_version: "0.2.0"
5 | title: Privileged Execute
6 | summary: '{{nowrap executer}} executes a transaction while bypassing authority checks'
7 | icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@
8 | ---
9 |
10 | {{executer}} executes the following transaction while bypassing authority checks:
11 | {{to_json trx}}
12 |
13 | {{$action.account}} must also authorize this action.
14 |
--------------------------------------------------------------------------------
/contracts/eosio.wrap/src/eosio.wrap.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | namespace eosio {
4 |
5 | void wrap::exec( ignore, ignore ) {
6 | require_auth( get_self() );
7 |
8 | name executer;
9 | _ds >> executer;
10 |
11 | require_auth( executer );
12 |
13 | transaction_header trx_header;
14 | std::vector context_free_actions;
15 | std::vector actions;
16 | _ds >> trx_header;
17 | _ds >> context_free_actions;
18 | check( context_free_actions.empty(), "not allowed to `exec` a transaction with context-free actions" );
19 | _ds >> actions;
20 |
21 | for (const auto& act : actions) {
22 | act.send();
23 | }
24 | }
25 |
26 | } /// namespace eosio
27 |
--------------------------------------------------------------------------------
/contracts/icons/account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/account.png
--------------------------------------------------------------------------------
/contracts/icons/account.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/admin.png
--------------------------------------------------------------------------------
/contracts/icons/admin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/multisig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/multisig.png
--------------------------------------------------------------------------------
/contracts/icons/multisig.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/resource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/resource.png
--------------------------------------------------------------------------------
/contracts/icons/resource.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/rex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/rex.png
--------------------------------------------------------------------------------
/contracts/icons/rex.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/token.png
--------------------------------------------------------------------------------
/contracts/icons/token.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/transfer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/transfer.png
--------------------------------------------------------------------------------
/contracts/icons/transfer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/icons/voting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/contracts/icons/voting.png
--------------------------------------------------------------------------------
/contracts/icons/voting.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/contracts/test_contracts/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(blockinfo_tester)
2 | add_subdirectory(sendinline)
--------------------------------------------------------------------------------
/contracts/test_contracts/blockinfo_tester/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(blockinfo_tester ${CMAKE_CURRENT_SOURCE_DIR}/src/blockinfo_tester.cpp)
2 |
3 | target_include_directories(blockinfo_tester PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
4 | "$")
5 |
6 | set_target_properties(blockinfo_tester PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
7 |
8 | target_compile_options(blockinfo_tester PUBLIC --no-abigen)
9 |
--------------------------------------------------------------------------------
/contracts/test_contracts/blockinfo_tester/include/blockinfo_tester/blockinfo_tester.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifdef TEST_INCLUDE
4 |
5 | #include
6 | #include
7 |
8 | #else
9 |
10 | #include
11 | #include
12 |
13 | #include
14 |
15 | #endif
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | namespace system_contracts::testing::test_contracts::blockinfo_tester {
22 |
23 | #ifdef TEST_INCLUDE
24 |
25 | using time_point = fc::time_point;
26 | using varint = fc::unsigned_int;
27 |
28 | #else
29 |
30 | using time_point = eosio::time_point;
31 | using varint = eosio::unsigned_int;
32 |
33 | #endif
34 |
35 | /**
36 | * @brief Input data structure for `get_latest_block_batch_info` RPC
37 | *
38 | * @details Use this struct as the input for a call to the `get_latest_block_batch_info` RPC. That call will return the
39 | * result as the `latest_block_batch_info_result` struct.
40 | */
41 | struct get_latest_block_batch_info
42 | {
43 | uint32_t batch_start_height_offset;
44 | uint32_t batch_size;
45 | };
46 |
47 | #ifdef TEST_INCLUDE
48 |
49 | struct block_batch_info
50 | {
51 | uint32_t batch_start_height;
52 | time_point batch_start_timestamp;
53 | uint32_t batch_current_end_height;
54 | time_point batch_current_end_timestamp;
55 | };
56 |
57 | #else
58 |
59 | using eosiosystem::block_info::block_batch_info;
60 |
61 | #endif
62 |
63 | /**
64 | * @brief Output data structure for `get_latest_block_batch_info` RPC
65 | */
66 | struct latest_block_batch_info_result
67 | {
68 | enum error_code_enum : uint32_t
69 | {
70 | no_error,
71 | invalid_input,
72 | unsupported_version,
73 | insufficient_data
74 | };
75 |
76 | std::optional result;
77 | varint error_code = no_error;
78 |
79 | bool has_error() const { return !(error_code.value == no_error && result.has_value()); }
80 |
81 | error_code_enum get_error() const { return static_cast(error_code.value); }
82 |
83 | #ifndef TEST_INCLUDE
84 |
85 | EOSLIB_SERIALIZE(latest_block_batch_info_result, (result)(error_code))
86 |
87 | #endif
88 | };
89 |
90 | using input_type = std::variant;
91 |
92 | using output_type = std::variant;
93 |
94 | } // namespace system_contracts::testing::test_contracts::blockinfo_tester
95 |
96 | #ifdef TEST_INCLUDE
97 |
98 | FC_REFLECT(system_contracts::testing::test_contracts::blockinfo_tester::get_latest_block_batch_info,
99 | (batch_start_height_offset)(batch_size))
100 | FC_REFLECT(system_contracts::testing::test_contracts::blockinfo_tester::block_batch_info,
101 | (batch_start_height)(batch_start_timestamp)(batch_current_end_height)(batch_current_end_timestamp))
102 | FC_REFLECT_ENUM(
103 | system_contracts::testing::test_contracts::blockinfo_tester::latest_block_batch_info_result::error_code_enum,
104 | (no_error)(invalid_input)(unsupported_version)(insufficient_data))
105 | FC_REFLECT(system_contracts::testing::test_contracts::blockinfo_tester::latest_block_batch_info_result,
106 | (result)(error_code))
107 |
108 | #endif
--------------------------------------------------------------------------------
/contracts/test_contracts/blockinfo_tester/src/blockinfo_tester.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | namespace {
13 |
14 | namespace block_info = eosiosystem::block_info;
15 |
16 | }
17 | namespace system_contracts::testing::test_contracts::blockinfo_tester {
18 |
19 | auto process(get_latest_block_batch_info request) -> latest_block_batch_info_result
20 | {
21 | latest_block_batch_info_result response;
22 |
23 | block_info::latest_block_batch_info_result res =
24 | block_info::get_latest_block_batch_info(request.batch_start_height_offset, request.batch_size);
25 |
26 | response.result = std::move(res.result);
27 | response.error_code.value = static_cast(res.error_code);
28 |
29 | eosio::print("get_latest_block_batch_info: response error_code = ", response.error_code.value, "\n");
30 | if (response.result.has_value()) {
31 | const auto& result = *response.result;
32 | eosio::print("get_latest_block_batch_info: response result:\n");
33 | eosio::print(" batch_start_height = ", result.batch_start_height, "\n");
34 | eosio::print(" batch_current_end_height = ", result.batch_current_end_height, "\n");
35 | }
36 |
37 | return response;
38 | }
39 |
40 | output_type process_call(input_type input)
41 | {
42 | return std::visit([](auto&& arg) -> output_type { return process(std::move(arg)); }, std::move(input));
43 | }
44 |
45 | } // namespace system_contracts::testing::test_contracts::blockinfo_tester
46 |
47 | [[eosio::wasm_entry]] extern "C" void apply(uint64_t receiver, uint64_t code, uint64_t action)
48 | {
49 | namespace ns = system_contracts::testing::test_contracts::blockinfo_tester;
50 |
51 | if (receiver == code) {
52 | if (action == "call"_n.value) {
53 | ns::input_type input;
54 |
55 | {
56 | std::vector buffer;
57 | buffer.resize(eosio::action_data_size());
58 | eosio::read_action_data(buffer.data(), buffer.size());
59 |
60 | eosio::datastream input_ds(static_cast(buffer.data()), buffer.size());
61 | input_ds >> input;
62 | }
63 |
64 | auto output = ns::process_call(std::move(input));
65 | static_assert(std::is_same_v);
66 |
67 | {
68 | eosio::action return_action;
69 | return_action.account = eosio::name{receiver};
70 | return_action.name = "return"_n;
71 |
72 | eosio::datastream output_size_ds;
73 | output_size_ds << output;
74 | return_action.data.resize(output_size_ds.tellp());
75 | eosio::datastream output_ds(static_cast(return_action.data.data()),
76 | return_action.data.size());
77 | output_ds << output;
78 |
79 | return_action.send();
80 | }
81 | } else if (action == "abort"_n.value) {
82 | eosio::check(false, 0ull);
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/contracts/test_contracts/sendinline/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_contract(sendinline sendinline ${CMAKE_CURRENT_SOURCE_DIR}/src/sendinline.cpp)
2 |
3 | target_include_directories(sendinline PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
4 | "$")
5 |
6 | set_target_properties(sendinline PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
--------------------------------------------------------------------------------
/contracts/test_contracts/sendinline/src/sendinline.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | /// `eosio.code` is a virtual permission (there is no private or public
8 | /// key associated with it). Therefore, this test tests how `eosio.msig`
9 | /// contract reacts to a smart contract submitting a proposal and
10 | /// approving/unnapproving itself.
11 | class [[eosio::contract]]
12 | sendinline : public eosio::contract {
13 | public:
14 | using contract::contract;
15 |
16 | [[eosio::action]]
17 | void send( eosio::name contract, eosio::name action_name, std::vector auths, std::vector payload) {
18 | eosio::action act;
19 | act.account = contract;
20 | act.name = action_name;
21 | act.authorization = auths;
22 | act.data = std::move(payload);
23 | act.send();
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/01_system.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: System contracts, system accounts, privileged accounts
3 | ---
4 |
5 | At the genesis of the Vaulta blockchain, there was only one account present, `eosio` account, which was and still is the main `system account`. During the Vaulta blockchain bootstrap process other `system account`s, were created by `eosio` account, which control specific actions of the `system contract`s. You can see them listed in the [About System Contract](../index.md#system-contracts-defined-in-system-contracts) section.
6 |
7 | __Note__ the terms `system contract` and `system account`. `Privileged accounts` are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to `eosio.prods` system account.
8 |
9 | As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows:
10 |
11 | |Account|Privileged|Has contract|Description|
12 | |---|---|---|---|
13 | |eosio|Yes|It contains the `eosio.system` contract|The main system account on the Vaulta blockchain.|
14 | |eosio.msig|Yes|It contains the `eosio.msig` contract|Allows the signing of a multi-sig transaction proposal for later execution if all required parties sign the proposal before the expiration time.|
15 | |eosio.wrap|Yes|It contains the `eosio.wrap` contract.|Simplifies block producer superuser actions by making them more readable and easier to audit.|
16 | |eosio.token|No|It contains the `eosio.token` contract.|Defines the structures and actions allowing users to create, issue, and manage tokens on the Vaulta blockchain.|
17 | |eosio.names|No|No|The account which is holding funds from namespace auctions.|
18 | |eosio.bpay|No|No|The account that pays the block producers for producing blocks. It assigns 0.25% of the inflation based on the amount of blocks a block producer created in the last 24 hours.|
19 | |eosio.prods|No|No|The account representing the union of all current active block producers permissions.|
20 | |eosio.ram|No|No|The account that keeps track of the Vaulta balances based on users actions of buying or selling RAM.|
21 | |eosio.ramfee|No|No|The account that keeps track of the fees collected from users RAM trading actions: 0.5% from the value of each trade goes into this account.|
22 | |eosio.saving|No|No|The account which holds the 4% of network inflation.|
23 | |eosio.stake|No|No|The account that keeps track of all Vaulta tokens which have been staked for voting.|
24 | |eosio.vpay|No|No|The account that pays the block producers accordingly with the votes won. It assigns 0.75% of inflation based on the amount of votes a block producer won in the last 24 hours.|
25 | |eosio.rex|No|No|The account that keeps track of fees and balances resulted from REX related actions execution.|
26 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/02_system_resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: System Resources
3 | ---
4 |
5 | The Vaulta blockchain works with three system resources: CPU, NET and RAM. The Vaulta accounts need sufficient system resources to interact with the smart contracts deployed on the blockchain.
6 |
7 | * [RAM Resource](./05_ram.md)
8 | * [CPU Resource](./03_cpu.md)
9 | * [NET Resource](./04_net.md)
10 |
11 | To allocate RAM resources to an account you have to [purchase RAM](./05_ram.md#how-to-purchase-ram).
12 | To allocate CPU and NET resources to an account you have to [power up the account](./07_powerup_model.md#power-up-your-account).
13 |
14 | ## Resource Cost Estimation
15 |
16 | As a developer if you want to estimate how much CPU and NET a transaction requires for execution, you can employ one of the following methods:
17 |
18 | * Use the `--dry-run` option for the `cleos push transaction` command.
19 | * Use any tool that can pack a transaction and send it to the blockchain and specify the `--dry-run` option.
20 | * Use the chain API endpoint [`compute_transaction`](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp#L557).
21 |
22 | In all cases, when the transaction is processed, the blockchain node simulates the execution of the transaction and, as a consequence, the state of the blockchain is changed speculatively, which allows for the CPU and NET measurements to be done. However, the transaction is not sent to the blockchain and the caller receives the estimated CPU and NET costs in return.
23 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/03_cpu.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CPU as system resource
3 | ---
4 |
5 | As NET and RAM, the CPU resource is a very important system resource in the Vaulta blockchain. The CPU system resource provides processing power to blockchain accounts. When the blockchain executes a transaction, it consumes CPU and NET. For transactions to complete, sufficient CPU must be allocated to the payer account. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output.
6 |
7 | ## How Is CPU Calculated
8 |
9 | Transactions executed by the blockchain contain one or more actions. Each transaction must consume an amount of CPU within the limits predefined by the minimum and maximum transaction CPU usage values. For Vaulta blockchain these limits are set in the blockchain's configuration. You can find out these limits by running the following command and consult the `min_transaction_cpu_usage` and the `max_transaction_cpu_usage` which are expressed in microseconds:
10 |
11 | ```shell
12 | cleos get consensus_parameters
13 | ```
14 |
15 | For accounts that execute transactions, the blockchain calculates and updates the remaining resources with each block before each transaction is executed. When a transaction is prepared for execution, the blockchain determines whether the payer account has enough CPU to cover the transaction execution. To calculate the necessary CPU, the node that actively builds the current block measures the time to execute the transaction. If the account has enough CPU, the transaction is executed; otherwise it is rejected. For technical details please refer to the following links:
16 |
17 | * [The CPU configuration variables](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/config.hpp#L69-L73)
18 | * [The transaction initialization](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/controller.cpp#L3012)
19 | * [The transaction CPU billing](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/controller.cpp#L3030)
20 | * [The check of CPU usage for a transaction](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/transaction_context.cpp#L457)
21 |
22 | ## Subjective CPU Billing
23 |
24 | Subjective billing is an optional feature of the Vaulta blockchain. It allows nodes to bill account resources locally in their own node without sharing the billing with the rest of the network. Since its introduction, subjective billing benefited the nodes that adopted it because it reduced the node CPU usage by almost 90%. But it can result in failed transactions or lost transactions. Subjective billing can trigger transaction failure when a smart contract code uses a "check" function, like `assert()` or `check()` command to verify data. When this situation occurs, assert or check earlier in the system contract execution to reduce the applied billing. If the lack of an error message does not affect the user experience, a system contract may benefit by replacing some asserts and checks with a return statement. This replacement ensures their transactions succeed and are billed objectively on-chain.
25 |
26 | Find more details about subjective billing in the [Introduction to subjective billing and lost transactions](https://eosnetwork.com/blog/api-plus-an-introduction-to-subjective-billing-and-lost-transactions/) article.
27 |
28 | ## How To Rent CPU
29 |
30 | For details on how to rent CPU resources refer to the [Account Power Up](./07_powerup_model.md#power-up-your-account) section.
31 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/04_net.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: NET as system resource
3 | ---
4 |
5 | As CPU and RAM, the NET resource is an important system resource in the Vaulta blockchain. When the blockchain executes a transaction, it consumes CPU and NET. Sufficient NET must be allocated to the payer account for transactions to complete. NET is referred to as `net bandwidth` on the `cleos get account` command output.
6 |
7 | ## How Is NET Calculated
8 |
9 | Each transaction must consume an amount of NET which can not exceed the predefined maximum transaction NET usage value. For Vaulta blockchain this limit is set in the blockchain's configuration. You can find out this limit by running the following command and consult the `max_transaction_net_usage` which is expressed in bytes.
10 |
11 | ```shell
12 | cleos get consensus_parameters
13 | ```
14 |
15 | For the accounts that execute transactions, the blockchain calculates and updates the remaining resources for each block before each transaction is executed. When a transaction is prepared for execution, the blockchain determines whether the payer account has enough NET to cover the transaction execution. The necessary NET is calculated based on the transaction size, which is the size of the packed transaction as it is stored in the blockchain. If the account has enough NET resources, the transaction can be executed; otherwise it is rejected. For technical details please refer to the following sources:
16 |
17 | * [The NET configuration variables](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/config.hpp#L60-L67)
18 | * [The transaction initialization](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/controller.cpp#L3012)
19 | * [The transaction NET billing](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/controller.cpp#L3030)
20 | * [The check of NET usage for a transaction](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/transaction_context.cpp#L416)
21 |
22 | ## How To Rent NET
23 |
24 | For details on how to rent NET resources refer to the [Account Power Up](./07_powerup_model.md#power-up-your-account) section.
25 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/05_ram.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: RAM as system resource
3 | ---
4 |
5 | The RAM resource is the memory, the storage space, where the blockchain stores data. If your contract needs to store data on the blockchain, it can store it in the blockchain's RAM as a `multi-index table` or a `singleton`.
6 |
7 | ## RAM High Performance
8 |
9 | Data stored on the Vaulta blockchain uses RAM as its storage medium. Therefore, access to the blockchain data is highly performant and fast. Its performance benchmarks can reach levels rarely achieved by other blockchains. This ability elevates the Vaulta blockchain to be a contender for the fastest blockchain worldwide.
10 |
11 | ## RAM Importance
12 |
13 | RAM is an important system resource because of the following reasons:
14 |
15 | * Ram is a limited resource. The public Vaulta blockchain started with 64GB of total RAM. After a brief period the block producers decided to increase the memory with 1KB per block. In this way the supply of RAM constantly increases, yet its price accelerates at a slower pace.
16 |
17 | * The execution of many actions by the blockchain uses RAM. For example, when you create a new account, the new account information is stored in the blockchain's RAM. Also, when an account accepts a token which it did not hold before, a new record has to be created, that holds the balance of the newly accepted token. The blockchain memory has to be purchased either by the account that transfers the tokens or by the account that accepts the new token type.
18 |
19 | * If a smart contract consumes all of its allocated RAM, it cannot store any additional information. To continue to save data in the blockchain database, one or both of the following conditions must be met:
20 |
21 | * A portion of the occupied RAM is freed by the smart contract.
22 | * More RAM is allocated to the smart contract account through the RAM purchase process.
23 |
24 | ## How To Purchase RAM
25 |
26 | The RAM resource must be bought with the `EOS` system token. The price of RAM is calculated according to the unique Bancor liquidity algorithm that is implemented in the system contract.
27 |
28 | The quickest way to calculate the price of RAM:
29 |
30 | 1. Run the following command: (**Note:** Make sure you run it against the mainnet or the testnet of your choice.)
31 |
32 | ```shell
33 | cleos get table eosio eosio rammarket
34 | ```
35 |
36 | 2. Observe the output which should look like the sample below:
37 |
38 | ```text
39 | {
40 | "supply": "10000000000.0000 RAMCORE",
41 | "base": {
42 | "balance": "35044821247 RAM",
43 | "weight": "0.50000000000000000"
44 | },
45 | "quote": {
46 | "balance": "3158350.8754 EOS",
47 | "weight": "0.50000000000000000"
48 | }
49 | }
50 | ```
51 |
52 | 3. Make note of the `base balance`, in this case it is 35044821247.
53 | 4. Make note of the `quote balance`, in this case it is 3158350.8754.
54 | 5. Calculate the price of 1Kib of RAM as `quote balance` * 1024 / `base balance` = 0.0922 EOS.
55 |
56 | ### Buy RAM With Command Line Interface
57 |
58 | You can buy RAM through the command line interface tool. You can buy either an explicit amount of RAM expressed in bytes or an amount of RAM worth an explicit amount of Vaulta.
59 |
60 | ### Buy RAM In EOS
61 |
62 | For example, the command below buys for account `bob` 0.1 EOS worth of RAM at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account.
63 |
64 | ```shell
65 | cleos system buyram alice bob "0.1 EOS" -p alice@active
66 | ```
67 |
68 | ### Buy RAM In Bytes
69 |
70 | For example, the command below buys for account `bob` 1000 RAM bytes at the current market RAM price. The cost for the RAM and the execution of this transaction is covered by the `alice` account and the transaction is authorized by the `active` key of the `alice` account.
71 |
72 | ```shell
73 | cleos system buyrambytes alice bob "1000" -p alice@active
74 | ```
75 |
76 | ## How Is RAM Calculated
77 |
78 | The necessary RAM needed for a smart contract to store its data is calculated from the used blockchain state.
79 |
80 | As a developer, to understand the amount of RAM your smart contract needs, pay attention to the data structure underlying the multi-index tables your smart contract instantiates and uses. The data structure underlying one multi-index table defines a row in the table. Each data member of the data structure corresponds with a row cell of the table.
81 | To approximate the amount of RAM one multi-index row needs to store on the blockchain, you have to add the size of the type of each data member and the memory overheads for each of the defined indexes, if any. Find below the overheads defined by the Vaulta code for multi-index tables, indexes, and data types:
82 |
83 | * [Multi-index RAM bytes overhead](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/contract_table_objects.hpp#L242-L285)
84 | * [Overhead per row per index RAM bytes](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/config.hpp#L114)
85 | * [Fixed overhead shared vector RAM bytes](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/config.hpp#L113)
86 | * [Overhead per account RAM bytes](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/config.hpp#L115)
87 | * [Setcode RAM bytes multiplier](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/include/eosio/chain/config.hpp#L116)
88 | * [RAM usage update function](https://github.com/AntelopeIO/spring/blob/7254bab917a17bcc0d82d23d03f4173176150239/libraries/chain/apply_context.cpp#L734)
89 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/06_vote.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Voting on Vaulta blockchain
3 | ---
4 |
5 | The Vaulta blockchain is kept alive by nodes which are interconnected between each other, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a voting process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain state. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' votes. It is the 21 active block producers which continuously advancing the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements.
6 |
7 | The 21 block producers are elected through the voting process. Each EOS token holder that wants to vote for one or up to 30 block producers must stake their tokens. The more tokens are stake the more voting power. The voting power of one account is proportional with the amount of tokens staked by that account versus the total amount of tokens staked by whole accounts that stake their tokens.
8 |
--------------------------------------------------------------------------------
/docs/01_key-concepts/07_powerup_model.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How To Use The PowerUp Model
3 | ---
4 |
5 | ## Power Up Your Account
6 |
7 | To power up an account is a technique to rent CPU and NET resources from the PowerUp resource model. A smart contract implements this model on the blockchain and allocates these resources to the account of your choice. The action to power up an account is `powerup`. It takes as parameters:
8 |
9 | * The `payer` of the fee, must be a valid Vaulta account.
10 | * The `receiver` of the resources, must be a valid Vaulta account.
11 | * The `days` which must always match `state.powerup_days` specified in the [PowerUp configuration settings](https://github.com/VaultaFoundation/system-contracts/blob/7cec470b17bd53b8c78465d4cbd889dbaf1baffb/contracts/eosio.system/include/eosio.system/eosio.system.hpp#L588).
12 | * The `net_frac`, and the `cpu_frac` are the percentage of the resources that you need. The easiest way to calculate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13.
13 | * The `max_payment`, must be expressed in EOS and is the maximum amount the `payer` is willing to pay.
14 |
15 | ```sh
16 | cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user
17 | ```
18 |
19 | To view the received NET and CPU weight as well as the amount of the fee, check the `eosio.reserv::powupresult` returned by the action, which should look similar to the one below:
20 |
21 | ```console
22 | executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us
23 | # eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","...
24 | # eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"}
25 | # eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 EOS","powup_net_weight":"16354","powup_cpu_weight":"65416"}
26 | # user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"}
27 | # eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"}
28 | ```
29 |
30 | The PowerUp resource model on the Vaulta blockchain is initialized with `"powerup_days": 1,`. This setting permits the maximum period to rent CPU and NET for 24 hours. If you do not use the resources within the 24 hour interval, the rented CPU and NET expires.
31 |
32 | ### Process Expired Orders
33 |
34 | The resources in loans that expire are not automatically reclaimed by the system. The expired loans remain in a queue that must be processed.
35 |
36 | Any calls to the `powerup` action does process also this queue (limited to two expired loans at a time). Therefore, the expired loans are automatically processed in a timely manner. Sometimes, it may be necessary to manually process expired loans in the queue to release resources back to the system, which reduces prices. Therefore, any account may process up to an arbitrary number of expired loans if it calls the `powerupexec` action.
37 |
38 | To view the orders table `powup.order` execute the following command:
39 |
40 | ```sh
41 | cleos get table eosio 0 powup.order
42 | ```
43 |
44 | ```json
45 | {
46 | "rows": [{
47 | "version": 0,
48 | "id": 0,
49 | "owner": "user",
50 | "net_weight": 16354,
51 | "cpu_weight": 65416,
52 | "expires": "2020-11-18T13:04:33"
53 | }
54 | ],
55 | "more": false,
56 | "next_key": ""
57 | }
58 | ```
59 |
60 | Example `powerupexec` call:
61 |
62 | ```sh
63 | cleos push action eosio powerupexec '[user, 2]' -p user
64 | ```
65 |
66 | ```console
67 | executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us
68 | # eosio <= eosio::powerupexec {"user":"user","max":2}
69 | warning: transaction executed locally, but may not be confirmed by the network yet ]
70 | ```
71 |
--------------------------------------------------------------------------------
/docs/03_build-and-deploy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to build the Vaulta system contracts
3 | ---
4 |
5 | For building instructions, refer to the [Building](https://github.com/VaultaFoundation/system-contracts#building) section.
6 |
--------------------------------------------------------------------------------
/docs/04_guides/02_how-to-buy-ram.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to buy RAM
3 | link_text: How to buy RAM
4 | ---
5 |
6 | ## Goal
7 |
8 | Setup an account that require multiple signatures for signing a transaction
9 |
10 | ## Before you begin
11 |
12 | * You have an account
13 |
14 | * Ensure the reference system contracts from `system-contracts` repository is deployed and used to manage system resources
15 |
16 | * You have sufficient token allocated to your account
17 |
18 | * Install the currently supported version of cleos
19 |
20 | * Unlock your wallet
21 |
22 | ## Steps
23 |
24 | Buys RAM in value of 10 EOS tokens for account `alice`:
25 |
26 | ```shell
27 | cleos system buyram alice alice "10 EOS" -p alice@active
28 | ```
--------------------------------------------------------------------------------
/docs/04_guides/03_how-to-stake.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to stake
3 | link_text: How to stake
4 | ---
5 |
6 | ## Goal
7 |
8 | Stake resources for your account to participate in the on-chain voting and governance.
9 |
10 | ## Before you begin
11 |
12 | * Install the currently supported version of cleos
13 |
14 | * Ensure the reference system contracts from `system-contracts` repository is deployed and used to manage system resources
15 |
16 | * Understand the following:
17 | * What is an account
18 | * What is network bandwidth
19 | * What is CPU bandwidth
20 |
21 | ## Steps
22 |
23 | Stake 10 EOS network bandwidth for `alice`
24 |
25 | ```shell
26 | cleos system delegatebw alice alice "0 EOS" "10 EOS"
27 | ```
28 |
29 | Stake 10 EOS CPU bandwidth for `alice`:
30 |
31 | ```shell
32 | cleos system delegatebw alice alice "10 EOS" "0 EOS"
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/04_guides/04_how-to-vote.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to vote
3 | link_text: How to vote
4 | ---
5 |
6 | ## Goal
7 |
8 | Vote for a block producer
9 |
10 | ## Before you begin
11 |
12 | * Install the current supported version of cleos
13 |
14 | * Ensure the reference system contracts from `system-contracts` repository is deployed and used to manage system resources
15 |
16 | * Understand the following:
17 | * What is a block producer
18 | * How does voting works
19 |
20 | * Unlock your wallet
21 |
22 | ## Steps
23 |
24 | Assume you are going to vote for blockproducer1 and blockproducer2 from an account called `eosiotestts2`, execute the following:
25 |
26 | ```bash
27 | cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2
28 | ```
29 |
30 | You should see something like below:
31 |
32 | ```console
33 | executed transaction: 2d8b58f7387aef52a1746d7a22d304bbbe0304481d7751fc4a50b619df62676d 128 bytes 374 us
34 | # eosio <= eosio::voteproducer {"voter":"eosiotestts2","proxy":"","producers":["blockproducer1","blockproducer2"]}
35 | ```
36 |
--------------------------------------------------------------------------------
/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to create, issue and transfer a token
3 | link_text: How to create, issue and transfer a token
4 | ---
5 |
6 | ## Step 1: Obtain Contract Source
7 |
8 | Navigate to your contracts directory.
9 |
10 | ```sh
11 | cd CONTRACTS_DIR
12 | ```
13 |
14 | Pull the source
15 |
16 | ```sh
17 | git clone https://github.com/VaultaFoundation/system-contracts --branch release/3.1 --single-branch
18 | ```
19 |
20 | ```sh
21 | cd system-contracts/contracts/eosio.token
22 | ```
23 |
24 | ## Step 2: Create Account for Contract
25 |
26 | [[info]]
27 | | You may have to unlock your wallet first!
28 |
29 | ```shell
30 | cleos create account eosio eosio.token EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
31 | ```
32 |
33 | ## Step 3: Compile the Contract
34 |
35 | ```shell
36 | eosio-cpp -I include -o eosio.token.wasm src/eosio.token.cpp --abigen
37 | ```
38 |
39 | ## Step 4: Deploy the Token Contract
40 |
41 | ```shell
42 |
43 | cleos set contract eosio.token CONTRACTS_DIR/system-contracts/contracts/eosio.token --abi eosio.token.abi -p eosio.token@active
44 | ```
45 |
46 | Result should look similar to the one below:
47 |
48 | ```console
49 | Reading WASM from ...
50 | Publishing contract...
51 | executed transaction: 69c68b1bd5d61a0cc146b11e89e11f02527f24e4b240731c4003ad1dc0c87c2c 9696 bytes 6290 us
52 | # eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d0100000001aa011c60037f7e7f0060047f...
53 | # eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30000605636c6f73650002056f776e6572046e61...
54 | warning: transaction executed locally, but may not be confirmed by the network yet ]
55 | ```
56 |
57 | ## Step 5: Create the Token
58 |
59 | ```shell
60 | cleos push action eosio.token create '[ "eosio", "1000000000.0000 NEWT"]' -p eosio.token@active
61 | ```
62 |
63 | Result should look similar to the one below:
64 |
65 | ```console
66 | executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles
67 | # eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 NEWT"}
68 | ```
69 |
70 | An alternate approach uses named arguments:
71 |
72 | ```shell
73 | cleos push action eosio.token create '{"issuer":"eosio", "maximum_supply":"1000000000.0000 NEWT"}' -p eosio.token@active
74 | ```
75 |
76 | Result should look similar to the one below:
77 |
78 | ```console
79 | executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles
80 | # eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 NEWT"}
81 | ```
82 |
83 | This command created a new token `NEWT` with a precision of 4 decimals and a maximum supply of 1000000000.0000 NEWT. To create this token requires the permission of the `eosio.token` contract. For this reason, `-p eosio.token@active` was passed to authorize the request.
84 |
85 | ## Step 6: Issue Tokens
86 |
87 | The issuer can issue new tokens to the issuer account in our case `eosio`.
88 |
89 | ```sh
90 | cleos push action eosio.token issue '[ "eosio", "100.0000 NEWT", "memo" ]' -p eosio@active
91 | ```
92 |
93 | Result should look similar to the one below:
94 |
95 | ```console
96 | executed transaction: a26b29d66044ad95edf0fc04bad3073e99718bc26d27f3c006589adedb717936 128 bytes 337 us
97 | # eosio.token <= eosio.token::issue {"to":"eosio","quantity":"100.0000 NEWT","memo":"memo"}
98 | warning: transaction executed locally, but may not be confirmed by the network yet ]
99 | ```
100 |
101 | ## Step 7: Transfer Tokens
102 |
103 | Now that account `eosio` has been issued tokens, transfer some of them to account `bob`.
104 |
105 | ```shell
106 | cleos push action eosio.token transfer '[ "eosio", "bob", "25.0000 NEWT", "m" ]' -p eosio@active
107 | ```
108 |
109 | Result should look similar to the one below:
110 |
111 | ```console
112 | executed transaction: 60d334850151cb95c35fe31ce2e8b536b51441c5fd4c3f2fea98edcc6d69f39d 128 bytes 497 us
113 | # eosio.token <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 NEWT","memo":"m"}
114 | # eosio <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 NEWT","memo":"m"}
115 | # bob <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 NEWT","memo":"m"}
116 | warning: transaction executed locally, but may not be confirmed by the network yet ]
117 | ```
118 |
119 | Now check if "bob" got the tokens using [cleos get currency balance](https://github.com/AntelopeIO/spring/blob/v1.0.0-rc2/docs/02_cleos/03_command-reference/get/currency-balance.md)
120 |
121 | ```shell
122 | cleos get currency balance eosio.token bob NEWT
123 | ```
124 |
125 | Result:
126 |
127 | ```console
128 | 25.00 NEWT
129 | ```
130 |
131 | Check "eosio's" balance, notice that tokens were deducted from the account
132 |
133 | ```shell
134 | cleos get currency balance eosio.token eosio NEWT
135 | ```
136 |
137 | Result:
138 |
139 | ```console
140 | 75.00 NEWT
141 | ```
142 |
--------------------------------------------------------------------------------
/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to sign a multisig transaction with eosio.msig
3 | link_text: How to sign a multisig transaction with eosio.msig
4 | ---
5 |
6 | ### eosio.msig
7 |
8 | ### Prerequisites:
9 | - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account.
10 | - account 'treasury' is the issuer of EOS token.
11 | - account 'tester' exists.
12 | - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked.
13 |
14 | ### One user creates a proposal:
15 | ```sh
16 | cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token issue '{"to": "tester", "quantity": "1000.0000 EOS", "memo": ""}' -p tester
17 | ```
18 | ```console
19 | executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles
20 | # eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]...
21 | ```
22 |
23 | ### Another user reviews the transaction:
24 | ```sh
25 | cleos multisig review tester test
26 | ```
27 | ```json
28 | {
29 | "proposal_name": "test",
30 | "requested_approvals": [{
31 | "actor": "treasury",
32 | "permission": "active"
33 | }
34 | ],
35 | "provided_approvals": [],
36 | "packed_transaction": "00aee75a0000000000000000000000000100a6823403ea30550000000000a5317601000000fe6a6cd4cd00000000a8ed323219000000005c95b1ca809698000000000004454f530000000000",
37 | "transaction": {
38 | "expiration": "2018-05-01T00:00:00",
39 | "region": 0,
40 | "ref_block_num": 0,
41 | "ref_block_prefix": 0,
42 | "max_net_usage_words": 0,
43 | "max_kcpu_usage": 0,
44 | "delay_sec": 0,
45 | "context_free_actions": [],
46 | "actions": [{
47 | "account": "eosio.token",
48 | "name": "issue",
49 | "authorization": [{
50 | "actor": "treasury",
51 | "permission": "active"
52 | }
53 | ],
54 | "data": {
55 | "to": "tester",
56 | "quantity": "1000.0000 EOS",
57 | "memo": ""
58 | },
59 | "hex_data": "000000005c95b1ca809698000000000004454f530000000000"
60 | }
61 | ]
62 | }
63 | }
64 | ```
65 |
66 | ### And then approves it:
67 | ```sh
68 | cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury
69 | ```
70 | ```console
71 | executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd95101b88d 256 bytes 108544 cycles
72 | # eosio.msig <= eosio.msig::approve {"proposer":"tester","proposal_name":"test","level":{"actor":"treasury","permission":"active"}}
73 | ```
74 |
75 | ### First user initiates execution:
76 | ```sh
77 | cleos multisig exec tester test -p tester
78 | ```
79 | ```console
80 | executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e56d6c2 248 bytes 109568 cycles
81 | # eosio.msig <= eosio.msig::exec {"proposer":"tester","proposal_name":"test","executer":"tester"}
82 | ```
83 |
84 |
85 | ## Cleos usage example for transferring tokens.
86 |
87 | ### Prerequisites:
88 | - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account.
89 | - account 'treasury' has at least 1.1000 EOS token balance.
90 | - account 'tester' exists.
91 | - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked.
92 |
93 | ### One user creates a proposal:
94 | ```sh
95 | cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token transfer '{"from": "treasury", "to": "tester", "quantity": "1.0000 EOS", "memo": ""}' -p tester
96 | ```
97 | ```console
98 | executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles
99 | # eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]...
100 | ```
101 |
102 | ### Another user reviews the transaction:
103 | ```sh
104 | cleos multisig review tester test
105 | ```
106 | ```json
107 | {
108 | "proposal_name": "test",
109 | "requested_approvals": [{
110 | "actor": "treasury",
111 | "permission": "active"
112 | }
113 | ],
114 | "provided_approvals": [],
115 | "packed_transaction": "00aee75a0000000000000000000000000100a6823403ea30550000000000a5317601000000fe6a6cd4cd00000000a8ed323219000000005c95b1ca809698000000000004454f530000000000",
116 | "transaction": {
117 | "expiration": "2018-05-01T00:00:00",
118 | "region": 0,
119 | "ref_block_num": 0,
120 | "ref_block_prefix": 0,
121 | "max_net_usage_words": 0,
122 | "max_kcpu_usage": 0,
123 | "delay_sec": 0,
124 | "context_free_actions": [],
125 | "actions": [{
126 | "account": "eosio.token",
127 | "name": "transfer",
128 | "authorization": [{
129 | "actor": "treasury",
130 | "permission": "active"
131 | }
132 | ],
133 | "data": {
134 | "from": "treasury",
135 | "to": "tester",
136 | "quantity": "1.0000 EOS",
137 | "memo": ""
138 | },
139 | "hex_data": "000000005c95b1ca809698000000000004454f530000000000"
140 | }
141 | ]
142 | }
143 | }
144 | ```
145 |
146 | ### And then approves it:
147 | ```sh
148 | cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury
149 | ```
150 | ```console
151 | executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd95101b88d 256 bytes 108544 cycles
152 | # eosio.msig <= eosio.msig::approve {"proposer":"tester","proposal_name":"test","level":{"actor":"treasury","permission":"active"}}
153 | ```
154 |
155 | ### First user check account balance before executing the proposed transaction
156 | ```sh
157 | cleos get table eosio.token tester accounts | jq '.rows[]'
158 | ```
159 | ```console
160 | ...
161 | EOS balances:
162 | liquid: 1.0487 EOS
163 | staked: 2.0000 EOS
164 | unstaking: 0.0000 EOS
165 | total: 4.0487 EOS
166 | ```
167 |
168 | ### First user initiates execution of proposed transaction:
169 | ```sh
170 | cleos multisig exec tester test -p tester
171 | ```
172 | ```console
173 | executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e56d6c2 248 bytes 109568 cycles
174 | # eosio.msig <= eosio.msig::exec {"proposer":"tester","proposal_name":"test","executer":"tester"}
175 | ```
176 |
177 | ### First user can check account balance, it should be increased by 1.0000 EOS
178 | ```sh
179 | cleos get table eosio.token tester accounts | jq '.rows[]'
180 | ```
181 | ```console
182 | ...
183 | EOS balances:
184 | liquid: 2.0487 EOS
185 | staked: 2.0000 EOS
186 | unstaking: 0.0000 EOS
187 | total: 4.0487 EOS
188 | ```
189 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About System Contracts
3 | ---
4 |
5 | The Vaulta blockchain is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit the Vaulta community needs. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, are implemented inside smart contracts which are deployed on the Vaulta blockchain.
6 |
7 | ## System contracts defined in system-contracts
8 |
9 | The `system-contracts` repository contains the system contracts encapsulating the base functionality for the Vaulta blockchain.
10 |
11 | 1. [eosio.bios](action-reference/eosio.bios)
12 | 2. [eosio.system](action-reference/eosio.system)
13 | 3. [eosio.msig](action-reference/eosio.msig)
14 | 4. [eosio.token](action-reference/eosio.token)
15 | 5. [eosio.wrap](action-reference/eosio.wrap)
16 |
17 | ## Key Concepts Implemented by eosio.system
18 |
19 | 1. [System](01_key-concepts/01_system.md)
20 | 2. [System Resources](01_key-concepts/02_system_resources.md)
21 | 3. [CPU](01_key-concepts/03_cpu.md)
22 | 4. [NET](01_key-concepts/04_net.md)
23 | 5. [RAM](01_key-concepts/05_ram.md)
24 | 6. [Vote](01_key-concepts/06_vote.md)
25 |
26 | ## Build and deploy
27 |
28 | To build and deploy the system contract follow the instruction from [Build and deploy](03_build-and-deploy.md) section.
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 |
3 | set(EOSIO_VERSION_MIN "1.0")
4 | set(EOSIO_VERSION_SOFT_MAX "1.0")
5 | # set(EOSIO_VERSION_HARD_MAX "")
6 |
7 | find_package(spring)
8 |
9 | # Check the version of Spring
10 | if(SYSTEM_ENABLE_SPRING_VERSION_CHECK)
11 | set(VERSION_MATCH_ERROR_MSG "")
12 | eosio_check_version(VERSION_OUTPUT "${EOSIO_VERSION}" "${EOSIO_VERSION_MIN}" "${EOSIO_VERSION_SOFT_MAX}"
13 | "${EOSIO_VERSION_HARD_MAX}" VERSION_MATCH_ERROR_MSG)
14 | if(VERSION_OUTPUT STREQUAL "MATCH")
15 | message(STATUS "Using Spring version ${EOSIO_VERSION}")
16 | elseif(VERSION_OUTPUT STREQUAL "WARN")
17 | message(
18 | WARNING
19 | "Using Spring version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use Spring version ${EOSIO_VERSION_SOFT_MAX}.x"
20 | )
21 | else() # INVALID OR MISMATCH
22 | message(
23 | FATAL_ERROR
24 | "Found Spring version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use Spring version ${EOSIO_VERSION_SOFT_MAX}.x"
25 | )
26 | endif(VERSION_OUTPUT STREQUAL "MATCH")
27 | endif()
28 |
29 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/contracts.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/contracts.hpp)
30 |
31 | include_directories(${CMAKE_CURRENT_BINARY_DIR})
32 | # UNIT TESTING ###
33 | include(CTest) # eliminates DartConfiguration.tcl errors at test runtime
34 | enable_testing()
35 | # build unit test executable
36 | file(GLOB UNIT_TESTS "*.cpp" "*.hpp") # find all unit test suites
37 | add_eosio_test_executable(unit_test ${UNIT_TESTS}) # build unit tests as one executable
38 | # mark test suites for execution
39 | foreach(TEST_SUITE ${UNIT_TESTS}) # create an independent target for each test suite
40 | execute_process(
41 | COMMAND
42 | bash -c
43 | "grep -E 'BOOST_AUTO_TEST_SUITE\\s*[(]' ${TEST_SUITE} | grep -vE '//.*BOOST_AUTO_TEST_SUITE\\s*[(]' | cut -d ')' -f 1 | cut -d '(' -f 2"
44 | OUTPUT_VARIABLE SUITE_NAMES
45 | OUTPUT_STRIP_TRAILING_WHITESPACE) # get all the test suite names from each *.cpp file
46 | string(REPLACE "\n" ";" SUITE_NAMES "${SUITE_NAMES}")
47 | foreach(SUITE_NAME IN LISTS SUITE_NAMES)
48 | if(NOT "" STREQUAL "${SUITE_NAME}") # ignore empty lines
49 | execute_process(
50 | COMMAND bash -c "echo ${SUITE_NAME} | sed -e 's/s$//' | sed -e 's/_test$//'"
51 | OUTPUT_VARIABLE TRIMMED_SUITE_NAME
52 | OUTPUT_STRIP_TRAILING_WHITESPACE) # trim "_test" or "_tests" from the end of ${SUITE_NAME}
53 | # to run unit_test with all log from blockchain displayed, put "--verbose" after "--", i.e. "unit_test -- --verbose"
54 | add_test(NAME ${TRIMMED_SUITE_NAME}_unit_test COMMAND unit_test --run_test=${SUITE_NAME} --report_level=detailed
55 | --color_output)
56 | endif()
57 | endforeach(SUITE_NAME)
58 | endforeach(TEST_SUITE)
59 |
--------------------------------------------------------------------------------
/tests/contracts.hpp.in:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | namespace eosio::testing {
5 |
6 | struct contracts {
7 | static std::vector system_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.system/eosio.system.wasm"); }
8 | static std::vector system_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.system/eosio.system.abi"); }
9 | static std::vector token_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.token/eosio.token.wasm"); }
10 | static std::vector fees_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.fees/eosio.fees.wasm"); }
11 | static std::vector token_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.token/eosio.token.abi"); }
12 | static std::vector msig_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.msig/eosio.msig.wasm"); }
13 | static std::vector msig_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.msig/eosio.msig.abi"); }
14 | static std::vector wrap_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.wrap/eosio.wrap.wasm"); }
15 | static std::vector wrap_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.wrap/eosio.wrap.abi"); }
16 | static std::vector bios_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.bios/eosio.bios.wasm"); }
17 | static std::vector bios_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.bios/eosio.bios.abi"); }
18 | static std::vector bpay_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/contracts/eosio.bpay/eosio.bpay.wasm"); }
19 | static std::vector bpay_abi() { return read_abi("${CMAKE_BINARY_DIR}/contracts/eosio.bpay/eosio.bpay.abi"); }
20 |
21 | struct util {
22 | static std::vector reject_all_wasm() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/reject_all.wasm"); }
23 | static std::vector exchange_wasm() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/exchange.wasm"); }
24 | static std::vector system_wasm_v1_8() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.8.3/eosio.system/eosio.system.wasm"); }
25 | static std::vector system_abi_v1_8() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.8.3/eosio.system/eosio.system.abi"); }
26 | static std::vector system_wasm_old() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.system/eosio.system.wasm"); }
27 | static std::vector system_abi_old() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.system/eosio.system.abi"); }
28 | static std::vector msig_wasm_old() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.wasm"); }
29 | static std::vector msig_abi_old() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.abi"); }
30 | };
31 | };
32 |
33 | } // namespace eosio::testing
34 |
35 | namespace system_contracts::testing::test_contracts {
36 |
37 | [[maybe_unused]] static std::vector blockinfo_tester_wasm()
38 | {
39 | return eosio::testing::read_wasm(
40 | "${CMAKE_BINARY_DIR}/contracts/test_contracts/blockinfo_tester/blockinfo_tester.wasm");
41 | }
42 | [[maybe_unused]] static std::vector sendinline_wasm()
43 | {
44 | return eosio::testing::read_wasm(
45 | "${CMAKE_BINARY_DIR}/contracts/test_contracts/sendinline/sendinline.wasm");
46 | }
47 | [[maybe_unused]] static std::vector sendinline_abi()
48 | {
49 | return eosio::testing::read_abi(
50 | "${CMAKE_BINARY_DIR}/contracts/test_contracts/sendinline/sendinline.abi");
51 | }
52 |
53 |
54 | } // namespace system_contracts::testing::test_contracts
--------------------------------------------------------------------------------
/tests/eosio.bpay_tests.cpp:
--------------------------------------------------------------------------------
1 | #include "eosio.system_tester.hpp"
2 |
3 | using namespace eosio_system;
4 |
5 | BOOST_AUTO_TEST_SUITE(eosio_bpay_tests);
6 |
7 | account_name voter = "alice1111111"_n;
8 | account_name standby = "bp.standby"_n;
9 | account_name inactive = "bp.inactive"_n;
10 | account_name fees = "eosio.fees"_n;
11 | account_name bpay = "eosio.bpay"_n;
12 |
13 | BOOST_FIXTURE_TEST_CASE( bpay_test, eosio_system_tester ) try {
14 |
15 |
16 | // Transferring some tokens to the fees account
17 | // since tokens from eosio will not be directly accepted as contributions to
18 | // the bpay contract
19 | transfer( config::system_account_name, fees, core_sym::from_string("100000.0000"), config::system_account_name );
20 |
21 |
22 | // Setting up the producers, standby and inactive producers, and voting them in
23 | setup_producer_accounts({standby, inactive});
24 | auto producer_names = active_and_vote_producers();
25 |
26 | BOOST_REQUIRE_EQUAL( success(), regproducer(standby) );
27 | BOOST_REQUIRE_EQUAL( success(), regproducer(inactive) );
28 | vector top_producers_and_inactive = {inactive};
29 | top_producers_and_inactive.insert( top_producers_and_inactive.end(), producer_names.begin(), producer_names.begin()+21 );
30 |
31 | BOOST_REQUIRE_EQUAL( success(), vote( voter, top_producers_and_inactive ) );
32 | produce_blocks( 250 );
33 |
34 |
35 | BOOST_REQUIRE_EQUAL( 0, get_producer_info( standby )["unpaid_blocks"].as() );
36 | BOOST_REQUIRE_EQUAL( get_producer_info( producer_names[0] )["unpaid_blocks"].as() > 0, true );
37 |
38 | // TODO: Check nothing happened here, no rewards since it comes from system account
39 |
40 | asset rewards_sent = core_sym::from_string("1000.0000");
41 | transfer( fees, bpay, rewards_sent, fees);
42 |
43 | // rewards / 21
44 | asset balance_per_producer = core_sym::from_string("47.6190");
45 |
46 | auto rewards = get_bpay_rewards(producer_names[0]);
47 |
48 | // bp.inactive is still active, so should be included in the rewards
49 | BOOST_REQUIRE_EQUAL( get_bpay_rewards(inactive)["quantity"].as(), balance_per_producer );
50 | // Random sample
51 | BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[11])["quantity"].as(), balance_per_producer );
52 |
53 |
54 | // Deactivating a producer
55 | BOOST_REQUIRE_EQUAL( success(), push_action(config::system_account_name, "rmvproducer"_n, mvo()("producer", inactive) ) );
56 | BOOST_REQUIRE_EQUAL( false, get_producer_info( inactive )["is_active"].as() );
57 |
58 | transfer( fees, bpay, rewards_sent, fees);
59 | BOOST_REQUIRE_EQUAL( get_bpay_rewards(inactive)["quantity"].as(), balance_per_producer );
60 | BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[11])["quantity"].as(), core_sym::from_string("95.2380") );
61 |
62 | // BP should be able to claim their rewards
63 | {
64 | auto prod = producer_names[11];
65 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( prod ) );
66 | BOOST_REQUIRE_EQUAL( success(), bpay_claimrewards( prod ) );
67 | BOOST_REQUIRE_EQUAL( core_sym::from_string("95.2380"), get_balance( prod ) );
68 | BOOST_REQUIRE_EQUAL( true, get_bpay_rewards(prod).is_null() );
69 |
70 | // should still have rewards for another producer
71 | BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[10])["quantity"].as(), core_sym::from_string("95.2380") );
72 | }
73 |
74 | // Should be able to claim rewards from a producer that is no longer active
75 | {
76 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( inactive ) );
77 | BOOST_REQUIRE_EQUAL( success(), bpay_claimrewards( inactive ) );
78 | BOOST_REQUIRE_EQUAL( core_sym::from_string("47.6190"), get_balance( inactive ) );
79 | BOOST_REQUIRE_EQUAL( true, get_bpay_rewards(inactive).is_null() );
80 | }
81 |
82 | // Should not have rewards for a producer that was never active
83 | {
84 | BOOST_REQUIRE_EQUAL( true, get_bpay_rewards(standby).is_null() );
85 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( standby ) );
86 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("no rewards to claim"), bpay_claimrewards( standby ) );
87 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( standby ) );
88 | }
89 |
90 | // Tokens transferred from the eosio account should be ignored
91 | {
92 | transfer( config::system_account_name, bpay, rewards_sent, config::system_account_name );
93 | BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[10])["quantity"].as(), core_sym::from_string("95.2380") );
94 | }
95 |
96 |
97 |
98 | } FC_LOG_AND_RETHROW()
99 |
100 |
101 | BOOST_AUTO_TEST_SUITE_END()
--------------------------------------------------------------------------------
/tests/eosio.fees_tests.cpp:
--------------------------------------------------------------------------------
1 | #include "eosio.system_tester.hpp"
2 |
3 | using namespace eosio_system;
4 |
5 | BOOST_AUTO_TEST_SUITE(eosio_fees_tests);
6 |
7 | BOOST_FIXTURE_TEST_CASE( fees_with_rex, eosio_system_tester ) try {
8 | // init REX
9 | const std::vector accounts = { "alice"_n };
10 | const account_name alice = accounts[0];
11 | const asset init_balance = core_sym::from_string("1000.0000");
12 | setup_rex_accounts( accounts, init_balance );
13 | buyrex( alice, core_sym::from_string("10.0000"));
14 |
15 | // manual token transfer to fees account
16 | const asset fees_before = get_balance( "eosio.fees" );
17 | const asset rex_before = get_balance( "eosio.rex" );
18 | const asset eosio_before = get_balance( "eosio" );
19 |
20 | const asset fee = core_sym::from_string("100.0000");
21 | transfer( config::system_account_name, "eosio.fees"_n, fee, config::system_account_name );
22 |
23 | const asset fees_after = get_balance( "eosio.fees" );
24 | const asset rex_after = get_balance( "eosio.rex" );
25 | const asset eosio_after = get_balance( "eosio" );
26 |
27 | BOOST_REQUIRE_EQUAL( fees_before, fees_after );
28 | BOOST_REQUIRE_EQUAL( rex_before + fee, rex_after );
29 | BOOST_REQUIRE_EQUAL( eosio_before - fee, eosio_after );
30 |
31 | } FC_LOG_AND_RETHROW()
32 |
33 | BOOST_FIXTURE_TEST_CASE( fees_without_rex, eosio_system_tester ) try {
34 | // manual token transfer to fees account
35 | const asset fees_before = get_balance( "eosio.fees" );
36 | const asset rex_before = get_balance( "eosio.rex" );
37 | const asset eosio_before = get_balance( "eosio" );
38 |
39 | const asset fee = core_sym::from_string("100.0000");
40 | transfer( config::system_account_name, "eosio.fees"_n, fee, config::system_account_name );
41 |
42 | const asset fees_after = get_balance( "eosio.fees" );
43 | const asset rex_after = get_balance( "eosio.rex" );
44 | const asset eosio_after = get_balance( "eosio" );
45 |
46 | BOOST_REQUIRE_EQUAL( fees_before + fee, fees_after );
47 | BOOST_REQUIRE_EQUAL( rex_before, rex_after );
48 | BOOST_REQUIRE_EQUAL( eosio_before - fee, eosio_after );
49 |
50 | } FC_LOG_AND_RETHROW()
51 |
52 |
53 | BOOST_AUTO_TEST_SUITE_END()
54 |
--------------------------------------------------------------------------------
/tests/eosio.system_rex_matured_tests.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "eosio.system_tester.hpp"
4 |
5 | using namespace eosio_system;
6 |
7 | BOOST_AUTO_TEST_SUITE(eosio_system_rex_tests)
8 |
9 | bool within_error(int64_t a, int64_t b, int64_t err) { return std::abs(a - b) <= err; };
10 | bool within_one(int64_t a, int64_t b) { return within_error(a, b, 1); }
11 |
12 | BOOST_FIXTURE_TEST_CASE( buy_sell_matured_rex, eosio_system_tester ) try {
13 | // @param num_of_maturity_buckets - used to calculate maturity time of purchase REX tokens from end of the day UTC.
14 | // @param sell_matured_rex - if true, matured REX is sold immediately.
15 | // @param buy_rex_to_savings - if true, buying REX is moved immediately to REX savings.
16 | //
17 | // https://github.com/VaultaFoundation/system-contracts/issues/132
18 | // https://github.com/VaultaFoundation/system-contracts/issues/134
19 | // https://github.com/VaultaFoundation/system-contracts/issues/135
20 |
21 | // setup accounts
22 | const int64_t ratio = 10000;
23 | const asset init_rent = core_sym::from_string("20000.0000");
24 | const asset init_balance = core_sym::from_string("1000.0000");
25 | const std::vector accounts = { "alice"_n, "bob"_n, "charly"_n, "david"_n, "mark"_n };
26 | account_name alice = accounts[0], bob = accounts[1], charly = accounts[2], david = accounts[3], mark = accounts[4];
27 | setup_rex_accounts( accounts, init_balance );
28 |
29 |
30 | // 1. set `num_of_maturity_buckets=21` to test increasing maturity time of buying REX tokens.
31 | BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, false, false ) );
32 | BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( alice, core_sym::from_string("2.5000") ) );
33 | produce_blocks(2);
34 | produce_block(fc::days(5));
35 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient available rex"), sellrex( alice, asset::from_string("25000.0000 REX") ) );
36 | produce_block(fc::days(16));
37 |
38 | BOOST_REQUIRE_EQUAL( core_sym::from_string("2.5000"), get_sellrex_result( alice, asset::from_string("25000.0000 REX") ) );
39 | BOOST_REQUIRE_EQUAL( success(), buyrex( alice, core_sym::from_string("13.0000") ) );
40 | BOOST_REQUIRE_EQUAL( core_sym::from_string("13.0000"), get_rex_vote_stake( alice ) );
41 | BOOST_REQUIRE_EQUAL( success(), buyrex( alice, core_sym::from_string("17.0000") ) );
42 | BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), get_rex_vote_stake( alice ) );
43 | BOOST_REQUIRE_EQUAL( core_sym::from_string("970.0000"), get_rex_fund(alice) );
44 | BOOST_REQUIRE_EQUAL( get_rex_balance(alice).get_amount(), ratio * asset::from_string("30.0000 REX").get_amount() );
45 | auto rex_pool = get_rex_pool();
46 | BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), rex_pool["total_lendable"].as() );
47 | BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), rex_pool["total_unlent"].as() );
48 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), rex_pool["total_lent"].as() );
49 | BOOST_REQUIRE_EQUAL( init_rent, rex_pool["total_rent"].as() );
50 | BOOST_REQUIRE_EQUAL( get_rex_balance(alice), rex_pool["total_rex"].as() );
51 |
52 | // 2. set `sell_matured_rex=true` and `buy_rex_to_savings=false` to test buying REX without moving it to REX savings
53 | BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, true, false ) );
54 | BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( bob, core_sym::from_string("2.5000") ) );
55 | produce_blocks(2);
56 | produce_block(fc::days(5));
57 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient available rex"), sellrex( bob, asset::from_string("25000.0000 REX") ) );
58 | produce_block(fc::days(16));
59 | BOOST_REQUIRE_EQUAL( core_sym::from_string("2.5000"), get_rex_vote_stake( bob ) );
60 | BOOST_REQUIRE_EQUAL( asset::from_string("10000.0000 REX"), get_buyrex_result( bob, core_sym::from_string("1.0000") ) ); // will also triggers sell matured REX
61 | BOOST_REQUIRE_EQUAL( core_sym::from_string("1.0000"), get_rex_vote_stake( bob ) );
62 |
63 | // 3. set `sell_matured_rex=false` and `buy_rex_to_savings=true` to test selling matured REX
64 | BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, false, true ) );
65 | BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( charly, core_sym::from_string("2.5000") ) ); // when buying REX, it will automatically be moved to REX savings
66 | BOOST_REQUIRE_EQUAL( success(), mvfrsavings( charly, asset::from_string("25000.0000 REX") ) ); // move REX from savings to initiate matured REX unstaking process
67 | produce_blocks(2);
68 | produce_block(fc::days(5));
69 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient available rex"), sellrex( charly, asset::from_string("25000.0000 REX") ) );
70 | produce_block(fc::days(16));
71 | BOOST_REQUIRE_EQUAL( success(), updaterex( charly ) ); // triggers sell matured REX (any REX action causes sell matured REX)
72 | BOOST_REQUIRE_EQUAL( core_sym::from_string("2.5000"), get_sellrex_result( charly, asset::from_string("25000.0000 REX") ) );
73 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_rex_vote_stake( charly ) );
74 | BOOST_REQUIRE_EQUAL( init_balance, get_rex_fund( charly ) );
75 |
76 | // 4. legacy holders with matured REX
77 | BOOST_REQUIRE_EQUAL( success(), setrexmature( 5, false, false ) );
78 | BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( david, core_sym::from_string("2.5000") ) ); // legacy 5 days maturity
79 | BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( mark, core_sym::from_string("2.5000") ) );
80 | produce_blocks(2);
81 | produce_block(fc::days(5));
82 | BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, true, true ) );
83 | BOOST_REQUIRE_EQUAL( asset::from_string("10000.0000 REX"), get_buyrex_result( david, core_sym::from_string("1.0000") ) ); // new 21 days maturity & triggers sell matured REX
84 |
85 | // 4.1. Test selling less than all their matured rex, and having all of their already matured rex sold regardless
86 | BOOST_REQUIRE_EQUAL( core_sym::from_string("2.5000"), get_sellrex_result( mark, asset::from_string("1.0000 REX") ) );
87 |
88 | BOOST_REQUIRE_EQUAL( success(), mvfrsavings( david, asset::from_string("10000.0000 REX") ) ); // must move REX from savings to initiate matured REX unstaking process
89 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient available rex"), sellrex( david, asset::from_string("25000.0000 REX") ) ); // already sold when previously buying REX
90 | produce_blocks(2);
91 | produce_block(fc::days(5));
92 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient available rex"), sellrex( david, asset::from_string("10000.0000 REX") ) ); // 21 day REX not matured yet
93 | produce_blocks(2);
94 | produce_block(fc::days(21));
95 | BOOST_REQUIRE_EQUAL( core_sym::from_string("1.0000"), get_sellrex_result( david, asset::from_string("10000.0000 REX") ) );
96 | BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_rex_vote_stake( david ) );
97 | BOOST_REQUIRE_EQUAL( init_balance, get_rex_fund( david ) );
98 |
99 | // 5.0 Instant maturation
100 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("num_of_maturity_buckets must be positive"), setrexmature( 0, true, true ) );
101 |
102 |
103 | } FC_LOG_AND_RETHROW()
104 |
105 | BOOST_AUTO_TEST_SUITE_END()
106 |
--------------------------------------------------------------------------------
/tests/eosio.system_schedules_tests.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "eosio.system_tester.hpp"
3 |
4 | using namespace eosio_system;
5 |
6 | BOOST_AUTO_TEST_SUITE(eosio_system_vesting_tests)
7 |
8 | BOOST_FIXTURE_TEST_CASE(set_schedules, eosio_system_tester) try {
9 |
10 |
11 | auto check_schedule = [&](time_point_sec time, double rate){
12 | auto schedule = get_vesting_schedule(time.sec_since_epoch());
13 | REQUIRE_MATCHING_OBJECT( schedule, mvo()
14 | ("start_time", time)
15 | ("continuous_rate", rate)
16 | );
17 | };
18 |
19 | const std::vector accounts = { "alice"_n };
20 | create_accounts_with_resources( accounts );
21 | const account_name alice = accounts[0];
22 |
23 | const uint32_t YEAR = 86400 * 365;
24 | uint32_t initial_start_time = control->pending_block_time().sec_since_epoch(); // 1577836853 (2020-01-01T00:00:56.000Z)
25 | time_point_sec start_time = time_point_sec(initial_start_time);
26 |
27 |
28 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("continuous_rate can't be over 100%"), setschedule(start_time, 1.00001) );
29 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("continuous_rate can't be negative"), setschedule(start_time, -1) );
30 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("schedule not found"), delschedule(start_time) );
31 |
32 | // action validation
33 | BOOST_REQUIRE_EQUAL( success(), setschedule(time_point_sec(0), 0.05) );
34 | BOOST_REQUIRE_EQUAL( success(), setschedule(start_time, 0.05) );
35 | check_schedule(start_time, 0.05);
36 |
37 | // allow override existing schedules
38 | BOOST_REQUIRE_EQUAL( success(), setschedule(start_time, 0.02) );
39 | check_schedule(start_time, 0.02);
40 |
41 |
42 | // Should be able to delete schedules, even in the past
43 | BOOST_REQUIRE_EQUAL( success(), delschedule(start_time) );
44 | BOOST_REQUIRE_EQUAL( success(), delschedule(time_point_sec(0)) );
45 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("schedule not found"), delschedule(start_time) );
46 |
47 | // Resetting timers to make math clean
48 | initial_start_time = control->pending_block_time().sec_since_epoch();
49 | start_time = time_point_sec(initial_start_time);
50 |
51 |
52 | // // set 4 future schedules
53 | BOOST_REQUIRE_EQUAL( success(), setschedule(start_time, 0.02) );
54 | check_schedule(start_time, 0.02);
55 | BOOST_REQUIRE_EQUAL( success(), setschedule(time_point_sec(initial_start_time + YEAR * 4), 0.01) );
56 | check_schedule(time_point_sec(initial_start_time + YEAR * 4), 0.01);
57 | BOOST_REQUIRE_EQUAL( success(), setschedule(time_point_sec(initial_start_time + YEAR * 8), 0.005) );
58 | check_schedule(time_point_sec(initial_start_time + YEAR * 8), 0.005);
59 | BOOST_REQUIRE_EQUAL( success(), setschedule(time_point_sec(initial_start_time + YEAR * 12), 0.0005) );
60 | check_schedule(time_point_sec(initial_start_time + YEAR * 12), 0.0005);
61 | BOOST_REQUIRE_EQUAL( success(), setschedule(time_point_sec(initial_start_time + YEAR * 13), 0) );
62 | check_schedule(time_point_sec(initial_start_time + YEAR * 13), 0);
63 |
64 | // current state prior to first schedule change execution
65 | const double before = get_global_state4()["continuous_rate"].as_double();
66 | BOOST_REQUIRE_EQUAL( before, 0.048790164169432007 ); // 5% continuous rate
67 |
68 | BOOST_REQUIRE_EQUAL( success(), execschedule(alice) );
69 | BOOST_REQUIRE_EQUAL( get_global_state4()["continuous_rate"].as_double(), 0.02 );
70 |
71 | // Cannot execute schedule before its time is due
72 | // (we did 6 actions so we're late 3s late)
73 | auto late = fc::seconds(3);
74 | produce_block( fc::seconds(YEAR * 4) - fc::seconds(1) - late ); // advance to year 4
75 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("no schedule to execute"), execschedule(alice) );
76 |
77 | // Can execute this schedule 1 second after, as that is its time
78 | produce_block( fc::seconds(1) ); // advance to year 4
79 | BOOST_REQUIRE_EQUAL( control->pending_block_time().sec_since_epoch(), initial_start_time + YEAR * 4 ); // 2024-01-01T00:00
80 | BOOST_REQUIRE_EQUAL( success(), execschedule(alice) );
81 | BOOST_REQUIRE_EQUAL( get_global_state4()["continuous_rate"].as_double(), 0.01 ); // 1% continuous rate
82 |
83 | produce_block( fc::days(365 * 4) ); // advanced to year 8
84 | BOOST_REQUIRE_EQUAL( success(), execschedule(alice) );
85 | BOOST_REQUIRE_EQUAL( get_global_state4()["continuous_rate"].as_double(), 0.005 ); // 0.5% continuous rate
86 |
87 | produce_block( fc::days(365 * 4) ); // advanced to year 12
88 | BOOST_REQUIRE_EQUAL( success(), execschedule(alice) );
89 | BOOST_REQUIRE_EQUAL( get_global_state4()["continuous_rate"].as_double(), 0.0005 ); // 0.05% continuous rate
90 |
91 | produce_block( fc::days(365 * 1) ); // advanced to year 13
92 | BOOST_REQUIRE_EQUAL( success(), execschedule(alice) );
93 | BOOST_REQUIRE_EQUAL( get_global_state4()["continuous_rate"].as_double(), 0.0 ); // 0% continuous rate
94 |
95 | // no more schedules
96 | BOOST_REQUIRE_EQUAL( wasm_assert_msg("no schedule to execute"), execschedule(alice) );
97 |
98 | } FC_LOG_AND_RETHROW()
99 |
100 | BOOST_AUTO_TEST_SUITE_END()
101 |
--------------------------------------------------------------------------------
/tests/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "eosio.system_tester.hpp"
13 |
14 | using namespace eosio_system;
15 | #define BOOST_TEST_STATIC_LINK
16 |
17 | void translate_fc_exception(const fc::exception &e) {
18 | std::cerr << "\033[33m" << e.to_detail_string() << "\033[0m" << std::endl;
19 | BOOST_TEST_FAIL("Caught Unexpected Exception");
20 | }
21 |
22 | boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
23 | // Turn off blockchain logging if no --verbose parameter is not added
24 | // To have verbose enabled, call "tests/chain_test -- --verbose"
25 | bool is_verbose = false;
26 | std::string verbose_arg = "--verbose";
27 | for (int i = 0; i < argc; i++) {
28 | if (verbose_arg == argv[i]) {
29 | is_verbose = true;
30 | break;
31 | }
32 | }
33 |
34 | if(is_verbose) {
35 | fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::debug);
36 | } else {
37 | fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::off);
38 | }
39 |
40 | // Register fc::exception translator
41 | boost::unit_test::unit_test_monitor.template register_exception_translator(&translate_fc_exception);
42 |
43 | std::srand(time(NULL));
44 | std::cout << "Random number generator seeded to " << time(NULL) << std::endl;
45 | return nullptr;
46 | }
47 |
--------------------------------------------------------------------------------
/tests/test_contracts/exchange.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/tests/test_contracts/exchange.wasm
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.2.1/eosio.msig/Readme.txt:
--------------------------------------------------------------------------------
1 | Compiled with
2 | eosio.contracts: ee6415b0d3f9cff3bafebf98b2e06b80545dfa36
3 | eosio.wasmsdk: 0d4befeee7abbef1db775b2e8833f7db8fca7ad2 (v1.1.1), CORE_SYMBOL_NAME = "SYS"
4 |
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.abi:
--------------------------------------------------------------------------------
1 | {
2 | "version": "eosio::abi/1.0",
3 | "types": [{
4 | "new_type_name": "account_name",
5 | "type": "name"
6 | },{
7 | "new_type_name": "permission_name",
8 | "type": "name"
9 | },{
10 | "new_type_name": "action_name",
11 | "type": "name"
12 | }],
13 | "structs": [{
14 | "name": "permission_level",
15 | "base": "",
16 | "fields": [
17 | {"name": "actor", "type": "account_name"},
18 | {"name": "permission", "type": "permission_name"}
19 | ]
20 | },{
21 | "name": "action",
22 | "base": "",
23 | "fields": [
24 | {"name": "account", "type": "account_name"},
25 | {"name": "name", "type": "action_name"},
26 | {"name": "authorization", "type": "permission_level[]"},
27 | {"name": "data", "type": "bytes"}
28 | ]
29 | },{
30 | "name": "transaction_header",
31 | "base": "",
32 | "fields": [
33 | {"name": "expiration", "type": "time_point_sec"},
34 | {"name": "ref_block_num", "type": "uint16"},
35 | {"name": "ref_block_prefix", "type": "uint32"},
36 | {"name": "max_net_usage_words", "type": "varuint32"},
37 | {"name": "max_cpu_usage_ms", "type": "uint8"},
38 | {"name": "delay_sec", "type": "varuint32"}
39 | ]
40 | },{
41 | "name": "extension",
42 | "base": "",
43 | "fields": [
44 | {"name": "type", "type" : "uint16" },
45 | {"name": "data", "type": "bytes"}
46 | ]
47 | },{
48 | "name": "transaction",
49 | "base": "transaction_header",
50 | "fields": [
51 | {"name": "context_free_actions", "type": "action[]"},
52 | {"name": "actions", "type": "action[]"},
53 | {"name": "transaction_extensions", "type": "extension[]"}
54 | ]
55 | },{
56 | "name": "propose",
57 | "base": "",
58 | "fields": [
59 | {"name":"proposer", "type":"account_name"},
60 | {"name":"proposal_name", "type":"name"},
61 | {"name":"requested", "type":"permission_level[]"},
62 | {"name":"trx", "type":"transaction"}
63 | ]
64 | },{
65 | "name": "approve",
66 | "base": "",
67 | "fields": [
68 | {"name":"proposer", "type":"account_name"},
69 | {"name":"proposal_name", "type":"name"},
70 | {"name":"level", "type":"permission_level"}
71 | ]
72 | },{
73 | "name": "unapprove",
74 | "base": "",
75 | "fields": [
76 | {"name":"proposer", "type":"account_name"},
77 | {"name":"proposal_name", "type":"name"},
78 | {"name":"level", "type":"permission_level"}
79 | ]
80 | },{
81 | "name": "cancel",
82 | "base": "",
83 | "fields": [
84 | {"name":"proposer", "type":"account_name"},
85 | {"name":"proposal_name", "type":"name"},
86 | {"name":"canceler", "type":"account_name"}
87 | ]
88 | },{
89 | "name": "exec",
90 | "base": "",
91 | "fields": [
92 | {"name":"proposer", "type":"account_name"},
93 | {"name":"proposal_name", "type":"name"},
94 | {"name":"executer", "type":"account_name"}
95 | ]
96 | },{
97 | "name": "proposal",
98 | "base": "",
99 | "fields": [
100 | {"name": "proposal_name", "type": "name"},
101 | {"name": "packed_transaction", "type": "bytes"}
102 | ]
103 | },{
104 | "name": "approvals_info",
105 | "base": "",
106 | "fields": [
107 | {"name": "proposal_name", "type": "name"},
108 | {"name": "requested_approvals", "type": "permission_level[]"},
109 | {"name": "provided_approvals", "type": "permission_level[]"}
110 | ]
111 | }
112 | ],
113 | "actions": [{
114 | "name": "propose",
115 | "type": "propose",
116 | "ricardian_contract": ""
117 | },{
118 | "name": "approve",
119 | "type": "approve",
120 | "ricardian_contract": ""
121 | },{
122 | "name": "unapprove",
123 | "type": "unapprove",
124 | "ricardian_contract": ""
125 | }, {
126 | "name": "cancel",
127 | "type": "cancel",
128 | "ricardian_contract": ""
129 | }, {
130 | "name": "exec",
131 | "type": "exec",
132 | "ricardian_contract": ""
133 | }
134 |
135 | ],
136 | "tables": [{
137 | "name": "proposal",
138 | "type": "proposal",
139 | "index_type": "i64",
140 | "key_names" : ["proposal_name"],
141 | "key_types" : ["name"]
142 | },{
143 | "name": "approvals",
144 | "type": "approvals_info",
145 | "index_type": "i64",
146 | "key_names" : ["proposal_name"],
147 | "key_types" : ["name"]
148 | }
149 | ],
150 | "ricardian_clauses": [],
151 | "abi_extensions": []
152 | }
153 |
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/tests/test_contracts/old_versions/v1.2.1/eosio.msig/eosio.msig.wasm
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.2.1/eosio.system/README.txt:
--------------------------------------------------------------------------------
1 | Compiled with
2 | eosio.contracts: bf28f8bbf9ee753966c95c586906e82d72f9dfac (v1.2.1)
3 | eosio.wasmsdk: 2c106a018f2e69d34325ef2376cf085426068e93, CORE_SYMBOL_NAME = "SYS"
4 |
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.2.1/eosio.system/eosio.system.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/tests/test_contracts/old_versions/v1.2.1/eosio.system/eosio.system.wasm
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.8.3/eosio.system/README.txt:
--------------------------------------------------------------------------------
1 | Compiled with
2 | eosio.contracts: 7109f002fa9afff18edcafce5c32b224a21eef98 (v1.8.3)
3 | eosio.cdt: 263e41cbb3e58dca71117401f43be104f1e58ae4 (v1.6.3)
4 |
--------------------------------------------------------------------------------
/tests/test_contracts/old_versions/v1.8.3/eosio.system/eosio.system.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/tests/test_contracts/old_versions/v1.8.3/eosio.system/eosio.system.wasm
--------------------------------------------------------------------------------
/tests/test_contracts/reject_all.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaultaFoundation/system-contracts/75fd36b56da410e767d950a47c2253650b14ea9d/tests/test_contracts/reject_all.wasm
--------------------------------------------------------------------------------
/tests/test_symbol.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define CORE_SYM_NAME "TST"
4 | #define CORE_SYM_PRECISION 4
5 |
6 | #define _STRINGIZE1(x) #x
7 | #define _STRINGIZE2(x) _STRINGIZE1(x)
8 |
9 | #define CORE_SYM_STR ( _STRINGIZE2(CORE_SYM_PRECISION) "," CORE_SYM_NAME )
10 | #define CORE_SYM ( ::eosio::chain::string_to_symbol_c( CORE_SYM_PRECISION, CORE_SYM_NAME ) )
11 |
12 | struct core_sym {
13 | static inline eosio::chain::asset from_string(const std::string& s) {
14 | return eosio::chain::asset::from_string(s + " " CORE_SYM_NAME);
15 | }
16 | };
17 |
--------------------------------------------------------------------------------