Skip to content
Permalink
Browse files

Merge pull request #45 from eosdac/Adds-checks-for-negative-amounts

Adds checks for negative amounts in requested pay
  • Loading branch information...
michaeljyeates committed Mar 12, 2019
2 parents 9a2a4d3 + 768e785 commit 043f6ea6a995600b7b66a541ff1c3a060298ebb5
@@ -229,8 +229,7 @@ class daccustodian : public contract {
contract_state.set(_currentState, _self); // This should not run during a contract_state migration since it will prevent changing the schema with data saved between runs.
}

[[eosio::action]]
void updateconfig(contr_config newconfig);
ACTION updateconfig(contr_config newconfig);

/** Action to listen to from the associated token contract to ensure registering should be allowed.
*
@@ -265,8 +264,7 @@ class daccustodian : public contract {
* ### Post Condition:
* The candidate should be present in the candidates table and be set to active. If they are a returning candidate they should be set to active again. The `locked_tokens` value should reflect the total of the tokens they have transferred to the contract for staking. The number of active candidates in the contract will incremented.
*/
[[eosio::action]]
void nominatecand(name cand, eosio::asset requestedpay);
ACTION nominatecand(name cand, eosio::asset requestedpay);

/**
* This action is used to withdraw a candidate from being active for custodian elections.
@@ -280,8 +278,7 @@ class daccustodian : public contract {
* ### Post Condition:
* The candidate should still be present in the candidates table and be set to inactive. If the were recently an elected custodian there may be a time delay on when they can unstake their tokens from the contract. If not they will be able to unstake their tokens immediately using the unstake action.
*/
[[eosio::action]]
void withdrawcand(name cand);
ACTION withdrawcand(name cand);

/**
* This action is used to remove a candidate from being a candidate for custodian elections.
@@ -296,8 +293,7 @@ class daccustodian : public contract {
* ### Post Condition:
* The candidate should still be present in the candidates table and be set to inactive. If the `lockupstake` parameter is true the stake will be locked until the time delay has passed. If not the candidate will be able to unstake their tokens immediately using the unstake action to have them returned.
*/
[[eosio::action]]
void firecand(name cand, bool lockupStake);
ACTION firecand(name cand, bool lockupStake);

/**
* This action is used to resign as a custodian.
@@ -311,8 +307,7 @@ class daccustodian : public contract {
* ### Post Condition:
* The custodian will be removed from the active custodians and should still be present in the candidates table but will be set to inactive. Their staked tokens will be locked up for the time delay added from the moment this action was called so they will not able to unstake until that time has passed. A replacement custodian will selected from the candidates to fill the missing place (based on vote ranking) then the auths for the controlling dac auth account will be set for the custodian board.
*/
[[eosio::action]]
void resigncust(name cust);
ACTION resigncust(name cust);

/**
* This action is used to remove a custodian.
@@ -326,8 +321,7 @@ class daccustodian : public contract {
* ### Post Condition:
* The custodian will be removed from the active custodians and should still be present in the candidates table but will be set to inactive. Their staked tokens will be locked up for the time delay added from the moment this action was called so they will not able to unstake until that time has passed. A replacement custodian will selected from the candidates to fill the missing place (based on vote ranking) then the auths for the controlling dac auth account will be set for the custodian board.
*/
[[eosio::action]]
void firecust(name cust);
ACTION firecust(name cust);

/**
* This action is used to update the bio for a candidate.
@@ -342,8 +336,7 @@ class daccustodian : public contract {
* ### Post Condition:
Nothing from this action is stored on the blockchain. It is only intended to ensure authentication of changing the bio which will be stored off chain.
*/
[[eosio::action]]
void updatebio(name cand, std::string bio);
ACTION updatebio(name cand, std::string bio);

[[eosio::action]]
inline void stprofile(name cand, std::string profile) { require_auth(cand); };
@@ -365,8 +358,7 @@ Nothing from this action is stored on the blockchain. It is only intended to ens
* ### Post Condition:
* The requested pay for the candidate should be updated to the new asset.
*/
[[eosio::action]]
void updatereqpay(name cand, eosio::asset requestedpay);
ACTION updatereqpay(name cand, eosio::asset requestedpay);

