Add non-transferable non-sellable properties to NFTs

This commit is contained in:
sierra19XX 2020-08-03 13:15:45 +00:00
parent ff70a88921
commit b2e2d7e966
7 changed files with 54 additions and 32 deletions

View file

@ -18,6 +18,8 @@ namespace graphene { namespace chain {
std::string base_uri;
optional<account_id_type> revenue_partner;
optional<double> revenue_split;
bool isTransferable = false;
bool isSellable = true;
};
class nft_object : public abstract_object<nft_object>
@ -91,7 +93,9 @@ FC_REFLECT_DERIVED( graphene::chain::nft_metadata_object, (graphene::db::object)
(symbol)
(base_uri)
(revenue_partner)
(revenue_split) )
(revenue_split)
(isTransferable)
(isSellable) )
FC_REFLECT_DERIVED( graphene::chain::nft_object, (graphene::db::object),
(nft_metadata_id)

View file

@ -15,6 +15,8 @@ namespace graphene { namespace chain {
std::string base_uri;
optional<account_id_type> revenue_partner;
optional<double> revenue_split;
bool isTransferable = false;
bool isSellable = true;
account_id_type fee_payer()const { return owner; }
void validate() const;
@ -32,6 +34,8 @@ namespace graphene { namespace chain {
optional<std::string> base_uri;
optional<account_id_type> revenue_partner;
optional<double> revenue_split;
optional<bool> isTransferable;
optional<bool> isSellable;
account_id_type fee_payer()const { return owner; }
void validate() const;
@ -104,8 +108,8 @@ FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation::fee_parameters_ty
FC_REFLECT( graphene::chain::nft_approve_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::nft_set_approval_for_all_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::nft_metadata_create_operation, (fee) (owner) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) )
FC_REFLECT( graphene::chain::nft_metadata_update_operation, (fee) (owner) (nft_metadata_id) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) )
FC_REFLECT( graphene::chain::nft_metadata_create_operation, (fee) (owner) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) (isTransferable) (isSellable) )
FC_REFLECT( graphene::chain::nft_metadata_update_operation, (fee) (owner) (nft_metadata_id) (name) (symbol) (base_uri) (revenue_partner) (revenue_split) (isTransferable) (isSellable) )
FC_REFLECT( graphene::chain::nft_mint_operation, (fee) (payer) (nft_metadata_id) (owner) (approved) (approved_operators) (token_uri) )
FC_REFLECT( graphene::chain::nft_safe_transfer_from_operation, (fee) (operator_) (from) (to) (token_id) (data) )
FC_REFLECT( graphene::chain::nft_approve_operation, (fee) (operator_) (approved) (token_id) )

View file

@ -27,6 +27,8 @@ object_id_type nft_metadata_create_evaluator::do_apply( const nft_metadata_creat
obj.base_uri = op.base_uri;
obj.revenue_partner = op.revenue_partner;
obj.revenue_split = op.revenue_split;
obj.isTransferable = op.isTransferable;
obj.isSellable = op.isSellable;
});
return new_nft_metadata_object.id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -60,6 +62,10 @@ void_result nft_metadata_update_evaluator::do_apply( const nft_metadata_update_o
obj.revenue_partner = op.revenue_partner;
if( op.revenue_split.valid() )
obj.revenue_split = op.revenue_split;
if( op.isTransferable.valid() )
obj.isTransferable = *op.isTransferable;
if( op.isSellable.valid() )
obj.isSellable = *op.isSellable;
});
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -120,6 +126,9 @@ void_result nft_safe_transfer_from_evaluator::do_evaluate( const nft_safe_transf
auto itr_approved_op = std::find(itr_nft->approved_operators.begin(), itr_nft->approved_operators.end(), op.operator_);
FC_ASSERT( (itr_nft->owner == op.operator_) || (itr_nft->approved == itr_operator->id) || (itr_approved_op != itr_nft->approved_operators.end()), "Operator is not NFT owner or approved operator" );
const auto& nft_meta_obj = itr_nft->nft_metadata_id(db());
FC_ASSERT( nft_meta_obj.isTransferable == true, "NFT is not transferable");
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -34,6 +34,8 @@ namespace graphene
{
FC_ASSERT(is_owner, "Issuer has no authority to sell the item");
}
const auto& nft_meta_obj = nft_obj.nft_metadata_id(d);
FC_ASSERT( nft_meta_obj.isSellable == true, "NFT is not sellable");
}
FC_ASSERT(op.offer_expiration_date > d.head_block_time(), "Expiration should be in future");
FC_ASSERT(op.fee.amount >= 0, "Invalid fee");
@ -229,7 +231,6 @@ namespace graphene
{
database &d = db();
offer_object offer = op.offer_id(d);
vector<nft_safe_transfer_from_operation> xfer_ops;
// Calculate the fees for all revenue partners of the items
auto calc_fee = [&](int64_t &tot_fees) {
map<account_id_type, asset> fee_map;
@ -282,25 +283,22 @@ namespace graphene
// Sell Offer, send the seller his amount
d.adjust_balance(offer.issuer, seller_amount);
}
// Safely tranfer the NFTs with the ops
for (const auto &item : offer.item_ids)
// Tranfer the NFTs
for (auto item : offer.item_ids)
{
const auto &nft_obj = item(d);
nft_safe_transfer_from_operation xfer_op;
xfer_op.from = nft_obj.owner;
xfer_op.token_id = item;
xfer_op.fee = asset(0, asset_id_type());
if (offer.buying_item)
{
xfer_op.to = offer.issuer;
xfer_op.operator_ = *offer.bidder;
}
else
{
xfer_op.to = *offer.bidder;
xfer_op.operator_ = offer.issuer;
}
xfer_ops.push_back(std::move(xfer_op));
auto &nft_obj = item(d);
d.modify(nft_obj, [&offer](nft_object &obj) {
if (offer.buying_item)
{
obj.owner = offer.issuer;
}
else
{
obj.owner = *offer.bidder;
}
obj.approved = {};
obj.approved_operators.clear();
});
}
}
else
@ -323,16 +321,6 @@ namespace graphene
});
// This should unlock the item
d.remove(op.offer_id(d));
// Send safe transfer from ops
if (xfer_ops.size() > 0)
{
transaction_evaluation_state xfer_context(&d);
xfer_context.skip_fee_schedule_check = true;
for (const auto &xfer_op : xfer_ops)
{
d.apply_operation(xfer_context, xfer_op);
}
}
return void_result();
}
FC_CAPTURE_AND_RETHROW((op))

