Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
b4ea9ec1
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,发现更多精彩内容 >>
提交
b4ea9ec1
编写于
3月 11, 2018
作者:
D
Daniel Larimer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
progress on margin
上级
9eb12ffd
变更
4
显示空白变更内容
内联
并排
Showing
4 changed file
with
244 addition
and
4 deletion
+244
-4
contracts/eosiolib/asset.hpp
contracts/eosiolib/asset.hpp
+21
-0
contracts/eosiolib/datastream.hpp
contracts/eosiolib/datastream.hpp
+14
-1
contracts/exchange/exchange.hpp
contracts/exchange/exchange.hpp
+197
-2
tests/wasm_tests/exchange_tests.cpp
tests/wasm_tests/exchange_tests.cpp
+12
-1
未找到文件。
contracts/eosiolib/asset.hpp
浏览文件 @
b4ea9ec1
...
...
@@ -185,6 +185,27 @@ namespace eosio {
return
result
;
}
friend
extended_asset
operator
-
(
const
extended_asset
&
a
,
const
extended_asset
&
b
)
{
eosio_assert
(
a
.
symbol
==
b
.
symbol
,
"type mismatch"
);
eosio_assert
(
a
.
contract
==
b
.
contract
,
"type mismatch"
);
extended_asset
result
(
asset
(
a
.
amount
-
b
.
amount
,
a
.
symbol
),
a
.
contract
);
if
(
b
.
amount
>
0
)
eosio_assert
(
a
.
amount
>
result
.
amount
,
"underflow"
);
if
(
b
.
amount
<
0
)
eosio_assert
(
a
.
amount
<
result
.
amount
,
"overflow"
);
return
result
;
}
friend
extended_asset
operator
+
(
const
extended_asset
&
a
,
const
extended_asset
&
b
)
{
eosio_assert
(
a
.
symbol
==
b
.
symbol
,
"type mismatch"
);
eosio_assert
(
a
.
contract
==
b
.
contract
,
"type mismatch"
);
extended_asset
result
(
asset
(
a
.
amount
+
b
.
amount
,
a
.
symbol
),
a
.
contract
);
return
result
;
}
EOSLIB_SERIALIZE
(
extended_asset
,
(
amount
)(
symbol
)(
contract
)
)
};
...
...
contracts/eosiolib/datastream.hpp
浏览文件 @
b4ea9ec1
...
...
@@ -291,10 +291,11 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, int64_t& d) {
* @param d value to serialize
*/
template
<
typename
Stream
>
inline
datastream
<
Stream
>&
operator
<<
(
datastream
<
Stream
>&
ds
,
const
uint64_t
d
)
{
inline
datastream
<
Stream
>&
operator
<<
(
datastream
<
Stream
>&
ds
,
const
uint64_t
&
d
)
{
ds
.
write
(
(
const
char
*
)
&
d
,
sizeof
(
d
)
);
return
ds
;
}
/**
* Deserialize a uint64_t from a stream
* @brief Deserialize a uint64_t
...
...
@@ -307,6 +308,18 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, uint64_t& d) {
return
ds
;
}
template
<
typename
Stream
>
inline
datastream
<
Stream
>&
operator
<<
(
datastream
<
Stream
>&
ds
,
const
double
&
d
)
{
ds
.
write
(
(
const
char
*
)
&
d
,
sizeof
(
d
)
);
return
ds
;
}
template
<
typename
Stream
>
inline
datastream
<
Stream
>&
operator
>>
(
datastream
<
Stream
>&
ds
,
double
&
d
)
{
ds
.
read
((
char
*
)
&
d
,
sizeof
(
d
)
);
return
ds
;
}
/**
* Serialize a int16_t into a stream
* @brief Serialize a int16_t
...
...
contracts/exchange/exchange.hpp
浏览文件 @
b4ea9ec1
...
...
@@ -7,6 +7,17 @@ namespace eosio {
typedef
double
real_type
;
using
boost
::
container
::
flat_map
;
struct
margin_state
{
extended_asset
total_lendable
;
extended_asset
total_lent
;
double
least_collateralized
=
0
;
extended_asset
interest_pool
;
double
interest_shares
=
0
;
EOSLIB_SERIALIZE
(
margin_state
,
(
total_lendable
)(
total_lent
)(
least_collateralized
)(
interest_pool
)(
interest_shares
)
)
};
struct
exchange_state
{
account_name
manager
;
extended_asset
supply
;
...
...
@@ -16,7 +27,9 @@ namespace eosio {
extended_asset
balance
;
uint32_t
weight
=
500
;
EOSLIB_SERIALIZE
(
connector
,
(
balance
)(
weight
)
)
margin_state
peer_margin
;
/// peer_connector collateral lending balance
EOSLIB_SERIALIZE
(
connector
,
(
balance
)(
weight
)(
peer_margin
)
)
};
connector
base
;
...
...
@@ -120,6 +133,28 @@ namespace eosio {
currency
_excurrencies
;
public:
/**
* We calculate a unique scope for each market/borrowed_symbol/collateral_symbol and then
* instantiate a table of margin positions... with in this table each user has exactly
* one position and therefore the owner can serve as the primary key.
*/
struct
margin_position
{
account_name
owner
;
extended_asset
borrowed
;
extended_asset
collateral
;
double
call_price
=
0
;
uint64_t
get_call
()
const
{
return
uint64_t
(
call_price
);
}
uint64_t
primary_key
()
const
{
return
owner
;
}
EOSLIB_SERIALIZE
(
margin_position
,
(
owner
)(
borrowed
)(
collateral
)(
call_price
)
)
};
typedef
eosio
::
multi_index
<
N
(
margins
),
margin_position
,
indexed_by
<
N
(
callprice
),
eosio
::
const_mem_fun
<
margin_position
,
uint64_t
,
&
margin_position
::
get_call
>
>
>
margins
;
exchange
(
account_name
self
)
:
_this_contract
(
self
),
_excurrencies
(
self
){}
...
...
@@ -158,6 +193,9 @@ namespace eosio {
EOSLIB_SERIALIZE
(
withdraw
,
(
from
)(
quantity
)
)
};
void
on
(
const
withdraw
&
w
)
{
require_auth
(
w
.
from
);
eosio_assert
(
w
.
quantity
.
amount
>=
0
,
"cannot withdraw negative balance"
);
...
...
@@ -165,6 +203,124 @@ namespace eosio {
currency
::
inline_transfer
(
_this_contract
,
w
.
from
,
w
.
quantity
,
"withdraw"
);
}
struct
upmargin
{
symbol_type
market
;
account_name
borrower
;
extended_asset
delta_borrow
;
extended_asset
delta_collateral
;
EOSLIB_SERIALIZE
(
upmargin
,
(
market
)(
borrower
)(
delta_borrow
)(
delta_collateral
)
)
};
void
margin_call
(
exchange_state
&
state
,
exchange_state
::
connector
&
c
,
margins
&
marginstable
)
{
auto
price_idx
=
marginstable
.
get_index
<
N
(
callprice
)
>
();
auto
pos
=
price_idx
.
begin
();
if
(
pos
==
price_idx
.
end
()
)
return
;
auto
receipt
=
convert
(
state
,
pos
->
collateral
,
pos
->
borrowed
.
get_extended_symbol
()
);
eosio_assert
(
receipt
.
amount
>=
pos
->
borrowed
.
amount
,
"programmer error: insufficient collateral to cover"
);
/// VERY BAD, SHOULD NOT HAPPEN
auto
change_debt
=
receipt
-
pos
->
borrowed
;
auto
change_collat
=
convert
(
state
,
change_debt
,
pos
->
collateral
.
get_extended_symbol
()
);
adjust_balance
(
pos
->
owner
,
change_collat
);
c
.
peer_margin
.
total_lent
.
amount
-=
pos
->
borrowed
.
amount
;
price_idx
.
erase
(
pos
);
pos
=
price_idx
.
begin
();
if
(
pos
!=
price_idx
.
end
()
)
c
.
peer_margin
.
least_collateralized
=
pos
->
call_price
;
else
c
.
peer_margin
.
least_collateralized
=
double
(
uint64_t
(
-
1
));
}
void
on
(
const
upmargin
&
b
)
{
require_auth
(
b
.
borrower
);
auto
marketid
=
b
.
market
.
name
();
margins
base_margins
(
_this_contract
,
marketid
);
margins
quote_margins
(
_this_contract
,
marketid
<<
1
);
markets
market_table
(
_this_contract
,
marketid
);
auto
market_state
=
market_table
.
find
(
marketid
);
eosio_assert
(
market_state
!=
market_table
.
end
(),
"unknown market"
);
auto
state
=
*
market_state
;
eosio_assert
(
b
.
delta_borrow
.
amount
!=
0
||
b
.
delta_collateral
.
amount
!=
0
,
"no effect"
);
eosio_assert
(
b
.
delta_borrow
.
get_extended_symbol
()
!=
b
.
delta_collateral
.
get_extended_symbol
(),
"invalid args"
);
eosio_assert
(
state
.
base
.
balance
.
get_extended_symbol
()
==
b
.
delta_borrow
.
get_extended_symbol
()
||
state
.
quote
.
balance
.
get_extended_symbol
()
==
b
.
delta_borrow
.
get_extended_symbol
(),
"invalid asset for market"
);
eosio_assert
(
state
.
base
.
balance
.
get_extended_symbol
()
==
b
.
delta_collateral
.
get_extended_symbol
()
||
state
.
quote
.
balance
.
get_extended_symbol
()
==
b
.
delta_collateral
.
get_extended_symbol
(),
"invalid asset for market"
);
auto
adjust_margin
=
[
&
b
](
exchange_state
::
connector
&
c
,
margins
&
mtable
)
{
margin_position
temp_pos
;
auto
existing
=
mtable
.
find
(
b
.
borrower
);
if
(
existing
==
mtable
.
end
()
)
{
eosio_assert
(
b
.
delta_borrow
.
amount
>
0
,
"borrow neg"
);
eosio_assert
(
b
.
delta_collateral
.
amount
>
0
,
"collat neg"
);
temp_pos
.
owner
=
b
.
borrower
;
temp_pos
.
borrowed
=
b
.
delta_borrow
;
temp_pos
.
collateral
=
b
.
delta_collateral
;
temp_pos
.
call_price
=
double
(
temp_pos
.
collateral
.
amount
)
/
temp_pos
.
borrowed
.
amount
;
}
else
{
temp_pos
=
*
existing
;
temp_pos
.
borrowed
+=
b
.
delta_borrow
;
temp_pos
.
collateral
+=
b
.
delta_borrow
;
eosio_assert
(
temp_pos
.
borrowed
.
amount
>
0
,
"neg borrowed"
);
eosio_assert
(
temp_pos
.
collateral
.
amount
>
0
,
"neg collateral"
);
if
(
temp_pos
.
borrowed
.
amount
>
0
)
temp_pos
.
call_price
=
double
(
temp_pos
.
collateral
.
amount
)
/
temp_pos
.
borrowed
.
amount
;
else
temp_pos
.
call_price
=
double
(
uint64_t
(
-
1
)
);
}
c
.
peer_margin
.
total_lent
+=
b
.
delta_borrow
;
auto
least
=
mtable
.
begin
();
if
(
least
==
existing
)
++
least
;
if
(
least
!=
mtable
.
end
()
)
c
.
peer_margin
.
least_collateralized
=
least
->
call_price
;
if
(
temp_pos
.
call_price
<
c
.
peer_margin
.
least_collateralized
)
c
.
peer_margin
.
least_collateralized
=
temp_pos
.
call_price
;
};
auto
temp_state
=
state
;
margins
*
mt
=
nullptr
;
auto
baseptr
=
&
exchange_state
::
base
;
auto
quoteptr
=
&
exchange_state
::
quote
;
auto
conptr
=
quoteptr
;
if
(
b
.
delta_borrow
.
get_extended_symbol
()
==
state
.
base
.
balance
.
get_extended_symbol
()
)
{
mt
=
&
base_margins
;
conptr
=
baseptr
;
}
else
{
mt
=
&
quote_margins
;
}
adjust_margin
(
temp_state
.
*
conptr
,
*
mt
);
while
(
requires_margin_call
(
temp_state
)
)
{
// margin_call( state );
temp_state
=
state
;
adjust_margin
(
temp_state
.
*
conptr
,
*
mt
);
}
adjust_margin
(
state
.
*
conptr
,
*
mt
);
/// if this succeeds then the borrower will see their balances adjusted accordingly,
/// if they don't have sufficient balance to either fund the collateral or pay off the
/// debt then this will fail before we go further.
adjust_balance
(
b
.
borrower
,
b
.
delta_borrow
,
"borrowed"
);
adjust_balance
(
b
.
borrower
,
-
b
.
delta_collateral
,
"collateral"
);
}
struct
trade
{
account_name
seller
;
symbol_type
market
;
...
...
@@ -176,6 +332,20 @@ namespace eosio {
EOSLIB_SERIALIZE
(
trade
,
(
seller
)(
market
)(
sell
)(
min_receive
)(
expire
)(
fill_or_kill
)
)
};
bool
requires_margin_call
(
const
exchange_state
&
state
,
const
exchange_state
::
connector
&
con
)
{
if
(
con
.
peer_margin
.
total_lent
.
amount
>
0
)
{
auto
tmp
=
state
;
auto
base_total_col
=
int64_t
(
con
.
peer_margin
.
total_lent
.
amount
*
con
.
peer_margin
.
least_collateralized
);
auto
covered
=
convert
(
tmp
,
extended_asset
(
base_total_col
,
con
.
balance
.
get_extended_symbol
()),
con
.
peer_margin
.
total_lent
.
get_extended_symbol
()
);
if
(
covered
.
amount
<=
con
.
peer_margin
.
total_lent
.
amount
)
return
true
;
}
return
false
;
}
bool
requires_margin_call
(
const
exchange_state
&
state
)
{
return
requires_margin_call
(
state
,
state
.
base
)
||
requires_margin_call
(
state
,
state
.
quote
);
}
extended_asset
convert
(
exchange_state
&
state
,
extended_asset
from
,
extended_symbol
to
)
{
auto
sell_symbol
=
from
.
get_extended_symbol
();
auto
ex_symbol
=
extended_symbol
(
state
.
supply
.
symbol
,
_this_contract
);
...
...
@@ -217,8 +387,22 @@ namespace eosio {
eosio_assert
(
market_state
!=
market_table
.
end
(),
"unknown market"
);
auto
state
=
*
market_state
;
auto
temp
=
state
;
auto
output
=
convert
(
temp
,
t
.
sell
,
t
.
min_receive
.
get_extended_symbol
()
);
margins
base_margins
(
_this_contract
,
marketid
);
margins
quote_margins
(
_this_contract
,
marketid
<<
1
);
while
(
requires_margin_call
(
temp
)
)
{
if
(
t
.
sell
.
get_extended_symbol
()
==
state
.
base
.
balance
.
get_extended_symbol
()
)
{
margin_call
(
state
,
state
.
quote
,
quote_margins
);
}
else
{
margin_call
(
state
,
state
.
base
,
base_margins
);
}
temp
=
state
;
output
=
convert
(
temp
,
t
.
sell
,
t
.
min_receive
.
get_extended_symbol
()
);
}
state
=
temp
;
auto
output
=
convert
(
state
,
t
.
sell
,
t
.
min_receive
.
get_extended_symbol
()
);
print
(
name
(
t
.
seller
),
" "
,
t
.
sell
,
" => "
,
output
,
"
\n
"
);
if
(
t
.
min_receive
.
amount
!=
0
)
{
...
...
@@ -259,6 +443,7 @@ namespace eosio {
typedef
eosio
::
multi_index
<
N
(
exaccounts
),
exaccount
>
exaccounts
;
/**
* Keep a cache of all accounts tables we access
*/
...
...
@@ -309,6 +494,16 @@ namespace eosio {
s
.
supply
=
extended_asset
(
c
.
initial_supply
,
_this_contract
);
s
.
base
.
balance
=
c
.
base_deposit
;
s
.
quote
.
balance
=
c
.
quote_deposit
;
s
.
base
.
peer_margin
.
total_lent
.
symbol
=
c
.
base_deposit
.
symbol
;
s
.
base
.
peer_margin
.
total_lent
.
contract
=
c
.
base_deposit
.
contract
;
s
.
base
.
peer_margin
.
total_lendable
.
symbol
=
c
.
base_deposit
.
symbol
;
s
.
base
.
peer_margin
.
total_lendable
.
contract
=
c
.
base_deposit
.
contract
;
s
.
quote
.
peer_margin
.
total_lent
.
symbol
=
c
.
quote_deposit
.
symbol
;
s
.
quote
.
peer_margin
.
total_lent
.
contract
=
c
.
quote_deposit
.
contract
;
s
.
quote
.
peer_margin
.
total_lendable
.
symbol
=
c
.
quote_deposit
.
symbol
;
s
.
quote
.
peer_margin
.
total_lendable
.
contract
=
c
.
quote_deposit
.
contract
;
});
_excurrencies
.
create_currency
(
{
.
issuer
=
_this_contract
,
...
...
tests/wasm_tests/exchange_tests.cpp
浏览文件 @
b4ea9ec1
...
...
@@ -24,6 +24,16 @@ using namespace eosio::chain::contracts;
using
namespace
eosio
::
testing
;
using
namespace
fc
;
struct
margin_state
{
extended_asset
total_lendable
;
extended_asset
total_lent
;
double
least_collateralized
=
0
;
extended_asset
interest_pool
;
double
interest_shares
=
0
;
};
FC_REFLECT
(
margin_state
,
(
total_lendable
)(
total_lent
)(
least_collateralized
)(
interest_pool
)(
interest_shares
)
)
struct
exchange_state
{
account_name
manager
;
extended_asset
supply
;
...
...
@@ -32,13 +42,14 @@ struct exchange_state {
struct
connector
{
extended_asset
balance
;
uint32_t
weight
=
500
;
margin_state
peer_margin
;
};
connector
base
;
connector
quote
;
};
FC_REFLECT
(
exchange_state
::
connector
,
(
balance
)(
weight
)
);
FC_REFLECT
(
exchange_state
::
connector
,
(
balance
)(
weight
)
(
peer_margin
)
);
FC_REFLECT
(
exchange_state
,
(
manager
)(
supply
)(
fee
)(
base
)(
quote
)
);
class
exchange_tester
:
public
tester
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录