/**
* This action is to facilitate voting for candidates to become custodians of the DAC. Each member will be able to vote a configurable number of custodians set by the contract configuration. When a voter calls this action either a new vote will be recorded or the existing vote for that voter will be modified. If an empty array of candidates is passed to the action an existing vote for that voter will be removed.
@@ -383,8 +375,7 @@ Nothing from this action is stored on the blockchain. It is only intended to ens
* ### Post Condition:
* An active vote record for the voter will have been created or modified to reflect the newvotes. Each of the candidates will have their total_votes amount updated to reflect the delta in voter's token balance. Eg. If a voter has 1000 tokens and votes for 5 candidates, each of those candidates will have their total_votes value increased by 1000. Then if they change their votes to now vote 2 different candidates while keeping the other 3 the same there would be a change of -1000 for 2 old candidates +1000 for 2 new candidates and the other 3 will remain unchanged.
*/
[[eosio::action]]
void votecust(name voter, std::vector<name> newvotes);
ACTION votecust(name voter, std::vector<name> newvotes);

// void voteproxy(name voter, name proxy);

@@ -403,8 +394,7 @@ Nothing from this action is stored on the blockchain. It is only intended to ens
* - After the initial vote quorum percent has been reached subsequent calls to this action will require a minimum of `vote_quorum_percent` to vote for the votes to be considered sufficient to trigger a new period with new custodians.
* @param message - a string that be used to log a message in the chain history logs. It serves no function in the contract logic.
*/
[[eosio::action]]
void newperiod(std::string message);
ACTION newperiod(std::string message);

/**
* This action is to claim pay as a custodian.
@@ -418,8 +408,7 @@ Nothing from this action is stored on the blockchain. It is only intended to ens
* ### Post Condition:
* The quantity owed to the custodian as referred to by the pay record is transferred to the claimer and then the pay record is removed from the pending pay table.
*/
[[eosio::action]]
void claimpay(uint64_t payid);
ACTION claimpay(uint64_t payid);

/**
* This action is used to unstake a candidates tokens and have them transferred to their account.
@@ -435,8 +424,7 @@ Nothing from this action is stored on the blockchain. It is only intended to ens
* ### Post Condition:
* The candidate should still be present in the candidates table and should be still set to inactive. The candidates tokens will be transferred back to their account and their `locked_tokens` value will be reduced to 0.
*/
[[eosio::action]]
void unstake(name cand);
ACTION unstake(name cand);


