提交 715b1219 编写于 作者: D Daniel Larimer

update exchange, implement find for secondary index

上级 fee30e1c
......@@ -8,15 +8,15 @@ add_subdirectory(eosiolib)
add_subdirectory(musl)
add_subdirectory(libc++)
add_subdirectory(multi_index_test)
add_subdirectory(eosio.system)
add_subdirectory(identity)
add_subdirectory(currency)
add_subdirectory(stltest)
add_subdirectory(exchange)
#add_subdirectory(bancor)
#add_subdirectory(eosio.system)
add_subdirectory(asserter)
#add_subdirectory(exchange)
add_subdirectory(infinite)
add_subdirectory(proxy)
add_subdirectory(test_api)
......
......@@ -246,6 +246,19 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, uint32_t& d) {
return ds;
}
template<typename Stream>
inline datastream<Stream>& operator<<(datastream<Stream>& ds, const bool& d) {
return ds << uint8_t(d);
}
template<typename Stream>
inline datastream<Stream>& operator>>(datastream<Stream>& ds, bool& d) {
uint8_t t;
ds >> t;
d = t;
return ds;
}
/**
* Serialize a int64_t into a stream
* @brief Serialize a int64_t
......
......@@ -6,7 +6,7 @@ namespace eosio {
template<typename Contract, typename FirstAction>
bool dispatch( uint64_t code, uint64_t act ) {
if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
Contract::on( unpack_action<FirstAction>() );
Contract().on( unpack_action<FirstAction>() );
return true;
}
return false;
......@@ -26,7 +26,7 @@ namespace eosio {
template<typename Contract, typename FirstAction, typename SecondAction, typename... Actions>
bool dispatch( uint64_t code, uint64_t act ) {
if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
Contract::on( unpack_action<FirstAction>() );
Contract().on( unpack_action<FirstAction>() );
return true;
}
return eosio::dispatch<Contract,SecondAction,Actions...>( code, act );
......
......@@ -96,7 +96,8 @@ struct indexed_by {
template<uint64_t TableName, uint64_t IndexName, typename T, typename Extractor, int N = 0>
struct index_by {
typedef Extractor extractor_secondary_type;
typedef Extractor extractor_secondary_type;
typedef Extractor secondary_extractor_type;
typedef typename std::decay<decltype( Extractor()(nullptr) )>::type secondary_type;
index_by(){}
......@@ -271,6 +272,7 @@ class multi_index
typedef typename IndexType::secondary_type secondary_key_type;
public:
typedef typename IndexType::secondary_extractor_type secondary_extractor_type;
static constexpr uint64_t name() { return IndexType::name(); }
struct const_iterator {
......@@ -367,6 +369,16 @@ class multi_index
const_iterator begin()const {
return lower_bound(typename IndexType::secondary_type());
}
const_iterator find( typename IndexType::secondary_type&& secondary )const {
auto lb = lower_bound( secondary );
auto e = end();
if( lb == e ) return e;
if( secondary != typename IndexType::extractor_secondary_type()(*lb) )
return e;
return lb;
}
const_iterator lower_bound( typename IndexType::secondary_type&& secondary )const {
return lower_bound( secondary );
}
......@@ -471,7 +483,8 @@ class multi_index
const_iterator end()const { return const_iterator( *this ); }
const_iterator begin()const { return lower_bound(); }
const_iterator lower_bound( uint64_t primary = 0 )const {
const_iterator lower_bound( uint64_t primary = 0 )const {
auto itr = db_lowerbound_i64( _code, _scope, TableName, primary );
if( itr < 0 ) return end();
auto& obj = load_object_by_primary_iterator( itr );
......@@ -604,7 +617,7 @@ class multi_index
void remove( const T& obj ) {
const auto& objitem = static_cast<const item&>(obj);
auto& mutableitem = const_cast<item&>(objitem);
//auto& mutableitem = const_cast<item&>(objitem);
// eosio_assert( &objitem.__idx == this, "invalid object" );
db_remove_i64( objitem.__primary_itr );
......
#pragma once
#include <eosiolib/system.h>
#include <eosiolib/db.h>
#include <eosiolib/datastream.hpp>
namespace eosio {
......
......@@ -9,6 +9,7 @@
#include <eosiolib/print.hpp>
#include <eosiolib/reflect.hpp>
#include <eosiolib/asset.hpp>
#include <eosiolib/serialize.hpp>
namespace eosio {
......@@ -20,6 +21,9 @@ namespace eosio {
* @{
*/
template<typename BaseToken, typename QuoteToken>
struct price;
template< uint64_t Code,
uint64_t Symbol,
typename NumberType = uint64_t
......@@ -38,6 +42,10 @@ namespace eosio {
*/
token(){}
template<typename Base, typename Quote>
friend price<Base,Quote> operator / ( const Base& b, const Quote& q );
operator asset()const { return asset( quantity, Symbol ); }
token( const asset& a ):quantity(a.amount) {
......@@ -190,6 +198,10 @@ namespace eosio {
QuoteToken quote;
};
template<typename Base, typename Quote>
price<Base,Quote> operator / ( const Base& b, const Quote& q ) {
return price<Base,Quote>(b,q);
}
/**
......@@ -250,6 +262,11 @@ namespace eosio {
* @brief Default constructor.
*/
price():base_per_quote(1ul){}
explicit price( uint128_t b ):base_per_quote(b){}
price& operator=( uint128_t b ) {
base_per_quote = b;
return *this;
}
/**
* Construction for price given the base token and quote token.
......@@ -343,14 +360,19 @@ namespace eosio {
*/
friend bool operator != ( const price& a, const price& b ) { return a.base_per_quote != b.base_per_quote; }
operator uint128_t()const { return base_per_quote; }
EOSLIB_SERIALIZE( price, (base_per_quote) )
private:
/**
* Represents as number of base tokens to purchase 1 quote token.
* @brief Represents number of base tokens to purchase 1 quote token.
*/
eosio::uint128 base_per_quote;
uint128_t base_per_quote;
};
/// @}
......
/**
* @file exchange.cpp
* @copyright defined in eos/LICENSE.txt
* @brief defines an example exchange contract
*
* This exchange contract assumes the existence of two currency contracts
* located at @currencya and @currencyb. These currency contracts have
* provided an API header defined in currency.hpp which the exchange
* contract will use to process messages related to deposits and withdraws.
*
* The exchange contract knows that the currency contracts require_notice()
* of both the sender and receiver; therefore, the exchange contract can
* implement a message handler that will be called anytime funds are deposited
* to or withdrawn from the exchange.
*
* When tokens are sent to @exchange from another account the exchange will
* credit the user's balance of the proper currency.
*
* To withdraw from the exchange, the user simply reverses the "to" and "from"
* fields of the currency contract transfer message. The currency contract will
* require the "authority" of the exchange, but the exchange's init() function
* configured this permission to allow *anyone* to transfer from the exchange.
*
* To prevent people from stealing all the money from the exchange, the
* exchange's transfer handler requires both the authority of the receiver and
* asserts that the user has a sufficient balance on the exchange. Lacking
* both of these the exchange will kill the transfer.
*
* The exchange and one of the currency contracts are forced to execute in the same
* thread anytime there is a deposit or withdraw. The transaction containing
* the transfer are already required to include the exchange in the scope by
* the currency contract.
*
* creating, canceling, and filling orders do not require blocking either currency
* contract. Users can only deposit or withdraw to their own currency account.
*/
#include <exchange/exchange.hpp> /// defines transfer struct
#include <eosiolib/print.hpp>
using namespace exchange;
using namespace eosio;
namespace exchange {
inline void save( const account& a ) {
if( a.is_empty() ) {
print("remove");
accounts::remove(a);
}
else {
print("store");
accounts::store(a);
}
}
template<typename Lambda>
inline void modify_account( account_name a, Lambda&& modify ) {
auto acnt = get_account( a );
modify( acnt );
save( acnt );
}
/**
* This method is called after the "transfer" action of code
* "currencya" is called and "exchange" is listed in the notifiers.
*/
void apply_currency_transfer( const currency::transfer& transfer ) {
if( transfer.to == N(exchange) ) {
modify_account( transfer.from, [&]( account& mod_account ){
mod_account.currency_balance += transfer.quantity;
});
} else if( transfer.from == N(exchange) ) {
require_auth( transfer.to ); /// require the receiver of funds (account owner) to authorize this transfer
modify_account( transfer.to, [&]( account& mod_account ){
mod_account.currency_balance -= transfer.quantity;
});
} else {
eosio_assert( false, "notified on transfer that is not relevant to this exchange" );
}
}
/**
* This method is called after the "transfer" action of code
* "currencya" is called and "exchange" is listed in the notifiers.
*/
void apply_eos_transfer( const eosio::transfer& transfer ) {
if( transfer.to == N(exchange) ) {
modify_account( transfer.from, [&]( account& mod_account ){
mod_account.eos_balance += transfer.quantity;
});
} else if( transfer.from == N(exchange) ) {
require_auth( transfer.to ); /// require the receiver of funds (account owner) to authorize this transfer
modify_account( transfer.to, [&]( account& mod_account ){
mod_account.eos_balance -= transfer.quantity;
});
} else {
eosio_assert( false, "notified on transfer that is not relevant to this exchange" );
}
}
void match( bid& bid_to_match, account& buyer, ask& ask_to_match, account& seller ) {
print( "match bid: ", bid_to_match, "\nmatch ask: ", ask_to_match, "\n");
eosio::tokens ask_eos = ask_to_match.quantity * ask_to_match.at_price;
eos_tokens fill_amount_eos = min<eosio::tokens>( ask_eos, bid_to_match.quantity );
currency_tokens fill_amount_currency;
if( fill_amount_eos == ask_eos ) { /// complete fill of ask_to_match
fill_amount_currency = ask_to_match.quantity;
} else { /// complete fill of buy
fill_amount_currency = fill_amount_eos / ask_to_match.at_price;
}
print( "\n\nmatch bid: ", name(bid_to_match.buyer.name), ":", bid_to_match.buyer.number,
"match ask: ", name(ask_to_match.seller.name), ":", ask_to_match.seller.number, "\n\n" );
bid_to_match.quantity -= fill_amount_eos;
seller.eos_balance += fill_amount_eos;
ask_to_match.quantity -= fill_amount_currency;
buyer.currency_balance += fill_amount_currency;
}
/**
*
*
*/
void apply_exchange_buy( buy_order order ) {
bid& exchange_bid = order;
require_auth( exchange_bid.buyer.name );
eosio_assert( exchange_bid.quantity > eosio::tokens(0), "invalid quantity" );
eosio_assert( exchange_bid.expiration > now(), "order expired" );
print( name(exchange_bid.buyer.name), " created bid for ", order.quantity, " currency at price: ", order.at_price, "\n" );
bid existing_bid;
eosio_assert( !bids_by_id::get( exchange_bid.buyer, existing_bid ), "order with this id already exists" );
print( __FILE__, __LINE__, "\n" );
auto buyer_account = get_account( exchange_bid.buyer.name );
buyer_account.eos_balance -= exchange_bid.quantity;
ask lowest_ask;
if( !asks_by_price::front( lowest_ask ) ) {
print( "\n No asks found, saving buyer account and storing bid\n" );
eosio_assert( !order.fill_or_kill, "order not completely filled" );
bids::store( exchange_bid );
buyer_account.open_orders++;
save( buyer_account );
return;
}
print( "ask: ", lowest_ask, "\n" );
print( "bid: ", exchange_bid, "\n" );
auto seller_account = get_account( lowest_ask.seller.name );
while( lowest_ask.at_price <= exchange_bid.at_price ) {
print( "lowest ask <= exchange_bid.at_price\n" );
match( exchange_bid, buyer_account, lowest_ask, seller_account );
if( lowest_ask.quantity == currency_tokens(0) ) {
seller_account.open_orders--;
save( seller_account );
save( buyer_account );
asks::remove( lowest_ask );
if( !asks_by_price::front( lowest_ask ) ) {
break;
}
seller_account = get_account( lowest_ask.seller.name );
} else {
break; // buyer's bid should be filled
}
}
print( "lowest_ask >= exchange_bid.at_price or buyer's bid has been filled\n" );
if( exchange_bid.quantity && !order.fill_or_kill ) buyer_account.open_orders++;
save( buyer_account );
print( "saving buyer's account\n" );
if( exchange_bid.quantity ) {
print( exchange_bid.quantity, " eos left over" );
eosio_assert( !order.fill_or_kill, "order not completely filled" );
bids::store( exchange_bid );
return;
}
print( "bid filled\n" );
}
void apply_exchange_sell( sell_order order ) {
ask& exchange_ask = order;
require_auth( exchange_ask.seller.name );
eosio_assert( exchange_ask.quantity > currency_tokens(0), "invalid quantity" );
eosio_assert( exchange_ask.expiration > now(), "order expired" );
print( "\n\n", name(exchange_ask.seller.name), " created sell for ", order.quantity,
" currency at price: ", order.at_price, "\n");
ask existing_ask;
eosio_assert( !asks_by_id::get( exchange_ask.seller, existing_ask ), "order with this id already exists" );
auto seller_account = get_account( exchange_ask.seller.name );
seller_account.currency_balance -= exchange_ask.quantity;
bid highest_bid;
if( !bids_by_price::back( highest_bid ) ) {
eosio_assert( !order.fill_or_kill, "order not completely filled" );
print( "\n No bids found, saving seller account and storing ask\n" );
asks::store( exchange_ask );
seller_account.open_orders++;
save( seller_account );
return;
}
print( "\n bids found, lets see what matches\n" );
auto buyer_account = get_account( highest_bid.buyer.name );
while( highest_bid.at_price >= exchange_ask.at_price ) {
match( highest_bid, buyer_account, exchange_ask, seller_account );
if( highest_bid.quantity == eos_tokens(0) ) {
buyer_account.open_orders--;
save( seller_account );
save( buyer_account );
bids::remove( highest_bid );
if( !bids_by_price::back( highest_bid ) ) {
break;
}
buyer_account = get_account( highest_bid.buyer.name );
} else {
break; // buyer's bid should be filled
}
}
if( exchange_ask.quantity && !order.fill_or_kill ) seller_account.open_orders++;
save( seller_account );
if( exchange_ask.quantity ) {
eosio_assert( !order.fill_or_kill, "order not completely filled" );
print( "saving ask\n" );
asks::store( exchange_ask );
return;
}
print( "ask filled\n" );
}
void apply_exchange_cancel_buy( order_id order ) {
require_auth( order.name );
bid bid_to_cancel;
eosio_assert( bids_by_id::get( order, bid_to_cancel ), "bid with this id does not exists" );
auto buyer_account = get_account( order.name );
buyer_account.eos_balance += bid_to_cancel.quantity;
buyer_account.open_orders--;
bids::remove( bid_to_cancel );
save( buyer_account );
print( "bid removed\n" );
}
void apply_exchange_cancel_sell( order_id order ) {
require_auth( order.name );
ask ask_to_cancel;
eosio_assert( asks_by_id::get( order, ask_to_cancel ), "ask with this id does not exists" );
auto seller_account = get_account( order.name );
seller_account.currency_balance += ask_to_cancel.quantity;
seller_account.open_orders--;
asks::remove( ask_to_cancel );
save( seller_account );
print( "ask removed\n" );
}
} // namespace exchange
#include "exchange.hpp"
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t act ) {
typedef eosio::generic_currency< eosio::token<N(eosio.system),S(4,EOS)> > eos;
typedef eosio::generic_currency< eosio::token<N(currency),S(4,CUR)> > cur;
// void validate( uint64_t code, uint64_t action ) { }
// void precondition( uint64_t code, uint64_t action ) { }
/**
* The apply method implements the dispatch of events to this contract
*/
void apply( uint64_t code, uint64_t action ) {
if( code == N(exchange) ) {
switch( action ) {
case N(buy):
apply_exchange_buy( current_action<exchange::buy_order>() );
break;
case N(sell):
apply_exchange_sell( current_action<exchange::sell_order>() );
break;
case N(cancelbuy):
apply_exchange_cancel_buy( current_action<exchange::order_id>() );
break;
case N(cancelsell):
apply_exchange_cancel_sell( current_action<exchange::order_id>() );
break;
default:
eosio_assert( false, "unknown action" );
}
}
else if( code == N(currency) ) {
if( action == N(transfer) )
apply_currency_transfer( current_action<currency::transfer>() );
}
else if( code == N(eos) ) {
if( action == N(transfer) )
apply_eos_transfer( current_action<eosio::transfer>() );
}
else {
}
}
exchange<N(exchange), S(4,EXC), eos, cur>::apply( code, act );
}
}
......@@ -2,78 +2,226 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <currency/currency.hpp>
#include <eosiolib/generic_currency.hpp>
#include <eosiolib/multi_index.hpp>
namespace exchange {
using eosio::asset;
using eosio::symbol_name;
using eosio::indexed_by;
using eosio::const_mem_fun;
using eosio::price_ratio;
using eosio::price;
using currency::currency_tokens;
using eos_tokens = eosio::tokens;
template<account_name ExchangeAccount, symbol_name ExchangeSymbol,
typename BaseCurrency, typename QuoteCurrency>
class exchange {
public:
typedef eosio::generic_currency< eosio::token<ExchangeAccount,ExchangeSymbol> > exchange_currency;
//@abi action cancelbuy cancelsell
struct order_id {
account_name name = 0;
uint64_t number = 0;
};
typedef typename BaseCurrency::token_type base_token_type;
typedef typename QuoteCurrency::token_type quote_token_type;
typedef typename exchange_currency::token_type ex_token_type;
typedef eosio::price<eos_tokens,currency_tokens> price;
struct account {
account_name owner;
base_token_type base_balance;
quote_token_type quote_balance;
//@abi table
struct PACKED( bid ) {
order_id buyer;
price at_price;
eosio::tokens quantity;
time expiration;
uint64_t primary_key()const { return owner; }
void print() {
eosio::print( "{ quantity: ", quantity, ", price: ", at_price, " }" );
EOSLIB_SERIALIZE( account, (owner)(base_balance)(quote_balance) )
};
typedef eosio::multi_index< N(accounts), account> account_index_type;
template<typename BaseTokenType, typename QuoteTokenType>
struct limit_order {
typedef eosio::price<BaseTokenType, QuoteTokenType> price_type;
static const uint64_t precision = (1000ll * 1000ll * 1000ll * 1000ll);
uint64_t primary;
account_name owner;
uint32_t id;
uint32_t expiration;
BaseTokenType for_sale;
price_type sell_price;
uint64_t primary_key()const { return primary; }
uint128_t by_owner_id()const { return get_owner_id( owner, id ); }
uint64_t by_expiration()const { return expiration; }
uint128_t by_price()const { return sell_price; }
static uint128_t get_price( BaseTokenType base, QuoteTokenType quote ) {
return (uint128_t( precision ) * base.quantity ) / quote.quantity;
}
static uint128_t get_owner_id( account_name owner, uint32_t id ) { return (uint128_t( owner ) << 64) | id; }
EOSLIB_SERIALIZE( limit_order, (primary)(owner)(id)(expiration)(for_sale)(sell_price) )
};
typedef limit_order<base_token_type, quote_token_type> limit_base_quote;
typedef eosio::multi_index< N(sellbq), limit_base_quote,
indexed_by< N(price), const_mem_fun<limit_base_quote, uint128_t, &limit_base_quote::by_price > >,
indexed_by< N(ownerid), const_mem_fun<limit_base_quote, uint128_t, &limit_base_quote::by_owner_id> >,
indexed_by< N(expire), const_mem_fun<limit_base_quote, uint64_t, &limit_base_quote::by_expiration> >
> limit_base_quote_index;
typedef limit_order<quote_token_type, base_token_type> limit_quote_base;
typedef eosio::multi_index< N(sellqb), limit_quote_base,
indexed_by< N(price), const_mem_fun<limit_quote_base, uint128_t, &limit_quote_base::by_price > >,
indexed_by< N(ownerid), const_mem_fun<limit_quote_base, uint128_t, &limit_quote_base::by_owner_id> >,
indexed_by< N(expire), const_mem_fun<limit_quote_base, uint64_t, &limit_quote_base::by_expiration> >
> limit_quote_base_index;
account_index_type _accounts;
limit_base_quote_index _base_quote_orders;
limit_base_quote_index _quote_base_orders;
exchange()
:_accounts( ExchangeAccount, ExchangeAccount ),
_base_quote_orders( ExchangeAccount, ExchangeAccount ),
_quote_base_orders( ExchangeAccount, ExchangeAccount )
{
}
};
static_assert( sizeof(bid) == 32+12, "unexpected padding" );
//@abi table
struct PACKED( ask ) {
order_id seller;
price at_price;
currency_tokens quantity;
time expiration;
void print() {
eosio::print( "{ quantity: ", quantity, ", price: ", at_price, " }" );
ACTION( ExchangeAccount, deposit ) {
account_name from;
asset amount;
EOSLIB_SERIALIZE( deposit, (from)(amount) )
};
void on( const deposit& d ) {
require_auth( d.from );
const account* owner = _accounts.find( d.from );
if( !owner ) {
owner = &_accounts.emplace( d.from, [&]( auto& a ) {
a.owner = d.from;
});
}
switch( d.amount.symbol ) {
case base_token_type::symbol:
BaseCurrency::inline_transfer( d.from, ExchangeAccount, base_token_type(d.amount.amount) );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.base_balance += base_token_type(d.amount);
});
break;
case quote_token_type::symbol:
QuoteCurrency::inline_transfer( d.from, ExchangeAccount, quote_token_type(d.amount.amount) );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.quote_balance += quote_token_type(d.amount);
});
break;
default:
eosio_assert( false, "invalid symbol" );
}
}
};
static_assert( sizeof(ask) == 32+12, "unexpected padding" );
//@abi table i64
struct PACKED( account ) {
account( account_name o = account_name() ):owner(o){}
ACTION( ExchangeAccount, withdraw ) {
account_name to;
asset amount;
account_name owner;
eos_tokens eos_balance;
currency_tokens currency_balance;
uint32_t open_orders = 0;
EOSLIB_SERIALIZE( withdraw, (to)(amount) )
};
bool is_empty()const { return ! ( bool(eos_balance) | bool(currency_balance) | open_orders); }
};
void on( const withdraw& w ) {
require_auth( w.to );
using accounts = eosio::table<N(exchange),N(exchange),N(account),account,uint64_t>;
const account* owner = _accounts.find( w.to );
eosio_assert( owner != nullptr, "unknown exchange account" );
TABLE2(bids,exchange,exchange,bids,bid,bids_by_id,order_id,bids_by_price,price);
TABLE2(asks,exchange,exchange,asks,ask,asks_by_id,order_id,asks_by_price,price);
switch( w.amount.symbol ) {
case base_token_type::symbol:
eosio_assert( owner->base_balance >= base_token_type(w.amount), "insufficient balance" );
_accounts.update( *owner, 0, [&]( auto& a ) {
a.base_balance -= base_token_type(w.amount);
});
BaseCurrency::inline_transfer( ExchangeAccount, w.to, base_token_type(w.amount.amount) );
break;
case quote_token_type::symbol:
eosio_assert( owner->quote_balance >= quote_token_type(w.amount), "insufficient balance" );
//@abi action buy
struct buy_order : public bid { uint8_t fill_or_kill = false; };
_accounts.update( *owner, 0, [&]( auto& a ) {
a.quote_balance -= quote_token_type(w.amount);
});
//@abi action sell
struct sell_order : public ask { uint8_t fill_or_kill = false; };
QuoteCurrency::inline_transfer( ExchangeAccount, w.to, quote_token_type(w.amount.amount) );
break;
default:
eosio_assert( false, "invalid symbol" );
}
}
ACTION( ExchangeAccount, neworder ) {
account_name owner;
uint32_t id;
asset amount_to_sell;
bool fill_or_kill;
uint128_t sell_price;
uint32_t expiration;
EOSLIB_SERIALIZE( neworder, (owner)(id)(amount_to_sell)(fill_or_kill)(sell_price)(expiration) )
};
void on( const neworder& order ) {
require_auth( order.owner );
if( order.amount_to_sell.symbol == base_token_type::symbol ) {
_base_quote_orders.emplace( order.owner, [&]( auto& o ) {
o.primary = 0;// _base_quote_orders.next_available_id()
o.owner = order.owner;
o.id = order.id;
o.expiration = order.expiration;
o.for_sale = order.amount_to_sell;
o.sell_price = order.sell_price;
});
}
else if( order.amount_to_sell.symbol == quote_token_type::symbol ) {
_quote_base_orders.emplace( order.owner, [&]( auto& o ) {
o.primary = 0;// _base_quote_orders.next_available_id()
o.owner = order.owner;
o.id = order.id;
o.expiration = order.expiration;
o.for_sale = order.amount_to_sell;
o.sell_price = order.sell_price;
});
}
}
inline account get_account( account_name owner ) {
account owned_account(owner);
accounts::get( owned_account );
return owned_account;
ACTION( ExchangeAccount, cancelorder ) {
account_name owner;
uint32_t id;
EOSLIB_SERIALIZE( cancelorder, (owner)(id) )
};
void on( const cancelorder& order ) {
require_auth( order.owner );
auto idx = _base_quote_orders.template get_index<N(ownerid)>();
auto itr = idx.find( limit_base_quote::get_owner_id( order.owner, order.id ) );
if( itr != idx.end() ) {
_base_quote_orders.remove(*itr);
}
}
}
}
static void apply( uint64_t code, uint64_t act ) {
if( !eosio::dispatch<exchange,
deposit, withdraw,
neworder, cancelorder
>( code, act ) ) {
exchange::exchange_currency::apply( code, act );
}
}
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册