View file

@ -1937,6 +1937,8 @@ class wallet_api
* @param base_uri Base URI for token URI
* @param revenue_partner revenue partner for this type of Token
* @param revenue_split revenue split for the sale
* @param isTransferable can transfer the NFT or not
* @param isSellable can sell NFT or not
* @param broadcast true to broadcast transaction to the network
* @return Signed transaction transfering the funds
*/
@ -1946,6 +1948,8 @@ class wallet_api
string base_uri,
optional<string> revenue_partner,
optional<double> revenue_split,
bool isTransferable,
bool isSellable,
bool broadcast);
/**
@ -1956,6 +1960,8 @@ class wallet_api
* @param base_uri Base URI for token URI
* @param revenue_partner revenue partner for this type of Token
* @param revenue_split revenue split for the sale
* @param isTransferable can transfer the NFT or not
* @param isSellable can sell NFT or not
* @param broadcast true to broadcast transaction to the network
* @return Signed transaction transfering the funds
*/
@ -1965,6 +1971,8 @@ class wallet_api
string base_uri,
optional<string> revenue_partner,
optional<double> revenue_split,
optional<bool> isTransferable,
optional<bool> isSellable,
bool broadcast);
/**

View file

@ -6373,6 +6373,8 @@ signed_transaction wallet_api::nft_metadata_create(string owner_account_id_or_na
string base_uri,
optional<string> revenue_partner,
optional<double> revenue_split,
bool isTransferable,
bool isSellable,
bool broadcast)
{
account_object owner_account = my->get_account(owner_account_id_or_name);
@ -6393,6 +6395,8 @@ signed_transaction wallet_api::nft_metadata_create(string owner_account_id_or_na
}
op.revenue_split = rev_split;
}
op.isTransferable = isTransferable;
op.isSellable = isSellable;
signed_transaction trx;
trx.operations.push_back(op);
@ -6408,6 +6412,8 @@ signed_transaction wallet_api::nft_metadata_update(string owner_account_id_or_na
string base_uri,
optional<string> revenue_partner,
optional<double> revenue_split,
optional<bool> isTransferable,
optional<bool> isSellable,
bool broadcast)
{
account_object owner_account = my->get_account(owner_account_id_or_name);
@ -6428,6 +6434,8 @@ signed_transaction wallet_api::nft_metadata_update(string owner_account_id_or_na
}
op.revenue_split = rev_split;
}
op.isTransferable = isTransferable;
op.isSellable = isSellable;
signed_transaction trx;
trx.operations.push_back(op);

View file

@ -30,6 +30,7 @@ BOOST_AUTO_TEST_CASE( nft_metadata_create_test ) {
op.symbol = "NFT";
op.base_uri = "http://nft.example.com";
op.name = "123";
op.isTransferable = true;
BOOST_CHECK_THROW(op.validate(), fc::exception);
op.name = "";
BOOST_CHECK_THROW(op.validate(), fc::exception);