private: // Private helper methods used by other actions.
@@ -14,13 +14,15 @@ void daccustodian::distributePay() {

asset medianAsset = reqpays[mid];

for (auto cust: custodians) {
pending_pay.emplace(_self, [&](pay &p) {
p.key = pending_pay.available_primary_key();
p.receiver = cust.cust_name;
p.quantity = medianAsset;
p.memo = "Custodian pay. Thank you.";
});
if (medianAsset.amount > 0) {
for (auto cust: custodians) {
pending_pay.emplace(_self, [&](pay &p) {
p.key = pending_pay.available_primary_key();
p.receiver = cust.cust_name;
p.quantity = medianAsset;
p.memo = "Custodian pay. Thank you.";
});
}
}

print("distribute pay");
@@ -41,14 +43,15 @@ void daccustodian::distributeMeanPay() {
asset meanAsset = count == 0 ? total : total / count;

// print_f("Calclulated mean is: %", meanAsset);

for (auto cust: custodians) {
pending_pay.emplace(_self, [&](pay &p) {
p.key = pending_pay.available_primary_key();
p.receiver = cust.cust_name;
p.quantity = meanAsset;
p.memo = "Custodian pay. Thank you.";
});
if (meanAsset.amount > 0) {
for (auto cust: custodians) {
pending_pay.emplace(_self, [&](pay &p) {
p.key = pending_pay.available_primary_key();
p.receiver = cust.cust_name;
p.quantity = meanAsset;
p.memo = "Custodian pay. Thank you.";
});
}
}

print("distribute mean pay");
@@ -1,5 +1,5 @@
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Wed Mar 6 09:26:53 2019",
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Thu Mar 7 11:58:06 2019",
"version": "eosio::abi/1.1",
"structs": [
{
Binary file not shown.
@@ -1,5 +1,5 @@
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Wed Mar 6 09:26:58 2019",
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Thu Mar 7 11:58:12 2019",
"version": "eosio::abi/1.1",
"structs": [
{
Binary file not shown.
@@ -1,5 +1,5 @@
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Wed Mar 6 09:27:04 2019",
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Thu Mar 7 11:58:18 2019",
"version": "eosio::abi/1.1",
"structs": [
{
Binary file not shown.
@@ -1,5 +1,5 @@
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Wed Mar 6 09:27:10 2019",
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Mon Mar 11 23:08:49 2019",
"version": "eosio::abi/1.1",
"structs": [
{
Binary file not shown.
@@ -31,7 +31,7 @@ void daccustodian::claimpay(uint64_t payid) {
}

deferredTrans.delay_sec = TRANSFER_DELAY;
deferredTrans.send(payid, _self);
deferredTrans.send(uint128_t(payid) << 64 | now(), _self);

pending_pay.erase(payClaim);
}
@@ -4,6 +4,7 @@
require_auth(cand);
assertValidMember(cand);

eosio_assert(requestedpay.amount >= 0, "ERR::UPDATEREQPAY_UNDER_ZERO::Requested pay amount must not be negative.");
// This implicitly asserts that the symbol of requestedpay matches the configs.max pay.
eosio_assert(requestedpay <= configs().requested_pay_max,
"ERR::NOMINATECAND_PAY_LIMIT_EXCEEDED::Requested pay limit for a candidate was exceeded.");
@@ -244,6 +244,11 @@ def configure_contracts
its(:stderr) {is_expected.to include('A registering candidate must transfer sufficient tokens to the contract for staking')}
end

context "with negative requestpay amount" do
command %(cleos push action daccustodian nominatecand '{ "cand": "testreguser1", "bio": "any bio", "requestedpay": "-11.5000 EOS"}' -p testreguser1), allow_error: true
its(:stderr) {is_expected.to include("ERR::UPDATEREQPAY_UNDER_ZERO")}
end

context "with valid and registered member after transferring sufficient staked tokens in multiple transfers" do
before(:all) do
`cleos push action eosdactokens transfer '{ "from": "testreguser1", "to": "daccustodian", "quantity": "5.0000 EOSDAC","memo":"daccustodian"}' -p testreguser1 -f`
@@ -379,6 +384,11 @@ def configure_contracts
its(:stderr) {is_expected.to include('Error 3090004')}
end

context "with negative requestpay amount" do
command %(cleos push action daccustodian updatereqpay '{ "cand": "updatepay2", "requestedpay": "-450.5000 EOS"}' -p updatepay2), allow_error: true
its(:stderr) {is_expected.to include("ERR::UPDATEREQPAY_UNDER_ZERO")}
end

context "with valid auth" do
context "exceeding the req pay limit" do
command %(cleos push action daccustodian updatereqpay '{ "cand": "updatepay2", "requestedpay": "450.5000 EOS"}' -p updatepay2), allow_error: true
@@ -12,10 +12,12 @@ void daccustodian::updatereqpay(name cand, asset requestedpay) {

require_auth(cand);
assertValidMember(cand);
eosio_assert(requestedpay.amount >= 0, "ERR::UPDATEREQPAY_UNDER_ZERO::Requested pay amount must not be negative.");
eosio_assert(requestedpay <= configs().requested_pay_max, "ERR::UPDATEREQPAY_EXCESS_MAX_PAY::Requested pay amount limit for a candidate was exceeded.");
const auto &reg_candidate = registered_candidates.get(cand.value, "ERR::UPDATEREQPAY_NOT_CURRENT_REG_CANDIDATE::Candidate is not already registered.");

registered_candidates.modify(reg_candidate, cand, [&](candidate &c) {
c.requestedpay = requestedpay;
});
}

0 comments on commit 043f6ea

Please sign in to comment.
You can’t perform that action at this time.