GMX v2项目资料库
2024-08-11 08:20:21 0 举报
gmx v2学习笔记
作者其他创作
大纲/内容
ETH
positionUtils.getExecutionPriceForIncreaseusd 经过price处理,得到token deltapositve 不能超过negative 是因为在暴跌场景,negative是有上限的,同时positive不能大于negative
ExchangeRouter.createDeposit添加流动性
如果marketSwapPath大于0,先执行上面swap流程,将token兑换成用户想抵押的token。span style=\"font-size:inherit;\
直接设置initialCollateralDeltaAmount为用户传入的数量
ChainlinkDataStreamProvider
getOraclePrice 传入的data信息经过verifier验证后返回
gasUtils.payExecutionFee1.计算之前的gas消耗,将这部分gas消耗从executionFee中扣除后,返还给调用方(用户或者keeper)2.如果executionFee还有剩余的,将其返还给用户
Oracle.setPrices1 _validatePrices2 _setPrices
DecreasePositionCollateralUtils.processCollateral:处理用户仓位抵押品的变化1.根据当前indexTokenPrice,要减少的头寸的价值计算对positionImpactPool的影响,计算出priceImpactUsd,以及和positionImpactPool设置的最大奖励的差距priceImpactDiffUsd,最后计算出一个用户接收范围内的结算头寸的价格。2. 计算用户头寸的盈亏3.获取结算头寸的费用4.根据计算得到的利润或损失以及价格变动,更新相关的资金池和头寸影响池5.将获得的利润部分转换为头寸的抵押品代币,或者swap为其他代币
ERC20
Valut
exchangeRouter.sendTokens发送代币BaseRouter.sendTokensrouter.pluginTransfer (仅routerPlugin可以操作)token.safeTransferFrom
updateOrder
循环swapPathMarkets,在每个market中执行swap,swap流程如下:首先获取market中另外一个token作为tokenOut,获取预言机中的token对应的primaryPrice。
_setPricesFromPriceFeeds 外部预言机价格1 获得价格预言机价格2 获取代币的稳定价格3 返回两个价格范围,稳定价格如果没有就使用预言机价格4 setPrimaryPrice5 emitOraclePriceUpdated
ChainlinkPriceFeedProvider
getOraclePrice 实时获取价格
Oracle._setPrices1 基本检查2 记录 primaryPrices[token] = price 记录 tokensWithPrices.add(token)span style=\"font-size:inherit;\
key
ExchangeRouter.cancelDeposit撤销订单检查key是否存在,必须本人操作
user交互阶段二,多空交易
MarketUtils.validateMaxPnl当前池子 pnl不能大于指定factor调用isPnlFactorExceeded 返回bool调用 getPnlToPoolFactor 返回当前pnl factorpnl / poolUsdWithoutPnlgetPnl 当前worth of all positions - the cost of all positions
校验:当前Gas是否充足
MarketUtils.applyDeltaToPositionImpactPool
vault
MarketUtils.validateMaxPnlgetPnl这里不太理解,如何获取cost of all positions如何统计盈利的
GasUtils.validateExecutionFee:校验executionFee有没有覆盖minExecutionFee。minExecutionFee = (baseGasLimit + OrderGasLimit * multiplierFactor) * currentGasPrice
user交互阶段一,增加/撤回流动性
TokenUtils.depositAndSendWrappedNativeToken
删除dataStore中的order
DepositHandler1 检查当前合约是否有权限2 取消操作距离创建必须超过x个区块2 调用utils
getStablePrice1 获取代币的稳定价格,如果是USDC 那么就是1
user
OracleModule.withOraclePrices
ExecuteDepositUtils._executeDeposit ⭐️⭐️span style=\"font-size:inherit;\
true
END
GmOracleUtils
validateSigner() ECDSA验证签名真实性
create_deposit
可以补充的模块
dataStore
roleStore
eventUtils
router继承逻辑
config(timelock)
glv
校验:如果order被冻结或者是限价交换,revert。需要frozen order keeper去执行
false
CallbackUtils.validateCallbackGasLimit:校验入参callbackGasLimit是否超过最大限制
DepositHandler._handleDepositError1 validateNonKeeperError 非订单本身错误 应该回滚,不要canelDeposit2 getRevertMessage from reasonBytes3 cancelDeposit特殊逻辑 \bkeeper 造成的gas 用尽,应该revert 给予重试的机会
orderKeeper
_validateRealtimeFeeds1 验证长度2 逐个验证 是否有预言机 验证预言机返回的签名(签名是入参中携带的) 买价 必须小于 卖价 验证区块hash (估计gas调用时 不进行hash验证) 验证 价格年龄 不能过期3 返回报告report
marketUtils.getNextFundingFactorPerSecond ⭐️⭐️⭐️⭐️logic:1 首先根据公式计算基本的 founding Fee 会有最大值限制 (funding factor per second) * (open interest imbalance) ^ (funding exponent factor) / (total open interest)2 如果存在fundingIncreaseFactorPerSecond 根据附加公式进行计算 2-1 基线 [abs(longOpenInterest - shortOpenInterest) / totalOpenInterest] ^ fundingExponentFactor 2-2 三段控制 0-- 3% -- 5% -- 2-2 不断在savedFundingFactorPerSecond 上进行累计 2-3 方向反转 直接置为1、-13 返回计算结果,同时返回正负,增加限界逻辑后的处理结果问题:第一种计算方式 没有时间因素在内
cancelOrder
PositionPricingUtils.getPriceImpactUsd当前池子计算一个priceImpactUsd虚拟池子 也算一个哪个小用哪个
VirtualInventory 虚拟空间Keys.virtualInventoryForPositionsKey(virtualTokenId)从store中获取一个value 就算作long/short的仓位如果usdDelta < 0 ,双方加上delta计算long/short 新旧的持仓初始化&更新 virtualInventory fixVirtualInventoryForPositions直接计算了另一个池子总仓位的imbalance fixVirtualInventoryForPositions.ts
processOrder
Oracle.span style=\"font-size:inherit;\
优先级低的模块
externalHandler
gov
reader
shift
_setPrices 021 验证2 emit3 _setPrimaryPrice
increase和swap类型的订单调用orderVault.transferOut将订单中的钱返还给用户
MarketUtils.validateMarketTokenBalance1 expectedMinTokenBalance cache.poolAmount + cache.swapImpactPoolAmount + cache.claimableCollateralAmount + cache.claimableFeeAmount + cache.claimableUiFeeAmount + cache.affiliateRewardAmount;2 collateral3 claimableFunding
1.NonceUtils.getNextKey获取系统自增key,并设置给Order。2.获取当前区块号,并设置给Order。3.将Order保存到dataStore。4.返回key给用户
GasUtils.estimateExecuteOrderGasLimit 计算OrderGasLimit = Position(incr/decr)最大限制+ Swap path.length * 单次SWAP最大限制+ callbackGasLimit
调用oracle获取tokens对应的预言机价格
校验1.BaseOrderUtils.validateNonEmptyOrder:是否为空订单2.BaseOrderUtils.validateOrderTriggerPrice:比对预言机价格是否达到了triggerPrice,如果是限价单,则遵循低买高卖原则,如果是止损单,则需尽快卖出
IPriceFeed
latestRoundData
_validatePrices ⭐️⭐️1 验证长度2 验证provider 为什么一定要传入3 data 怎么验证的4 非atomicProvider timestamp为什么调整5
StrickBankis bank在当前合约也维护一份 tokenBalancesrecordTransferIn 返回token.balance[address(this)] 更新tokenBalancessyncTokenBalance 更新tokenBalances
createOrder
IncreasePositionUtils.increasepriceImpactUsd = positionUtils.getExecutionPriceForIncreaseMarketUtils.applyDeltaToPositionImpactPool
OracleStore
addSignerremoveSignergetSigner (s)getSignerCount
setPrices 废了 - 旧版1 使用外部价格预言机设置价格;2 使用实时价格预言机设置价格3 使用内部价格预言机设置价格4 验证区块范围
重新计算OrderGasLimit和校验executionFee有没有覆盖minExecutionFee.在修改过程中,gas费用由调用方承担
marketUtils.updateFundingStatelogic:1 getNextFundingAmountPerSize 计算下一个资金费率2 更新 fundingFeeAmountPerSize 每个单位仓位需要支付的资金费率,累计,0.05tokens per $10000 claimableFundingAmountPerSize 每个单位仓位可以领取的资金费率3 设置 nextSavedFundingFactorPerSecond4 更新updateTime
exchangeRouter.sendWnt发送原生代币ETHBaseRouter.sendWntTokenUtils.depositAndSendWrappedNativeToken
校验:如果订单类型是一个SwapOrder,path中的每个market必须存在并启用
根据入参referralCode设置推荐码(后续研究实现)
execute_withdraw
key tokens[]providers[]data[]
_setPricesFromRealtimeFeeds 实时预言机价格1 验证传入的实时预言机价格,入参格式化为report返回2 买价 卖价 精度转换为303 获取预言机价格4 检查传入价格 ,预言机价格 误差不超过factor(可能是控制价差 防止在行情动荡时期 某些LP获得不公平的份额)5 setPrimaryPrice6 emitOraclePriceUpdated7 返回report
1.用户发送资产给Valut。如果用户只发送了ETH,后续executionFee会在ETH中扣除。如果用户发送的是ERC20代币,那么用户还需要发送一笔ETH作为exectionFee
SwapPriceingUtils.getPriceImpactUsd 计算影响价格
IERC20(token).safeTransferFrom
TokenUtils
1.根据入参initialCollateralToken查询OrderValut对应token 的入账数量,作为initialCollateralDeltaAmount。2.如果是initialCollateralToken类型为wnt,则直接扣除executionFee,initialCollateralDeltaAmount -= params.numbers.executionFee;
入参:struct CreateDepositParams { address receiver; 订单LP接收人 address callbackContract; 发送订单/取消订单后会回进行回调 address uiFeeReceiver; uiFee就是一个服务费,平台会自动发送到这个地址 address market; 池子合约 address initialLongToken; 做多token address initialShortToken; 多空token address[] longTokenSwapPath; swapPath address[] shortTokenSwapPath; swapPath uint256 minMarketTokens; 最少要获得的LP数量 bool shouldUnwrapNativeToken; 是否需要转换为原生代币 uint256 executionFee; 为本次调用准备的gas数量,必须要满足全流程的gas消耗,否则直接revert uint256 callbackGasLimit; 提前告知回调预计的gas消耗,接口要预留这部分费用 }存储订单中信息 大体与上面重叠;不同的部分:currentBlockNumberkey 唯一key,可以理解为订单id
executeOrder
PositionPricingUtils._getPriceImpactUsd根据imbalance 计算impactpositve 不能超过negative 是因为在暴跌场景,negative是有上限的,同时positive不能大于negative
DepositHandler1 检查当前合约是否有权限2 调用utils
sendNativeToken depositAndSendWrappedNativeToken withdrawAndSendNativeToken transfer -- nonRevertingTransferWithGasLimit
cancel_deposit
更新仓位和池子的各种状态
直接将ERC20代币转给Valut
更新仓位信息
MarketUtils.distributePositionImpactPool1 rate * seconds 施加在positionImpactPool2 applyDeltaToPositionImpactPool3 updateTimeconfigKeys.positionImpactPoolAmountKey(market)rateKeys.positionImpactPoolDistributionRateKey(market)
Bank存取tokenexternal:transferOut01transferOut02 根据标志优先进行_transferOutNativeTokentransferOutNativeTokeninternal:_transferOut 对应TokenUtil路线4_transferOutNativeToken 对应TokenUtils 路线3
查询key对应的订单
transfer
execute_deposit
_validatePrices1 一大坨
ChainlinkDataStreamProvider 使用chainlink提供的数据流价格信息;优势:低延迟,高频,支持更高精度使用:先拿到数据流信息,调用getOraclePrice方法,需要使用chainlink合约辅助签名验证
_setPrimaryPrice1 检查不能已经存在2 维护primaryPrices3 维护 tokensWithPrices
根据入参key查询Order是否存在
OrderStoreUtils.remove:删除dataStore中的order
1.如果willBeSufficient = false,也就是说用户期望减掉的抵押品不满足用户期望减掉的仓位后的最低抵押率,那么将这部分抵押品的价值加回去estimatedRemainingCollateralUsd += initialCollateralDeltaAmount * collateralTokenPrice.min设置order.setInitialCollateralDeltaAmount(0);2.如果减掉了用户期望的抵押品后抵押品价值 estimatedRemainingCollateralUsd +用户期望减仓后仓位量estimatedRemainingPnlUsd 小于market中设置的最小抵押品量,设置 order.setSizeDeltaUsd(position.sizeInUsd()); order.setInitialCollateralDeltaAmount(0);3.如果用户原来的仓位量position.sizeInUsd - 用户期望的减仓量order.sizeDeltaUsd < market中设置的最小仓位量,设置order.setSizeDeltaUsd(params.position.sizeInUsd());order.setInitialCollateralDeltaAmount(0);
GmOracleProvider
getOraclePrice(包括解码数据、验证签名者、验证价格排序、验证价格有效性等,以确保价格数据的真实性和完整性)_getSigners_getSalt
MULTICALL
将所有入参封装为一个Order对象
ChainlinkPriceFeedUtils
getPriceFeedPrice 已经进行multiplier处理getPriceFeedMultiplier internal
Oracle
用户可以选择追加executionFee,前提是要提前转一笔ETH给OrderVault
CallbackUtils.afterOrderCancellation:执行用户设置的CallbackContract,gas = order.callbackGasLimit
更新order的区块号,将order保存到dataStore
swap或increase类型的订单?
2.用户发送业务请求,主要包括Deposit,Withdrawal,Order。请求入口都在ExchangeRouter中
positionImpactPool
orderKeeper执行阶段,多空交易
IOracleProvider
IChainlinkDataStreamVerifier
校验order的sizeDeltaUsd,initialCollateralDeltaAmount设置给position,并且不得大于当前position的sizeInUsd,collateralAmount
setPricevalidatePricegetPriceclearPrice
校验:如果订单类型是一个PositionOrder,对应的market必须存在并启用
SwapPricingUtils.getSwapFeeslogic:
keeper
组装参数:ExecuteOrderParams{keyorderswapPathMarketsminOracleTimestampmaxOracleTimestampkeeperstartingGassecondaryOrderTypeExecuteOrderParamsContracts};ExecuteOrderParamsContracts{dataStoreeventEmitterorderVaultoracleswapHandlerreferralStorage}
Precision各种数值的精度转换(浮点数 wei 基点)applyFactor 乘法运算 + 精度管理支持uint256 int256可以选择 向上取整 向下取整 向零取整toFactor 除法float wei 单位换算等
MarketUtils.updateCumulativeBorrowingFactorlogic:也是一个累计值
OracleUtils
struct多个isOracleErrorisEmptyPriceErrorisOracleTimestampError
OracleModule
收藏
0 条评论
下一页