Add non-transferable non-sellable properties to NFTs
This commit is contained in:
parent
ff70a88921
commit
b2e2d7e966
7 changed files with 54 additions and 32 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) )
|
||||
|
|
|
|||
|
|
@ -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) ) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue