GMX V2版本上线之后短短两个月TVL做到5千万,让我们逐步解析他背后的技术
GMX 是一种去中心化的现货和永续交易所,支持低swap费用和零价格影响交易。 交易由独特的多资产池支持,该池通过做市、swap费、杠杆交易(点差、融资费和清算)和资产再平衡赚取流动性提供者费用。V2版本上线之后短短两个月TVL做到5千万,GMX也是Arbitrum 网络 TVL 最高的Dapp ,让我们逐步解析他背后的技术。
这是我发起交易的交易 hash , 这笔交易通过muticall将3步操作合成一步,感兴趣的可以通过tenderly打开查看交易细节
通过 ExchangeRouter中的 sendWnt 方法将本笔交易的执行费先从ETH兑换成WETH 并转入 DespositVault
// @dev Wraps the specified amount of native tokens into WNT then sends the WNT to the specified address
function sendWnt(address receiver, uint256 amount) external payable nonReentrant {
//校验receiver不能为零地址
AccountUtils.validateReceiver(receiver);
//将
TokenUtils.depositAndSendWrappedNativeToken(dataStore, receiver, amount);
}
通过ExchangeRouter中的 sendTokens 方法将要铸流资金转入 DespositVault
function sendTokens(address token, address receiver, uint256 amount) external payable nonReentrant {
AccountUtils.validateReceiver(receiver);
address account = msg.sender;
router.pluginTransfer(token, account, receiver, amount);
}
通过ExchangeRouter中的createDeposit的方法经过DepositHandler的createDeposit方法最终会调到DepositUtils的createDeposit的方法。 DepositUtils的createDeposit的方法是创建订单的核心函数,接下来我们看下createDeposit方法得详细信息
// @dev creates a deposit
//
// @param dataStore DataStore
// @param eventEmitter EventEmitter
// @param depositVault DepositVault
// @param account the depositing account
// @param params CreateDepositParams
function createDeposit(
DataStore dataStore,
EventEmitter eventEmitter,
DepositVault depositVault,
address account,
CreateDepositParams memory params
) external returns (bytes32) {
//验证account地址不能为0
AccountUtils.validateAccount(account);
//验证这个市场是否开启
Market.Props memory market = MarketUtils.getEnabledMarket(dataStore, params.market);
//校验swap路径是否正确
MarketUtils.validateSwapPath(dataStore, params.longTokenSwapPath);
MarketUtils.validateSwapPath(dataStore, params.shortTokenSwapPath);
// if the initialLongToken and initialShortToken are the same, only the initialLongTokenAmount would
// be non-zero, the initialShortTokenAmount would be zero
//如果initialLongToken和initialShortToken相同的话,initialLongTokenAmount 不为0,initialShortTokenAmount应该为0
//recordTransferIn计算一下本次交易转进来多少代币
uint256 initialLongTokenAmount = depositVault.recordTransferIn(params.initialLongToken);
uint256 initialShortTokenAmount = depositVault.recordTransferIn(params.initialShortToken);
address wnt = TokenUtils.wnt(dataStore);
//如果是该链的治理代币的Wrap应该扣除执行费
//检查initialLongToken和initialShortToken是否为治理代币
//如果是就扣除执行费
//如果不是,查看一下本笔交易转入的治理代币的金额是否够支付执行费
//如果不够 则终止交易
if (params.initialLongToken == wnt) {
initialLongTokenAmount -= params.executionFee;
} else if (params.initialShortToken == wnt) {
initialShortTokenAmount -= params.executionFee;
} else {
//应该在muticall 函数将执行费计算好,进行扣除
uint256 wntAmount = depositVault.recordTransferIn(wnt);
if (wntAmount < params.executionFee) {
revert Errors.InsufficientWntAmountForExecutionFee(wntAmount, params.executionFee);
}
params.executionFee = wntAmount;
}
//如果initialLongTokenAmount和initialShortTokenAmount都为0的话
//说明没有任何金额进来这个池子,终止交易
if (initialLongTokenAmount == 0 && initialShortTokenAmount == 0) {
revert Errors.EmptyDepositAmounts();
}
//验证接收者地址不能为0
AccountUtils.validateReceiver(params.receiver);
//构造Deposit订单的参数
Deposit.Props memory deposit = Deposit.Props(
Deposit.Addresses(
account,
params.receiver,
params.callbackContract,
params.uiFeeReceiver,
market.marketToken,
params.initialLongToken,
params.initialShortToken,
params.longTokenSwapPath,
params.shortTokenSwapPath
),
Deposit.Numbers(
initialLongTokenAmount,
initialShortTokenAmount,
params.minMarketTokens,
Chain.currentBlockNumber(),
params.executionFee,
params.callbackGasLimit
),
Deposit.Flags(params.shouldUnwrapNativeToken)
);
//验证不超过 gas Limit
CallbackUtils.validateCallbackGasLimit(dataStore, deposit.callbackGasLimit());
//预估一下执行gas
uint256 estimatedGasLimit = GasUtils.estimateExecuteDepositGasLimit(dataStore, deposit);
//如果执行费不够支付 gas*gasprice 则终止交易
GasUtils.validateExecutionFee(dataStore, estimatedGasLimit, params.executionFee);
//生成订单key
bytes32 key = NonceUtils.getNextKey(dataStore);
//存储到数据库
DepositStoreUtils.set(dataStore, key, deposit);
//触发event
DepositEventUtils.emitDepositCreated(eventEmitter, key, deposit);
return key;
}
这个函数比较简单,大体逻辑就是校验参数,必须明确有足够的执行费转移到DespositVault中,然后构造铸入流动性的参数,并存储到数据库
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!