基于以太坊的交易所BANCOR算法实现-转换算法框架
V刘晨曦
发表于 2022-11-26 14:54:17
2344
1
0
0 f/ O8 R' Z3 f8 y; K: q
若利用智能合约的强大而灵活的“资金流转控制”能力,在通证合约中控制着一定量的储备金,让通证与储备金之间拥有一定的兑换能力,那么Token的价值就可以储备金为锚定物,而不完全依赖于项目方。通证持有者也就不用承担项目失败或者项目方可能诈骗跑路的风险。
若通证与锚定物之间的兑换算法采用了Bancor算法,又符合ERC20标准,则被称为智能通证(Smart-Token) 。为了简单起见,以下的论述以ETH作为锚定物举例说明。购买与售卖Token的过程如下:, c2 ~2 ^' X4 v+ R
“购买者”发送一定量的ETH到Token合约地址,触发了合约代码自动执行"购买功能代码",获得对应数量的Token;“售卖者”发送一定量的Token到Token合约地址,触发了合约代码自动执行“售卖功能代码”,获得对应数量的ETH。
若AToken与BToken都是以ETH为锚定物的智能通证,那么Token持有者无需通过交易所,仅仅凭借智能合约提供的买卖与兑换功能,就能实现AToken与BToken的自由兑换,比如AToken–>ETH–>BToken,多种智能通证之间通过共同的锚定物串接起来,就形成了一个价值网络(Bancor Network)。7 L; Q6 z4 h9 C. S& L
$ [1 q; b8 U( O5 e
【核心智能合约简单描述】$ D( W% m1 a! B% g$ v1 U4 q
1,contract BancorConverter- D7 x9 O$ y9 D; |1 w* V0 B- o
功能说明:代币转换器,允许一个智能代币和其他代币之间的转换,ERC20连接器的余额可以是虚拟的,从而不需要依赖于真实的余额,这有助于避免在一个协约中有大量金额的风险。转换器可以升级。
2,ITokenConverter
功能说明:BancorConverter的父类接口之一,EIP228 Token Converter接口,用于智能代币的买卖和数量计算接口。9 v) t q1 P1 V! }+ x( B
3,SmartTokenController
功能说明:BancorConverter的父类接口之一,智能代币管理器。智能代币管理器是一个可以升级的模块,从而允许更多功能和问题修复。当它接受了代币的所有权,它会成为代币的唯一管理器,执行各个功能。0 B4 Q9 F. h3 h
4,Managed2 P g" L- P6 G' \
功能说明: BancorConverter的父类之一,提供协议管理的支持。
5,IBancorConverterExtensions% h# \. G/ J1 }
功能说明:BancorConverter的公开变量类,bancor converter extensions 协议。能返回formula,gasPriceLimit,quickConverter等3类接口合约。
#4,核心函数分析
##4.1 convert(…)函数
convert(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256)功能: 将一定数量的_fromToken 转换为 _toToken;源码:* U1 l! W# [+ y0 @9 H/ V
! b' L. @3 F9 o9 P4 `
/**
@dev 将一定数量的_fromToken 转换为 _toToken
@param _fromToken 用来转换ERC20代币+ X! _2 J) l6 S5 k) g- \9 L* O
@param _toToken 被转换到的ERC20代币
@param _amount 转换的数量,基于fromToken: ~6 w5 |3 z$ T& r* V
@param _minReturn 限制转换的结果需要高于minReturn,否则取消! i' B! K# p- P- s2 `
@return conversion 返回数量
*/
function convert(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256) {0 F8 M5 s& R: q+ g9 W3 ~
convertPath = [_fromToken, token, _toToken];
return quickConvert(convertPath, _amount, _minReturn);# ^: X/ K4 ?) D F5 p8 x6 s
}
/**
@dev 通过之前定义的转换路径来转换代币
注意:当从ERC20代币进行转换,需要提前设置补贴/ S6 v; L; a7 N( i+ h
@param _path 转换路径4 ^; [) A8 |1 h0 S& }2 R: v
@param _amount 转换的数量1 ]! I( ^6 E4 @: W7 M+ j
@param _minReturn 限制转换的结果需要高于minReturn,否则取消
@return 返回数量
*/
quickConvertfunction quickConvert(IERC20Token[] _path, uint256 _amount, uint256 _minReturn)
public2 L9 g# J x* Q% N; O
payable
validConversionPath(_path)
returns (uint256)% i# o$ b% ]% N6 o
{! @: O5 u9 u( o9 @
return quickConvertPrioritized(_path, _amount, _minReturn, 0x0, 0x0, 0x0, 0x0, 0x0);( N. D: ~' e5 _% E- |2 M
}
/**! t( D4 F$ v& P/ d( P. z' G7 X
@dev 通过之前定义的转换路径来转换代币
注意:当从ERC20代币进行转换,需要提前设置补贴
@param _path 转换路径
@param _amount 转换的数量7 r$ N& v: ?& n$ k) j; `
@param _minReturn 限制转换的结果需要高于minReturn,否则取消
@param _block 如果当前的区块超过了参数,则取消
@param _nonce 发送者地址的nonce
@param _v 通过交易签名提取
@param _r 通过交易签名提取
@param _s 通过交易签名提取
@return 返回数量
*/
function quickConvertPrioritized(IERC20Token[] _path, uint256 _amount, uint256 _minReturn, uint256 _block, uint256 _nonce, uint8 _v, bytes32 _r, bytes32 _s)) v4 v* [# P7 J6 D, _: M
public
payable! o- @- i3 @8 L
validConversionPath(_path)
returns (uint256)6 N5 i1 p$ r# d8 x
{
IERC20Token fromToken = _path[0];
IBancorQuickConverter quickConverter = extensions.quickConverter();5 Z& n" `: H2 m/ x! n0 n" V
// 我们需要从调用者向快速转换着把源代币转化
// 因此他能基于调用者进行转换5 c o* e+ Y8 d* \. U P& l: I
if (msg.value == 0) {' K2 n' C* R9 Y
// 如果不是ETH,把源代币发给快速调用者
// 如果是智能代币,不需要补贴 —— 销毁代币,然后发给快速转换者
if (fromToken == token) {$ n0 i8 e% M7 M! R
token.destroy(msg.sender, _amount); // 销毁调用者的_amount代币* l2 n. T' z) Y" V0 e, K6 W+ O" q
token.issue(quickConverter, _amount); // 把_amount的新代币发给快速转换者3 }+ T( o$ b- {3 P+ p* P3 |
} else {' k# g: [5 K( ]# R- ]4 \
// 否则,我们假设有了补贴,发给快速转换者
assert(fromToken.transferFrom(msg.sender, quickConverter, _amount));2 G* Y# ]: r, w% m6 N c3 @
}
}
// 执行转换,把ETH转回/ g( d; O- R3 T+ X# F
return quickConverter.convertForPrioritized.value(msg.value)(_path, _amount, _minReturn, msg.sender, _block, _nonce, _v, _r, _s);
}6 m, }. \+ {3 V$ o
. Y6 U. e0 h5 i. m4 f7 d
##4.2 change(…)函数8 ?2 ]* u4 c3 J7 S: C1 Z& T E$ N
** function change**(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256)功能: 将一定数量的_fromToken 转换为 _toToken。弃用了,向后兼容。设计思路和源码结构挺好的代码:
既然是过期代码,源代码就不放了。2 F+ R- L" d3 q
##4.3 getReturn(…)函数# }9 @2 P( h3 }$ D1 f
! Z* E5 k6 l, [$ S2 Z
function getReturn(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount) public view returns (uint256)
功能:2 b: T& p n( T w1 Q
返回从一个代币转换为另一个代币的预期数源码:$ ~! G4 z0 P* u* n6 `* J$ N( u0 T9 |
/**' h! r7 {" v! h+ F+ A
@dev 返回从一个代币转换为另一个代币的预期数量
@param _fromToken ERC20 被转换的代币
@param _toToken ERC20 转换成的代币 a7 I" `7 V: o
@param _amount 转换的数量
@return 与其转换的数量- M; a8 c6 L: _7 y+ J
*/% X* I9 V7 M# E0 K+ ~, d2 W
function getReturn(IERC20Token _fromToken, IERC20Token _toToken, uint256 _amount) public view returns (uint256) {
require(_fromToken != _toToken); // 验证输入
// 基于当前代币转换
if (_toToken == token). o- D j2 @! k" ^
return getPurchaseReturn(_fromToken, _amount);4 }( ? F# a% j3 U
else if (_fromToken == token)/ x/ y( t6 J. H9 _5 ~3 L+ E8 Z: i
return getSaleReturn(_toToken, _amount);6 ]" u; Z4 {! n
// 在两个连接器之间转换9 E8 I! y/ E! v
uint256 purchaseReturnAmount = getPurchaseReturn(_fromToken, _amount);; b+ {8 \9 o- k9 W7 k( ]
return getSaleReturn(_toToken, purchaseReturnAmount, safeAdd(token.totalSupply(), purchaseReturnAmount));
}
/**
@dev 返回通过一个连接器代币购买代币的预期结果
@param _connectorToken 连接器代币协约地址
@param _depositAmount 买入的数量$ j9 s6 [6 f2 m; W; u6 T9 z; _( I# }" q
@return 预期的数量
*/
function getPurchaseReturn(IERC20Token _connectorToken, uint256 _depositAmount)3 R: h* e& T+ {* O) _1 H
public) _7 B. _$ ~: O" o/ }; H% ]7 B& F
view
active
validConnector(_connectorToken)8 y( X$ ?& } ]% k
returns (uint256)) j, i" v/ A' W& T4 F4 R/ @$ ]
{/ k% Z ? Y" m7 H2 y
Connector storage connector = connectors[_connectorToken];
require(connector.isPurchaseEnabled); // validate input- f# N3 v8 R' ?& c" M( Q2 V
uint256 tokenSupply = token.totalSupply();, k! H' g! `0 e; u
uint256 connectorBalance = getConnectorBalance(_connectorToken);
uint256 amount = extensions.formula().calculatePurchaseReturn(tokenSupply, connectorBalance, connector.weight, _depositAmount);# ^3 X( A* C4 X2 a6 W# d
// 扣除费用
uint256 feeAmount = getConversionFeeAmount(amount);
return safeSub(amount, feeAmount);6 H v* S$ x! x+ [/ U; e" H
}" q1 t) f4 { v5 u& E3 K8 I7 _/ i
/**$ Z: U$ X( D: }" a
@dev 返回通过一个连接器代币卖出代币的预期结果, u% p& b$ v: p& Z( h
@param _connectorToken 连接器代币协约地址5 {+ e! M5 a) T- o+ C6 f, K
@param _sellAmount 卖出的数量
@return 预期得到的数量
*/+ P! V" o0 `1 g- r* e' @ b
function getSaleReturn(IERC20Token _connectorToken, uint256 _sellAmount) public view returns (uint256) {
return getSaleReturn(_connectorToken, _sellAmount, token.totalSupply());2 j( X" W$ ]' f8 R
}- T; W) w! V0 [5 @+ `, F
/*** q, F }( `) u! c) O! O/ i
@dev 工具,基于一个总供应量,返回基于一个连接器代币来卖掉代币的期待返回. c+ v' N! B& d6 O
@param _connectorToken 连接器代币协议地址
@param _sellAmount 销售的数量
@param _totalSupply 设置总供应量6 i9 U/ { X( Z' l
@return 返回的数量
*/, k( k X3 | v* Q
function getSaleReturn(IERC20Token _connectorToken, uint256 _sellAmount, uint256 _totalSupply)
private
view
active
validConnector(_connectorToken) h q& p6 B% \! a* w$ p
greaterThanZero(_totalSupply)- T5 M, u% E0 D3 L6 H, w, T; @; K
returns (uint256)
{
Connector storage connector = connectors[_connectorToken];+ T9 C# D8 E7 r9 ]
uint256 connectorBalance = getConnectorBalance(_connectorToken);
uint256 amount = extensions.formula().calculateSaleReturn(_totalSupply, connectorBalance, connector.weight, _sellAmount);
// 从返回的数量中剪掉费用; Z' ~; r: m) f" u
uint256 feeAmount = getConversionFeeAmount(amount);
return safeSub(amount, feeAmount);
}
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
成为第一个吐槽的人