diff --git a/include/atomicassets.hpp b/include/atomicassets.hpp index 188d9d5..0645564 100644 --- a/include/atomicassets.hpp +++ b/include/atomicassets.hpp @@ -11,6 +11,7 @@ using namespace atomicdata; static constexpr double MAX_MARKET_FEE = 0.15; +static constexpr uint32_t AUTHOR_SWAP_TIME_DELTA = 60 * 60 * 24 * 7; // 1 week, valid for 1 week CONTRACT atomicassets : public contract { @@ -78,6 +79,19 @@ CONTRACT atomicassets : public contract { name collection_name ); + ACTION createauswap( + name collection_name, + name new_author, + bool owner + ); + + ACTION acceptauswap( + name collection_name + ); + + ACTION rejectauswap( + name collection_name + ); ACTION createschema( name authorized_creator, @@ -254,6 +268,17 @@ CONTRACT atomicassets : public contract { private: + TABLE author_swaps_s { + name collection_name; + name current_author; + name new_author; + uint32_t acceptance_date; + + uint64_t primary_key() const { return collection_name.value; }; + }; + + typedef multi_index author_swaps_t; + TABLE collections_s { name collection_name; name author; @@ -363,7 +388,7 @@ CONTRACT atomicassets : public contract { // https://github.com/EOSIO/eosio.cdt/issues/280 typedef multi_index tokenconfigs_t_for_abi; - + author_swaps_t authorswaps = author_swaps_t(get_self(), get_self().value); collections_t collections = collections_t(get_self(), get_self().value); offers_t offers = offers_t(get_self(), get_self().value); balances_t balances = balances_t(get_self(), get_self().value); diff --git a/src/atomicassets.cpp b/src/atomicassets.cpp index 19514ba..8bc1aa5 100644 --- a/src/atomicassets.cpp +++ b/src/atomicassets.cpp @@ -327,6 +327,94 @@ ACTION atomicassets::forbidnotify( }); } +/** +* Creates a swap offer for a collection +* Acceptance functionality depends on the authorization being 'owner' or 'active' (7 days gate) +*/ + +ACTION atomicassets::createauswap( + name collection_name, + name new_author, + bool owner +) { + auto collection_itr = collections.require_find(collection_name.value, + "No collection with this name exists"); + + if (owner){ + require_auth(permission_level{collection_itr->author, name("owner")}); + } else { + require_auth(collection_itr->author); + } + + check(authorswaps.find(collection_name.value) == authorswaps.end(), + "Can't swap author's while an authorswap is underway for this collection"); + + authorswaps.emplace(collection_itr->author, [&](auto &_author_swaps) { + _author_swaps.collection_name = collection_name; + _author_swaps.current_author = collection_itr->author; + _author_swaps.new_author = new_author; + _author_swaps.acceptance_date = eosio::current_time_point().sec_since_epoch() + (owner ? 0 : AUTHOR_SWAP_TIME_DELTA); + }); +} + +/** +* Accepts an author swap, with time constraints based on 'owner' or 'active' permissions used when creating the author swap +* With default parameters, author swaps created by 'active' permissions can only be accepted after 1 week has passed +* With default parameters, author swaps remain valid for up to 3 weeks +*/ + +ACTION atomicassets::acceptauswap( + name collection_name +) { + auto collection_itr = collections.require_find(collection_name.value, + "No collection with this name exists"); + + auto author_swaps_itr = authorswaps.require_find(collection_name.value, + "No author swaps for this collection found"); + + // Just in case** + check(collection_itr->author == author_swaps_itr->current_author, + "Current author mismatch"); + + require_auth(author_swaps_itr->new_author); + + uint32_t now = eosio::current_time_point().sec_since_epoch(); + + check (now > author_swaps_itr->acceptance_date, + ("[ " + to_string(author_swaps_itr->acceptance_date - now) + " ] seconds remaining until this author swap can be accepted").c_str()); + + check (now < author_swaps_itr->acceptance_date + AUTHOR_SWAP_TIME_DELTA, "Author swap for this collection has expired"); + + collections.modify(collection_itr, author_swaps_itr->new_author, [&](auto &_collection){ + _collection.author = author_swaps_itr->new_author; + }); + + authorswaps.erase(author_swaps_itr); +} + +/** +* Rejects author swaps +* Can be used by either the current author or by the new author +*/ + +ACTION atomicassets::rejectauswap( + name collection_name +) { + auto collection_itr = collections.require_find(collection_name.value, + "No collection with this name exists"); + + auto author_swaps_itr = authorswaps.require_find(collection_name.value, + "No author swaps for this collection found"); + + // Just in case** + check(collection_itr->author == author_swaps_itr->current_author, + "Current author mismatch"); + + check(has_auth(author_swaps_itr->current_author) || has_auth(author_swaps_itr->new_author), + "Missing required authorizations"); + + authorswaps.erase(author_swaps_itr); +} /** * Creates a new schema