Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
715b1219
Y
YTBP
项目概览
YottaChain
/
YTBP
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
YTBP
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
715b1219
编写于
3月 02, 2018
作者:
D
Daniel Larimer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update exchange, implement find for secondary index
上级
fee30e1c
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
267 addition
and
382 deletion
+267
-382
contracts/CMakeLists.txt
contracts/CMakeLists.txt
+2
-2
contracts/eosiolib/datastream.hpp
contracts/eosiolib/datastream.hpp
+13
-0
contracts/eosiolib/dispatcher.hpp
contracts/eosiolib/dispatcher.hpp
+2
-2
contracts/eosiolib/multi_index.hpp
contracts/eosiolib/multi_index.hpp
+16
-3
contracts/eosiolib/table.hpp
contracts/eosiolib/table.hpp
+2
-0
contracts/eosiolib/token.hpp
contracts/eosiolib/token.hpp
+23
-1
contracts/exchange/exchange.cpp
contracts/exchange/exchange.cpp
+7
-320
contracts/exchange/exchange.hpp
contracts/exchange/exchange.hpp
+202
-54
未找到文件。
contracts/CMakeLists.txt
浏览文件 @
715b1219
...
...
@@ -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
)
...
...
contracts/eosiolib/datastream.hpp
浏览文件 @
715b1219
...
...
@@ -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
...
...
contracts/eosiolib/dispatcher.hpp
浏览文件 @
715b1219
...
...
@@ -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
);
...
...
contracts/eosiolib/multi_index.hpp
浏览文件 @
715b1219
...
...
@@ -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
);
...
...
contracts/eosiolib/table.hpp
浏览文件 @
715b1219
#pragma once
#include <eosiolib/system.h>
#include <eosiolib/db.h>
#include <eosiolib/datastream.hpp>
namespace
eosio
{
...
...
contracts/eosiolib/token.hpp
浏览文件 @
715b1219
...
...
@@ -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
;
};
/// @}
...
...
contracts/exchange/exchange.cpp
浏览文件 @
715b1219
/**
* @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
,
"
\n
match 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\n
match 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
);
}
}
contracts/exchange/exchange.hpp
浏览文件 @
715b1219
...
...
@@ -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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录