From afa247f7f7d9cda6b518b1714e8a13e45f4d520b Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 3 Feb 2023 11:21:16 -0700 Subject: [PATCH 1/2] FIPs36-40 make new dev branch in synch with develop FIPs36-40 make new dev branch in synch with develop --- contracts/fio.address/fio.address.abi | 96 +++-- contracts/fio.address/fio.address.cpp | 340 +++++++++++------- contracts/fio.address/fio.address.hpp | 25 ++ contracts/fio.common/fio.common.hpp | 20 +- .../include/fio.system/fio.system.hpp | 10 + .../fio.system/include/fio.system/native.hpp | 6 - contracts/fio.system/src/fio.system.cpp | 138 ++++++- .../fio.token/include/fio.token/fio.token.hpp | 18 +- contracts/fio.treasury/fio.treasury.cpp | 4 +- 9 files changed, 462 insertions(+), 195 deletions(-) diff --git a/contracts/fio.address/fio.address.abi b/contracts/fio.address/fio.address.abi index 558730b1..6cc948c4 100644 --- a/contracts/fio.address/fio.address.abi +++ b/contracts/fio.address/fio.address.abi @@ -44,6 +44,28 @@ } ] }, + { + "name": "fioname_info_item", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "fionameid", + "type": "uint64" + }, + { + "name": "datadesc", + "type": "string" + }, + { + "name": "datavalue", + "type": "string" + } + ] + }, { "name": "domain", "base": "", @@ -132,37 +154,32 @@ } ] }, - { - "name": "regdomadd", - "base": "", - "fields": [ - { - "name": "fio_address", - "type": "string" - }, - { - "name": "is_public", - "type": "int8" - }, - { - "name": "owner_fio_public_key", - "type": "string" - }, - { - "name": "max_fee", - "type": "int64" - }, - { - "name": "tpid", - "type": "string" - }, - { - "name": "actor", - "type": "name" - }, - - ] - }, + { + "name": "updcryptkey", + "base": "", + "fields": [ + { + "name": "fio_address", + "type": "string" + }, + { + "name": "encrypt_public_key", + "type": "string" + }, + { + "name": "max_fee", + "type": "int64" + }, + { + "name": "actor", + "type": "name" + }, + { + "name": "tpid", + "type": "string" + } + ] + }, { "name": "tokenpubaddr", "base": "", @@ -721,6 +738,11 @@ "type": "regaddress", "ricardian_contract": "" }, + { + "name": "updcryptkey", + "type": "updcryptkey", + "ricardian_contract": "" + }, { "name": "addaddress", "type": "addaddress", @@ -741,11 +763,6 @@ "type": "regdomain", "ricardian_contract": "" }, - { - "name": "regdomadd", - "type": "regdomadd", - "ricardian_contract": "" - }, { "name": "renewdomain", "type": "renewdomain", @@ -828,6 +845,13 @@ ], "type": "fioname" }, + { + "name": "fionameinfo", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "fioname_info_item" + }, { "name": "domains", "index_type": "i64", diff --git a/contracts/fio.address/fio.address.cpp b/contracts/fio.address/fio.address.cpp index e2d5b3ac..5d4e61cf 100644 --- a/contracts/fio.address/fio.address.cpp +++ b/contracts/fio.address/fio.address.cpp @@ -23,6 +23,9 @@ namespace fioio { domains_table domains; domainsales_table domainsales; fionames_table fionames; + //FIP-39 begin + fionameinfo_table fionameinfo; + //FIP-39 end fiofee_table fiofees; eosio_names_table accountmap; bundlevoters_table bundlevoters; @@ -42,6 +45,9 @@ namespace fioio { domains(_self, _self.value), domainsales(EscrowContract, EscrowContract.value), fionames(_self, _self.value), + //FIP-39 begin + fionameinfo(_self, _self.value), + //FIP-39 end fiofees(FeeContract, FeeContract.value), bundlevoters(FeeContract, FeeContract.value), accountmap(_self, _self.value), @@ -144,6 +150,66 @@ namespace fioio { } + // FIP-39 begin + inline void updfionminf(const string &datavalue, const string &datadesc, const uint64_t &fionameid, const name &actor) { + auto fionameinfobynameid = fionameinfo.get_index<"byfionameid"_n>(); + auto fionameinfo_iter = fionameinfobynameid.find(fionameid); + if(fionameinfo_iter == fionameinfobynameid.end()){ + uint64_t id = fionameinfo.available_primary_key(); + fionameinfo.emplace(actor, [&](struct fioname_info_item &d) { + d.id = id; + d.fionameid = fionameid; + d.datadesc = datadesc; + d.datavalue = datavalue; + }); + }else { + auto matchdesc_iter = fionameinfo_iter; + //now check for multiples of same desc, enforce no duplicate datadesc values permitted in table. + int countem = 0; + while (fionameinfo_iter != fionameinfobynameid.end()) { + if (fionameinfo_iter->datadesc.compare(datadesc) == 0) { + countem++; + matchdesc_iter = fionameinfo_iter; + } + fionameinfo_iter++; + } + + //this code if(countem == 0) is not tested by the existing contracts because we have only got one data description used by the contracts + // in the first delivery of the new table. + if(countem == 0){ + uint64_t id = fionameinfo.available_primary_key(); + fionameinfo.emplace(actor, [&](struct fioname_info_item &d) { + d.id = id; + d.fionameid = fionameid; + d.datadesc = datadesc; + d.datavalue = datavalue; + }); + } + else { + //we found one to get into this block so if more than one then error. + fio_400_assert(countem == 1, "datadesc", datadesc, + "handle info error -- multiple data values present for datadesc", + ErrorInvalidValue); + fionameinfobynameid.modify(matchdesc_iter, actor, [&](struct fioname_info_item &d) { + d.datavalue = datavalue; + }); + } + } + + } + + inline void remhandleinf(const uint64_t &fionameid) { + auto fionameinfobynameid = fionameinfo.get_index<"byfionameid"_n>(); + auto fionameinfo_iter = fionameinfobynameid.find(fionameid); + if(fionameinfo_iter != fionameinfobynameid.end()){ + auto next_iter = fionameinfo_iter; + next_iter++; + fionameinfobynameid.erase(fionameinfo_iter); + fionameinfo_iter = next_iter; + } + } + //FIP-39 end + inline void register_errors(const FioAddress &fa, bool domain) const { string fioname = "fio_address"; string fioerror = "Invalid FIO address"; @@ -229,6 +295,8 @@ namespace fioio { fio_400_assert(key_iter != accountmap.end(), "owner", to_string(owner.value), "Owner is not bound in the account map.", ErrorActorNotInFioAccountMap); + + uint64_t id = fionames.available_primary_key(); vector pubaddresses; tokenpubaddr t1; @@ -249,6 +317,11 @@ namespace fioio { a.bundleeligiblecountdown = getBundledAmount(); }); + //FIP-39 begin + //update the encryption key to use. + updfionminf(key_iter->clientkey, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,id,owner); + //FIP-39 end + uint64_t fee_amount = chain_data_update(fa.fioaddress, pubaddresses, max_fee, fa, actor, owner, true, tpid); @@ -386,8 +459,6 @@ namespace fioio { "Fee exceeds supplied maximum.", ErrorMaxFeeExceeded); - //NOTE -- question here, should we always record the transfer for the fees, even when its zero, - //or should we do as this code does and not do a transaction when the fees are 0. fio_fees(actor, asset(reg_amount, FIOSYMBOL), REMOVE_PUB_ADDRESS_ENDPOINT); process_rewards(tpid, reg_amount, get_self(), actor); @@ -488,8 +559,6 @@ namespace fioio { "Fee exceeds supplied maximum.", ErrorMaxFeeExceeded); - //NOTE -- question here, should we always record the transfer for the fees, even when its zero, - //or should we do as this code does and not do a transaction when the fees are 0. fio_fees(actor, asset(reg_amount, FIOSYMBOL), REMOVE_ALL_PUB_ENDPOINT); process_rewards(tpid, reg_amount, get_self(), actor); @@ -669,81 +738,135 @@ namespace fioio { /********* CONTRACT ACTIONS ********/ + //FIP-39 begin [[eosio::action]] void - regaddress(const string &fio_address, const string &owner_fio_public_key, const int64_t &max_fee, + updcryptkey(const string &fio_address, const string &encrypt_public_key, const int64_t &max_fee, const name &actor, const string &tpid) { + + print("updcryptkey -- called. \n"); + + //VERIFY INPUTS FioAddress fa; fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, "TPID must be empty or valid FIO address", ErrorPubKeyValid); + fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", ErrorMaxFeeInvalid); - if (owner_fio_public_key.length() > 0) { - fio_400_assert(isPubKeyValid(owner_fio_public_key), "owner_fio_public_key", owner_fio_public_key, - "Invalid FIO Public Key", + //requirement, allow empty string to be used! + if (encrypt_public_key.length() > 0) { + fio_400_assert(isPubKeyValid(encrypt_public_key), "encrypt_public_key", encrypt_public_key, + "Encrypt key not a valid FIO Public Key", ErrorPubKeyValid); } - name owner_account_name = accountmgnt(actor, owner_fio_public_key); - getFioAddressStruct(fio_address, fa); - register_errors(fa, false); - const name nm = name{owner_account_name}; + const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); + const uint128_t domainHash = string_to_uint128_hash(fa.fiodomain.c_str()); - const uint64_t expiration_time = fio_address_update(actor, nm, max_fee, fa, tpid); + fio_400_assert(!fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO address", + ErrorInvalidFioNameFormat); - struct tm timeinfo; - fioio::convertfiotime(expiration_time, &timeinfo); - std::string timebuffer = fioio::tmstringformat(timeinfo); + auto domainsbyname = domains.get_index<"byname"_n>(); + auto domains_iter = domainsbyname.find(domainHash); - const uint128_t endpoint_hash = string_to_uint128_hash(REGISTER_ADDRESS_ENDPOINT); + fio_400_assert(domains_iter != domainsbyname.end(), "fio_address", fa.fioaddress, + "FIO Domain not registered", + ErrorDomainNotRegistered); + + //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, "fio_address", fa.fioaddress, "FIO Domain expired", + ErrorDomainExpired); + + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO address not registered", ErrorFioNameNotRegistered); + fio_403_assert(fioname_iter->owner_account == actor.value, + ErrorSignature); // check if actor owns FIO Address + + + + + //FEE PROCESSING + uint64_t fee_amount = 0; + + //begin fees, bundle eligible fee logic + const uint128_t endpoint_hash = string_to_uint128_hash(UPDATE_ENCRYPT_KEY_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", REGISTER_ADDRESS_ENDPOINT, + + //if the fee isnt found for the endpoint, then 400 error. + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UPDATE_ENCRYPT_KEY_ENDPOINT, "FIO fee not found for endpoint", ErrorNoEndpoint); - const uint64_t reg_amount = fee_iter->suf_amount; + const int64_t reg_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 register_fio_address, expected 0", + fio_400_assert(fee_type == 1, "fee_type", to_string(fee_type), + "update_encrypt_key unexpected fee type for endpoint update_encrypt_key, expected 1", ErrorNoEndpoint); - fio_400_assert(max_fee >= (int64_t) reg_amount, "max_fee", to_string(max_fee), - "Fee exceeds supplied maximum.", - ErrorMaxFeeExceeded); + const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; - fio_fees(actor, asset(reg_amount, FIOSYMBOL), REGISTER_ADDRESS_ENDPOINT); - processbucketrewards(tpid, reg_amount, get_self(), actor); + if (bundleeligiblecountdown > 0) { + namesbyname.modify(fioname_iter, _self, [&](struct fioname &a) { + a.bundleeligiblecountdown = (bundleeligiblecountdown - 1); + }); + } else { + fee_amount = fee_iter->suf_amount; + fio_400_assert(max_fee >= (int64_t) fee_amount, "max_fee", to_string(max_fee), + "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); - if (REGADDRESSRAM > 0) { + fio_fees(actor, asset(reg_amount, FIOSYMBOL), UPDATE_ENCRYPT_KEY_ENDPOINT); + process_rewards(tpid, reg_amount, get_self(), actor); + + if (reg_amount > 0) { + INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) + ("eosio"_n, {{_self, "active"_n}}, + {actor, true} + ); + } + } + + if (UPDENCRYPTKEYRAM > 0) { action( permission_level{SYSTEMACCOUNT, "active"_n}, "eosio"_n, "incram"_n, - std::make_tuple(actor, REGADDRESSRAM) + std::make_tuple(actor, UPDENCRYPTKEYRAM) ).send(); } + updfionminf(encrypt_public_key, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,fioname_iter->id,actor); - const string response_string = string("{\"status\": \"OK\",\"expiration\":\"") + - timebuffer + string("\",\"fee_collected\":") + + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UPDATE_ENCRYPT_KEY_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + to_string(reg_amount) + string("}"); - fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), - "Transaction is too large", ErrorTransactionTooLarge); - send_response(response_string.c_str()); + } + //FIP-39 end [[eosio::action]] - void regdomain(const string &fio_domain, const string &owner_fio_public_key, - const int64_t &max_fee, const name &actor, const string &tpid) { + void + regaddress(const string &fio_address, const string &owner_fio_public_key, const int64_t &max_fee, + const name &actor, + const string &tpid) { + + FioAddress fa; fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, "TPID must be empty or valid FIO address", ErrorPubKeyValid); @@ -758,180 +881,123 @@ namespace fioio { name owner_account_name = accountmgnt(actor, owner_fio_public_key); - FioAddress fa; - getFioAddressStruct(fio_domain, fa); - register_errors(fa, true); + getFioAddressStruct(fio_address, fa); + register_errors(fa, false); const name nm = name{owner_account_name}; - const uint32_t expiration_time = fio_domain_update(nm, fa, actor); + const uint64_t expiration_time = fio_address_update(actor, nm, max_fee, fa, tpid); struct tm timeinfo; fioio::convertfiotime(expiration_time, &timeinfo); std::string timebuffer = fioio::tmstringformat(timeinfo); - const uint128_t endpoint_hash = string_to_uint128_hash(REGISTER_DOMAIN_ENDPOINT); + const uint128_t endpoint_hash = string_to_uint128_hash(REGISTER_ADDRESS_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", REGISTER_DOMAIN_ENDPOINT, + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", REGISTER_ADDRESS_ENDPOINT, "FIO fee not found for endpoint", ErrorNoEndpoint); const uint64_t reg_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 register_fio_domain, expected 0", + "unexpected fee type for endpoint register_fio_address, expected 0", ErrorNoEndpoint); fio_400_assert(max_fee >= (int64_t) reg_amount, "max_fee", to_string(max_fee), "Fee exceeds supplied maximum.", ErrorMaxFeeExceeded); - fio_fees(actor, asset(reg_amount, FIOSYMBOL), REGISTER_DOMAIN_ENDPOINT); + fio_fees(actor, asset(reg_amount, FIOSYMBOL), REGISTER_ADDRESS_ENDPOINT); processbucketrewards(tpid, reg_amount, get_self(), actor); - const string response_string = string("{\"status\": \"OK\",\"expiration\":\"") + - timebuffer + string("\",\"fee_collected\":") + - to_string(reg_amount) + string("}"); - - if (REGDOMAINRAM > 0) { + if (REGADDRESSRAM > 0) { action( permission_level{SYSTEMACCOUNT, "active"_n}, "eosio"_n, "incram"_n, - std::make_tuple(actor, REGDOMAINRAM) + std::make_tuple(actor, REGADDRESSRAM) ).send(); } + + const string response_string = string("{\"status\": \"OK\",\"expiration\":\"") + + timebuffer + string("\",\"fee_collected\":") + + to_string(reg_amount) + string("}"); + fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), "Transaction is too large", ErrorTransactionTooLarge); send_response(response_string.c_str()); } - - /*********** - * This action will register a fio domain and fio handle on the domain. T - * @param fio_address this is the fio address that will be registered to the domain. Domain must not already be registered. - * @param is_public 0 - the domain will be private; 1 - the new domain will be public - * @param owner_fio_public_key this is the public key that will own the registered fio address and fio domain - * @param max_fee this is the maximum fee that is willing to be paid for this transaction on the blockchain. - * @param tpid this is the fio address of the owner of the domain. - * @param actor this is the fio account that has sent this transaction. - */ [[eosio::action]] - void - regdomadd(const string &fio_address, const uint8_t &is_public, const string &owner_fio_public_key, const int64_t &max_fee, const string &tpid, const name &actor) - { - - FioAddress fa; + void regdomain(const string &fio_domain, const string &owner_fio_public_key, + const int64_t &max_fee, const name &actor, const string &tpid) { fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, "TPID must be empty or valid FIO address", ErrorPubKeyValid); fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", ErrorMaxFeeInvalid); - - fio_400_assert((is_public == 1 || is_public == 0), "is_public", to_string(is_public), "Only 0 or 1 allowed", - ErrorMaxFeeInvalid); - if (owner_fio_public_key.length() > 0) { fio_400_assert(isPubKeyValid(owner_fio_public_key), "owner_fio_public_key", owner_fio_public_key, - "Invalid FIO Public Key format", + "Invalid FIO Public Key", ErrorPubKeyValid); } - - name owner_account_name = accountmgnt(actor, owner_fio_public_key); - - getFioAddressStruct(fio_address, fa); - - fio_400_assert(validateFioNameFormat(fa), "fio_address", fa.fioaddress, "Invalid FIO Address format", ErrorInvalidFioNameFormat); - 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(), "fio_name", fa.fioaddress, - "Domain already registered, use regaddress instead.", ErrorDomainAlreadyRegistered); - - uint32_t domain_expiration = get_now_plus_one_year(); - domains.emplace(actor, [&](struct domain &d) { - d.id = domains.available_primary_key();; - d.name = fa.fiodomain; - d.domainhash = domainHash; - d.expiration = domain_expiration; - d.account = owner_account_name.value; - d.is_public = is_public; - }); + name owner_account_name = accountmgnt(actor, owner_fio_public_key); - auto key_iter = accountmap.find(owner_account_name.value); + FioAddress fa; + getFioAddressStruct(fio_domain, fa); + register_errors(fa, true); + const name nm = name{owner_account_name}; - fio_400_assert(key_iter != accountmap.end(), "owner", to_string(owner_account_name.value), - "Owner is not bound in the account map.", ErrorActorNotInFioAccountMap); + const uint32_t expiration_time = fio_domain_update(nm, fa, actor); - vector pubaddresses; - tokenpubaddr t1; - t1.public_address = key_iter->clientkey; - t1.token_code = "FIO"; - t1.chain_code = "FIO"; - pubaddresses.push_back(t1); + struct tm timeinfo; + fioio::convertfiotime(expiration_time, &timeinfo); + std::string timebuffer = fioio::tmstringformat(timeinfo); - fionames.emplace(actor, [&](struct fioname &a) { - a.id = fionames.available_primary_key();; - a.name = fa.fioaddress; - a.addresses = pubaddresses; - a.namehash = string_to_uint128_hash(fa.fioaddress.c_str());; - a.domain = fa.fiodomain; - a.domainhash = domainHash; - a.expiration = 4294967295; //Sunday, February 7, 2106 6:28:15 AM GMT+0000 (Max 32 bit expiration) - a.owner_account = owner_account_name.value; - a.bundleeligiblecountdown = getBundledAmount(); - }); - - const uint128_t endpoint_hash = string_to_uint128_hash(REGISTER_FIO_DOMAIN_ADDRESS_ENDPOINT); + const uint128_t endpoint_hash = string_to_uint128_hash(REGISTER_DOMAIN_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", REGISTER_FIO_DOMAIN_ADDRESS_ENDPOINT, + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", REGISTER_DOMAIN_ENDPOINT, "FIO fee not found for endpoint", ErrorNoEndpoint); const uint64_t reg_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 register_fio_address, expected 0", + "unexpected fee type for endpoint register_fio_domain, expected 0", ErrorNoEndpoint); fio_400_assert(max_fee >= (int64_t) reg_amount, "max_fee", to_string(max_fee), "Fee exceeds supplied maximum.", ErrorMaxFeeExceeded); - fio_fees(actor, asset(reg_amount, FIOSYMBOL), REGISTER_FIO_DOMAIN_ADDRESS_ENDPOINT); + fio_fees(actor, asset(reg_amount, FIOSYMBOL), REGISTER_DOMAIN_ENDPOINT); processbucketrewards(tpid, reg_amount, get_self(), actor); - if (REGDOMADDRAM > 0) { + const string response_string = string("{\"status\": \"OK\",\"expiration\":\"") + + timebuffer + string("\",\"fee_collected\":") + + to_string(reg_amount) + string("}"); + + if (REGDOMAINRAM > 0) { action( permission_level{SYSTEMACCOUNT, "active"_n}, "eosio"_n, "incram"_n, - std::make_tuple(actor, REGDOMADDRAM) + std::make_tuple(actor, REGDOMAINRAM) ).send(); } - - struct tm timeinfo; - fioio::convertfiotime(domain_expiration, &timeinfo); - std::string timebuffer = fioio::tmstringformat(timeinfo); - - const string response_string = string("{\"status\": \"OK\",\"expiration\":\"") + - timebuffer + string("\",\"fee_collected\":") + - to_string(reg_amount) + string("}"); fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), "Transaction is too large", ErrorTransactionTooLarge); - send_response(response_string.c_str()); - + send_response(response_string.c_str()); } /*********** @@ -2023,6 +2089,11 @@ namespace fioio { a.addresses = pubaddresses; }); + //FIP-39 begin + //update the encryption key to use. + updfionminf(new_owner_fio_public_key, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,fioname_iter->id,nm); + //FIP-39 end + // Burn the NFTs belonging to the FIO address that was just transferred auto contractsbyname = nftstable.get_index<"byaddress"_n>(); @@ -2106,6 +2177,10 @@ namespace fioio { //do the burn const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + //FIP-39 begin + //remove the associated handle information. + remhandleinf(fioname_iter->id); + //FIP-39 end namesbyname.erase(fioname_iter); if (tpid_iter != tpid_by_name.end()) { tpid_by_name.erase(tpid_iter); } @@ -2358,7 +2433,8 @@ namespace fioio { }; - EOSIO_DISPATCH(FioNameLookup, (regaddress)(addaddress)(remaddress)(remalladdr)(regdomain)(renewdomain)(renewaddress) - (setdomainpub)(burnexpired)(decrcounter)(bind2eosio)(burnaddress)(xferdomain)(xferaddress)(addbundles)(xferescrow) - (addnft)(remnft)(remallnfts)(burnnfts)(regdomadd)) + EOSIO_DISPATCH(FioNameLookup, (regaddress)(addaddress)(remaddress)(remalladdr)(regdomain)(renewdomain)(renewaddress)( + setdomainpub)(burnexpired)(decrcounter)(updcryptkey) + (bind2eosio)(burnaddress)(xferdomain)(xferaddress)(addbundles)(xferescrow)(addnft)(remnft)(remallnfts) + (burnnfts)) } diff --git a/contracts/fio.address/fio.address.hpp b/contracts/fio.address/fio.address.hpp index c02d4d6f..4ba9f163 100644 --- a/contracts/fio.address/fio.address.hpp +++ b/contracts/fio.address/fio.address.hpp @@ -19,6 +19,31 @@ namespace fioio { using namespace eosio; + //FIP-39 begin + struct [[eosio::action]] fioname_info_item { + + uint64_t id = 0; + uint64_t fionameid = 0; + string datadesc = ""; + string datavalue = ""; + + + // primary_key is required to store structure in multi_index table + uint64_t primary_key() const { return id; } + uint64_t by_fionameid() const { return fionameid; } + + EOSLIB_SERIALIZE(fioname_info_item, (id)(fionameid)(datadesc)(datavalue)) + }; + //this state table contains string formatted intfo associated with a fio name/fio handle/ fio address + //todo --describe the process of adding new entries into this table here!! + typedef multi_index<"fionameinfo"_n, fioname_info_item, + indexed_by<"byfionameid"_n, const_mem_fun < fioname_info_item, uint64_t, &fioname_info_item::by_fionameid>> + > + fionameinfo_table; + + //FIP-39 end + + struct tokenpubaddr { string token_code; string chain_code; diff --git a/contracts/fio.common/fio.common.hpp b/contracts/fio.common/fio.common.hpp index 461f94c3..eef12ec4 100644 --- a/contracts/fio.common/fio.common.hpp +++ b/contracts/fio.common/fio.common.hpp @@ -53,6 +53,9 @@ #define TRANSFER_DOMAIN_ENDPOINT "transfer_fio_domain" #define REMOVE_ALL_PUB_ENDPOINT "remove_all_pub_addresses" #define REMOVE_PUB_ADDRESS_ENDPOINT "remove_pub_address" +//FIP-39 begin +#define UPDATE_ENCRYPT_KEY_ENDPOINT "update_encrypt_key" +//FIP-39 end #define REGISTER_PRODUCER_ENDPOINT "register_producer" #define ADD_PUB_ADDRESS_ENDPOINT "add_pub_address" #define UNREGISTER_PRODUCER_ENDPOINT "unregister_producer" @@ -77,14 +80,19 @@ #define ADD_NFT_ENDPOINT "add_nft" #define REM_NFT_ENDPOINT "remove_nft" #define REM_ALL_NFTS_ENDPOINT "remove_all_nfts" +//FIP-38 begin +#define NEW_FIO_CHAIN_ACCOUNT_ENDPOINT "new_fio_chain_account" +//FIP-38 end +//FIP-39 begin +//the following section contains the set of data descriptions used in the fionameinfo table. +#define FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC "FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY" +//FIP-39 end #define LIST_DOMAIN_ENDPOINT "list_domain" #define CANCEL_LIST_DOMAIN_ENDPOINT "cancel_list_domain" #define BUY_DOMAIN_ENDPOINT "buy_domain" #define SET_MARKETPLACE_CONFIG_ENDPOINT "set_marketplace_config" -#define REGISTER_FIO_DOMAIN_ADDRESS_ENDPOINT "register_fio_domain_address" - namespace fioio { using namespace eosio; @@ -483,8 +491,10 @@ namespace fioio { static const uint64_t STAKEFIOTOKENSRAM = 512; //integrated. static const uint64_t UNSTAKEFIOTOKENSRAM = 512; //integrated. static const uint64_t REGDOMAINRAM = 2560; //integrated. + //FIP-39 begin + static const uint64_t UPDENCRYPTKEYRAM = 2560; + //FIP-39 end static const uint64_t REGADDRESSRAM = 2560; //integrated. - static const uint64_t REGDOMADDRAM = 5120; static const uint64_t ADDADDRESSRAM = 512; //integrated. static const uint64_t SETDOMAINPUBRAM = 256; //integrated. static const uint64_t NEWFUNDSREQUESTRAM = 3120; //integrated. @@ -504,7 +514,9 @@ namespace fioio { static const uint64_t LISTDOMAINRAM = 1536; // FIOESCROW - List Domain 1140 bytes round to 512 x 3 static const uint64_t BASECONTENTAMOUNT = 1000; // base amount for content on newfundsreq and obt transactions - + //FIP-38 begin + static const uint64_t NEWFIOCHAINACCOUNTRAM = 0; + //FIP-38 end } // namespace fioio diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 0d1114d6..84cb195f 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -438,6 +438,13 @@ class [[eosio::contract("fio.system")]] system_contract : public native { [[eosio::action]] void setpriv(const name &account,const uint8_t &is_priv); + //FIP-38 begin + [[eosio::action]] + void newfioacc(const string &fio_public_key, const authority &owner, const authority &active, const int64_t &max_fee, + const name &actor, + const string &tpid); + //FIP-38 end + [[eosio::action]] void rmvproducer(const name &producer); @@ -457,6 +464,9 @@ class [[eosio::contract("fio.system")]] system_contract : public native { using rmvproducer_action = eosio::action_wrapper<"rmvproducer"_n, &system_contract::rmvproducer>; using updtrevision_action = eosio::action_wrapper<"updtrevision"_n, &system_contract::updtrevision>; using setpriv_action = eosio::action_wrapper<"setpriv"_n, &system_contract::setpriv>; + //FIP-38 begin + using newfioacc_action = eosio::action_wrapper<"newfioacc"_n, &system_contract::newfioacc>; + //FIP-38 end using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; private: diff --git a/contracts/fio.system/include/fio.system/native.hpp b/contracts/fio.system/include/fio.system/native.hpp index b5b782ea..c0d97810 100755 --- a/contracts/fio.system/include/fio.system/native.hpp +++ b/contracts/fio.system/include/fio.system/native.hpp @@ -163,12 +163,6 @@ namespace eosiosystem { }.send(); } - if (permission == fioio::ACTIVE || permission == fioio::OWNER){ - eosio_assert((auth.keys.size() == 0) || (auth.keys.size() == 1), - "update auth not permitted on owner or active unless keys is empty or has a single entry matching the account public key"); - //todo add code to check that if there is a single auth key, the key matches the value in the account map. - } - fio_400_assert(auth.waits.size() == 0, "authorization_waits", "authorization_waits", "Waits not supported", ErrorNoAuthWaits); diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 119d8652..92187be9 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -13,6 +13,7 @@ #include "delegate_bandwidth.cpp" #include "voting.cpp" #include +#include #include namespace eosiosystem { @@ -101,6 +102,131 @@ namespace eosiosystem { _gstate2.revision = revision; } + + //FIP-38 begin + + + + + + + + + + void eosiosystem::system_contract::newfioacc(const string &fio_public_key, const authority &owner, const authority &active, const int64_t &max_fee, + const name &actor, + const string &tpid) { + + + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, + "TPID must be empty or valid FIO address", + ErrorPubKeyValid); + fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", + ErrorMaxFeeInvalid); + + if (fio_public_key.length() > 0) { + fio_400_assert(isPubKeyValid(fio_public_key), "fio_public_key", fio_public_key, + "Invalid FIO Public Key format", + ErrorPubKeyValid); + } + + string owner_account; + key_to_account(fio_public_key, owner_account); + name owner_account_name = name(owner_account.c_str()); + + eosio_assert(owner_account.length() == 12, "Length of account name should be 12"); + + //account should NOT exist, and should NOT be in the FIO account map + const bool accountExists = is_account(owner_account_name); + auto other = _accountmap.find(owner_account_name.value); + + fio_400_assert(!accountExists, "fio_public_key", fio_public_key, + "Invalid public key used, Account already exists on FIO chain", + ErrorPubAddressExist); + + if (other == _accountmap.end()) { //the name is not in the table. go forth and create the account + + const auto owner_pubkey = abieos::string_to_public_key(fio_public_key); + + eosiosystem::key_weight pubkey_weight = { + .key = owner_pubkey, + .weight = 1, + }; + + authority owner_auth = owner; + if (owner.accounts.size() == 0) { + owner_auth = authority{1, {pubkey_weight}, {}, {}}; + } + + authority active_auth = active; + if (active.accounts.size() == 0) { + active_auth = authority{1, {pubkey_weight}, {}, {}}; + } + + action(permission_level{SYSTEMACCOUNT, "active"_n}, + SYSTEMACCOUNT, "newaccount"_n, + make_tuple(_self, owner_account_name, owner_auth,active_auth) + ).send(); + + action{ + permission_level{_self, "active"_n}, + AddressContract, + "bind2eosio"_n, + bind2eosio{ + .accountName = owner_account_name, + .public_key = fio_public_key, + .existing = accountExists + } + }.send(); + + } else { + fio_400_assert(accountExists, "fio_public_key", fio_public_key, + "Account does not exist on FIO chain but is bound in accountmap", + ErrorPubAddressExist); + } + + + const uint128_t endpoint_hash = string_to_uint128_hash(NEW_FIO_CHAIN_ACCOUNT_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", NEW_FIO_CHAIN_ACCOUNT_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const uint64_t reg_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 new_fio_chain_account, expected 0", + ErrorNoEndpoint); + + fio_400_assert(max_fee >= (int64_t) reg_amount, "max_fee", to_string(max_fee), + "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(reg_amount, FIOSYMBOL), NEW_FIO_CHAIN_ACCOUNT_ENDPOINT); + processbucketrewards(tpid, reg_amount, get_self(), actor); + + if (NEWFIOCHAINACCOUNTRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, NEWFIOCHAINACCOUNTRAM) + ).send(); + } + const string response_string = string("{\"status\": \"OK\",\"account\":\"") + + owner_account + string("\",\"fee_collected\":") + + to_string(reg_amount) + string("}"); + + + fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), + "Transaction is too large", ErrorTransactionTooLarge); + + send_response(response_string.c_str()); + } + //FIP-38 end + /** * Called after a new account is created. This code enforces resource-limits rules * for new accounts as well as new account naming conventions. @@ -240,16 +366,6 @@ namespace eosiosystem { check(is_account(owner),"account must pre exist"); check(amount > 0,"cannot add locked token amount less or equal 0."); - //BD-4082 begin - - auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); - auto lockiter = locks_by_owner.find(owner.value); - check(lockiter == locks_by_owner.end(),"cannot emplace locks when locks pre-exist."); - - - //BD-4082 end - - _generallockedtokens.emplace(owner, [&](struct locked_tokens_info_v2 &a) { a.id = _generallockedtokens.available_primary_key(); a.owner_account = owner; @@ -333,7 +449,7 @@ EOSIO_DISPATCH( eosiosystem::system_contract, (newaccount)(addaction)(remaction)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)(setabi) // fio.system.cpp (init)(setnolimits)(addlocked)(addgenlocked)(modgenlocked)(clrgenlocked)(setparams)(setpriv) - (rmvproducer)(updtrevision) + (rmvproducer)(updtrevision)(newfioacc) // delegate_bandwidth.cpp (updatepower) // voting.cpp diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index 700271a5..4f455a9f 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -15,6 +15,15 @@ #include #include +//FIP-38 begin +struct bind2eosio { + name accountName; + string public_key; + bool existing; +}; +//FIP-38 end + + namespace eosiosystem { class system_contract; } @@ -36,6 +45,8 @@ namespace eosio { fioio::account_staking_table accountstaking; public: + + token(name s, name code, datastream ds) : contract(s, code, ds), eosionames(fioio::AddressContract, fioio::AddressContract.value), @@ -50,6 +61,7 @@ namespace eosio { appConfig = configsSingleton.get_or_default(fioio::config()); } + [[eosio::action]] void create(asset maximum_supply); @@ -151,11 +163,7 @@ namespace eosio { string memo; }; - struct bind2eosio { - name accountName; - string public_key; - bool existing; - }; + //This action will compute the number of unlocked tokens contained within an account. // This considers diff --git a/contracts/fio.treasury/fio.treasury.cpp b/contracts/fio.treasury/fio.treasury.cpp index b7e91236..107ed4dd 100644 --- a/contracts/fio.treasury/fio.treasury.cpp +++ b/contracts/fio.treasury/fio.treasury.cpp @@ -408,9 +408,11 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { // @abi action [[eosio::action]] void bppoolupdate(const uint64_t &amount) { - eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || + //FIP-38 begin + 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 fio.address, fio.treasury, fio.token, fio.oracle or fio.reqobt"); + //FIP-38 end bucketrewards.set(bucketrewards.exists() ? bucketpool{bucketrewards.get().rewards + amount} : bucketpool{amount}, get_self()); } From 83ffe2d14bd0c65d1820757fff8073d00bdb46c8 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 3 Feb 2023 11:49:53 -0700 Subject: [PATCH 2/2] try o get PR cleaned up try to get pr cleaned up --- contracts/fio.address/fio.address.cpp | 470 +++++++++++++++++--------- 1 file changed, 308 insertions(+), 162 deletions(-) diff --git a/contracts/fio.address/fio.address.cpp b/contracts/fio.address/fio.address.cpp index 5d4e61cf..a48e8a7d 100644 --- a/contracts/fio.address/fio.address.cpp +++ b/contracts/fio.address/fio.address.cpp @@ -23,9 +23,6 @@ namespace fioio { domains_table domains; domainsales_table domainsales; fionames_table fionames; - //FIP-39 begin - fionameinfo_table fionameinfo; - //FIP-39 end fiofee_table fiofees; eosio_names_table accountmap; bundlevoters_table bundlevoters; @@ -37,6 +34,10 @@ namespace fioio { eosiosystem::locked_tokens_table lockedTokensTable; nfts_table nftstable; config appConfig; + + //FIP-39 begin + fionameinfo_table fionameinfo; + //FIP-39 end public: using contract::contract; @@ -45,9 +46,6 @@ namespace fioio { domains(_self, _self.value), domainsales(EscrowContract, EscrowContract.value), fionames(_self, _self.value), - //FIP-39 begin - fionameinfo(_self, _self.value), - //FIP-39 end fiofees(FeeContract, FeeContract.value), bundlevoters(FeeContract, FeeContract.value), accountmap(_self, _self.value), @@ -58,7 +56,10 @@ namespace fioio { topprods(SYSTEMACCOUNT, SYSTEMACCOUNT.value), producers(SYSTEMACCOUNT, SYSTEMACCOUNT.value), lockedTokensTable(SYSTEMACCOUNT, - SYSTEMACCOUNT.value) { + SYSTEMACCOUNT.value), + //FIP-39 begin + fionameinfo(_self, _self.value), + //FIP-39 end{ configs_singleton configsSingleton(FeeContract, FeeContract.value); appConfig = configsSingleton.get_or_default(config()); } @@ -150,65 +151,71 @@ namespace fioio { } - // FIP-39 begin - inline void updfionminf(const string &datavalue, const string &datadesc, const uint64_t &fionameid, const name &actor) { - auto fionameinfobynameid = fionameinfo.get_index<"byfionameid"_n>(); - auto fionameinfo_iter = fionameinfobynameid.find(fionameid); - if(fionameinfo_iter == fionameinfobynameid.end()){ - uint64_t id = fionameinfo.available_primary_key(); - fionameinfo.emplace(actor, [&](struct fioname_info_item &d) { - d.id = id; - d.fionameid = fionameid; - d.datadesc = datadesc; - d.datavalue = datavalue; - }); - }else { - auto matchdesc_iter = fionameinfo_iter; - //now check for multiples of same desc, enforce no duplicate datadesc values permitted in table. - int countem = 0; - while (fionameinfo_iter != fionameinfobynameid.end()) { - if (fionameinfo_iter->datadesc.compare(datadesc) == 0) { - countem++; - matchdesc_iter = fionameinfo_iter; - } - fionameinfo_iter++; - } - //this code if(countem == 0) is not tested by the existing contracts because we have only got one data description used by the contracts - // in the first delivery of the new table. - if(countem == 0){ - uint64_t id = fionameinfo.available_primary_key(); - fionameinfo.emplace(actor, [&](struct fioname_info_item &d) { - d.id = id; - d.fionameid = fionameid; - d.datadesc = datadesc; - d.datavalue = datavalue; - }); - } - else { - //we found one to get into this block so if more than one then error. - fio_400_assert(countem == 1, "datadesc", datadesc, - "handle info error -- multiple data values present for datadesc", - ErrorInvalidValue); - fionameinfobynameid.modify(matchdesc_iter, actor, [&](struct fioname_info_item &d) { - d.datavalue = datavalue; - }); - } - } +// FIP-39 begin +inline void updfionminf(const string &datavalue, const string &datadesc, const uint64_t &fionameid, const name &actor) { + auto fionameinfobynameid = fionameinfo.get_index<"byfionameid"_n>(); + auto fionameinfo_iter = fionameinfobynameid.find(fionameid); + if(fionameinfo_iter == fionameinfobynameid.end()){ + uint64_t id = fionameinfo.available_primary_key(); + fionameinfo.emplace(actor, [&](struct fioname_info_item &d) { + d.id = id; + d.fionameid = fionameid; + d.datadesc = datadesc; + d.datavalue = datavalue; + }); + }else { + auto matchdesc_iter = fionameinfo_iter; + //now check for multiples of same desc, enforce no duplicate datadesc values permitted in table. + int countem = 0; + while (fionameinfo_iter != fionameinfobynameid.end()) { + if (fionameinfo_iter->datadesc.compare(datadesc) == 0) { + countem++; + matchdesc_iter = fionameinfo_iter; + } + fionameinfo_iter++; } - inline void remhandleinf(const uint64_t &fionameid) { - auto fionameinfobynameid = fionameinfo.get_index<"byfionameid"_n>(); - auto fionameinfo_iter = fionameinfobynameid.find(fionameid); - if(fionameinfo_iter != fionameinfobynameid.end()){ - auto next_iter = fionameinfo_iter; - next_iter++; - fionameinfobynameid.erase(fionameinfo_iter); - fionameinfo_iter = next_iter; - } + //this code if(countem == 0) is not tested by the existing contracts because we have only got one data description used by the contracts + // in the first delivery of the new table. + if(countem == 0){ + uint64_t id = fionameinfo.available_primary_key(); + fionameinfo.emplace(actor, [&](struct fioname_info_item &d) { + d.id = id; + d.fionameid = fionameid; + d.datadesc = datadesc; + d.datavalue = datavalue; + }); } - //FIP-39 end + else { + //we found one to get into this block so if more than one then error. + fio_400_assert(countem == 1, "datadesc", datadesc, + "handle info error -- multiple data values present for datadesc", + ErrorInvalidValue); + fionameinfobynameid.modify(matchdesc_iter, actor, [&](struct fioname_info_item &d) { + d.datavalue = datavalue; + }); + } + } + +} + +inline void remhandleinf(const uint64_t &fionameid) { + auto fionameinfobynameid = fionameinfo.get_index<"byfionameid"_n>(); + auto fionameinfo_iter = fionameinfobynameid.find(fionameid); + if(fionameinfo_iter != fionameinfobynameid.end()){ + auto next_iter = fionameinfo_iter; + next_iter++; + fionameinfobynameid.erase(fionameinfo_iter); + fionameinfo_iter = next_iter; + } +} +//FIP-39 end + + + + inline void register_errors(const FioAddress &fa, bool domain) const { string fioname = "fio_address"; @@ -295,8 +302,6 @@ namespace fioio { fio_400_assert(key_iter != accountmap.end(), "owner", to_string(owner.value), "Owner is not bound in the account map.", ErrorActorNotInFioAccountMap); - - uint64_t id = fionames.available_primary_key(); vector pubaddresses; tokenpubaddr t1; @@ -321,7 +326,8 @@ namespace fioio { //update the encryption key to use. updfionminf(key_iter->clientkey, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,id,owner); //FIP-39 end - + + uint64_t fee_amount = chain_data_update(fa.fioaddress, pubaddresses, max_fee, fa, actor, owner, true, tpid); @@ -459,6 +465,8 @@ namespace fioio { "Fee exceeds supplied maximum.", ErrorMaxFeeExceeded); + //NOTE -- question here, should we always record the transfer for the fees, even when its zero, + //or should we do as this code does and not do a transaction when the fees are 0. fio_fees(actor, asset(reg_amount, FIOSYMBOL), REMOVE_PUB_ADDRESS_ENDPOINT); process_rewards(tpid, reg_amount, get_self(), actor); @@ -559,6 +567,8 @@ namespace fioio { "Fee exceeds supplied maximum.", ErrorMaxFeeExceeded); + //NOTE -- question here, should we always record the transfer for the fees, even when its zero, + //or should we do as this code does and not do a transaction when the fees are 0. fio_fees(actor, asset(reg_amount, FIOSYMBOL), REMOVE_ALL_PUB_ENDPOINT); process_rewards(tpid, reg_amount, get_self(), actor); @@ -738,127 +748,134 @@ namespace fioio { /********* CONTRACT ACTIONS ********/ - //FIP-39 begin - [[eosio::action]] - void - updcryptkey(const string &fio_address, const string &encrypt_public_key, const int64_t &max_fee, - const name &actor, - const string &tpid) { +//FIP-39 begin +[[eosio::action]] +void +updcryptkey(const string &fio_address, const string &encrypt_public_key, const int64_t &max_fee, + const name &actor, + const string &tpid) { - print("updcryptkey -- called. \n"); + print("updcryptkey -- called. \n"); - //VERIFY INPUTS - FioAddress fa; - fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, - "TPID must be empty or valid FIO address", - ErrorPubKeyValid); + //VERIFY INPUTS + FioAddress fa; + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, + "TPID must be empty or valid FIO address", + ErrorPubKeyValid); - fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", - ErrorMaxFeeInvalid); + fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", + ErrorMaxFeeInvalid); - //requirement, allow empty string to be used! - if (encrypt_public_key.length() > 0) { - fio_400_assert(isPubKeyValid(encrypt_public_key), "encrypt_public_key", encrypt_public_key, - "Encrypt key not a valid FIO Public Key", - ErrorPubKeyValid); - } + //requirement, allow empty string to be used! + if (encrypt_public_key.length() > 0) { + fio_400_assert(isPubKeyValid(encrypt_public_key), "encrypt_public_key", encrypt_public_key, + "Encrypt key not a valid FIO Public Key", + ErrorPubKeyValid); + } - getFioAddressStruct(fio_address, fa); - const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); - const uint128_t domainHash = string_to_uint128_hash(fa.fiodomain.c_str()); + getFioAddressStruct(fio_address, fa); + const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); + const uint128_t domainHash = string_to_uint128_hash(fa.fiodomain.c_str()); - fio_400_assert(!fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO address", - ErrorInvalidFioNameFormat); + fio_400_assert(!fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO address", + ErrorInvalidFioNameFormat); - auto domainsbyname = domains.get_index<"byname"_n>(); - auto domains_iter = domainsbyname.find(domainHash); + auto domainsbyname = domains.get_index<"byname"_n>(); + auto domains_iter = domainsbyname.find(domainHash); - fio_400_assert(domains_iter != domainsbyname.end(), "fio_address", fa.fioaddress, - "FIO Domain not registered", - ErrorDomainNotRegistered); + fio_400_assert(domains_iter != domainsbyname.end(), "fio_address", fa.fioaddress, + "FIO Domain not registered", + ErrorDomainNotRegistered); - //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); + //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, "fio_address", fa.fioaddress, "FIO Domain expired", - ErrorDomainExpired); + const uint32_t present_time = now(); + fio_400_assert(present_time <= domain_expiration, "fio_address", fa.fioaddress, "FIO Domain expired", + ErrorDomainExpired); - auto namesbyname = fionames.get_index<"byname"_n>(); - auto fioname_iter = namesbyname.find(nameHash); - fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, - "FIO address not registered", ErrorFioNameNotRegistered); - fio_403_assert(fioname_iter->owner_account == actor.value, - ErrorSignature); // check if actor owns FIO Address + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO address not registered", ErrorFioNameNotRegistered); + fio_403_assert(fioname_iter->owner_account == actor.value, + ErrorSignature); // check if actor owns FIO Address - //FEE PROCESSING - uint64_t fee_amount = 0; + //FEE PROCESSING + uint64_t fee_amount = 0; - //begin fees, bundle eligible fee logic - const uint128_t endpoint_hash = string_to_uint128_hash(UPDATE_ENCRYPT_KEY_ENDPOINT); + //begin fees, bundle eligible fee logic + const uint128_t endpoint_hash = string_to_uint128_hash(UPDATE_ENCRYPT_KEY_ENDPOINT); - auto fees_by_endpoint = fiofees.get_index<"byendpoint"_n>(); - auto fee_iter = fees_by_endpoint.find(endpoint_hash); + auto fees_by_endpoint = fiofees.get_index<"byendpoint"_n>(); + auto fee_iter = fees_by_endpoint.find(endpoint_hash); - //if the fee isnt found for the endpoint, then 400 error. - fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UPDATE_ENCRYPT_KEY_ENDPOINT, - "FIO fee not found for endpoint", ErrorNoEndpoint); + //if the fee isnt found for the endpoint, then 400 error. + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UPDATE_ENCRYPT_KEY_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); - const int64_t reg_amount = fee_iter->suf_amount; - const uint64_t fee_type = fee_iter->type; + const int64_t reg_amount = fee_iter->suf_amount; + const uint64_t fee_type = fee_iter->type; - fio_400_assert(fee_type == 1, "fee_type", to_string(fee_type), - "update_encrypt_key unexpected fee type for endpoint update_encrypt_key, expected 1", - ErrorNoEndpoint); + fio_400_assert(fee_type == 1, "fee_type", to_string(fee_type), + "update_encrypt_key unexpected fee type for endpoint update_encrypt_key, expected 1", + ErrorNoEndpoint); - const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; - if (bundleeligiblecountdown > 0) { - namesbyname.modify(fioname_iter, _self, [&](struct fioname &a) { - a.bundleeligiblecountdown = (bundleeligiblecountdown - 1); - }); - } else { - fee_amount = fee_iter->suf_amount; - fio_400_assert(max_fee >= (int64_t) fee_amount, "max_fee", to_string(max_fee), - "Fee exceeds supplied maximum.", - ErrorMaxFeeExceeded); + if (bundleeligiblecountdown > 0) { + namesbyname.modify(fioname_iter, _self, [&](struct fioname &a) { + a.bundleeligiblecountdown = (bundleeligiblecountdown - 1); + }); + } else { + fee_amount = fee_iter->suf_amount; + fio_400_assert(max_fee >= (int64_t) fee_amount, "max_fee", to_string(max_fee), + "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(reg_amount, FIOSYMBOL), UPDATE_ENCRYPT_KEY_ENDPOINT); + process_rewards(tpid, reg_amount, get_self(), actor); + + if (reg_amount > 0) { + INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) + ("eosio"_n, {{_self, "active"_n}}, + {actor, true} + ); + } + } + + if (UPDENCRYPTKEYRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, UPDENCRYPTKEYRAM) + ).send(); + } + + updfionminf(encrypt_public_key, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,fioname_iter->id,actor); + + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UPDATE_ENCRYPT_KEY_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + + to_string(reg_amount) + string("}"); + + send_response(response_string.c_str()); + +} +//FIP-39 end - fio_fees(actor, asset(reg_amount, FIOSYMBOL), UPDATE_ENCRYPT_KEY_ENDPOINT); - process_rewards(tpid, reg_amount, get_self(), actor); - if (reg_amount > 0) { - INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) - ("eosio"_n, {{_self, "active"_n}}, - {actor, true} - ); - } - } - if (UPDENCRYPTKEYRAM > 0) { - action( - permission_level{SYSTEMACCOUNT, "active"_n}, - "eosio"_n, - "incram"_n, - std::make_tuple(actor, UPDENCRYPTKEYRAM) - ).send(); - } - updfionminf(encrypt_public_key, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,fioname_iter->id,actor); - fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UPDATE_ENCRYPT_KEY_ENDPOINT, - "FIO fee not found for endpoint", ErrorNoEndpoint); - - const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + - to_string(reg_amount) + string("}"); - send_response(response_string.c_str()); - } - //FIP-39 end [[eosio::action]] void @@ -1000,6 +1017,131 @@ namespace fioio { send_response(response_string.c_str()); } + + /*********** + * This action will register a fio domain and fio handle on the domain. T + * @param fio_address this is the fio address that will be registered to the domain. Domain must not already be registered. + * @param is_public 0 - the domain will be private; 1 - the new domain will be public + * @param owner_fio_public_key this is the public key that will own the registered fio address and fio domain + * @param max_fee this is the maximum fee that is willing to be paid for this transaction on the blockchain. + * @param tpid this is the fio address of the owner of the domain. + * @param actor this is the fio account that has sent this transaction. + */ + [[eosio::action]] + void + regdomadd(const string &fio_address, const uint8_t &is_public, const string &owner_fio_public_key, const int64_t &max_fee, const string &tpid, const name &actor) + { + + FioAddress fa; + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid, + "TPID must be empty or valid FIO address", + ErrorPubKeyValid); + fio_400_assert(max_fee >= 0, "max_fee", to_string(max_fee), "Invalid fee value", + ErrorMaxFeeInvalid); + + + fio_400_assert((is_public == 1 || is_public == 0), "is_public", to_string(is_public), "Only 0 or 1 allowed", + ErrorMaxFeeInvalid); + + if (owner_fio_public_key.length() > 0) { + fio_400_assert(isPubKeyValid(owner_fio_public_key), "owner_fio_public_key", owner_fio_public_key, + "Invalid FIO Public Key format", + ErrorPubKeyValid); + } + + name owner_account_name = accountmgnt(actor, owner_fio_public_key); + + getFioAddressStruct(fio_address, fa); + + fio_400_assert(validateFioNameFormat(fa), "fio_address", fa.fioaddress, "Invalid FIO Address format", ErrorInvalidFioNameFormat); + + 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(), "fio_name", fa.fioaddress, + "Domain already registered, use regaddress instead.", ErrorDomainAlreadyRegistered); + + uint32_t domain_expiration = get_now_plus_one_year(); + domains.emplace(actor, [&](struct domain &d) { + d.id = domains.available_primary_key();; + d.name = fa.fiodomain; + d.domainhash = domainHash; + d.expiration = domain_expiration; + d.account = owner_account_name.value; + d.is_public = is_public; + }); + + auto key_iter = accountmap.find(owner_account_name.value); + + fio_400_assert(key_iter != accountmap.end(), "owner", to_string(owner_account_name.value), + "Owner is not bound in the account map.", ErrorActorNotInFioAccountMap); + + vector pubaddresses; + tokenpubaddr t1; + t1.public_address = key_iter->clientkey; + t1.token_code = "FIO"; + t1.chain_code = "FIO"; + pubaddresses.push_back(t1); + + fionames.emplace(actor, [&](struct fioname &a) { + a.id = fionames.available_primary_key();; + a.name = fa.fioaddress; + a.addresses = pubaddresses; + a.namehash = string_to_uint128_hash(fa.fioaddress.c_str());; + a.domain = fa.fiodomain; + a.domainhash = domainHash; + a.expiration = 4294967295; //Sunday, February 7, 2106 6:28:15 AM GMT+0000 (Max 32 bit expiration) + a.owner_account = owner_account_name.value; + a.bundleeligiblecountdown = getBundledAmount(); + }); + + const uint128_t endpoint_hash = string_to_uint128_hash(REGISTER_FIO_DOMAIN_ADDRESS_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", REGISTER_FIO_DOMAIN_ADDRESS_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const uint64_t reg_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 register_fio_address, expected 0", + ErrorNoEndpoint); + + fio_400_assert(max_fee >= (int64_t) reg_amount, "max_fee", to_string(max_fee), + "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(reg_amount, FIOSYMBOL), REGISTER_FIO_DOMAIN_ADDRESS_ENDPOINT); + processbucketrewards(tpid, reg_amount, get_self(), actor); + + if (REGDOMADDRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, REGDOMADDRAM) + ).send(); + } + + struct tm timeinfo; + fioio::convertfiotime(domain_expiration, &timeinfo); + std::string timebuffer = fioio::tmstringformat(timeinfo); + + const string response_string = string("{\"status\": \"OK\",\"expiration\":\"") + + timebuffer + string("\",\"fee_collected\":") + + to_string(reg_amount) + string("}"); + + fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), + "Transaction is too large", ErrorTransactionTooLarge); + + send_response(response_string.c_str()); + + } + /*********** * This action will renew a fio domain, the domains expiration time will be extended by one year. * @param fio_domain this is the fio domain to be renewed. @@ -2093,7 +2235,8 @@ namespace fioio { //update the encryption key to use. updfionminf(new_owner_fio_public_key, FIO_REQUEST_CONTENT_ENCRYPTION_PUB_KEY_DATA_DESC,fioname_iter->id,nm); //FIP-39 end - + + // Burn the NFTs belonging to the FIO address that was just transferred auto contractsbyname = nftstable.get_index<"byaddress"_n>(); @@ -2177,13 +2320,16 @@ namespace fioio { //do the burn const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + namesbyname.erase(fioname_iter); + if (tpid_iter != tpid_by_name.end()) { tpid_by_name.erase(tpid_iter); } + + //FIP-39 begin //remove the associated handle information. remhandleinf(fioname_iter->id); //FIP-39 end - namesbyname.erase(fioname_iter); - if (tpid_iter != tpid_by_name.end()) { tpid_by_name.erase(tpid_iter); } - + + //// NEW inline function call //// addburnq(fio_address, nameHash); @@ -2434,7 +2580,7 @@ namespace fioio { }; EOSIO_DISPATCH(FioNameLookup, (regaddress)(addaddress)(remaddress)(remalladdr)(regdomain)(renewdomain)(renewaddress)( - setdomainpub)(burnexpired)(decrcounter)(updcryptkey) - (bind2eosio)(burnaddress)(xferdomain)(xferaddress)(addbundles)(xferescrow)(addnft)(remnft)(remallnfts) - (burnnfts)) + setdomainpub)(burnexpired)(decrcounter)(updcryptkey) + (bind2eosio)(burnaddress)(xferdomain)(xferaddress)(addbundles)(xferescrow)(addnft)(remnft)(remallnfts) +(burnnfts)) }