diff --git a/fio.contracts/contracts/fio.address/fio.address.abi b/fio.contracts/contracts/fio.address/fio.address.abi index 823cf83f4d..032ce1d3f6 100644 --- a/fio.contracts/contracts/fio.address/fio.address.abi +++ b/fio.contracts/contracts/fio.address/fio.address.abi @@ -226,7 +226,26 @@ "name": "existing", "type": "bool" }] - } + },{ + "name": "xferdomain", + "base": "", + "fields": [{ + "name": "fio_domain", + "type": "string" + },{ + "name": "new_owner_fio_public_key", + "type": "string" + },{ + "name": "max_fee", + "type": "int64" + },{ + "name": "tpid", + "type": "string" + },{ + "name": "actor", + "type": "name" + }] + } ], "actions": [{ "name": "regaddress", @@ -260,6 +279,10 @@ "name": "bind2eosio", "type": "bind2eosio", "ricardian_contract": "" + },{ + "name": "xferdomain", + "type": "xferdomain", + "ricardian_contract": "" } ], "tables": [{ diff --git a/fio.contracts/contracts/fio.address/fio.address.cpp b/fio.contracts/contracts/fio.address/fio.address.cpp index ab08249e75..a6208a8ef3 100644 --- a/fio.contracts/contracts/fio.address/fio.address.cpp +++ b/fio.contracts/contracts/fio.address/fio.address.cpp @@ -471,7 +471,7 @@ namespace fioio { 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); @@ -923,9 +923,6 @@ namespace fioio { send_response(response_string.c_str()); } //addaddress - - - [[eosio::action]] void setdomainpub(const string &fio_domain, const int8_t is_public, const int64_t &max_fee, const name &actor, @@ -1048,6 +1045,79 @@ namespace fioio { } } + [[eosio::action]] + void xferdomain(const string &fio_domain, const string &new_owner_fio_public_key, const int64_t &max_fee, + const string &tpid, const name &actor) { + require_auth(actor); + + fio_400_assert(isPubKeyValid(new_owner_fio_public_key), "new_owner_fio_public_key", new_owner_fio_public_key, + "Invalid FIO Public Key", ErrorChainAddressEmpty); + 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); + + auto domainsbyname = domains.get_index<"byname"_n>(); + auto domains_iter = domainsbyname.find(string_to_uint128_hash(fio_domain)); + fio_400_assert(domains_iter != domainsbyname.end(), "fio_domain", fio_domain, + "FIO Domain not registered", ErrorDomainNotRegistered); + + const uint32_t domain_expiration = domains_iter->expiration; + const uint32_t present_time = now(); + fio_400_assert(present_time <= domain_expiration, "fio_domain", fio_domain, "FIO Domain expired. Renew first.", + ErrorDomainExpired); + + fio_403_assert(domains_iter->account == actor.value, ErrorSignature); + require_auth(domains_iter->account); + const uint128_t endpoint_hash = string_to_uint128_hash("transfer_fio_domain"); + + 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", "transfer_fio_domain", + "FIO fee not found for endpoint", ErrorNoEndpoint); + + //Transfer the domain + string owner_account; + key_to_account(new_owner_fio_public_key, owner_account); + const name nm = name{owner_account}; + domainsbyname.modify(domains_iter, actor, [&](struct domain &a) { + a.account = nm.value; + }); + + //fees + 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), + "register_fio_address unexpected fee type for endpoint register_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)); + processbucketrewards(tpid, fee_amount, get_self()); + + if (XFERDOMAINRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, XFERDOMAINRAM) + ).send(); + } + + const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + + to_string(fee_amount) + string("}"); + + fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), + "Transaction is too large", ErrorTransaction); + + send_response(response_string.c_str()); + } + void decrcounter(const string &fio_address, const int32_t step) { check(step > 0, "step must be greater than 0"); @@ -1070,5 +1140,5 @@ namespace fioio { }; EOSIO_DISPATCH(FioNameLookup, (regaddress)(addaddress)(regdomain)(renewdomain)(renewaddress)(setdomainpub)(burnexpired)(decrcounter) - (bind2eosio)) + (bind2eosio) (xferdomain)) } diff --git a/fio.contracts/contracts/fio.common/fio.common.hpp b/fio.contracts/contracts/fio.common/fio.common.hpp index ab02ed6d88..418ea55d10 100644 --- a/fio.contracts/contracts/fio.common/fio.common.hpp +++ b/fio.contracts/contracts/fio.common/fio.common.hpp @@ -364,6 +364,7 @@ namespace fioio { static const uint64_t RECORDOBTRAM = 2048; //integrated. static const uint64_t RENEWADDRESSRAM = 1024; //integrated. static const uint64_t RENEWDOMAINRAM = 1024; //integrated. + static const uint64_t XFERDOMAINRAM = 1024; //integrated. static const uint64_t TRANSFERPUBKEYRAM = 1024; //integrated. static const uint64_t REJECTFUNDSRAM = 512; //integrated. static const uint64_t SETFEEVOTERAM = 0; //integrated. diff --git a/fio.contracts/contracts/fio.common/fioerror.hpp b/fio.contracts/contracts/fio.common/fioerror.hpp index bd813fae46..96d7852d1c 100644 --- a/fio.contracts/contracts/fio.common/fioerror.hpp +++ b/fio.contracts/contracts/fio.common/fioerror.hpp @@ -85,7 +85,9 @@ namespace fioio { constexpr auto ErrorClientKeyNotFound = ident | httpDataError | 149; // Fioname not yet registered (No clientkey) constexpr auto ErrorTimeViolation = ident | httpDataError | 150; constexpr auto ErrorNoAuthWaits = ident | httpDataError | 151; + constexpr auto ErrorDomainOwner = ident | httpInvalidError | 153; constexpr auto ErrorTransactionTooLarge = ident | httpDataError | 152; // Transaction too large + /** * Helper funtions for detecting rich error messages and extracting bitfielded values */ diff --git a/libraries/chain/include/eosio/chain/fioio/actionmapping.hpp b/libraries/chain/include/eosio/chain/fioio/actionmapping.hpp index e9a17707b9..41ed4de6fd 100644 --- a/libraries/chain/include/eosio/chain/fioio/actionmapping.hpp +++ b/libraries/chain/include/eosio/chain/fioio/actionmapping.hpp @@ -24,7 +24,7 @@ namespace fioio { if (action == "regaddress" || action == "regdomain" || action == "addaddress" || action == "renewdomain" || action == "renewaddress" || action == "setdomainpub" || action == "bind2eosio" || - action == "burnexpired" || action == "decrcounter" ) + action == "burnexpired" || action == "decrcounter" || action == "xferdomain" ) return "fio.address"; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 82d15a6e86..a1b6010565 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -3643,6 +3643,54 @@ if( options.count(name) ) { \ } CATCH_AND_CALL(next); } + void read_write::transfer_fio_domain(const read_write::transfer_fio_domain_params ¶ms, + next_function next) { + try { + FIO_403_ASSERT(params.size() == 4, + fioio::ErrorTransaction); // variant object contains authorization, account, name, data + auto pretty_input = std::make_shared(); + auto resolver = make_resolver(this, abi_serializer_max_time); + transaction_metadata_ptr ptrx; + dlog("transfer_fio_domain called"); + try { + abi_serializer::from_variant(params, *pretty_input, resolver, abi_serializer_max_time); + ptrx = std::make_shared(pretty_input); + } EOS_RETHROW_EXCEPTIONS(chain::fio_invalid_trans_exception, "Invalid transaction") + + transaction trx = pretty_input->get_transaction(); + vector &actions = trx.actions; + dlog("\n"); + dlog(actions[0].name.to_string()); + FIO_403_ASSERT(trx.total_actions() == 1, fioio::InvalidAccountOrAction); + FIO_403_ASSERT(actions[0].authorization.size() > 0, fioio::ErrorTransaction); + FIO_403_ASSERT(actions[0].account.to_string() == "fio.address", fioio::InvalidAccountOrAction); + FIO_403_ASSERT(actions[0].name.to_string() == "xferdomain", fioio::InvalidAccountOrAction); + + app().get_method()(ptrx, true, [this, next]( + const fc::static_variant &result) -> void { + if (result.contains()) { + next(result.get()); + } else { + auto trx_trace_ptr = result.get(); + + try { + fc::variant output; + try { + output = db.to_variant_with_abi(*trx_trace_ptr, abi_serializer_max_time); + } catch (chain::abi_exception &) { + output = *trx_trace_ptr; + } + const chain::transaction_id_type &id = trx_trace_ptr->id; + next(read_write::transfer_fio_domain_results{id, output}); + } CATCH_AND_CALL(next); + } + }); + + } catch (boost::interprocess::bad_alloc &) { + chain_plugin::handle_db_exhaustion(); + } CATCH_AND_CALL(next); + } + /*** * unregister_proxy - This enpoint will set the specified fio address account to no longer be a proxy. * @param p Accepts a variant object of from a pushed fio transaction that contains a public key in packed actions diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index e8d7d75add..0c922de5aa 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -923,6 +923,15 @@ namespace eosio { //end renew_address + //begin transfer_fio_domain + using transfer_fio_domain_params = fc::variant_object; + struct transfer_fio_domain_results { + chain::transaction_id_type transaction_id; + fc::variant processed; + }; + + void transfer_fio_domain(const transfer_fio_domain_params ¶ms, + chain::plugin_interface::next_function next); //begin burn_expired using burn_expired_params = fc::variant_object; @@ -1306,6 +1315,7 @@ FC_REFLECT(eosio::chain_apis::read_only::avail_check_result, (is_registered)); FC_REFLECT(eosio::chain_apis::read_only::fio_key_lookup_params, (key)(chain)) FC_REFLECT(eosio::chain_apis::read_only::fio_key_lookup_result, (name)(expiration)); FC_REFLECT(eosio::chain_apis::read_write::register_fio_address_results, (transaction_id)(processed)); +FC_REFLECT(eosio::chain_apis::read_write::transfer_fio_domain_results, (transaction_id)(processed)); FC_REFLECT(eosio::chain_apis::read_write::set_fio_domain_public_results, (transaction_id)(processed)); FC_REFLECT(eosio::chain_apis::read_write::register_fio_domain_results, (transaction_id)(processed)); FC_REFLECT(eosio::chain_apis::read_write::reject_funds_request_results, (transaction_id)(processed));