What are the characteristics of blockchain exchanges?
1.Decentralization
Players or investors can trade directly without the intervention of a third party intermediary,making the transaction more convenient,fast and transparent.Optimize resource allocation.
2.Good user experience
The exchange is directly customer-oriented,so it will put user needs first in design,pay more attention to user experience,and also provide customers with more value-added services to ensure user stickiness.
3.Open platform,information symmetry
The core of making money in many traditional industries is to make use of the asymmetry of information.On the digital currency trading platform,both parties conduct direct transactions,which is more timely,fair and transparent.
4.Low transaction cost
Low transaction cost and fast speed greatly optimize the environment for small-cap investment.
5.Big data plays a prominent role
Taking full advantage of the accumulation and mining of Internet technology and data information,the scale of customers in the Internet financial ecosystem has reached a high level and the cost of customer selection is low.
在NonfungiblePositionManager中回调函数的实现如下:
struct MintCallbackData{
PoolAddress.PoolKey poolKey;
address payer;//支付token的地址
}
///inheritdoc IUniswapV3MintCallback
function uniswapV3MintCallback(
uint256 amount0Owed,
uint256 amount1Owed,
bytes calldata data
)external override{
MintCallbackData memory decoded=abi.decode(data,(MintCallbackData));
CallbackValidation.verifyCallback(factory,decoded.poolKey);
//根据传入的参数,使用transferFrom代用户向Pool中支付token
if(amount0Owed>0)pay(decoded.poolKey.token0,decoded.payer,msg.sender,amount0Owed);
if(amount1Owed>0)pay(decoded.poolKey.token1,decoded.payer,msg.sender,amount1Owed);
}
流动性的添加主要在UniswapV3Pool._modifyPosition中,这个函会先调用_updatePosition来创建或修改一个用户的Position,省略其中的非关键步骤:
function _updatePosition(
address owner,
int24 tickLower,
int24 tickUpper,
int128 liquidityDelta,
int24 tick
)private returns(Position.Info storage position){
//获取用户的Postion
position=positions.get(owner,tickLower,tickUpper);
...
//根据传入的参数修改Position对应的lower/upper tick中
//的数据,这里可以是增加流动性,也可以是移出流动性
bool flippedLower;
bool flippedUpper;
if(liquidityDelta!=0){
uint32 blockTimestamp=_blockTimestamp();
//更新lower tikc和upper tick
//fippedX变量表示是此tick的引用状态是否发生变化,即
//被引用->未被引用或
//未被引用->被引用
//后续需要根据这个变量的值来更新tick位图
flippedLower=ticks.update(
tickLower,
tick,
liquidityDelta,
_feeGrowthGlobal0X128,
_feeGrowthGlobal1X128,
false,
maxLiquidityPerTick
);
flippedUpper=ticks.update(
tickUpper,
tick,
liquidityDelta,
_feeGrowthGlobal0X128,
_feeGrowthGlobal1X128,
true,
maxLiquidityPerTick
);
//如果一个tick第一次被引用,或者移除了所有引用
//那么更新tick位图
if(flippedLower){
tickBitmap.flipTick(tickLower,tickSpacing);
secondsOutside.initialize(tickLower,tick,tickSpacing,blockTimestamp);
}
if(flippedUpper){
tickBitmap.flipTick(tickUpper,tickSpacing);
secondsOutside.initialize(tickUpper,tick,tickSpacing,blockTimestamp);
}
}
...
//更新position中的数据
position.update(liquidityDelta,feeGrowthInside0X128,feeGrowthInside1X128);
//如果移除了对tick的引用,那么清除之前记录的元数据
//这只会发生在移除流动性的操作中
if(liquidityDelta<0){
if(flippedLower){
ticks.clear(tickLower);
secondsOutside.clear(tickLower,tickSpacing);
}
if(flippedUpper){
ticks.clear(tickUpper);
secondsOutside.clear(tickUpper,tickSpacing);
}
}
}
先忽略费率相关的操作,这个函数所做的操作是:
添加/移除流动性时,先更新这个Positon对应的lower/upper tick中记录的元数据
更新position
根据需要更新tick位图
Postion是以owner,lower tick,uppper tick作为键来存储的,注意这里的owner实际上是NonfungiblePositionManager合约的地址。这样当多个用户在同一个价格区间提供流动性时,在底层的UniswapV3Pool合约中会将他们合并存储。而在NonfungiblePositionManager合约中会按用户来区别每个用户拥有的Position.
Postion中包含的字段中,除去费率相关的字段,只有一个即流动性LL:
library Position{
//info stored for each user's position
struct Info{
//此position中包含的流动性大小,即L值
uint128 liquidity;
...
}
更新position只需要一行调用:
position.update(liquidityDelta,feeGrowthInside0X128,feeGrowthInside1X128);
其中包含了position中流动性LL的更新,以及手续费相关的计算。