基于以太坊的交易所BANCOR算法实现-转换算法框架
V刘晨曦
发表于 2022-11-26 14:54:17
2396
1
0
Q- ^1 {# j7 C9 E, J" V
若利用智能合约的强大而灵活的“资金流转控制”能力,在通证合约中控制着一定量的储备金,让通证与储备金之间拥有一定的兑换能力,那么Token的价值就可以储备金为锚定物,而不完全依赖于项目方。通证持有者也就不用承担项目失败或者项目方可能诈骗跑路的风险。+ e0 \1 ]4 v% j$ S2 Z
若通证与锚定物之间的兑换算法采用了Bancor算法,又符合ERC20标准,则被称为智能通证(Smart-Token) 。为了简单起见,以下的论述以ETH作为锚定物举例说明。购买与售卖Token的过程如下:
“购买者”发送一定量的ETH到Token合约地址,触发了合约代码自动执行"购买功能代码",获得对应数量的Token;“售卖者”发送一定量的Token到Token合约地址,触发了合约代码自动执行“售卖功能代码”,获得对应数量的ETH。
若AToken与BToken都是以ETH为锚定物的智能通证,那么Token持有者无需通过交易所,仅仅凭借智能合约提供的买卖与兑换功能,就能实现AToken与BToken的自由兑换,比如AToken–>ETH–>BToken,多种智能通证之间通过共同的锚定物串接起来,就形成了一个价值网络(Bancor Network)。& s ]: i0 H2 h* E9 F' m- D( Q
【核心智能合约简单描述】
1,contract BancorConverter, Z! D' v$ f( x5 J
功能说明:代币转换器,允许一个智能代币和其他代币之间的转换,ERC20连接器的余额可以是虚拟的,从而不需要依赖于真实的余额,这有助于避免在一个协约中有大量金额的风险。转换器可以升级。7 R+ Q8 b# J" c3 n5 m
2,ITokenConverter
功能说明:BancorConverter的父类接口之一,EIP228 Token Converter接口,用于智能代币的买卖和数量计算接口。
3,SmartTokenController
功能说明:BancorConverter的父类接口之一,智能代币管理器。智能代币管理器是一个可以升级的模块,从而允许更多功能和问题修复。当它接受了代币的所有权,它会成为代币的唯一管理器,执行各个功能。
4,Managed
功能说明: BancorConverter的父类之一,提供协议管理的支持。( q) z- X2 R9 X3 h; f
5,IBancorConverterExtensions
功能说明:BancorConverter的公开变量类,bancor converter extensions 协议。能返回formula,gasPriceLimit,quickConverter等3类接口合约。 F* s0 w# }) \0 m( k/ C
#4,核心函数分析
##4.1 convert(…)函数& I# a: S+ z% K
convert(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256)功能: 将一定数量的_fromToken 转换为 _toToken;源码:
/**
@dev 将一定数量的_fromToken 转换为 _toToken
@param _fromToken 用来转换ERC20代币# w: X2 r' |$ K' [. r! T
@param _toToken 被转换到的ERC20代币
@param _amount 转换的数量,基于fromToken- c0 n4 d- d1 ], t
@param _minReturn 限制转换的结果需要高于minReturn,否则取消
@return conversion 返回数量- m- d K9 K' Q. T2 {
*/, u$ G+ B2 K, }6 N: L2 U
function convert(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256) {
convertPath = [_fromToken, token, _toToken];
return quickConvert(convertPath, _amount, _minReturn);8 p% l/ D+ P9 u7 n
}1 V7 U9 X+ }6 E2 u4 L5 {6 P
/**
@dev 通过之前定义的转换路径来转换代币: i* I' ^5 D. v9 O9 x* M
注意:当从ERC20代币进行转换,需要提前设置补贴& Q2 E4 B8 a6 l
@param _path 转换路径
@param _amount 转换的数量 s& O. y+ x7 T, O% Z2 B
@param _minReturn 限制转换的结果需要高于minReturn,否则取消; m, e4 w; q6 p6 B
@return 返回数量$ A+ k3 L& Y; z8 q7 N- w, d3 W
*/
quickConvertfunction quickConvert(IERC20Token[] _path, uint256 _amount, uint256 _minReturn)
public
payable) l8 x4 P; T* o' ?( I& \4 b6 g
validConversionPath(_path)/ {/ K# E8 y. Z2 _! j# \
returns (uint256); O) [2 x2 t! W% v
{
return quickConvertPrioritized(_path, _amount, _minReturn, 0x0, 0x0, 0x0, 0x0, 0x0);: Z9 L9 _1 r; U/ E' C7 F
}
/**) }3 E, B# z- z& C" Z
@dev 通过之前定义的转换路径来转换代币/ _" R6 {1 b! C( O! P; c
注意:当从ERC20代币进行转换,需要提前设置补贴
@param _path 转换路径
@param _amount 转换的数量, F8 m5 x, C& s+ G5 B% H1 L6 K
@param _minReturn 限制转换的结果需要高于minReturn,否则取消
@param _block 如果当前的区块超过了参数,则取消% A9 ~+ O ~# x/ R: g( P
@param _nonce 发送者地址的nonce
@param _v 通过交易签名提取5 d6 j0 f% `$ I5 u
@param _r 通过交易签名提取
@param _s 通过交易签名提取3 _8 I. ]# h! s: n8 g3 O# P
@return 返回数量' |" s+ D$ t8 E4 _; T8 w2 u
*/; I. @4 |2 I) O: q$ G3 [, i; t+ ~+ {
function quickConvertPrioritized(IERC20Token[] _path, uint256 _amount, uint256 _minReturn, uint256 _block, uint256 _nonce, uint8 _v, bytes32 _r, bytes32 _s)
public
payable
validConversionPath(_path)
returns (uint256)
{
IERC20Token fromToken = _path[0];
IBancorQuickConverter quickConverter = extensions.quickConverter();
// 我们需要从调用者向快速转换着把源代币转化) R6 t! _7 G7 m+ b# i+ |
// 因此他能基于调用者进行转换
if (msg.value == 0) {
// 如果不是ETH,把源代币发给快速调用者: o6 y1 B/ N" n- u
// 如果是智能代币,不需要补贴 —— 销毁代币,然后发给快速转换者- u' B( `; T+ x" t* M
if (fromToken == token) {
token.destroy(msg.sender, _amount); // 销毁调用者的_amount代币- t. v4 d8 A( q, ~
token.issue(quickConverter, _amount); // 把_amount的新代币发给快速转换者
} else {; f5 b5 K4 ]1 ^/ I3 |7 V& Z
// 否则,我们假设有了补贴,发给快速转换者
assert(fromToken.transferFrom(msg.sender, quickConverter, _amount));/ u6 Y d' u+ y& A
}6 N" R; K0 R9 }' \
}
// 执行转换,把ETH转回. Z, B* A/ |6 U9 s5 R
return quickConverter.convertForPrioritized.value(msg.value)(_path, _amount, _minReturn, msg.sender, _block, _nonce, _v, _r, _s);
}9 o# L* }. L! J
##4.2 change(…)函数
** function change**(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256)功能: 将一定数量的_fromToken 转换为 _toToken。弃用了,向后兼容。设计思路和源码结构挺好的代码:
: v- o$ V* Z; r8 S7 N
既然是过期代码,源代码就不放了。9 p7 }% q' m' W1 s
##4.3 getReturn(…)函数; s7 a' q1 I( p
4 R! Y1 d5 h( S$ a. K1 w6 Z
function getReturn(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount) public view returns (uint256)) y$ k6 n6 @! z7 P
% b ^) P$ o2 n6 }* s) S: C8 h% \
功能:
返回从一个代币转换为另一个代币的预期数源码:
6 c4 W" C; M( N& G+ c; J: c: x
/**& j1 f u# Y) l5 q- h# r p
@dev 返回从一个代币转换为另一个代币的预期数量
@param _fromToken ERC20 被转换的代币
@param _toToken ERC20 转换成的代币, O# [; k3 ^( o* k( u' P6 E
@param _amount 转换的数量/ g: P0 ^& i! c' B
@return 与其转换的数量
*/- P# Z/ v9 ^4 n! S/ ~8 `
function getReturn(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount) public view returns (uint256) {- u$ b* \% R6 o& q! j, R
require(_fromToken != _toToken); // 验证输入( A" u% C2 _/ z" c- ^* ~, H3 \
// 基于当前代币转换
if (_toToken == token)
return getPurchaseReturn(_fromToken, _amount);4 [5 f4 Y2 i( [: u) C7 U- X0 f
else if (_fromToken == token)# _; k# J" s8 C0 v' Y0 ~" }
return getSaleReturn(_toToken, _amount);
// 在两个连接器之间转换: M. a& k) o$ v( L
uint256 purchaseReturnAmount = getPurchaseReturn(_fromToken, _amount);! I$ q ?; {' J5 P
return getSaleReturn(_toToken, purchaseReturnAmount, safeAdd(token.totalSupply(), purchaseReturnAmount));8 U+ R0 J# G0 ]- \ @; o
}
/**' H. I+ y- z: H6 w3 Q- p) m- I
@dev 返回通过一个连接器代币购买代币的预期结果. W( Z$ X) v) f% ^; E h6 h
@param _connectorToken 连接器代币协约地址
@param _depositAmount 买入的数量. s5 n! M$ o) r7 A) j% ]) H# H% x
@return 预期的数量! K; I7 ^- h! `- Q& ?+ {( ^: e
*/0 @4 n6 c' A& F7 B. Y& d& ?* R5 B; `/ z5 S
function getPurchaseReturn(IERC20Token _connectorToken, uint256 _depositAmount)
public
view
active4 t6 U2 S- H a0 l2 P7 Z; E; i
validConnector(_connectorToken)
returns (uint256)* ]5 w# f9 h3 N! C& i' `
{7 i3 R, d- s* [4 O/ x* A
Connector storage connector = connectors[_connectorToken];+ `4 e# T9 B9 ]
require(connector.isPurchaseEnabled); // validate input9 Y: a9 u8 n: ?7 h+ \7 H
uint256 tokenSupply = token.totalSupply();
uint256 connectorBalance = getConnectorBalance(_connectorToken);' A: O! T' R! z4 D) P
uint256 amount = extensions.formula().calculatePurchaseReturn(tokenSupply, connectorBalance, connector.weight, _depositAmount);0 d3 q+ v a; R
// 扣除费用* H+ s& n$ W7 U& ~
uint256 feeAmount = getConversionFeeAmount(amount);
return safeSub(amount, feeAmount);4 E- @) }- B% I8 r% B- u* ?
}3 ~0 L% x0 o3 G4 _3 A
/*** f3 f# x5 n! z
@dev 返回通过一个连接器代币卖出代币的预期结果& r6 q" z; P$ {' ?& U
@param _connectorToken 连接器代币协约地址* }* \. [. R4 ~! I% m2 Y
@param _sellAmount 卖出的数量. h* z# R1 t1 x
@return 预期得到的数量; W% _8 p. B. l) i- o1 f$ y3 Y0 H
*/
function getSaleReturn(IERC20Token _connectorToken, uint256 _sellAmount) public view returns (uint256) {
return getSaleReturn(_connectorToken, _sellAmount, token.totalSupply());
}1 ?2 L9 k- r1 [7 _/ L4 g5 {' C
/**
@dev 工具,基于一个总供应量,返回基于一个连接器代币来卖掉代币的期待返回
@param _connectorToken 连接器代币协议地址
@param _sellAmount 销售的数量" s8 ]( n) O @! d# O" V S/ `& w# f. j
@param _totalSupply 设置总供应量$ u' H _- P0 {+ `7 O* f: i; M
@return 返回的数量: W' G* ^+ k; D& p
*/
function getSaleReturn(IERC20Token _connectorToken, uint256 _sellAmount, uint256 _totalSupply): E1 i9 s2 _& ^. j8 N
private
view
active0 Q. Y) ]9 L* C5 y: V( N* Q# y2 x
validConnector(_connectorToken)
greaterThanZero(_totalSupply)
returns (uint256)
{* ?8 e- P: w- D6 x& o' G
Connector storage connector = connectors[_connectorToken];
uint256 connectorBalance = getConnectorBalance(_connectorToken);) @/ ~9 K1 |) m2 j) Q$ I
uint256 amount = extensions.formula().calculateSaleReturn(_totalSupply, connectorBalance, connector.weight, _sellAmount);, Q$ q: V5 L3 Y* g) t3 B
// 从返回的数量中剪掉费用$ ?! C& I a$ Q0 h! S$ w
uint256 feeAmount = getConversionFeeAmount(amount);
return safeSub(amount, feeAmount);! }* e% c# \, ]" N6 [& K. v
}
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
成为第一个吐槽的人