Add or revive a few NFT-listing APIs
This commit is contained in:
parent
6037e89df0
commit
ca69a692cc
6 changed files with 384 additions and 104 deletions
|
|
@ -269,8 +269,9 @@ public:
|
||||||
uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const;
|
uint64_t nft_get_total_supply(const nft_metadata_id_type nft_metadata_id) const;
|
||||||
nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const;
|
nft_object nft_token_by_index(const nft_metadata_id_type nft_metadata_id, const uint64_t token_idx) const;
|
||||||
nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const;
|
nft_object nft_token_of_owner_by_index(const nft_metadata_id_type nft_metadata_id, const account_id_type owner, const uint64_t token_idx) const;
|
||||||
vector<nft_object> nft_get_all_tokens() const;
|
vector<nft_object> nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const;
|
||||||
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner) const;
|
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const;
|
||||||
|
vector<nft_metadata_object> nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
// Marketplace
|
// Marketplace
|
||||||
vector<offer_object> list_offers(const offer_id_type lower_id, uint32_t limit) const;
|
vector<offer_object> list_offers(const offer_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
@ -291,6 +292,7 @@ public:
|
||||||
uint32_t api_limit_get_limit_orders_by_account = 101;
|
uint32_t api_limit_get_limit_orders_by_account = 101;
|
||||||
uint32_t api_limit_get_order_book = 50;
|
uint32_t api_limit_get_order_book = 50;
|
||||||
uint32_t api_limit_all_offers_count = 100;
|
uint32_t api_limit_all_offers_count = 100;
|
||||||
|
uint32_t api_limit_nft_tokens = 100;
|
||||||
uint32_t api_limit_lookup_accounts = 1000;
|
uint32_t api_limit_lookup_accounts = 1000;
|
||||||
uint32_t api_limit_lookup_witness_accounts = 1000;
|
uint32_t api_limit_lookup_witness_accounts = 1000;
|
||||||
uint32_t api_limit_lookup_committee_member_accounts = 1000;
|
uint32_t api_limit_lookup_committee_member_accounts = 1000;
|
||||||
|
|
@ -3102,30 +3104,61 @@ nft_object database_api_impl::nft_token_of_owner_by_index(const nft_metadata_id_
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api::nft_get_all_tokens() const {
|
vector<nft_object> database_api::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const {
|
||||||
return my->nft_get_all_tokens();
|
return my->nft_get_all_tokens(lower_id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api_impl::nft_get_all_tokens() const {
|
vector<nft_object> database_api_impl::nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const {
|
||||||
|
FC_ASSERT(limit <= api_limit_nft_tokens,
|
||||||
|
"Number of queried nft tokens can not be greater than ${configured_limit}",
|
||||||
|
("configured_limit", api_limit_nft_tokens));
|
||||||
|
|
||||||
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
|
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_id>();
|
||||||
vector<nft_object> result;
|
vector<nft_object> result;
|
||||||
for (auto itr = idx_nft.begin(); itr != idx_nft.end(); ++itr) {
|
result.reserve(limit);
|
||||||
result.push_back(*itr);
|
auto itr = idx_nft.lower_bound(lower_id);
|
||||||
}
|
while (limit-- && itr != idx_nft.end())
|
||||||
|
result.emplace_back(*itr++);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api::nft_get_tokens_by_owner(const account_id_type owner) const {
|
vector<nft_object> database_api::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const {
|
||||||
return my->nft_get_tokens_by_owner(owner);
|
return my->nft_get_tokens_by_owner(owner, lower_id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> database_api_impl::nft_get_tokens_by_owner(const account_id_type owner) const {
|
vector<nft_object> database_api_impl::nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const {
|
||||||
|
FC_ASSERT(limit <= api_limit_nft_tokens,
|
||||||
|
"Number of queried nft tokens can not be greater than ${configured_limit}",
|
||||||
|
("configured_limit", api_limit_nft_tokens));
|
||||||
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
|
const auto &idx_nft = _db.get_index_type<nft_index>().indices().get<by_owner>();
|
||||||
auto idx_nft_range = idx_nft.equal_range(owner);
|
auto idx_nft_range = idx_nft.equal_range(owner);
|
||||||
vector<nft_object> result;
|
vector<nft_object> result;
|
||||||
for (auto itr = idx_nft_range.first; itr != idx_nft_range.second; ++itr) {
|
result.reserve(limit);
|
||||||
result.push_back(*itr);
|
auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_object &obj) {
|
||||||
}
|
return !(obj.id.instance() < lower_id.instance);
|
||||||
|
});
|
||||||
|
while (limit-- && itr != idx_nft_range.second)
|
||||||
|
result.emplace_back(*itr++);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<nft_metadata_object> database_api::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const {
|
||||||
|
return my->nft_get_metadata_by_owner(owner, lower_id, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<nft_metadata_object> database_api_impl::nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const {
|
||||||
|
FC_ASSERT(limit <= api_limit_nft_tokens,
|
||||||
|
"Number of queried nft metadata objects can not be greater than ${configured_limit}",
|
||||||
|
("configured_limit", api_limit_nft_tokens));
|
||||||
|
const auto &idx_nft = _db.get_index_type<nft_metadata_index>().indices().get<by_owner>();
|
||||||
|
auto idx_nft_range = idx_nft.equal_range(owner);
|
||||||
|
vector<nft_metadata_object> result;
|
||||||
|
result.reserve(limit);
|
||||||
|
auto itr = std::find_if(idx_nft_range.first, idx_nft_range.second, [&lower_id](const nft_metadata_object &obj) {
|
||||||
|
return !(obj.id.instance() < lower_id.instance);
|
||||||
|
});
|
||||||
|
while (limit-- && itr != idx_nft_range.second)
|
||||||
|
result.emplace_back(*itr++);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1027,14 +1027,25 @@ public:
|
||||||
* @brief Returns list of all available NTF's
|
* @brief Returns list of all available NTF's
|
||||||
* @return List of all available NFT's
|
* @return List of all available NFT's
|
||||||
*/
|
*/
|
||||||
vector<nft_object> nft_get_all_tokens() const;
|
vector<nft_object> nft_get_all_tokens(const nft_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns NFT's owned by owner
|
* @brief Returns NFT's owned by owner
|
||||||
* @param owner NFT owner
|
* @param owner NFT owner
|
||||||
|
* @param lower_id ID of the first NFT to return
|
||||||
|
* @param limit Maximum number of results to return
|
||||||
* @return List of NFT owned by owner
|
* @return List of NFT owned by owner
|
||||||
*/
|
*/
|
||||||
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner) const;
|
vector<nft_object> nft_get_tokens_by_owner(const account_id_type owner, const nft_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns NFT metadata owned by owner
|
||||||
|
* @param owner NFT owner
|
||||||
|
* @param lower_id ID of the first NFT metadata to return
|
||||||
|
* @param limit Maximum number of results to return
|
||||||
|
* @return List of NFT owned by owner
|
||||||
|
*/
|
||||||
|
vector<nft_metadata_object> nft_get_metadata_by_owner(const account_id_type owner, const nft_metadata_id_type lower_id, uint32_t limit) const;
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
// MARKET PLACE //
|
// MARKET PLACE //
|
||||||
|
|
@ -1249,6 +1260,7 @@ FC_API(graphene::app::database_api,
|
||||||
(nft_token_of_owner_by_index)
|
(nft_token_of_owner_by_index)
|
||||||
(nft_get_all_tokens)
|
(nft_get_all_tokens)
|
||||||
(nft_get_tokens_by_owner)
|
(nft_get_tokens_by_owner)
|
||||||
|
(nft_get_metadata_by_owner)
|
||||||
|
|
||||||
// Marketplace
|
// Marketplace
|
||||||
(list_offers)
|
(list_offers)
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,9 @@ namespace graphene { namespace chain {
|
||||||
std::greater< uint32_t >,
|
std::greater< uint32_t >,
|
||||||
std::greater< object_id_type >
|
std::greater< object_id_type >
|
||||||
>
|
>
|
||||||
|
>,
|
||||||
|
ordered_non_unique< tag<by_owner>,
|
||||||
|
member<nft_metadata_object, account_id_type, &nft_metadata_object::owner>
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
|
|
|
||||||
|
|
@ -2571,9 +2571,29 @@ class wallet_api
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns all tokens
|
* @brief Returns all tokens
|
||||||
|
* @param limit the maximum number of NFT objects to return (max: 100)
|
||||||
|
* @param lower_id ID of the first NFT object to include in the list.
|
||||||
* @return Returns vector of NFT objects, empty vector if none
|
* @return Returns vector of NFT objects, empty vector if none
|
||||||
*/
|
*/
|
||||||
vector<nft_object> nft_get_all_tokens() const;
|
vector<nft_object> nft_get_all_tokens(uint32_t limit, optional<nft_id_type> lower_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns all tokens owned by owner
|
||||||
|
* @param owner NFT owner account ID
|
||||||
|
* @param limit the maximum number of NFT objects to return (max: 100)
|
||||||
|
* @param lower_id ID of the first NFT object to include in the list.
|
||||||
|
* @return Returns vector of NFT objects, empty vector if none
|
||||||
|
*/
|
||||||
|
vector<nft_object> nft_get_tokens_by_owner(account_id_type owner, uint32_t limit, optional<nft_id_type> lower_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns all NFT metadata objects owned by owner
|
||||||
|
* @param owner NFT owner account ID
|
||||||
|
* @param limit the maximum number of NFT metadata objects to return (max: 100)
|
||||||
|
* @param lower_id ID of the first NFT metadata object to include in the list.
|
||||||
|
* @return Returns vector of NFT metadata objects, empty vector if none
|
||||||
|
*/
|
||||||
|
vector<nft_metadata_object> nft_get_metadata_by_owner(account_id_type owner, uint32_t limit, optional<nft_metadata_id_type> lower_id) const;
|
||||||
signed_transaction nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast );
|
signed_transaction nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast );
|
||||||
|
|
||||||
signed_transaction create_offer(set<nft_id_type> item_ids,
|
signed_transaction create_offer(set<nft_id_type> item_ids,
|
||||||
|
|
@ -2943,6 +2963,8 @@ FC_API( graphene::wallet::wallet_api,
|
||||||
(nft_get_approved)
|
(nft_get_approved)
|
||||||
(nft_is_approved_for_all)
|
(nft_is_approved_for_all)
|
||||||
(nft_get_all_tokens)
|
(nft_get_all_tokens)
|
||||||
|
(nft_get_tokens_by_owner)
|
||||||
|
(nft_get_metadata_by_owner)
|
||||||
(nft_lottery_buy_ticket)
|
(nft_lottery_buy_ticket)
|
||||||
(create_offer)
|
(create_offer)
|
||||||
(create_bid)
|
(create_bid)
|
||||||
|
|
|
||||||
|
|
@ -7027,9 +7027,28 @@ bool wallet_api::nft_is_approved_for_all(string owner_account_id_or_name, string
|
||||||
return my->_remote_db->nft_is_approved_for_all(owner_account.id, operator_account.id);
|
return my->_remote_db->nft_is_approved_for_all(owner_account.id, operator_account.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<nft_object> wallet_api::nft_get_all_tokens() const
|
vector<nft_object> wallet_api::nft_get_all_tokens(uint32_t limit, optional<nft_id_type> lower_id) const
|
||||||
{
|
{
|
||||||
return my->_remote_db->nft_get_all_tokens();
|
nft_id_type lb_id;
|
||||||
|
if(lower_id)
|
||||||
|
lb_id = *lower_id;
|
||||||
|
return my->_remote_db->nft_get_all_tokens(lb_id, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<nft_object> wallet_api::nft_get_tokens_by_owner(account_id_type owner, uint32_t limit, optional<nft_id_type> lower_id) const
|
||||||
|
{
|
||||||
|
nft_id_type lb_id;
|
||||||
|
if(lower_id)
|
||||||
|
lb_id = *lower_id;
|
||||||
|
return my->_remote_db->nft_get_tokens_by_owner(owner, lb_id, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<nft_metadata_object> wallet_api::nft_get_metadata_by_owner(account_id_type owner, uint32_t limit, optional<nft_metadata_id_type> lower_id) const
|
||||||
|
{
|
||||||
|
nft_metadata_id_type lb_id;
|
||||||
|
if(lower_id)
|
||||||
|
lb_id = *lower_id;
|
||||||
|
return my->_remote_db->nft_get_metadata_by_owner(owner, lb_id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
signed_transaction wallet_api::nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast )
|
signed_transaction wallet_api::nft_lottery_buy_ticket( nft_metadata_id_type lottery, account_id_type buyer, uint64_t tickets_to_buy, bool broadcast )
|
||||||
|
|
|
||||||
|
|
@ -4,76 +4,204 @@
|
||||||
|
|
||||||
#include <graphene/chain/hardfork.hpp>
|
#include <graphene/chain/hardfork.hpp>
|
||||||
#include <graphene/chain/nft_object.hpp>
|
#include <graphene/chain/nft_object.hpp>
|
||||||
|
#include <graphene/app/database_api.hpp>
|
||||||
|
|
||||||
|
|
||||||
using namespace graphene::chain;
|
using namespace graphene::chain;
|
||||||
using namespace graphene::chain::test;
|
using namespace graphene::chain::test;
|
||||||
|
|
||||||
|
|
||||||
|
class nft_test_helper
|
||||||
|
{
|
||||||
|
database_fixture& fixture_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
nft_test_helper(database_fixture& fixture):
|
||||||
|
fixture_(fixture)
|
||||||
|
{
|
||||||
|
fixture_.generate_blocks(HARDFORK_NFT_TIME);
|
||||||
|
fixture_.generate_block();
|
||||||
|
fixture_.generate_block();
|
||||||
|
set_expiration(fixture_.db, fixture_.trx);
|
||||||
|
}
|
||||||
|
|
||||||
|
nft_metadata_object create_metadata(const std::string& name, const std::string& symbol, const std::string& uri, const account_id_type& owner, const fc::ecc::private_key &priv_key)
|
||||||
|
{
|
||||||
|
const auto& idx_by_id = fixture_.db.get_index_type<nft_metadata_index>().indices().get<by_id>();
|
||||||
|
size_t obj_count0 = idx_by_id.size();
|
||||||
|
|
||||||
|
fixture_.generate_block();
|
||||||
|
|
||||||
|
signed_transaction trx;
|
||||||
|
set_expiration(fixture_.db, trx);
|
||||||
|
|
||||||
|
nft_metadata_create_operation op;
|
||||||
|
op.owner = owner;
|
||||||
|
op.symbol = symbol;
|
||||||
|
op.base_uri = uri;
|
||||||
|
op.name = name;
|
||||||
|
op.is_transferable = true;
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
fixture_.sign(trx, priv_key);
|
||||||
|
PUSH_TX(fixture_.db, trx, ~0);
|
||||||
|
fixture_.generate_block();
|
||||||
|
|
||||||
|
BOOST_REQUIRE( idx_by_id.size() == obj_count0 + 1 ); // one more metadata created
|
||||||
|
|
||||||
|
const auto& idx_by_name = fixture_.db.get_index_type<nft_metadata_index>().indices().get<by_name>();
|
||||||
|
auto obj = idx_by_name.find(name);
|
||||||
|
BOOST_CHECK( obj->owner == owner );
|
||||||
|
BOOST_CHECK( obj->name == name );
|
||||||
|
BOOST_CHECK( obj->symbol == symbol );
|
||||||
|
BOOST_CHECK( obj->base_uri == uri );
|
||||||
|
return *obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nft_object mint(const nft_metadata_id_type& metadata, const account_id_type& owner, const account_id_type& payer,
|
||||||
|
const fc::optional<account_id_type>& approved, const std::vector<account_id_type>& approved_operators,
|
||||||
|
const fc::ecc::private_key &priv_key)
|
||||||
|
{
|
||||||
|
const auto& idx_by_id = fixture_.db.get_index_type<nft_index>().indices().get<by_id>();
|
||||||
|
size_t obj_count0 = idx_by_id.size();
|
||||||
|
|
||||||
|
fixture_.generate_block();
|
||||||
|
|
||||||
|
signed_transaction trx;
|
||||||
|
set_expiration(fixture_.db, trx);
|
||||||
|
|
||||||
|
nft_mint_operation op;
|
||||||
|
op.nft_metadata_id = metadata;
|
||||||
|
op.payer = payer;
|
||||||
|
op.owner = owner;
|
||||||
|
if (approved)
|
||||||
|
op.approved = *approved;
|
||||||
|
op.approved_operators = approved_operators;
|
||||||
|
|
||||||
|
trx.operations.push_back(op);
|
||||||
|
fixture_.sign(trx, priv_key);
|
||||||
|
PUSH_TX(fixture_.db, trx, ~0);
|
||||||
|
|
||||||
|
fixture_.generate_block();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(idx_by_id.size() == obj_count0 + 1); // one more created
|
||||||
|
|
||||||
|
auto obj = idx_by_id.rbegin();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(obj != idx_by_id.rend());
|
||||||
|
BOOST_CHECK(obj->owner == owner);
|
||||||
|
BOOST_CHECK(obj->approved_operators.size() == approved_operators.size());
|
||||||
|
BOOST_CHECK(obj->approved_operators == approved_operators);
|
||||||
|
|
||||||
|
return *obj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE( nft_tests, database_fixture )
|
BOOST_FIXTURE_TEST_SUITE( nft_tests, database_fixture )
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( nft_metadata_name_validation_test ) {
|
||||||
|
BOOST_TEST_MESSAGE("nft_metadata_name_validation_test");
|
||||||
|
ACTORS((mdowner));
|
||||||
|
nft_metadata_create_operation op;
|
||||||
|
op.owner = mdowner_id;
|
||||||
|
op.symbol = "NFT";
|
||||||
|
op.base_uri = "http://nft.example.com";
|
||||||
|
op.name = "123";
|
||||||
|
op.is_transferable = true;
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "1ab";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = ".abc";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "abc.";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "ABC";
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
op.name = "abcdefghijklmnopq";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "ab";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "***";
|
||||||
|
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
||||||
|
op.name = "a12";
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
op.name = "a1b";
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
op.name = "abc";
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
op.name = "abc123defg12345";
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
op.name = "NFT Test";
|
||||||
|
BOOST_CHECK_NO_THROW(op.validate());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( nft_metadata_create_test ) {
|
BOOST_AUTO_TEST_CASE( nft_metadata_create_test ) {
|
||||||
|
|
||||||
BOOST_TEST_MESSAGE("nft_metadata_create_test");
|
BOOST_TEST_MESSAGE("nft_metadata_create_test");
|
||||||
generate_blocks(HARDFORK_NFT_TIME);
|
nft_test_helper nfth(*this);
|
||||||
generate_block();
|
|
||||||
generate_block();
|
|
||||||
set_expiration(db, trx);
|
|
||||||
|
|
||||||
ACTORS((mdowner));
|
ACTORS((mdowner));
|
||||||
|
nfth.create_metadata("NFT Test", "NFT", "http://nft.example.com", mdowner_id, mdowner_private_key);
|
||||||
|
}
|
||||||
|
|
||||||
generate_block();
|
|
||||||
set_expiration(db, trx);
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( nft_metadata_listing_test ) {
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("nft_metadata_listing_test");
|
||||||
|
|
||||||
|
nft_test_helper nfth(*this);
|
||||||
|
|
||||||
|
ACTORS((mdowner1));
|
||||||
|
ACTORS((mdowner2));
|
||||||
|
|
||||||
|
// prepare metadata set
|
||||||
|
for (int i=0; i < 200; i++)
|
||||||
{
|
{
|
||||||
BOOST_TEST_MESSAGE("Send nft_metadata_create_operation");
|
string sfx = fc::to_pretty_string(i);
|
||||||
|
nft_metadata_object md = nfth.create_metadata("NFT Test " + sfx, "NFT" + sfx, "http://nft.example.com", mdowner1_id, mdowner1_private_key);
|
||||||
nft_metadata_create_operation op;
|
BOOST_REQUIRE(md.id == nft_metadata_id_type(i));
|
||||||
op.owner = mdowner_id;
|
}
|
||||||
op.symbol = "NFT";
|
for (int i=200; i < 250; i++)
|
||||||
op.base_uri = "http://nft.example.com";
|
{
|
||||||
op.name = "123";
|
string sfx = fc::to_pretty_string(i);
|
||||||
op.is_transferable = true;
|
nft_metadata_object md = nfth.create_metadata("NFT Test " + sfx, "NFT" + sfx, "http://nft.example.com", mdowner2_id, mdowner2_private_key);
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
BOOST_REQUIRE(md.id == nft_metadata_id_type(i));
|
||||||
op.name = "";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = "1ab";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = ".abc";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = "abc.";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = "ABC";
|
|
||||||
BOOST_CHECK_NO_THROW(op.validate());
|
|
||||||
op.name = "abcdefghijklmnopq";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = "ab";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = "***";
|
|
||||||
BOOST_CHECK_THROW(op.validate(), fc::exception);
|
|
||||||
op.name = "a12";
|
|
||||||
BOOST_CHECK_NO_THROW(op.validate());
|
|
||||||
op.name = "a1b";
|
|
||||||
BOOST_CHECK_NO_THROW(op.validate());
|
|
||||||
op.name = "abc";
|
|
||||||
BOOST_CHECK_NO_THROW(op.validate());
|
|
||||||
op.name = "abc123defg12345";
|
|
||||||
BOOST_CHECK_NO_THROW(op.validate());
|
|
||||||
op.name = "NFT Test";
|
|
||||||
trx.operations.push_back(op);
|
|
||||||
sign(trx, mdowner_private_key);
|
|
||||||
PUSH_TX(db, trx, ~0);
|
|
||||||
}
|
}
|
||||||
generate_block();
|
|
||||||
|
|
||||||
BOOST_TEST_MESSAGE("Check nft_metadata_create_operation results");
|
graphene::app::database_api db_api(db);
|
||||||
|
vector<nft_metadata_object> listed;
|
||||||
|
|
||||||
const auto& idx = db.get_index_type<nft_metadata_index>().indices().get<by_id>();
|
// first 100 returned
|
||||||
BOOST_REQUIRE( idx.size() == 1 );
|
listed = db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(0), 100);
|
||||||
auto obj = idx.begin();
|
BOOST_REQUIRE(listed.size() == 100);
|
||||||
BOOST_REQUIRE( obj != idx.end() );
|
BOOST_REQUIRE(listed[ 0].id == nft_metadata_id_type( 0));
|
||||||
BOOST_CHECK( obj->owner == mdowner_id );
|
BOOST_REQUIRE(listed[99].id == nft_metadata_id_type(99));
|
||||||
BOOST_CHECK( obj->name == "NFT Test" );
|
|
||||||
BOOST_CHECK( obj->symbol == "NFT" );
|
// 100 starting from 50
|
||||||
BOOST_CHECK( obj->base_uri == "http://nft.example.com" );
|
listed = db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(50), 100);
|
||||||
|
BOOST_REQUIRE(listed.size() == 100);
|
||||||
|
BOOST_REQUIRE(listed[ 0].id == nft_metadata_id_type( 50));
|
||||||
|
BOOST_REQUIRE(listed[99].id == nft_metadata_id_type(149));
|
||||||
|
|
||||||
|
// the last 5 must be returned
|
||||||
|
listed = db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(195), 10);
|
||||||
|
BOOST_REQUIRE(listed.size() == 5);
|
||||||
|
BOOST_REQUIRE(listed[0].id == nft_metadata_id_type(195));
|
||||||
|
BOOST_REQUIRE(listed[4].id == nft_metadata_id_type(199));
|
||||||
|
|
||||||
|
// too much requested at once
|
||||||
|
BOOST_CHECK_THROW(db_api.nft_get_metadata_by_owner(mdowner1_id, nft_metadata_id_type(0), 101), fc::exception);
|
||||||
|
|
||||||
|
// the last 40 must be returned
|
||||||
|
listed = db_api.nft_get_metadata_by_owner(mdowner2_id, nft_metadata_id_type(210), 100);
|
||||||
|
BOOST_REQUIRE(listed.size() == 40);
|
||||||
|
BOOST_REQUIRE(listed[ 0].id == nft_metadata_id_type(210));
|
||||||
|
BOOST_REQUIRE(listed[39].id == nft_metadata_id_type(249));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -120,49 +248,112 @@ BOOST_AUTO_TEST_CASE( nft_mint_test ) {
|
||||||
generate_block();
|
generate_block();
|
||||||
set_expiration(db, trx);
|
set_expiration(db, trx);
|
||||||
|
|
||||||
INVOKE(nft_metadata_create_test);
|
nft_test_helper nfth(*this);
|
||||||
|
|
||||||
|
ACTORS((mdowner));
|
||||||
ACTORS((alice));
|
ACTORS((alice));
|
||||||
ACTORS((bob));
|
ACTORS((bob));
|
||||||
ACTORS((operator1));
|
ACTORS((operator1));
|
||||||
ACTORS((operator2));
|
ACTORS((operator2));
|
||||||
|
|
||||||
GET_ACTOR(mdowner);
|
nft_metadata_object md = nfth.create_metadata("NFT Test", "NFT", "http://nft.example.com", mdowner_id, mdowner_private_key);
|
||||||
|
|
||||||
generate_block();
|
nfth.mint(md.id, alice_id, mdowner_id, alice_id, {operator1_id, operator2_id}, alice_private_key);
|
||||||
set_expiration(db, trx);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE( nft_object_listing_test ) {
|
||||||
|
|
||||||
|
BOOST_TEST_MESSAGE("nft_object_listing_test");
|
||||||
|
|
||||||
|
nft_test_helper nfth(*this);
|
||||||
|
|
||||||
|
ACTORS((mdowner1));
|
||||||
|
ACTORS((mdowner2));
|
||||||
|
ACTORS((alice));
|
||||||
|
ACTORS((bob));
|
||||||
|
|
||||||
|
nft_metadata_object md1 = nfth.create_metadata("NFT Test 1", "NFT1", "http://nft.example.com", mdowner1_id, mdowner1_private_key);
|
||||||
|
nft_metadata_object md2 = nfth.create_metadata("NFT Test 2", "NFT2", "http://nft.example.com", mdowner2_id, mdowner2_private_key);
|
||||||
|
|
||||||
|
// create NFT objects: 200 owned by alice and 200 by bob
|
||||||
|
for (int i=0; i < 200; i++)
|
||||||
{
|
{
|
||||||
BOOST_TEST_MESSAGE("Send nft_mint_operation");
|
nft_object nft = nfth.mint(md1.id, alice_id, mdowner1_id, alice_id, {}, alice_private_key);
|
||||||
|
BOOST_REQUIRE(nft.id == nft_id_type(i));
|
||||||
const auto& idx = db.get_index_type<nft_metadata_index>().indices().get<by_id>();
|
}
|
||||||
BOOST_REQUIRE( idx.size() == 1 );
|
for (int i=200; i < 250; i++)
|
||||||
auto nft_md_obj = idx.begin();
|
{
|
||||||
|
nft_object nft = nfth.mint(md1.id, bob_id, mdowner1_id, bob_id, {}, bob_private_key);
|
||||||
nft_mint_operation op;
|
BOOST_REQUIRE(nft.id == nft_id_type(i));
|
||||||
op.payer = mdowner_id;
|
|
||||||
op.nft_metadata_id = nft_md_obj->id;
|
|
||||||
op.owner = alice_id;
|
|
||||||
op.approved = alice_id;
|
|
||||||
op.approved_operators.push_back(operator1_id);
|
|
||||||
op.approved_operators.push_back(operator2_id);
|
|
||||||
|
|
||||||
trx.operations.push_back(op);
|
|
||||||
sign(trx, alice_private_key);
|
|
||||||
PUSH_TX(db, trx, ~0);
|
|
||||||
}
|
}
|
||||||
generate_block();
|
|
||||||
|
|
||||||
BOOST_TEST_MESSAGE("Check nft_mint_operation results");
|
graphene::app::database_api db_api(db);
|
||||||
|
vector<nft_object> listed;
|
||||||
|
|
||||||
const auto& idx = db.get_index_type<nft_index>().indices().get<by_id>();
|
//
|
||||||
BOOST_REQUIRE( idx.size() == 1 );
|
// listing all tokens:
|
||||||
auto obj = idx.begin();
|
//
|
||||||
BOOST_REQUIRE( obj != idx.end() );
|
// first 100 returned, all alice's
|
||||||
BOOST_CHECK( obj->owner == alice_id );
|
listed = db_api.nft_get_all_tokens(nft_id_type(0), 100);
|
||||||
BOOST_CHECK( obj->approved_operators.size() == 2 );
|
BOOST_REQUIRE(listed.size() == 100);
|
||||||
BOOST_CHECK( obj->approved_operators.at(0) == operator1_id );
|
BOOST_REQUIRE(listed[ 0].id == nft_id_type( 0));
|
||||||
BOOST_CHECK( obj->approved_operators.at(1) == operator2_id );
|
BOOST_REQUIRE(listed[99].id == nft_id_type(99));
|
||||||
|
BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; }));
|
||||||
|
|
||||||
|
// 100 starting from 50, all alice's
|
||||||
|
listed = db_api.nft_get_all_tokens(nft_id_type(50), 100);
|
||||||
|
BOOST_REQUIRE(listed.size() == 100);
|
||||||
|
BOOST_REQUIRE(listed[ 0].id == nft_id_type( 50));
|
||||||
|
BOOST_REQUIRE(listed[99].id == nft_id_type(149));
|
||||||
|
BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; }));
|
||||||
|
|
||||||
|
// the last 5 must be returned, all bob's
|
||||||
|
listed = db_api.nft_get_all_tokens(nft_id_type(245), 10);
|
||||||
|
BOOST_REQUIRE(listed.size() == 5);
|
||||||
|
BOOST_REQUIRE(listed[0].id == nft_id_type(245));
|
||||||
|
BOOST_REQUIRE(listed[4].id == nft_id_type(249));
|
||||||
|
BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [bob_id](const nft_object &obj){ return obj.owner == bob_id; }));
|
||||||
|
|
||||||
|
// 10 from the middle of the set, half alice's, half bob's
|
||||||
|
listed = db_api.nft_get_all_tokens(nft_id_type(195), 10);
|
||||||
|
BOOST_REQUIRE(listed.size() == 10);
|
||||||
|
BOOST_REQUIRE(listed[0].id == nft_id_type(195));
|
||||||
|
BOOST_REQUIRE(listed[9].id == nft_id_type(204));
|
||||||
|
BOOST_REQUIRE(listed[0].owner == alice_id);
|
||||||
|
BOOST_REQUIRE(listed[4].owner == alice_id);
|
||||||
|
BOOST_REQUIRE(listed[5].owner == bob_id);
|
||||||
|
BOOST_REQUIRE(listed[9].owner == bob_id);
|
||||||
|
|
||||||
|
// too much requested at once
|
||||||
|
BOOST_CHECK_THROW(db_api.nft_get_all_tokens(nft_id_type(0), 101), fc::exception);
|
||||||
|
|
||||||
|
//
|
||||||
|
// listing tokens by owner:
|
||||||
|
//
|
||||||
|
// first 100 alice's
|
||||||
|
listed = db_api.nft_get_tokens_by_owner(alice_id, nft_id_type(0), 100);
|
||||||
|
BOOST_REQUIRE(listed.size() == 100);
|
||||||
|
BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; }));
|
||||||
|
BOOST_REQUIRE(listed[ 0].id == nft_id_type( 0));
|
||||||
|
BOOST_REQUIRE(listed[99].id == nft_id_type(99));
|
||||||
|
|
||||||
|
// the last 5 alice's must be returned
|
||||||
|
listed = db_api.nft_get_tokens_by_owner(alice_id, nft_id_type(195), 10);
|
||||||
|
BOOST_REQUIRE(listed.size() == 5);
|
||||||
|
BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [alice_id](const nft_object &obj){ return obj.owner == alice_id; }));
|
||||||
|
BOOST_REQUIRE(listed[0].id == nft_id_type(195));
|
||||||
|
BOOST_REQUIRE(listed[4].id == nft_id_type(199));
|
||||||
|
|
||||||
|
// all 50 bob's
|
||||||
|
listed = db_api.nft_get_tokens_by_owner(bob_id, nft_id_type(0), 60);
|
||||||
|
BOOST_REQUIRE(listed.size() == 50);
|
||||||
|
BOOST_REQUIRE(all_of(listed.begin(), listed.end(), [bob_id](const nft_object &obj){ return obj.owner == bob_id; }));
|
||||||
|
BOOST_REQUIRE(listed[ 0].id == nft_id_type(200));
|
||||||
|
BOOST_REQUIRE(listed[49].id == nft_id_type(249));
|
||||||
|
|
||||||
|
// too much requested at once
|
||||||
|
BOOST_CHECK_THROW(db_api.nft_get_tokens_by_owner(alice_id, nft_id_type(0), 101), fc::exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue