diff --git a/libraries/api/types.json b/libraries/api/types.json index 153f25731..86dc147f7 100644 --- a/libraries/api/types.json +++ b/libraries/api/types.json @@ -11,6 +11,14 @@ "cpp_return_type" : "bts::blockchain::blockchain_security_state", "cpp_include_file" : "bts/blockchain/types.hpp" }, + { + "type_name" : "asset_permission", + "cpp_return_type" : "asset_permissions" + }, + { + "type_name" : "asset_permission_array", + "cpp_return_type" : "std::vector" + }, { "type_name": "float", "cpp_return_type" : "float", diff --git a/libraries/api/wallet_api.json b/libraries/api/wallet_api.json index d10f4ad96..4b7d9ee62 100644 --- a/libraries/api/wallet_api.json +++ b/libraries/api/wallet_api.json @@ -1627,16 +1627,22 @@ "default_value" : 0 }, { - "name" : "restricted", - "type" : "bool", - "description" : "whether or not ownership of the asset is restricted to authorized keys", - "default_value" : false + "name" : "flags", + "type" : "asset_permission_array", + "description" : "a set of flags set by the issuer (if they have permission to set them)", + "default_value" : [] }, { - "name" : "retractable", - "type" : "bool", - "description" : "whether or not issuer is a co-signer on all balances", - "default_value" : true + "name" : "issuer_permissions", + "type" : "asset_permission_array", + "description" : "a set of permissions an issuer retains", + "default_value" : ["retractable","market_halt","balance_halt","supply_limit"] + }, + { + "name" : "issuer_account_name", + "type" : "account_name", + "description" : "used to transfer the asset to a new user", + "default_value" : "" }, { "name" : "required_sigs", diff --git a/libraries/blockchain/asset_operations.cpp b/libraries/blockchain/asset_operations.cpp index da11b5d30..0576feb98 100644 --- a/libraries/blockchain/asset_operations.cpp +++ b/libraries/blockchain/asset_operations.cpp @@ -169,7 +169,8 @@ namespace bts { namespace blockchain { // Cannot update max share supply, or precision if any shares have been issued if( current_asset_record->current_share_supply > 0 ) { - FC_ASSERT( !this->maximum_share_supply.valid() ); + if( !(current_asset_record->flags & supply_unlimit) ) + FC_ASSERT( !this->maximum_share_supply.valid() ); FC_ASSERT( !this->precision.valid() ); } @@ -208,18 +209,49 @@ namespace bts { namespace blockchain { if( !current_asset_record->is_market_issued() ) { - if( this->restricted ) FC_ASSERT( current_asset_record->current_share_supply == 0 ); - - current_asset_record->restricted = this->restricted; - if( current_asset_record->retractable ) + + // you can only remove these permissions, but not add them if there are current shares + if( current_asset_record->current_share_supply > 0 ) { - current_asset_record->retractable = this->retractable; + if( this->issuer_permissions & retractable ) + FC_ASSERT( current_asset_record->issuer_permissions & retractable ); + if( this->issuer_permissions & restricted ) + FC_ASSERT( current_asset_record->issuer_permissions & restricted ); + if( this->issuer_permissions & market_halt ) + FC_ASSERT( current_asset_record->issuer_permissions & market_halt ); + if( this->issuer_permissions & balance_halt ) + FC_ASSERT( current_asset_record->issuer_permissions & balance_halt ); + if( this->issuer_permissions & supply_unlimit ) + FC_ASSERT( current_asset_record->issuer_permissions & supply_unlimit ); } - else FC_ASSERT( !this->retractable ); - current_asset_record->transaction_fee = this->transaction_fee; - current_asset_record->authority = this->authority; + current_asset_record->issuer_permissions = this->issuer_permissions; + + if( this->flags & restricted ) FC_ASSERT( current_asset_record->issuer_permissions & restricted ); + if( this->flags & retractable ) FC_ASSERT( current_asset_record->issuer_permissions & retractable ); + if( this->flags & market_halt ) FC_ASSERT( current_asset_record->issuer_permissions & market_halt ); + if( this->flags & balance_halt ) FC_ASSERT( current_asset_record->issuer_permissions & balance_halt ); + current_asset_record->flags = this->flags; + + current_asset_record->transaction_fee = this->transaction_fee; + current_asset_record->authority = this->authority; + } + + if( current_asset_record->is_market_issued() ) + { + FC_ASSERT( this->issuer_account_id == asset_record::market_issued_asset ); + } + else + { + FC_ASSERT( this->issuer_account_id != asset_record::market_issued_asset ); + if( this->issuer_account_id != current_asset_record->issuer_account_id ) + { + auto issuer_account_record = eval_state._current_state->get_account_record( this->issuer_account_id ); + if( NOT issuer_account_record.valid() ) + FC_CAPTURE_AND_THROW( unknown_account_id, (issuer_account_id) ); + } } + current_asset_record->issuer_account_id = this->issuer_account_id; current_asset_record->last_update = eval_state._current_state->now(); eval_state._current_state->store_asset_record( *current_asset_record ); @@ -258,7 +290,7 @@ namespace bts { namespace blockchain { if( NOT current_asset_record.valid() ) FC_CAPTURE_AND_THROW( unknown_asset_id, (this->asset_id) ); - FC_ASSERT( current_asset_record->restricted ); + FC_ASSERT( current_asset_record->issuer_permissions & restricted ); FC_ASSERT( current_asset_record->issuer_account_id != asset_record::market_issued_asset ); eval_state._current_state->authorize( this->asset_id, this->owner, this->meta_id ); diff --git a/libraries/blockchain/balance_operations.cpp b/libraries/blockchain/balance_operations.cpp index a6086505f..50d514db9 100644 --- a/libraries/blockchain/balance_operations.cpp +++ b/libraries/blockchain/balance_operations.cpp @@ -152,6 +152,7 @@ namespace bts { namespace blockchain { if( !current_balance_record.valid() ) FC_CAPTURE_AND_THROW( unknown_balance_record, (balance_id) ); + if( this->amount > current_balance_record->get_spendable_balance( eval_state._current_state->now() ).amount ) FC_CAPTURE_AND_THROW( insufficient_funds, (current_balance_record)(amount) ); @@ -159,8 +160,17 @@ namespace bts { namespace blockchain { FC_ASSERT( asset_rec.valid() ); bool issuer_override = asset_rec->is_retractable() && eval_state.verify_authority( asset_rec->authority ); + if( !issuer_override ) { + FC_ASSERT( !asset_rec->is_balance_frozen() ); + if( asset_rec->is_restricted() ) + { + for(auto owner : current_balance_record->owners()) + { + FC_ASSERT(eval_state._current_state->get_authorization(asset_rec->id, owner)); + } + } switch( (withdraw_condition_types)current_balance_record->condition.type ) { case withdraw_signature_type: @@ -327,7 +337,7 @@ namespace bts { namespace blockchain { escrow_balance_record->balance -= total_released; auto asset_rec = eval_state._current_state->get_asset_record( escrow_balance_record->condition.asset_id ); - if( asset_rec->restricted ) + if( asset_rec->is_restricted() ) { FC_ASSERT( eval_state._current_state->get_authorization( escrow_balance_record->condition.asset_id, escrow_condition.receiver ) ); } diff --git a/libraries/blockchain/include/bts/blockchain/asset_operations.hpp b/libraries/blockchain/include/bts/blockchain/asset_operations.hpp index ab2635f46..0fcee175a 100644 --- a/libraries/blockchain/include/bts/blockchain/asset_operations.hpp +++ b/libraries/blockchain/include/bts/blockchain/asset_operations.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace bts { namespace blockchain { @@ -76,17 +77,17 @@ namespace bts { namespace blockchain { struct update_asset_ext_operation : public update_asset_operation { static const operation_type_enum type; + update_asset_ext_operation(){} + update_asset_ext_operation( const update_asset_operation& c ):update_asset_operation(c){} /** * A restricted asset can only be held/controlled by keys * on the authorized list. */ - bool restricted = false; + uint32_t flags = none; + uint32_t issuer_permissions = default_permissions; + account_id_type issuer_account_id; - /** - * Asset is retractable by the issuer. - */ - bool retractable = true; /** * The issuer can specify a transaction fee (of the asset type) @@ -161,8 +162,9 @@ FC_REFLECT( bts::blockchain::update_asset_operation, ) FC_REFLECT_DERIVED( bts::blockchain::update_asset_ext_operation, (bts::blockchain::update_asset_operation), - (restricted) - (retractable) + (flags) + (issuer_permissions) + (issuer_account_id) (transaction_fee) (authority) ) diff --git a/libraries/blockchain/include/bts/blockchain/asset_record.hpp b/libraries/blockchain/include/bts/blockchain/asset_record.hpp index 63fbd41e1..75d35df0a 100644 --- a/libraries/blockchain/include/bts/blockchain/asset_record.hpp +++ b/libraries/blockchain/include/bts/blockchain/asset_record.hpp @@ -5,6 +5,18 @@ namespace bts { namespace blockchain { + enum asset_permissions + { + none = 0, + retractable = 0x01, ///& maximum_share_supply, const optional& precision ); + void update_asset_ext( const asset_id_type& asset_id, + const optional& name, + const optional& description, + const optional& public_data, + const optional& maximum_share_supply, + const optional& precision, + const share_type& issuer_fee, + uint32_t issuer_permissions, + uint32_t flags, + account_id_type issuer_account_id, + uint32_t required_sigs, + const vector
& authority + ); + void burn( const asset& quantity, account_id_type for_or_against, const string& public_message, diff --git a/libraries/blockchain/market_engine.cpp b/libraries/blockchain/market_engine.cpp index a15025bbc..61f61afdf 100644 --- a/libraries/blockchain/market_engine.cpp +++ b/libraries/blockchain/market_engine.cpp @@ -39,7 +39,10 @@ namespace bts { namespace blockchain { namespace detail { oasset_record quote_asset = _pending_state->get_asset_record( _quote_id ); oasset_record base_asset = _pending_state->get_asset_record( _base_id ); + FC_ASSERT( quote_asset.valid() && base_asset.valid() ); + FC_ASSERT( !quote_asset->is_market_frozen() ); + FC_ASSERT( !base_asset->is_market_frozen() ); // The order book is sorted from low to high price. So to get the last item (highest bid), // we need to go to the first item in the next market class and then back up one diff --git a/libraries/blockchain/market_operations.cpp b/libraries/blockchain/market_operations.cpp index 721af95da..cce7f3e30 100644 --- a/libraries/blockchain/market_operations.cpp +++ b/libraries/blockchain/market_operations.cpp @@ -33,6 +33,8 @@ namespace bts { namespace blockchain { if( !issuer_override && !eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (bid_index.owner) ); + FC_ASSERT( !issuer_override && !quote_asset_rec->is_balance_frozen() ); + asset delta_amount = this->get_amount(); eval_state.validate_asset( delta_amount ); @@ -148,6 +150,7 @@ namespace bts { namespace blockchain { if( !issuer_override && !eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (ask_index.owner) ); + FC_ASSERT( !issuer_override && !base_asset_rec->is_balance_frozen() ); asset delta_amount = this->get_amount(); diff --git a/libraries/blockchain/transaction.cpp b/libraries/blockchain/transaction.cpp index 10d350e08..5fc55d5a4 100644 --- a/libraries/blockchain/transaction.cpp +++ b/libraries/blockchain/transaction.cpp @@ -317,6 +317,31 @@ namespace bts { namespace blockchain { { operations.push_back( update_asset_operation{ asset_id, name, description, public_data, maximum_share_supply, precision } ); } + void transaction::update_asset_ext( const asset_id_type& asset_id, + const optional& name, + const optional& description, + const optional& public_data, + const optional& maximum_share_supply, + const optional& precision, + const share_type& issuer_fee, + uint32_t issuer_permissions, + uint32_t flags, + account_id_type issuer_account_id, + uint32_t required_sigs, + const vector
& authority + ) + { + multisig_meta_info auth_info; + auth_info.required = required_sigs; + auth_info.owners.insert( authority.begin(), authority.end() ); + update_asset_ext_operation op( update_asset_operation{asset_id, name, description, public_data, maximum_share_supply, precision} ); + op.flags = flags; + op.issuer_permissions = issuer_permissions; + op.issuer_account_id = issuer_account_id; + op.transaction_fee = issuer_fee, + op.authority = auth_info; + operations.push_back( op ); + } void transaction::issue( const asset& amount_to_issue ) { diff --git a/libraries/client/wallet_api.cpp b/libraries/client/wallet_api.cpp index 456ebdd46..19dd32297 100644 --- a/libraries/client/wallet_api.cpp +++ b/libraries/client/wallet_api.cpp @@ -643,16 +643,24 @@ wallet_transaction_record detail::client_impl::wallet_asset_update( const optional& maximum_share_supply, const optional& precision, const share_type& issuer_fee, - bool restricted, - bool retractable, + const vector& flags, + const vector& issuer_permissions, + const string& issuer_account_name, uint32_t required_sigs, const vector
& authority ) { - auto record = _wallet->update_asset( symbol, name, description, public_data, maximum_share_supply, precision, true ); - _wallet->cache_transaction( record ); - network_broadcast_transaction( record.trx ); - return record; + uint32_t flags_int = 0; + uint32_t issuer_perms_int = 0; + for( auto item : flags ) flags_int |= item; + for( auto item : issuer_permissions ) issuer_perms_int |= item; + auto record = _wallet->update_asset( symbol, name, description, public_data, maximum_share_supply, + precision, issuer_fee, flags_int, issuer_perms_int, issuer_account_name, + required_sigs, authority); + + _wallet->cache_transaction( record ); + network_broadcast_transaction( record.trx ); + return record; } wallet_transaction_record detail::client_impl::wallet_asset_issue( diff --git a/libraries/wallet/include/bts/wallet/transaction_builder.hpp b/libraries/wallet/include/bts/wallet/transaction_builder.hpp index b42e94737..37c0a1f72 100644 --- a/libraries/wallet/include/bts/wallet/transaction_builder.hpp +++ b/libraries/wallet/include/bts/wallet/transaction_builder.hpp @@ -288,7 +288,14 @@ namespace bts { namespace wallet { const optional& description, const optional& public_data, const optional& maximum_share_supply, - const optional& precision ); + const optional& precision, + const share_type& issuer_fee, + uint32_t issuer_perms, + uint32_t flags, + account_id_type issuer_account_id, + uint32_t required_sigs, + const vector
& authority + ); /** * @brief Balance the books and pay the fees diff --git a/libraries/wallet/include/bts/wallet/wallet.hpp b/libraries/wallet/include/bts/wallet/wallet.hpp index 23643488d..f1d47c9c1 100644 --- a/libraries/wallet/include/bts/wallet/wallet.hpp +++ b/libraries/wallet/include/bts/wallet/wallet.hpp @@ -419,7 +419,13 @@ namespace bts { namespace wallet { const optional& public_data, const optional& maximum_share_supply, const optional& precision, - bool sign + const share_type& issuer_fee, + uint32_t issuer_perms, + uint32_t flags, + const string& issuer_account_name, + uint32_t required_sigs, + const vector
& authority, + bool sign = true ); wallet_transaction_record issue_asset( double amount, diff --git a/libraries/wallet/transaction_builder.cpp b/libraries/wallet/transaction_builder.cpp index dc663f606..bcfdde41d 100644 --- a/libraries/wallet/transaction_builder.cpp +++ b/libraries/wallet/transaction_builder.cpp @@ -689,7 +689,14 @@ transaction_builder& transaction_builder::update_asset( const string& symbol, const optional& description, const optional& public_data, const optional& maximum_share_supply, - const optional& precision ) + const optional& precision, + const share_type& issuer_fee, + uint32_t issuer_perms, + uint32_t flags, + account_id_type issuer_account_id, + uint32_t required_sigs, + const vector
& authority + ) { try { const oasset_record asset_record = _wimpl->_blockchain->get_asset_record( symbol ); FC_ASSERT( asset_record.valid() ); @@ -698,7 +705,8 @@ transaction_builder& transaction_builder::update_asset( const string& symbol, if( !issuer_account_record.valid() ) FC_THROW_EXCEPTION( unknown_account, "Unknown issuer account id!" ); - trx.update_asset( asset_record->id, name, description, public_data, maximum_share_supply, precision ); + trx.update_asset_ext( asset_record->id, name, description, public_data, maximum_share_supply, precision, + issuer_fee, issuer_perms, flags, issuer_account_id, required_sigs, authority ); deduct_balance( issuer_account_record->active_key(), asset() ); ledger_entry entry; @@ -708,7 +716,8 @@ transaction_builder& transaction_builder::update_asset( const string& symbol, transaction_record.ledger_entries.push_back( entry ); - required_signatures.insert( issuer_account_record->active_key() ); + for( auto owner : asset_record->authority.owners ) + required_signatures.insert( owner ); return *this; } FC_CAPTURE_AND_RETHROW( (symbol)(name)(description)(public_data)(maximum_share_supply)(precision) ) } diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 0ddaabac8..5d35414c8 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -3017,20 +3017,30 @@ namespace detail { const optional& public_data, const optional& maximum_share_supply, const optional& precision, + const share_type& issuer_fee, + uint32_t issuer_perms, + uint32_t flags, + const string& issuer_account_name, + uint32_t required_sigs, + const vector
& authority, bool sign ) { try { if( NOT is_open() ) FC_CAPTURE_AND_THROW( wallet_closed ); if( NOT is_unlocked() ) FC_CAPTURE_AND_THROW( wallet_locked ); + auto issuer_account = my->_blockchain->get_account_record( issuer_account_name ); + FC_ASSERT( issuer_account.valid() ); + transaction_builder_ptr builder = create_transaction_builder(); - builder->update_asset( symbol, name, description, public_data, maximum_share_supply, precision ); + builder->update_asset( symbol, name, description, public_data, maximum_share_supply, precision, + issuer_fee, issuer_perms, flags, issuer_account->id, required_sigs, authority ); builder->finalize(); if( sign ) return builder->sign(); return builder->transaction_record; - } FC_CAPTURE_AND_RETHROW( (symbol)(name)(description)(public_data)(maximum_share_supply)(precision)(sign) ) } + } FC_CAPTURE_AND_RETHROW( (symbol)(name)(description)(public_data)(precision)(issuer_fee)(restricted)(retractable)(required_sigs)(authority)(sign) ) } wallet_transaction_record wallet::issue_asset( double amount_to_issue,