diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index 2d6c3f09..d9a2efb7 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -17,4 +17,5 @@ add_subdirectory(fio.request.obt) add_subdirectory(fio.tpid) add_subdirectory(fio.treasury) add_subdirectory(fio.escrow) +add_subdirectory(fio.perms) add_subdirectory(fio.staking) diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index 459dfa6a..37c8b330 100755 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -88,6 +88,8 @@ namespace eosio { _proposer == fioio::TREASURYACCOUNT || _proposer == fioio::FIOSYSTEMACCOUNT || _proposer == fioio::FIOACCOUNT || + //FIP-40 + _proposer == fioio::PERMSACCOUNT || isTopProd) ) { //collect fees. diff --git a/contracts/fio.address/fio.address.cpp b/contracts/fio.address/fio.address.cpp index fe7c480d..be05168a 100644 --- a/contracts/fio.address/fio.address.cpp +++ b/contracts/fio.address/fio.address.cpp @@ -5,6 +5,7 @@ * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) Dapix */ + #include "fio.address.hpp" #include #include @@ -13,6 +14,7 @@ #include #include //TEMP FOR XFERADDRESS #include +#include namespace fioio { @@ -33,6 +35,8 @@ namespace fioio { eosiosystem::producers_table producers; eosiosystem::locked_tokens_table lockedTokensTable; nfts_table nftstable; + permissions_table permissions_table; + access_table accesses_table; config appConfig; //FIP-39 begin @@ -56,8 +60,9 @@ namespace fioio { voters(SYSTEMACCOUNT, SYSTEMACCOUNT.value), topprods(SYSTEMACCOUNT, SYSTEMACCOUNT.value), producers(SYSTEMACCOUNT, SYSTEMACCOUNT.value), - lockedTokensTable(SYSTEMACCOUNT, - SYSTEMACCOUNT.value), + lockedTokensTable(SYSTEMACCOUNT,SYSTEMACCOUNT.value), + permissions_table(PERMSACCOUNT,PERMSACCOUNT.value), + accesses_table(PERMSACCOUNT,PERMSACCOUNT.value), //FIP-39 begin fionameinfo(_self, _self.value){ //FIP-39 end @@ -282,7 +287,40 @@ namespace fioio { const bool isPublic = domains_iter->is_public; uint64_t domain_owner = domains_iter->account; - if (!isPublic) { + bool hasDomainAccess = false; + + //if actor is NOT owner, check for permissions + if(actor.value != domain_owner) { + + name grantor_account = name(domain_owner); + name grantee_account = actor; + string permctrl = + grantor_account.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + fa.fiodomain + REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME; + uint128_t permctrlhash = string_to_uint128_hash(permctrl.c_str()); + auto permissionbyctrl = permissions_table.get_index<"bypermctrl"_n>(); + auto permsbypermctrl_iter = permissionbyctrl.find(permctrlhash); + + if (permsbypermctrl_iter == permissionbyctrl.end()) { + permissionbyctrl = permissions_table.get_index<"bypermctrl"_n>(); + permctrl = + grantor_account.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + "*" + REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME; + permctrlhash = string_to_uint128_hash(permctrl.c_str()); + permsbypermctrl_iter = permissionbyctrl.find(permctrlhash); + + } + + if(permsbypermctrl_iter != permissionbyctrl.end()){ + string accessctrl = actor.to_string() + to_string(permsbypermctrl_iter->id); + uint128_t accessctrlhash = string_to_uint128_hash(accessctrl.c_str()); + auto accessesbyctrl = accesses_table.get_index<"byaccess"_n>(); + auto accessesbyctrl_iter = accessesbyctrl.find(accessctrlhash); + if (accessesbyctrl_iter != accessesbyctrl.end()) { + hasDomainAccess = true; + } + } + } + + if (!(isPublic || hasDomainAccess)) { fio_400_assert(domain_owner == actor.value, "fio_address", fa.fioaddress, "FIO Domain is not public. Only owner can create FIO Addresses.", ErrorInvalidFioNameFormat); @@ -1354,10 +1392,30 @@ namespace fioio { while (domainiter != domains.end()) { const uint64_t expire = domainiter->expiration; if ((expire + DOMAINWAITFORBURNDAYS) < nowtime) { + name grantor_account = name(domainiter->account); + string permcontrol = grantor_account.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + domainiter->name + REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME; + const uint128_t permcontrolHash = string_to_uint128_hash(permcontrol.c_str()); + auto permissionsbycontrolhash = permissions_table.get_index<"bypermctrl"_n>(); + auto permctrl_iter = permissionsbycontrolhash.find(permcontrolHash); + if (permctrl_iter != permissionsbycontrolhash.end() ) { + // clear all the permissions for this domain. + //FIP-40 + action( + permission_level{get_self(), "active"_n}, + "fio.perms"_n, + "clearperm"_n, + std::make_tuple(grantor_account, REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME, domainiter->name) + ).send(); + + // increment the number record processed by one + //this increment helps manage the time used by the burn + recordProcessed++; + if (recordProcessed == numbertoburn) { break; } + } + const auto domainhash = domainiter->domainhash; auto nameexpidx = fionames.get_index<"bydomain"_n>(); auto nameiter = nameexpidx.find(domainhash); - while (nameiter != nameexpidx.end()) { auto nextname = nameiter; nextname++; @@ -2021,7 +2079,7 @@ namespace fioio { uint16_t counter = 0; auto nft_iter = contractsbyname.begin(); while (nftburnq_iter != burnqbyname.end()) { - nft_iter = contractsbyname.find(nftburnq_iter->fio_address_hash); + nft_iter = contractsbyname.find(nftburnq_iter->fio_address_hash); counter++; if (nft_iter != contractsbyname.end()) { // if row, delete an nft nft_iter = contractsbyname.erase(nft_iter); @@ -2407,6 +2465,27 @@ namespace fioio { a.account = nm.value; }); + //clear all the permissions for this domain as part of the transfer + //note we limit grantees to 100 in the protocol to permit this kind of operation. + //see fio.perms.hpp MAX_GRANTEES documentation for further details. + //FIP-40 + + string permcontrol = actor.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + fio_domain + REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME; + const uint128_t permcontrolHash = string_to_uint128_hash(permcontrol.c_str()); + auto permissionsbycontrolhash = permissions_table.get_index<"bypermctrl"_n>(); + auto permctrl_iter = permissionsbycontrolhash.find(permcontrolHash); + if (permctrl_iter != permissionsbycontrolhash.end() ) { + // clear all the permissions for this domain. + //FIP-40 + action( + permission_level{get_self(), "active"_n}, + "fio.perms"_n, + "clearperm"_n, + std::make_tuple(actor, REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME, fio_domain) + ).send(); + } + + //fees const uint64_t fee_amount = fee_iter->suf_amount; const uint64_t fee_type = fee_iter->type; @@ -2516,9 +2595,10 @@ namespace fioio { void decrcounter(const string &fio_address, const int32_t &step) { check(step > 0, "step must be greater than 0"); + //FIP-40 check((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || has_auth(STAKINGACCOUNT) || - has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), - "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.reqobt, fio.system, fio.staking "); + has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract) || has_auth(PERMSACCOUNT)), + "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.reqobt, fio.system, fio.staking fio.perms"); auto namesbyname = fionames.get_index<"byname"_n>(); auto fioname_iter = namesbyname.find(string_to_uint128_hash(fio_address.c_str())); @@ -2580,7 +2660,7 @@ namespace fioio { }; - EOSIO_DISPATCH(FioNameLookup, (regaddress)(addaddress)(remaddress)(remalladdr)(regdomain)(renewdomain)(renewaddress) + EOSIO_DISPATCH(FioNameLookup,(regaddress)(addaddress)(remaddress)(remalladdr)(regdomain)(renewdomain)(renewaddress) (setdomainpub)(burnexpired)(decrcounter)(bind2eosio)(burnaddress)(xferdomain)(xferaddress)(addbundles)(xferescrow) (addnft)(remnft)(remallnfts)(burnnfts)(regdomadd)(updcryptkey)) } diff --git a/contracts/fio.common/fio.accounts.hpp b/contracts/fio.common/fio.accounts.hpp index 1bdaab66..6c444874 100644 --- a/contracts/fio.common/fio.accounts.hpp +++ b/contracts/fio.common/fio.accounts.hpp @@ -41,6 +41,8 @@ namespace fioio { static const name EscrowContract = name("fio.escrow"); static const name FIOACCOUNT = name("fio"); static const name FIOORACLEContract = name("fio.oracle"); + //FIP-40 + static const name PERMSACCOUNT = name("fio.perms"); static constexpr name FIOISSUER = name("eosio"_n); static constexpr eosio::symbol FIOSYMBOL = eosio::symbol("FIO", 9); diff --git a/contracts/fio.common/fio.common.hpp b/contracts/fio.common/fio.common.hpp index 11cf96b7..b76f60dc 100644 --- a/contracts/fio.common/fio.common.hpp +++ b/contracts/fio.common/fio.common.hpp @@ -80,6 +80,10 @@ #define ADD_NFT_ENDPOINT "add_nft" #define REM_NFT_ENDPOINT "remove_nft" #define REM_ALL_NFTS_ENDPOINT "remove_all_nfts" +//FIP-40 +#define ADD_PERMISSION_ENDPOINT "add_fio_permission" +#define REMOVE_PERMISSION_ENDPOINT "remove_fio_permission" +#define PERMISSION_OBJECT_TYPE_DOMAIN "domain" //FIP-38 begin #define NEW_FIO_CHAIN_ACCOUNT_ENDPOINT "new_fio_chain_account" //FIP-38 end @@ -145,7 +149,9 @@ namespace fioio { actor == fioio::FIOSYSTEMACCOUNT || actor == fioio::FIOACCOUNT || actor == fioio::EscrowContract || - actor == FIOORACLEContract); + actor == FIOORACLEContract || + //FIP-40 + actor == PERMSACCOUNT); } static constexpr uint64_t string_to_uint64_hash(const char *str) { @@ -514,6 +520,9 @@ namespace fioio { static const uint64_t BUNDLEVOTERAM = 0; //integrated. static const uint64_t ADDNFTRAMBASE = 512; static const uint64_t ADDNFTRAM = 2048; + //FIP-40 + static const uint64_t ADDPERMISSIONRAMBASE = 2560; + static const uint64_t ADDPERMISSIONRAM = 2048; static const uint64_t LISTDOMAINRAM = 1536; // FIOESCROW - List Domain 1140 bytes round to 512 x 3 //FIP-38 begin static const uint64_t NEWFIOCHAINACCOUNTRAM = 0; diff --git a/contracts/fio.common/fio_common_validator.hpp b/contracts/fio.common/fio_common_validator.hpp index 7485ae76..88a1145b 100644 --- a/contracts/fio.common/fio_common_validator.hpp +++ b/contracts/fio.common/fio_common_validator.hpp @@ -66,6 +66,22 @@ namespace fioio { return true; } + inline bool validateFioNameFormatTPID(const FioAddress &fa) { + if (fa.domainOnly) { + return false; + } else { + if (fa.fioaddress.size() < 3 || fa.fioaddress.size() > maxFioLen) { + return false; + } + if (!validateCharName(fa.fioname) || !validateCharName(fa.fiodomain)) { + return false; + }; + } + + return true; + } + + inline bool validateFioNameFormat(const FioAddress &fa) { if (fa.domainOnly) { if (fa.fiodomain.size() < 1 || fa.fiodomain.size() > maxFioDomainLen) { @@ -107,7 +123,7 @@ namespace fioio { if (tpid.size() > 0) { FioAddress fa; getFioAddressStruct(tpid, fa); - return validateFioNameFormat(fa); + return validateFioNameFormatTPID(fa); } return true; } diff --git a/contracts/fio.common/fioerror.hpp b/contracts/fio.common/fioerror.hpp index 55444a38..a219bf8c 100644 --- a/contracts/fio.common/fioerror.hpp +++ b/contracts/fio.common/fioerror.hpp @@ -97,6 +97,12 @@ namespace fioio { constexpr auto ErrorRetireQuantity = ident | httpDataError | 159; constexpr auto ErrorInvalidMemo = ident | httpDataError | 160; constexpr auto ErrorDomainSaleNotFound = ident | httpInvalidError | 161; // domain not found in domainsales table + //FIP-40 + constexpr auto ErrorInvalidPermissionName = ident | httpDataError | 162; + constexpr auto ErrorInvalidPermissionInfo = ident | httpDataError | 163; + constexpr auto ErrorInvalidObjectName = ident | httpDataError | 164; + constexpr auto ErrorInvalidGranteeAccount = ident | httpDataError | 165; + constexpr auto ErrorPermissionExists = ident | httpDataError | 166; /** * Helper funtions for detecting rich error messages and extracting bitfielded values diff --git a/contracts/fio.perms/CMakeLists.txt b/contracts/fio.perms/CMakeLists.txt new file mode 100644 index 00000000..e5ba9e59 --- /dev/null +++ b/contracts/fio.perms/CMakeLists.txt @@ -0,0 +1,14 @@ +add_contract(fio.perms fio.perms ${CMAKE_CURRENT_SOURCE_DIR}/fio.perms.cpp) + +target_include_directories(fio.perms + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../fio.perms/include + ${CMAKE_CURRENT_SOURCE_DIR}/../fio.address/include + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ) + + +set_target_properties(fio.perms + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/contracts/fio.perms/fio.perms.abi b/contracts/fio.perms/fio.perms.abi new file mode 100644 index 00000000..f7de9c0a --- /dev/null +++ b/contracts/fio.perms/fio.perms.abi @@ -0,0 +1,209 @@ +{ + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "permission_info", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "object_type", + "type": "string" + }, + { + "name": "object_type_hash", + "type": "uint128" + }, + { + "name": "object_name", + "type": "string" + }, + { + "name": "object_name_hash", + "type": "uint128" + }, + { + "name": "permission_name", + "type": "string" + }, + { + "name": "permission_name_hash", + "type": "uint128" + }, + { + "name": "permission_control_hash", + "type": "uint128" + }, + { + "name": "grantor_account", + "type": "name" + }, + { + "name": "auxiliary_info", + "type": "string" + } + ] + }, + { + "name": "access_info", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "permission_id", + "type": "uint64" + }, + { + "name": "grantee_account", + "type": "name" + }, + { + "name": "access_hash", + "type": "uint128" + }, + { + "name": "grantor_account", + "type": "name" + }, + { + "name": "names_hash", + "type": "uint128" + } + ] + }, + { + "name": "addperm", + "base": "", + "fields": [ + { + "name": "grantee_account", + "type": "name" + }, + { + "name": "permission_name", + "type": "string" + }, + { + "name": "permission_info", + "type": "string" + }, + { + "name": "object_name", + "type": "string" + }, + { + "name": "max_fee", + "type": "int64" + }, + { + "name": "tpid", + "type": "string" + }, + { + "name": "actor", + "type": "name" + } + ] + }, + { + "name": "remperm", + "base": "", + "fields": [ + { + "name": "grantee_account", + "type": "name" + }, + { + "name": "permission_name", + "type": "string" + }, + { + "name": "object_name", + "type": "string" + }, + { + "name": "max_fee", + "type": "int64" + }, + { + "name": "tpid", + "type": "string" + }, + { + "name": "actor", + "type": "name" + } + ] + }, + { + "name": "clearperm", + "base": "", + "fields": [ + { + "name": "grantor_account", + "type": "name" + }, + { + "name": "permission_name", + "type": "string" + }, + { + "name": "object_name", + "type": "string" + } + ] + } + ], + "actions": [ + { + "name": "addperm", + "type": "addperm", + "ricardian_contract": "" + }, + { + "name": "remperm", + "type": "remperm", + "ricardian_contract": "" + }, + { + "name": "clearperm", + "type": "clearperm", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "permissions", + "index_type": "i64", + "key_names": [ + "id" + ], + "key_types": [ + "string" + ], + "type": "permission_info" + }, + { + "name": "accesses", + "index_type": "i64", + "key_names": [ + "id" + ], + "key_types": [ + "string" + ], + "type": "access_info" + } + ], + "ricardian_clauses": [], + "error_messages": [], + "abi_extensions": [], + "variants": [] +} diff --git a/contracts/fio.perms/fio.perms.cpp b/contracts/fio.perms/fio.perms.cpp new file mode 100644 index 00000000..9a66fb6d --- /dev/null +++ b/contracts/fio.perms/fio.perms.cpp @@ -0,0 +1,490 @@ +/** FIO permissions contract + * Description: + * + * + * We will introduce a notion of a permission, a permission is a definition of information that provides some + * access control to objects in state which are owned by the account that creates the permission. + * Permissions definitions will be extensible within the FIO protocol. new permissions can be added into + * the FIO protocol by performing the following process: + * + * Step 1: define the functionality of the permission desired. + * Step 2: modify the fio.contracts to enforce and integrate the new permission. + * Step 3: rollout the new permission into testnet and main net using the following actions + * 3.1. rollout the new version of the contracts supporting the new permission. + * 3.2 FIO user accounts then begin using the permission as indicated in the spec. + * + * The following vernacular is used throughout our design: + * Permission – the name of the permission, + * Permission info -- the object type that is to be controlled, the name of the object to be controlled, + * the owning account, and also including all parameterized data used by the permission according to the + * business logic required (such as access levels, or other abstractions that can be set when an + * account grants the permission). + * Permission Auxiliary Info – the json definition of all of the parameterized data used by a given permission that is unique for a permission. + * for FIP-40 no additional data is necessary. this field provides extensibility such that we can introduce new + * or novel parameters and dials used by a new permission if this is necessary. + * Grantor – the granting/owning account of the object that relates to the permission. + * Object – the object that is being access controlled by a permission (for FIP-40 this is the domain). + * Grantee – the non grantor account that is given a permission. + * Access -- an account has access to a permission when a permission is granted to an account. + * + * + * + * + * + * + * @author Ed Rotthoff + * @file fio.perms.cpp + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) + */ + +#include "fio.perms.hpp" +#include +#include +#include +#include +#include +#include + +namespace fioio { + + class [[eosio::contract("FioPermissions")]] FioPermissions : public eosio::contract { + + private: + + domains_table domains; + fionames_table fionames; + fiofee_table fiofees; + eosio_names_table accountmap; + permissions_table permissions; + access_table accesses; + config appConfig; + + + + public: + using contract::contract; + + FioPermissions(name s, name code, datastream ds) : contract(s, code, ds), + permissions(_self,_self.value), + accesses(_self,_self.value), + domains(AddressContract, AddressContract.value), + fionames(AddressContract, AddressContract.value), + fiofees(FeeContract, FeeContract.value), + accountmap(_self, _self.value){ + configs_singleton configsSingleton(FeeContract, FeeContract.value); + appConfig = configsSingleton.get_or_default(config()); + } + + + /* + * This action will check if a permission exists for the specified arguments, if it does not + * yet exist in the permissions table a new record will be added, the accesses table will also + * be updated to indicate the grantee account access that has been granted. please see the code + * for error logic and parameter descriptions. + */ + [[eosio::action]] + void + addperm(const name &grantee_account, + const string &permission_name, //one permission is permitted register_address_on_domain + const string &permission_info, //this is empty for FIP-40, an extensibility field for the future. + const string &object_name, //the name of the fio domain + const int64_t &max_fee, + const string &tpid, + const name &actor + ) { + + + //print("addperm -- called. \n"); + + require_auth(actor); + string useperm = makeLowerCase(permission_name); + + + fio_400_assert(permission_name.length() > 0, "permission_name", permission_name, + "Permission name is invalid.", ErrorInvalidPermissionName); + // error if permission name is not the expected name register_address_on_domain. + //one permission name is integrated for fip 40, modify this logic for any new permission names + //being supported + fio_400_assert(useperm.compare(REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME) == 0, "permission_name", permission_name, + "Permission name is invalid.", ErrorInvalidPermissionName); + + // error if permission info is not empty. + fio_400_assert(permission_info.size() == 0, "permission_info", permission_info, + "Permission Info is invalid.", ErrorInvalidPermissionInfo); + // error if object name is not * or is not in the domains table + fio_400_assert(object_name.size() > 0, "object_name", object_name, + "Object Name is invalid.", ErrorInvalidObjectName); + + if(object_name.compare("*")!=0) { + //verify domain name, and that domain is owned by the actor account. + FioAddress fa; + getFioAddressStruct(object_name, fa); + + fio_400_assert(fa.domainOnly, "object_name", object_name, "Object Name is invalid.", + ErrorInvalidObjectName); + + const uint128_t domainHash = string_to_uint128_hash(fa.fiodomain.c_str()); + auto domainsbyname = domains.get_index<"byname"_n>(); + auto domains_iter = domainsbyname.find(domainHash); + + fio_400_assert(domains_iter != domainsbyname.end(), "object_name", object_name, + "Object Name is invalid.", + ErrorInvalidObjectName); + + //add 30 days to the domain expiration, this call will work until 30 days past expire. + const uint32_t domain_expiration = get_time_plus_seconds(domains_iter->expiration, SECONDS30DAYS); + + const uint32_t present_time = now(); + fio_400_assert(present_time <= domain_expiration, "object_name", object_name, "Object Name is invalid.", + ErrorInvalidObjectName); + + //check domain owner is actor + fio_400_assert((actor.value == domains_iter->account), "object_name", object_name, + "Object Name is invalid.", ErrorInvalidObjectName); + } + + + //check grantee exists. + fio_400_assert(is_account(grantee_account), "grantee_account", grantee_account.to_string(), + "Account is invalid or does not exist.", ErrorInvalidGranteeAccount); + + fio_400_assert((grantee_account.value != actor.value), "grantee_account", grantee_account.to_string(), + "Account is invalid or does not exist.", ErrorInvalidGranteeAccount); + + + //error if the grantee account already has this permission. + string permcontrol = actor.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + object_name + useperm; + const uint128_t permcontrolhash = string_to_uint128_hash(permcontrol.c_str()); + const uint128_t objectnamehash = string_to_uint128_hash(object_name); + auto accessbyhash = accesses.get_index<"byaccess"_n>(); + auto accessbypermid = accesses.get_index<"bypermid"_n>(); + auto permissionsbycontrolhash = permissions.get_index<"bypermctrl"_n>(); + auto permctrl_iter = permissionsbycontrolhash.find(permcontrolhash); + uint64_t permid = 0; + + if(permctrl_iter == permissionsbycontrolhash.end()) + { //insert the permission + //one permission name is integrated for fip 40, modify this logic for any new permission names + //being supported + string object_type = PERMISSION_OBJECT_TYPE_DOMAIN; + permid = permissions.available_primary_key(); + permissions.emplace(get_self(), [&](struct permission_info &p) { + p.id = permid; + p.object_type = PERMISSION_OBJECT_TYPE_DOMAIN; + p.object_type_hash = string_to_uint128_hash(PERMISSION_OBJECT_TYPE_DOMAIN); + p.object_name = object_name; + p.object_name_hash = objectnamehash; + p.permission_name = useperm; + p.permission_name_hash = string_to_uint128_hash(useperm); + p.permission_control_hash = permcontrolhash; + p.grantor_account = actor.value; + p.auxiliary_info = ""; + }); + } + else { + //get the id for the perm + permid = permctrl_iter->id; + } + + + string accessctrl = grantee_account.to_string() + to_string(permid); + const uint128_t accesshash = string_to_uint128_hash(accessctrl.c_str()); + auto access_iter = accessbyhash.find(accesshash); + + fio_400_assert((access_iter == accessbyhash.end() ), "grantee_account", grantee_account.to_string(), + "Permission already exists", ErrorPermissionExists); + + //count the number of grantees. + auto grantees_iter = accessbypermid.find(permid); + + //enforce the limit on the number of grantee accounts see the comments in fio.perms.hpp for MAX_GRANTEES + //for details + int countgrantees = 0; + while(grantees_iter != accessbypermid.end()){ + countgrantees ++; + grantees_iter ++; + } + + string msg = "Number of grantees exceeded, Max number grantees permitted is "+ to_string(MAX_GRANTEES); + + fio_400_assert((countgrantees <= MAX_GRANTEES ), "grantee_account", grantee_account.to_string(), + msg , ErrorPermissionExists); + + + //add the record to accesses. + const uint64_t accessid = accesses.available_primary_key(); + accesses.emplace(get_self(), [&](struct access_info &a) { + a.id = accessid; + a.permission_id = permid; + a.grantee_account = grantee_account.value; + a.access_hash = accesshash; + a.grantor_account = actor.value; + a.names_hash = string_to_uint128_hash(object_name + useperm); + }); + + + fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", + ErrorMaxFeeInvalid); + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, + "TPID must be empty or valid FIO address", + ErrorPubKeyValid); + + + //fees + const uint128_t endpoint_hash = string_to_uint128_hash(ADD_PERMISSION_ENDPOINT); + auto fees_by_endpoint = fiofees.get_index<"byendpoint"_n>(); + auto fee_iter = fees_by_endpoint.find(endpoint_hash); + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", ADD_PERMISSION_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + const uint64_t fee_amount = fee_iter->suf_amount; + const uint64_t fee_type = fee_iter->type; + + fio_400_assert(fee_type == 0, "fee_type", to_string(fee_type), + "unexpected fee type for endpoint transfer_fio_domain, expected 0", + ErrorNoEndpoint); + + fio_400_assert(max_fee >= (int64_t) fee_amount, "max_fee", to_string(max_fee), + "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(fee_amount, FIOSYMBOL), ADD_PERMISSION_ENDPOINT); + processbucketrewards(tpid, fee_amount, get_self(), actor); + + if (fee_amount > 0) { + INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) + (SYSTEMACCOUNT, {{_self, "active"_n}}, + {actor, true} + ); + } + + //ram bump + if (ADDPERMISSIONRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, ADDPERMISSIONRAMBASE + (ADDPERMISSIONRAM * permission_info.size())) + ).send(); + } + const string response_string = "{\"status\": \"OK\", \"fee_collected\" : "+ to_string(fee_amount) +"}"; + send_response(response_string.c_str()); + + } + + /* + * This action will remove the specified account from the accesses table, if the resulting permission + * has no remaining grantees then the permission will be removed from the permissions table. + */ + [[eosio::action]] + void + remperm(const name &grantee_account, + const string &permission_name, + const string &object_name, + const int64_t &max_fee, + const string &tpid, + const name &actor + ) { + + + // print("remperm -- called. \n"); + + require_auth(actor); + + + fio_400_assert(permission_name.length() > 0, "permission_name", permission_name, + "Permission name is invalid.", ErrorInvalidPermissionName); + + string useperm = makeLowerCase(permission_name); + + // error if permission name is not the expected name register_address_on_domain. + fio_400_assert(useperm.compare(REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME) == 0, "permission_name", permission_name, + "Permission name is invalid.", ErrorInvalidPermissionName); + + // error if object name is not * or is not in the domains table + fio_400_assert(object_name.size() > 0, "object_name", object_name, + "Object Name is invalid.", ErrorInvalidObjectName); + + if(object_name.compare("*")!= 0) { + + //verify domain name, and that domain is owned by the actor account. + FioAddress fa; + getFioAddressStruct(object_name, fa); + + fio_400_assert(fa.domainOnly, "object_name", object_name, "Object Name is invalid.", + ErrorInvalidObjectName); + + const uint128_t domainHash = string_to_uint128_hash(fa.fiodomain.c_str()); + auto domainsbyname = domains.get_index<"byname"_n>(); + auto domains_iter = domainsbyname.find(domainHash); + + fio_400_assert(domains_iter != domainsbyname.end(), "object_name", object_name, + "Object Name is invalid.", + ErrorInvalidObjectName); + + //add 30 days to the domain expiration, this call will work until 30 days past expire. + const uint32_t domain_expiration = get_time_plus_seconds(domains_iter->expiration, SECONDS30DAYS); + const uint32_t present_time = now(); + + fio_400_assert(present_time <= domain_expiration, "object_name", object_name, "Object Name is invalid.", + ErrorInvalidObjectName); + + //check domain owner is actor + fio_400_assert((actor.value == domains_iter->account), "object_name", object_name, + "Object Name is invalid.", ErrorInvalidObjectName); + } + + + //check grantee exists. + fio_400_assert(is_account(grantee_account), "grantee_account", grantee_account.to_string(), + "Account is invalid or does not exist.", ErrorInvalidGranteeAccount); + + fio_400_assert((grantee_account.value != actor.value), "grantee_account", grantee_account.to_string(), + "Account is invalid or does not exist.", ErrorInvalidGranteeAccount); + + string permcontrol = actor.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + object_name + REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME; + + const uint128_t permcontrolHash = string_to_uint128_hash(permcontrol.c_str()); + + auto permissionsbycontrolhash = permissions.get_index<"bypermctrl"_n>(); + auto permctrl_iter = permissionsbycontrolhash.find(permcontrolHash); + if (permctrl_iter != permissionsbycontrolhash.end() ){ + //get the id and look in access, remove it if its there, error if not there + uint64_t permid = permctrl_iter->id; + string accessctrl = grantee_account.to_string() + to_string(permid); + const uint128_t accessHash = string_to_uint128_hash(accessctrl.c_str()); + auto accessbyhash = accesses.get_index<"byaccess"_n>(); + auto access_iter = accessbyhash.find(accessHash); + + fio_400_assert((access_iter != accessbyhash.end() ), "grantee_account", grantee_account.to_string(), + "Permission not found", ErrorPermissionExists); + accessbyhash.erase(access_iter); + //do one more check for this access by permission id, if no results then + //remove from permissions. + auto accessbypermid = accesses.get_index<"bypermid"_n>(); + auto accessbyperm_iter = accessbypermid.find(permid); + if(accessbyperm_iter == accessbypermid.end()){ + //no accounts with this access left, remove the permission. + permissionsbycontrolhash.erase(permctrl_iter); + } + }else{ + //cant find access by control hash. permission not found + fio_400_assert((permctrl_iter != permissionsbycontrolhash.end()), "grantee_account", grantee_account.to_string(), + "Permission not found", ErrorPermissionExists); + } + + fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", + ErrorMaxFeeInvalid); + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, + "TPID must be empty or valid FIO address", + ErrorPubKeyValid); + + //fees + const uint128_t endpoint_hash = string_to_uint128_hash(REMOVE_PERMISSION_ENDPOINT); + auto fees_by_endpoint = fiofees.get_index<"byendpoint"_n>(); + auto fee_iter = fees_by_endpoint.find(endpoint_hash); + + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", REMOVE_PERMISSION_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const uint64_t fee_amount = fee_iter->suf_amount; + const uint64_t fee_type = fee_iter->type; + + fio_400_assert(fee_type == 0, "fee_type", to_string(fee_type), + "unexpected fee type for endpoint remove permission, expected 0", + ErrorNoEndpoint); + + fio_400_assert(max_fee >= (int64_t) fee_amount, "max_fee", to_string(max_fee), + "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(fee_amount, FIOSYMBOL), REMOVE_PERMISSION_ENDPOINT); + processbucketrewards(tpid, fee_amount, get_self(), actor); + + if (fee_amount > 0) { + INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) + (SYSTEMACCOUNT, {{_self, "active"_n}}, + {actor, true} + ); + } + const string response_string = "{\"status\": \"OK\", \"fee_collected\" : "+ to_string(fee_amount) +"}"; + send_response(response_string.c_str()); + } + + + //This action will clear the specified permission for the specified object and specified grantor account. + //all granted accesses will be removed. + [[eosio::action]] + void + clearperm( + const name &grantor_account, + const string &permission_name, + const string &object_name + ) { + + + // print("clearperm -- called. \n"); + + eosio_assert((has_auth(AddressContract) ), + "missing required authority of fio.addresss"); + + + fio_400_assert(permission_name.length() > 0, "permission_name", permission_name, + "Permission name is invalid.", ErrorInvalidPermissionName); + + string useperm = makeLowerCase(permission_name); + + // error if permission name is not the expected name register_address_on_domain. + fio_400_assert(useperm.compare(REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME) == 0, "permission_name", permission_name, + "Permission name is invalid.", ErrorInvalidPermissionName); + + // error if object name is not * or is not in the domains table + fio_400_assert(object_name.size() > 0, "object_name", object_name, + "Object Name is invalid.", ErrorInvalidObjectName); + + //verify domain name, and that domain is owned by the actor account. + FioAddress fa; + getFioAddressStruct(object_name, fa); + + fio_400_assert(fa.domainOnly, "object_name", object_name, "Object Name is invalid.", + ErrorInvalidObjectName); + + string permcontrol = grantor_account.to_string() + REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE + object_name + REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME; + + const uint128_t permcontrolHash = string_to_uint128_hash(permcontrol.c_str()); + + auto permissionsbycontrolhash = permissions.get_index<"bypermctrl"_n>(); + auto permctrl_iter = permissionsbycontrolhash.find(permcontrolHash); + if (permctrl_iter != permissionsbycontrolhash.end() ) { + int numcleared =0; + //get the id and look in access, remove it if its there, error if not there + uint64_t permid = permctrl_iter->id; + auto accessbypermid1 = accesses.get_index<"bypermid"_n>(); + auto accessbypermid_iter = accessbypermid1.find(permid); + //remove all accesses, this code assumes that there are less than 5k accesses per permission. + //if there are more than this, then the method of removal must be changed to be more + //like the NFT clearing in FIO. make a queue and remove some number at a time. + //for register address on domain we limit the number of grantees to 100. + while (accessbypermid_iter != accessbypermid1.end()) { + numcleared++; + auto nextaccess = accessbypermid_iter; + nextaccess++; + accessbypermid1.erase(accessbypermid_iter); + accessbypermid_iter = nextaccess; + } + permissionsbycontrolhash.erase(permctrl_iter); + }else{ + //cant find access by control hash. permission not found + fio_400_assert((permctrl_iter != permissionsbycontrolhash.end()), "permission_name", permission_name, + "Permission not found", ErrorPermissionExists); + } + + + const string response_string = "{\"status\": \"OK\"}"; + send_response(response_string.c_str()); + } +}; + + + + EOSIO_DISPATCH(FioPermissions, (addperm)(remperm)(clearperm)) +} diff --git a/contracts/fio.perms/fio.perms.hpp b/contracts/fio.perms/fio.perms.hpp new file mode 100644 index 00000000..2913c8e7 --- /dev/null +++ b/contracts/fio.perms/fio.perms.hpp @@ -0,0 +1,120 @@ +/** FIO permissions + * Description: see fio.perm.cpp. + * @author Ed Rotthoff + * @file fio.perms.hpp + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) + */ + +#pragma once + +#include +#include +#include + +#include + +using std::string; + +namespace fioio { + + using namespace eosio; + + const static string REGISTER_ADDRESS_ON_DOMAIN_PERMISSION_NAME = "register_address_on_domain"; + const static string REGISTER_ADDRESS_ON_DOMAIN_OBJECT_TYPE = "domain"; + /** + * The fio protocol could permit users to grant a host of accounts a given permission, just like any + * well known permissions schemes users could then grant so many accounts permissioins that it becomes an + * extended offline effort to perform housekeeping and other analysis when the permission changes or are removed. + * we decide to enforce that 100 accounts can be granted a permission, this number provides that + * house keeping of permissions in state can have a chance to be performed by the contracts when users + * perform operations that necessitate that pre-existing permissions be removed as part of an operation + * (for example for FIP-40 when transferring a domain, we must remove pre-exisitng permissions + * for the user or we could give an error and make users clean permissions offline before allowing the + * transfer). + */ + const static int MAX_GRANTEES = 100; + + struct [[eosio::action]] permission_info { + + uint64_t id = 0; + // this is a string whose acceptable values should be defined in this file, we use "domain" for FIP-40. + string object_type = ""; + uint128_t object_type_hash = 0; + //this is the name of the object being controlled in state, for FIP-40 this will be the name of the domain + //being permissed to create new addresses. + string object_name = ""; + uint128_t object_name_hash = 0; + //this is the name of the permission, these values should be constants defined in this file. + //for FIP-40 we will use register_address_on_domain as the value. + string permission_name = ""; + uint128_t permission_name_hash = 0; + //by convention we will store the hashed value of the following concatination in this field to provide a + //unique search key by grantor object_type, object_name, and permission_name + uint128_t permission_control_hash = 0; + uint64_t grantor_account = 0; + //this field can contain any string based info that is useful for the permission. + //it shouldbe json based. for FIP-40 this is unused. + string auxiliary_info = ""; + + + uint64_t primary_key() const { return id; } + uint128_t by_object_type_hash() const { return object_type_hash; } + uint128_t by_object_name_hash() const { return object_name_hash; } + uint128_t by_permission_name_hash() const { return permission_name_hash; } + uint128_t by_permission_control_hash() const { return permission_control_hash; } + uint64_t by_grantor_account() const { return grantor_account; } + + + EOSLIB_SERIALIZE(permission_info, (id)(object_type)(object_type_hash)(object_name)(object_name_hash) + (permission_name)(permission_name_hash)(permission_control_hash)(grantor_account)(auxiliary_info)) + }; + //this state table contains information relating to the permissions that are granted in the FIO protocol + //please examine fio.perms.cpp for details relating to FIO permissions. + typedef multi_index<"permissions"_n, permission_info, + indexed_by<"byobjtype"_n, const_mem_fun < permission_info, uint128_t, &permission_info::by_object_type_hash>>, + indexed_by<"byobjname"_n, const_mem_fun < permission_info, uint128_t, &permission_info::by_object_name_hash>>, + indexed_by<"bypermname"_n, const_mem_fun < permission_info, uint128_t, &permission_info::by_permission_name_hash>>, + indexed_by<"bypermctrl"_n, const_mem_fun < permission_info, uint128_t, &permission_info::by_permission_control_hash>>, + indexed_by<"bygrantor"_n, const_mem_fun < permission_info, uint64_t, &permission_info::by_grantor_account>> + > + permissions_table; + + + + + +struct [[eosio::action]] access_info { + + uint64_t id = 0; + uint64_t permission_id = 0; + uint64_t grantee_account = 0; + //this is the hashed value of the string concatination of grantee account, permission id + uint128_t access_hash = 0; + uint64_t grantor_account = 0; + uint128_t names_hash = 0; //the hashed value of the string concatination of the object name and permission name. + + + uint64_t primary_key() const { return id; } + uint64_t by_permission_id() const { return permission_id; } + uint64_t by_grantee_account() const { return grantee_account; } + uint128_t by_access_hash() const { return access_hash; } + uint64_t by_grantor_account() const {return grantor_account; } + uint128_t by_names_hash() const { return names_hash; } + + + EOSLIB_SERIALIZE(access_info, (id)(permission_id)(grantee_account)(access_hash)(grantor_account)(names_hash)) +}; +//this state table contains information relating to the accesses that are granted in the FIO protocol +//please examine fio.perms.cpp for details relating to FIO permissions. +typedef multi_index<"accesses"_n, access_info, + indexed_by<"bypermid"_n, const_mem_fun < access_info, uint64_t, &access_info::by_permission_id>>, + indexed_by<"bygrantee"_n, const_mem_fun < access_info, uint64_t, &access_info::by_grantee_account>>, + indexed_by<"byaccess"_n, const_mem_fun < access_info, uint128_t, &access_info::by_access_hash>>, + indexed_by<"bygrantor"_n, const_mem_fun < access_info, uint64_t, &access_info::by_grantor_account>>, + indexed_by<"bynames"_n, const_mem_fun < access_info, uint128_t, &access_info::by_names_hash>> +> +access_table; + + + +} diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 0bbd5075..5cd59b2d 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -56,8 +56,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { void incgrewards(const int64_t &fioamountsufs) { eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || has_auth(STAKINGACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || - has_auth(FeeContract) || has_auth(FIOORACLEContract) || has_auth(EscrowContract)), - "missing required authority of fio.address, fio.treasury, fio.fee, fio.token, fio.staking, fio.oracle, fio.escrow, eosio or fio.reqobt"); + has_auth(FeeContract) || has_auth(FIOORACLEContract) || has_auth(EscrowContract) || + has_auth(PERMSACCOUNT) ), + "missing required authority of fio.address, fio.treasury, fio.fee, fio.token, fio.staking, fio.oracle, fio.escrow, eosio, fio.perms or fio.reqobt"); const uint32_t present_time = now(); gstaking.rewards_token_pool += fioamountsufs; diff --git a/contracts/fio.system/include/fio.system/native.hpp b/contracts/fio.system/include/fio.system/native.hpp index f2da5032..6dca3d1e 100755 --- a/contracts/fio.system/include/fio.system/native.hpp +++ b/contracts/fio.system/include/fio.system/native.hpp @@ -150,7 +150,8 @@ namespace eosiosystem { account == fioio::STAKINGACCOUNT || account == fioio::FIOACCOUNT || account == fioio::FIOORACLEContract || - account == fioio::FIOACCOUNT) + account == fioio::FIOACCOUNT || + account == fioio::PERMSACCOUNT) ) { //get the sizes of the tx. diff --git a/contracts/fio.system/src/delegate_bandwidth.cpp b/contracts/fio.system/src/delegate_bandwidth.cpp index 20c12e41..d01e1346 100755 --- a/contracts/fio.system/src/delegate_bandwidth.cpp +++ b/contracts/fio.system/src/delegate_bandwidth.cpp @@ -61,9 +61,10 @@ namespace eosiosystem { has_auth(SYSTEMACCOUNT) || has_auth(FeeContract) || has_auth(StakingContract) || - has_auth(REQOBTACCOUNT) + //FIP-40 + has_auth(PERMSACCOUNT) ), - "missing required authority of fio.address, fio.treasury, eosio, fio.fee, fio.token, fio.staking, or fio.reqobt"); + "missing required authority of fio.address, fio.treasury, eosio, fio.fee, fio.token, fio.staking, fio.perms or fio.reqobt"); auto votersbyowner = _voters.get_index<"byowner"_n>(); auto voter_itr = votersbyowner.find(voter.value); diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 6e7ea9b1..7b3835d8 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -304,7 +304,8 @@ namespace eosiosystem { acnt == FIOSYSTEMACCOUNT || acnt == EscrowContract || acnt == FIOORACLEContract || - acnt == FIOACCOUNT),"set abi not permitted." ); + acnt == FIOACCOUNT || + acnt == PERMSACCOUNT),"set abi not permitted." ); eosio::multi_index<"abihash"_n, abi_hash> table(_self, _self.value); @@ -426,8 +427,9 @@ namespace eosiosystem { eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || has_auth(STAKINGACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || - has_auth(FIOORACLEContract) || has_auth(FeeContract) || has_auth(EscrowContract)), - "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.oracle, fio.escrow, fio.staking, or fio.reqobt"); + has_auth(FIOORACLEContract) || has_auth(FeeContract) || has_auth(EscrowContract) || + has_auth(PERMSACCOUNT)), + "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.oracle, fio.escrow, fio.staking, fio.perms or fio.reqobt"); check(is_account(owner), "account must pre exist"); auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); auto lockiter = locks_by_owner.find(owner.value); diff --git a/contracts/fio.token/src/fio.token.cpp b/contracts/fio.token/src/fio.token.cpp index 56fea754..5589c178 100755 --- a/contracts/fio.token/src/fio.token.cpp +++ b/contracts/fio.token/src/fio.token.cpp @@ -420,7 +420,8 @@ namespace eosio { * we permit the use of transfer from the treasury account to any other accounts. * we permit the use of transfer from any other accounts to the treasury account for fees. */ - if (from != SYSTEMACCOUNT && from != TREASURYACCOUNT && from != EscrowContract && from != FIOORACLEContract) { + if (from != SYSTEMACCOUNT && from != TREASURYACCOUNT && from != EscrowContract + && from != FIOORACLEContract) { if(!has_auth(EscrowContract) && !has_auth(FIOORACLEContract)){ check(to == TREASURYACCOUNT, "transfer not allowed"); } diff --git a/contracts/fio.tpid/fio.tpid.cpp b/contracts/fio.tpid/fio.tpid.cpp index a422f00c..7f88affb 100644 --- a/contracts/fio.tpid/fio.tpid.cpp +++ b/contracts/fio.tpid/fio.tpid.cpp @@ -94,9 +94,10 @@ class [[eosio::contract("TPIDController")]] TPIDController: public eosio::contr [[eosio::action]] void updatetpid(const string &tpid, const name owner, const uint64_t &amount) { - eosio_assert(has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || has_auth(FIOORACLEContract) || - has_auth(STAKINGACCOUNT) || has_auth("fio.reqobt"_n) || has_auth("eosio"_n) || has_auth(EscrowContract), - "missing required authority of fio.address, fio.treasury, fio.token, eosio or fio.reqobt or fio.staking"); + eosio_assert(has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) + || has_auth(FIOORACLEContract) || has_auth(STAKINGACCOUNT) || has_auth("fio.reqobt"_n) + || has_auth("eosio"_n) || has_auth(EscrowContract) || has_auth(PERMSACCOUNT), + "missing required authority of fio.address, fio.treasury, fio.token, eosio or fio.reqobt fio.perms or fio.staking"); if (debugout) { print("update tpid calling updatetpid with tpid ", tpid, " owner ", owner, "\n"); } diff --git a/contracts/fio.treasury/fio.treasury.cpp b/contracts/fio.treasury/fio.treasury.cpp index f549d8c0..13ca1e87 100644 --- a/contracts/fio.treasury/fio.treasury.cpp +++ b/contracts/fio.treasury/fio.treasury.cpp @@ -408,17 +408,20 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { // @abi action [[eosio::action]] void bppoolupdate(const uint64_t &amount) { - eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || - has_auth(REQOBTACCOUNT) || has_auth(FIOORACLEContract) || has_auth(EscrowContract)), - "missing required authority of eosio, fio.address, fio.treasury, fio.token, fio.oracle or fio.reqobt"); + eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(AddressContract) || has_auth(TokenContract) + || has_auth(TREASURYACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(FIOORACLEContract) + || has_auth(EscrowContract) || has_auth(PERMSACCOUNT)), + "missing required authority of eosio, fio.address, fio.treasury, fio.token, fio.oracle fio.perms or fio.reqobt"); bucketrewards.set(bucketrewards.exists() ? bucketpool{bucketrewards.get().rewards + amount} : bucketpool{amount}, get_self()); } // @abi action [[eosio::action]] void fdtnrwdupdat(const uint64_t &amount) { - eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(StakingContract) || has_auth(TREASURYACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract) || has_auth(FIOORACLEContract) || has_auth(EscrowContract)), - "missing required authority of fio.address, fio.token, fio.staking, fio.fee, fio.treasury, fio.oracle or fio.reqobt"); + eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(StakingContract) || has_auth(TREASURYACCOUNT) + || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract) || has_auth(FIOORACLEContract) + || has_auth(EscrowContract) || has_auth(PERMSACCOUNT)), + "missing required authority of fio.address, fio.token, fio.staking, fio.fee, fio.treasury, fio.oracle fio.perms or fio.reqobt"); fdtnrewards.set(fdtnrewards.exists() ? fdtnreward{fdtnrewards.get().rewards + amount} : fdtnreward{amount}, get_self()); }