Contrats pour GMX Synthetics.
Cette section donne un aperçu général du fonctionnement du système.
Pour un aperçu technique, veuillez consulter la section ci-dessous.
Les marchés prennent en charge à la fois le trading au comptant et le trading perp. Ils sont créés en spécifiant un jeton de garantie long, un jeton de garantie court et un jeton d'indice.
Exemples :
Les fournisseurs de liquidité peuvent déposer le jeton de garantie long ou court, ou les deux, pour créer des jetons de liquidité.
Le jeton de garantie long est utilisé pour garantir des positions longues, tandis que le jeton de garantie court est utilisé pour garantir des positions courtes.
Les fournisseurs de liquidité assument les profits et les pertes des traders pour le marché pour lequel ils fournissent des liquidités.
Le fait d'avoir des marchés séparés permet d'isoler les risques, les fournisseurs de liquidité ne sont exposés qu'aux marchés sur lesquels ils déposent, ce qui permet potentiellement des cotations sans autorisation.
Les traders peuvent utiliser le jeton long ou court comme garantie du marché.
Les contrats prennent en charge les fonctionnalités principales suivantes :
Pour éviter les problèmes de premier plan, la plupart des actions nécessitent deux étapes pour être exécutées :
Les prix sont fournis par un système oracle hors chaîne, qui signe en permanence les prix en fonction du moment où les prix ont été demandés.
Un prix minimum et un prix maximum sont signés, ce qui permet d'inclure des informations sur les spreads bid-ask.
Les prix stockés dans le contrat Oracle représentent le prix d'une unité du jeton en utilisant une valeur avec 30 décimales de précision.
Représenter les prix de cette manière permet de simplifier les conversions entre les montants symboliques et les valeurs fiduciaires, par exemple pour calculer la valeur fiduciaire d'un nombre donné de jetons, le calcul serait simplement : montant symbolique * prix oracle, pour calculer le montant symbolique pour un valeur fiduciaire, ce serait : valeur fiduciaire / prix oracle.
Les frais de financement et l'impact sur les prix maintiennent l'équilibre entre les positions longues et courtes tout en réduisant le risque de manipulation des prix.
Il y a quelques gardiens et nœuds dans le système :
Il existe quelques grands types de contrats :
Les contrats sont séparés en ces types pour permettre une évolutivité progressive.
La majorité des données sont stockées à l'aide du contrat DataStore.
Les contrats *storeUtils stockent les données de structure à l'aide du DataStore, ce qui permet d'ajouter de nouvelles clés aux structures.
Les EnumberableSets sont utilisés pour permettre aux listes de commandes et aux listes de positions d'être facilement interrogées par les interfaces ou les gardiens. Ceci est utilisé sur les indexeurs car il peut y avoir un décalage pour que les indexeurs synchronisent le dernier bloc. Le fait de stocker les listes directement dans le contrat permet également de garantir que des données précises peuvent être récupérées et vérifiées en cas de besoin.
Les contrats *eventUtils émettent des événements à l'aide de l'émetteur d'événements, les événements sont généralisés pour permettre d'ajouter de nouvelles valeurs-clés aux événements sans nécessiter une mise à jour des ABI.
Abréviation de GMX Liquidity Vault : un wrapper de plusieurs marchés avec les mêmes jetons longs et courts. La liquidité est automatiquement rééquilibrée entre les marchés sous-jacents en fonction de l'utilisation des marchés.
Cette section fournit une description technique des contrats.
Les marchés sont créés à l'aide de MarketFactory.createMarket
, cela crée un MarketToken et stocke une structure Market.Props dans le MarketStore.
Le MarketToken est utilisé pour suivre la part des fournisseurs de liquidité dans le pool de marché et pour stocker les jetons pour chaque marché.
À tout moment, le prix d'un MarketToken est (worth of market pool) / MarketToken.totalSupply()
, la fonction MarketUtils.getMarketTokenPrice
peut être utilisée pour récupérer cette valeur.
La valeur du pool de marché est la somme de
Les dépôts ajoutent des jetons longs/courts au pool du marché et génèrent des MarketTokens au déposant.
Les demandes de dépôt sont créées en appelant ExchangeRouter.createDeposit, en spécifiant :
Les demandes de dépôt sont exécutées à l'aide de DepositHandler.executeDeposit, si le dépôt a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Le nombre de MarketTokens à frapper, avant frais et impact sur le prix, est calculé comme suit : (worth of tokens deposited) / (worth of market pool) * MarketToken.totalSupply()
.
Les retraits brûlent des MarketTokens en échange des tokens long/short d'un pool de marché.
Les demandes de retrait sont créées en appelant ExchangeRouter.createWithdrawal, en précisant :
Les demandes de retrait sont exécutées à l'aide de WithdrawalHandler.executeWithdrawal, si le retrait a été créé à l'horodatage n
, il doit être exécuté avec les prix oracle après l'horodatage n
.
Le montant des tokens longs ou courts à racheter, avant frais et impact sur le prix, est calculé comme (worth of market tokens) / (long / short token price)
.
Les jetons longs et courts d'un marché peuvent être échangés les uns contre les autres.
Par exemple, si le marché ETH/USD a WETH comme jeton long et USDC comme jeton court, WETH peut être envoyé sur le marché pour être échangé contre de l'USDC et l'USDC peut être envoyé sur le marché pour être échangé contre WETH.
Les demandes d'ordre de swap sont créées en appelant ExchangeRouter.createOrder, en spécifiant :
Le montant de la sortie du swap, avant frais et impact sur le prix, (amount of tokens in) * (token in price) / (token out price)
.
Les demandes d'ordres de swap de marché sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Ordres de swap passifs qui doivent être exécutés lorsque le montant de sortie correspond au montant de sortie minimum spécifié par l'utilisateur.
Les demandes d'ordres de swap limité sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Ouvrez ou augmentez une position longue/courte.
Les demandes d'ordres d'augmentation du marché sont créées en appelant ExchangeRouter.createOrder, en spécifiant :
Les demandes d'ordre d'augmentation du marché sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Ordres d'augmentation passive de position qui doivent être exécutés lorsque le prix du jeton d'indice correspond au prix acceptable spécifié par l'utilisateur.
Exemple de position longue : si le prix actuel du jeton d'indice est de 5 000 $, un ordre d'augmentation de limite peut être créé avec un prix acceptable de 4 990 $, l'ordre peut être exécuté lorsque le prix du jeton d'indice est <= 4 990 $.
Exemple de position courte : si le prix actuel du jeton d'indice est de 5 000 $, un ordre d'augmentation de limite peut être créé avec un prix acceptable de 5 010 $, l'ordre peut être exécuté lorsque le prix du jeton d'indice est >= 5 010 $.
Les demandes d'ordre d'augmentation de limite sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Fermez ou diminuez une position longue/courte.
Les demandes d'ordres de baisse du marché sont créées en appelant ExchangeRouter.createOrder, en spécifiant :
Les demandes d'ordres de baisse du marché sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Ordres de diminution passive de position qui doivent être exécutés lorsque le prix du jeton d'indice correspond au prix acceptable spécifié par l'utilisateur.
Exemple de position longue : si le prix actuel du jeton d'indice est de 5 000 $, un ordre de diminution limite peut être créé avec un prix acceptable de 5 010 $, l'ordre peut être exécuté lorsque le prix du jeton d'indice est >= 5 010 $.
Exemple de position courte : si le prix actuel du jeton d'indice est de 5 000 $, un ordre de diminution limite peut être créé avec un prix acceptable de 4 990 $, l'ordre peut être exécuté lorsque le prix du jeton d'indice est <= 4 990 $.
Les demandes d'ordre de diminution à limite sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Ordres de diminution passive de position qui doivent être exécutés lorsque le prix du jeton d'indice dépasse le prix acceptable spécifié par l'utilisateur.
Exemple de position longue : si le prix actuel du jeton d'indice est de 5 000 $, un ordre stop-loss de diminution peut être créé avec un prix acceptable de 4 990 $, l'ordre peut être exécuté lorsque le prix du jeton d'indice est <= 4 990 $.
Exemple de position courte : si le prix actuel du jeton d'indice est de 5 000 $, un ordre stop-loss de diminution peut être créé avec un prix acceptable de 5 010 $, l'ordre peut être exécuté lorsque le prix du jeton d'indice est >= 5 010 $.
Les demandes d'ordre de diminution stop-loss sont exécutées à l'aide de OrderHandler.executeOrder, si l'ordre a été créé à l'horodatage n
, il doit être exécuté avec les prix Oracle après l'horodatage n
.
Le prix de l’ETH est de 5 000 et l’ETH comporte 18 décimales.
Le prix d'une unité d'ETH est de 5000 / (10 ^ 18), 5 * (10 ^ -15)
.
Pour gérer les décimales, multipliez la valeur par (10 ^ 30)
.
Le prix serait stocké sous la forme 5000 / (10 ^ 18) * (10 ^ 30) => 5000 * (10 ^ 12)
.
Pour l'optimisation du gaz, ces prix sont envoyés à l'oracle sous la forme d'une valeur de multiplicateur décimal uint8 et d'une valeur de prix uint32.
Si la valeur du multiplicateur décimal est définie sur 8, la valeur uint32 serait 5000 * (10 ^ 12) / (10 ^ 8) => 5000 * (10 ^ 4)
.
Avec cette configuration, les prix des ETH peuvent avoir une valeur maximale de (2 ^ 32) / (10 ^ 4) => 4,294,967,296 / (10 ^ 4) => 429,496.7296
avec 4 décimales de précision.
Le prix du BTC est de 60 000 et le BTC comporte 8 décimales.
Le prix d'une unité de BTC est 60,000 / (10 ^ 8), 6 * (10 ^ -4)
.
Le prix serait stocké sous la forme 60,000 / (10 ^ 8) * (10 ^ 30) => 6 * (10 ^ 26) => 60,000 * (10 ^ 22)
.
Valeur maximale des prix BTC : (2 ^ 64) / (10 ^ 2) => 4,294,967,296 / (10 ^ 2) => 42,949,672.96
.
Décimales de précision : 2.
Le prix de l’USDC est de 1 et l’USDC comporte 6 décimales.
Le prix d'une unité d'USDC est 1 / (10 ^ 6), 1 * (10 ^ -6)
.
Le prix serait stocké sous la forme 1 / (10 ^ 6) * (10 ^ 30) => 1 * (10 ^ 24)
.
Valeur maximale des prix USDC : (2 ^ 64) / (10 ^ 6) => 4,294,967,296 / (10 ^ 6) => 4294.967296
.
Décimales de précision : 6.
Le prix du DG est de 0,00000001 et le DG comporte 18 décimales.
Le prix d'une unité de DG est 0.00000001 / (10 ^ 18), 1 * (10 ^ -26)
.
Le prix serait stocké sous la forme 1 * (10 ^ -26) * (10 ^ 30) => 1 * (10 ^ 3)
.
Valeur maximale des prix DG : (2 ^ 64) / (10 ^ 11) => 4,294,967,296 / (10 ^ 11) => 0.04294967296
.
Décimales de précision : 11.
La formule pour calculer la valeur du multiplicateur décimal :
Décimales : 30 - (décimales symboliques) - (nombre de décimales souhaité pour la précision)
Exemple de calcul pour WNT :
dataStreamPrice / (10 ^ 8) / (10 ^ 18) * (10 ^ 30)
(5000 * (10 ^ 8)) / (10 ^ 8) / (10 ^ 18) * (10 ^ 30) = 5000 * (10 ^ 12)
dataStreamPrice * multiplier / (10 ^ 30)
(5000 * (10 ^ 8)) * (10 ^ 34) / (10 ^ 30) = 5000 * (10 ^ 12)
Exemple de calcul pour WBTC :
dataStreamPrice / (10 ^ 8) / (10 ^ 8) * (10 ^ 30)
(50,000 * (10 ^ 8)) / (10 ^ 8) / (10 ^ 8) * (10 ^ 30) = 50,000 * (10 ^ 22)
dataStreamPrice * multiplier / (10 ^ 30)
(50,000 * (10 ^ 8)) * (10 ^ 44) / (10 ^ 30) = 50,000 * (10 ^ 22)
La formule du multiplicateur est : 10 ^ (60 - dataStreamDecimals - tokenDecimals)
Les frais de financement encouragent l'équilibrage des positions longues et courtes, le côté avec l'intérêt ouvert le plus important paie des frais de financement au côté avec l'intérêt ouvert le plus petit.
Les frais de financement pour le côté le plus important sont calculés comme suit : (funding factor per second) * (open interest imbalance) ^ (funding exponent factor) / (total open interest)
.
Par exemple, si le facteur de financement par seconde est de 1/50 000, que le facteur d'exposant de financement est de 1, que l'intérêt ouvert long est de 150 000 $ et que l'intérêt ouvert court est de 50 000 $, les frais de financement par seconde pour les positions longues seraient de (1 / 50,000) * 100,000 / 200,000 => 0.00001 => 0.001%
.
Les frais de financement par seconde pour les courts métrages seraient -0.00001 * 150,000 / 50,000 => 0.00003 => -0.003%
.
Il est également possible de définir une valeurfundingIncreaseFactorPerSecond, cela se traduirait par la logique de financement suivante :
longShortImbalance
est calculé comme suit : [abs(longOpenInterest - shortOpenInterest) / totalOpenInterest] ^ fundingExponentFactor
longShortImbalance
actuel est supérieur au thresholdForStableFunding
, le taux de financement augmentera de longShortImbalance * fundingIncreaseFactorPerSecond
longShortImbalance
actuel est supérieur à thresholdForDecreaseFunding
et inférieur à thresholdForStableFunding
et que l'inclinaison est dans la même direction que le financement, alors le taux de financement ne changera pas.longShortImbalance
actuel est inférieur au thresholdForDecreaseFunding
et que l'asymétrie est dans la même direction que le financement, alors le taux de financement diminuera fundingDecreaseFactorPerSecond
Depuis longShortImbalance > ThreuilForStableFunding, SaveFundingFactorPerSecond devrait augmenter de 0.0001% * 6% * 600 = 0.0036%
Puisque les positions longues sont déjà des positions courtes, l'asymétrie est la même et le longShortImbalance <seuilForStableFunding, SaveFundingFactorPerSecond ne devrait pas changer.
Puisque longShortImbalance <seuilForDecreaseFunding, SaveFundingFactorPerSecond devrait diminuer de 0.000002% * 600 = 0.0012%
Étant donné que l'inclinaison est dans l'autre sens, SaveFundingFactorPerSecond devrait diminuer de 0.0001% * 1% * 600 = 0.0006%
Notez qu'il existe des moyens possibles de jouer sur les frais de financement, les facteurs de financement doivent être ajustés pour minimiser cette possibilité :
Si longOpenInterest > shortOpenInterest et longShortImbalance sont dans le seuil ForStableFunding, un utilisateur détenant une position courte peut ouvrir une position longue pour augmenter le longShortImbalance et tenter de faire augmenter les frais de financement. Dans un marché actif, il devrait être difficile de prédire quand une position courte opposée sera ouverte par quelqu'un d'autre pour gagner des frais de financement accrus, ce qui devrait rendre ce jeu difficile. Les facteurs de financement peuvent également être ajustés pour aider à minimiser les avantages de ce jeu. .
Si longOpenInterest > shortOpenInterest et longShortImbalance > ThreuilForStableFunding, un trader détenant une position longue pourrait effectuer plusieurs petites transactions pendant cette période pour garantir que le facteur de financement est continuellement mis à jour au lieu d'utiliser une valeur plus élevée pendant toute la durée, cela devrait minimiser le frais de financement pour les positions longues, mais ne devrait pas diminuer les frais de financement en dessous des taux attendus.
Des frais d'emprunt sont payés aux fournisseurs de liquidités, ce qui empêche les utilisateurs d'ouvrir des positions longues et courtes pour utiliser la capacité du pool sans payer de frais.
Les frais d’emprunt peuvent utiliser un modèle de courbe ou un modèle de coude.
Pour utiliser le modèle de courbe, les clés à configurer seraient BORROWING_FACTOR
et BORROWING_EXPONENT_FACTOR
, le facteur d'emprunt par seconde serait calculé comme suit :
// reservedUsd is the total USD value reserved for positions
reservedUsd = MarketUtils.getReservedUsd(...)
// poolUsd is the USD value of the pool excluding pending trader PnL
poolUsd = MarketUtils.getPoolUsdWithoutPnl(...)
// reservedUsdAfterExponent is the reservedUsd after applying the borrowingExponentFactor for the market
reservedUsdAfterExponent = applyExponentFactor(reservedUsd, borrowingExponentFactor)
borrowingFactorPerSecond = borrowingFactor * reservedUsdAfterExponent / poolUsd
Pour utiliser le modèle kink, les clés à configurer seraient OPTIMAL_USAGE_FACTOR
, BASE_BORROWING_FACTOR
et ABOVE_OPTIMAL_USAGE_BORROWING_FACTOR
, le facteur d'emprunt par seconde serait calculé comme suit :
// usageFactor is the ratio of value reserved for positions to available value that can be reserved
usageFactor = MarketUtils.getUsageFactor(...)
borrowingFactorPerSecond = baseBorrowingFactor * usageFactor
if (usageFactor > optimalUsageFactor) {
diff = usageFactor - optimalUsageFactor
additionalBorrowingFactorPerSecond = aboveOptimalUsageBorrowingFactor - baseBorrowingFactor
borrowingFactorPerSecond += additionalBorrowingFactorPerSecond * diff / (Precision.FLOAT_PRECISION - optimalUsageFactor)
}
Il existe également une option permettant de définir un indicateur skipBorrowingFeeForSmallerSide, ce qui entraînerait la mise à zéro des frais d'emprunt pour le côté le plus petit. Par exemple, s’il y a plus de positions longues que de positions courtes et que skipBorrowingFeeForSmallerSide est vrai, alors les frais d’emprunt pour les positions courtes seraient nuls.
Le code d'impact sur les prix se trouve dans les contrats /pricing
.
L’impact sur les prix est calculé comme suit :
(initial USD difference) ^ (price impact exponent) * (price impact factor) - (next USD difference) ^ (price impact exponent) * (price impact factor)
Pour les swaps, le déséquilibre est calculé comme la différence entre la valeur des jetons longs et des jetons courts.
Par exemple:
price impact exponent
est défini sur 2 et price impact factor
est défini sur 0.01 / 50,000
0 ^ 2 * (0.01 / 50,000) - 50,000 ^ 2 * (0.01 / 50,000) => -$500
50,000 ^ 2 * (0.01 / 50,000) - 25,000 ^ 2 * (0.01 / 50,000) => $375
Pour les actions de position (augmentation/diminution de la position), le déséquilibre est calculé comme la différence entre les intérêts ouverts longs et courts.
price impact exponents
et price impact factors
sont configurés par marché et peuvent différer pour les actions au comptant et de position.
Notez que ce calcul correspond à l'impact sur le prix de la transaction d'un utilisateur et non à l'impact sur le prix du pool. Par exemple, la transaction d'un utilisateur peut avoir un impact sur le prix de 0,25 %, la prochaine transaction pour un très petit montant peut avoir un impact sur le prix de 0,5 %.
L’objectif de l’impact prix est de :
Étant donné que les contrats utilisent un prix oracle qui serait un prix moyen ou médian de plusieurs échanges de référence. Sans impact sur les prix, il peut être rentable de manipuler les prix sur les bourses de référence tout en exécutant les ordres sur les contrats.
Ce risque sera également présent si les valeurs d'impact positif et négatif sur les prix sont similaires, c'est pourquoi l'impact positif sur les prix doit être fixé à une valeur faible en période de volatilité ou de mouvements de prix irréguliers.
Pour l'impact du prix sur les augmentations/diminutions de la position, si un impact négatif sur le prix est déduit comme garantie de la position, cela pourrait conduire à ce que la position ait un effet de levier différent de celui prévu par l'utilisateur, donc au lieu de déduire la garantie, le prix d'entrée/de sortie de la position est ajusté en fonction de l’impact des prix.
Par exemple:
Si le jeton d'indice est différent du jeton long et du jeton court du marché, il est alors possible que la valeur du pool soit affectée de manière significative par le pool d'impact de position, si le pool d'impact de position est très grand et que le jeton d'indice a un prix élevé. augmenter. Une option permettant de réduire progressivement la taille du pool d’impact des positions peut être ajoutée si cela devient un problème.
L'impact sur les prix est également suivi à l'aide d'une valeur d'inventaire virtuel pour les positions et les swaps, ce qui permet de suivre le déséquilibre des jetons sur des marchés similaires, par exemple ETH/USDC, ETH/USDT.
En cas de mouvement important des prix, il est possible qu'un grand nombre de positions soient diminuées ou liquidées d'un côté, provoquant un déséquilibre important entre les intérêts ouverts longs et courts, ce qui pourrait conduire à des valeurs d'impact sur les prix très élevées. Pour atténuer cela, une valeur maximale de facteur d'impact de position peut être configurée. Si l'impact actuel sur le prix dépasse l'impact négatif maximal sur le prix, alors toute garantie excédentaire déduite au-delà de l'impact négatif maximal sur le prix serait conservée dans le contrat. Si aucune manipulation de prix n'a été détectée, cette garantie peut être remise à l'utilisateur. Lorsque l’impact négatif sur les prix est plafonné, il peut être rentable d’ouvrir et de fermer immédiatement des positions, puisque l’impact positif sur les prix peut désormais être supérieur à l’impact négatif plafonné sur les prix. Pour éviter cela, l’impact positif maximum sur les prix doit être configuré pour être inférieur à l’impact négatif maximum sur les prix.
Il existe des frais de swap et des frais de position configurables et par marché.
Les frais d'exécution sont également estimés et comptabilisés lors de la création des demandes de dépôt, de retrait et d'ordre afin que les détenteurs puissent exécuter des transactions à un coût proche de zéro net.
Si un marché a des pièces stables comme jeton de garantie à court terme, il devrait être en mesure de payer intégralement les bénéfices à court terme si l'intérêt ouvert maximum à court terme ne dépasse pas le montant des pièces stables dans le pool.
Si un marché dispose d'un jeton de garantie long différent du jeton d'indice, les bénéfices longs peuvent ne pas être entièrement payés si l'augmentation du prix du jeton d'indice dépasse l'augmentation du prix du jeton de garantie long.
Les marchés disposent d'un facteur de réserve qui permet de plafonner les intérêts ouverts à un pourcentage de la taille du pool, ce qui réduit l'impact des bénéfices des positions courtes et réduit le risque que les positions longues ne puissent pas être entièrement remboursées.
Le prix d'un jeton de marché dépend de la valeur des actifs du pool et du PnL net en attente des positions ouvertes des traders.
Il est possible que les PnL en attente soient plafonnés, les facteurs utilisés pour calculer le prix du token du marché peuvent différer selon l'activité :
Keys.MAX_PNL_FACTOR_FOR_DEPOSITS : il s'agit du plafond du facteur PnL lors du calcul du prix du jeton de marché pour les dépôts
Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS : il s'agit du plafond du facteur PnL lors du calcul du prix du jeton de marché pour les retraits
Keys.MAX_PNL_FACTOR_FOR_TRADERS : il s'agit du plafond du facteur PnL lors du calcul du prix du jeton de marché pour la clôture d'une position.
Ces différents facteurs peuvent être configurés pour aider les fournisseurs de liquidité à gérer les risques et à encourager les dépôts en cas de besoin, par exemple, le plafonnement du PnL du trader aide à plafonner le montant dont le prix du jeton de marché peut être diminué en raison du PnL du trader, le plafonnement du PnL pour les dépôts et les retraits peut entraîner à un prix symbolique de marché inférieur pour les dépôts par rapport aux retraits, ce qui peut inciter les dépôts lorsque le PnL en attente est élevé.
minCollatéralFactor : Ceci détermine le ratio minimum autorisé de (garantie de position) / (taille de la position)
maxPoolAmount : le montant maximum de jetons pouvant être déposés sur un marché
maxOpenInterest : l'intérêt ouvert maximum pouvant être ouvert pour un marché
reserveFactor : Ceci détermine le ratio maximum autorisé de (valeur des jetons réservés aux positions) / (jetons dans le pool)
maxPnlFactor : le ratio maximum de (PnL / valeur des jetons dans le pool)
positionFeeFactor : Ceci détermine le pourcentage de frais à déduire pour les actions d'augmentation/diminution de position, le montant des frais est basé sur le changement de taille de position.
positionImpactFactor : Il s'agit du « facteur d'impact sur le prix » pour les positions décrites dans la section « Impact sur le prix »
maxPositionImpactFactor : Il s'agit de « l'impact maximum sur le prix » pour les positions décrites dans la section « Impact sur le prix »
positionImpactExponentFactor : il s'agit de la valeur de « l'exposant d'impact sur le prix » pour les actions de position, décrite dans la section « Impact sur le prix »
swapFeeFactor : Ceci détermine le pourcentage des frais à déduire pour les swaps, le montant des frais est basé sur le montant du swap.
swapImpactFactor : Il s'agit du « facteur d'impact sur le prix » décrit dans la section « Impact sur le prix »
swapImpactExponentFactor : il s'agit de la valeur de « l'exposant d'impact sur le prix » pour les dépôts et les swaps, décrite dans la section « Impact sur le prix » ci-dessus.
financementFactor : il s'agit de la valeur du "facteur de financement par seconde" décrite dans la section "Frais de financement".
BorrowingFactorForLongs : Il s'agit du "facteur d'emprunt" pour les positions longues décrit dans la section "Frais d'emprunt".
BorrowingFactorForShorts : Il s'agit du "facteur d'emprunt" pour les positions courtes décrit dans la section "Frais d'emprunt".
BorrowingExponentFactorForLongs : Il s'agit du "facteur d'exposant d'emprunt" pour les positions longues décrit dans la section "Frais d'emprunt".
BorrowingExponentFactorForShorts : Il s'agit du "facteur d'exposant d'emprunt" pour les positions longues décrit dans la section "Frais d'emprunt".
Les rôles sont gérés dans le RoleStore, le RoleAdmin a accès pour accorder et révoquer n'importe quel rôle.
Le RoleAdmin sera initialement le déployeur, mais il doit être supprimé une fois les rôles configurés.
Après la configuration initiale :
Seul le contrat Timelock doit avoir le rôle RoleAdmin
De nouveaux rôles peuvent être accordés par les administrateurs Timelock avec un délai
Les valeurs système ne doivent être définies qu'à l'aide du contrat Config.
Aucun EOA ne devrait avoir un rôle de contrôleur
Les gestionnaires de configuration et les administrateurs de timelock pourraient potentiellement perturber le fonctionnement régulier en désactivant des fonctionnalités, en définissant des valeurs incorrectes, en mettant sur liste blanche des jetons malveillants, en abusant de la valeur d'impact positif sur les prix, etc.
Il est prévu que le timelock multisig révoque les autorisations des comptes malveillants ou compromis
Les détenteurs d'ordres et les détenteurs d'ordres gelés pourraient potentiellement extraire de la valeur via l'ordre des transactions, l'exécution retardée des transactions, l'exécution de l'ADL, etc., cela sera partiellement atténué par un réseau de gardiens.
Les signataires d'Oracle doivent déclarer avec précision le prix des jetons
Les jetons de garantie doivent être ajoutés à la liste blanche avec un TOKEN_TRANSFER_GAS_LIMIT configuré
Les jetons de rebasage, les jetons qui modifient le solde lors du transfert, avec des brûlures de jetons, les jetons avec des rappels, par exemple les jetons ERC-777, etc., ne sont pas compatibles avec le système et ne doivent pas être ajoutés à la liste blanche.
Les détenteurs d'ordres peuvent utiliser des prix de différents horodatages pour les ordres limités avec un swap, ce qui entraînerait des montants de sortie différents
Les responsables des ordres doivent valider si une transaction sera annulée avant de l'envoyer afin de minimiser le gaspillage de gaz.
Les détenteurs d'ordres peuvent provoquer l'annulation des demandes au lieu d'être exécutées en exécutant la demande avec suffisamment de gaz.
Si une transaction d'exécution nécessite une grande quantité de gaz proche de la limite maximale de gaz du bloc, il peut être possible de bourrer des blocs pour empêcher la transaction d'être incluse dans les blocs.
Dans certaines blockchains, il est possible pour le détenteur d'avoir un contrôle sur le tx.gasprice utilisé pour exécuter une transaction, ce qui affecterait les frais d'exécution payés au détenteur.
L'exécution des ordres peut être empêchée par un utilisateur malveillant, provoquant intentionnellement un déséquilibre du marché, entraînant un impact élevé sur les prix. Cela devrait être coûteux et difficile à exploiter.
L'impact sur les prix peut être réduit en utilisant des positions et des swaps et en négociant sur les marchés, les chaînes, les forks et d'autres protocoles, ceci est partiellement atténué grâce au suivi des stocks virtuels.
Un utilisateur peut réduire l'impact sur les prix en utilisant des positions à effet de levier élevé, ceci est partiellement atténué par la valeur MIN_COLLATERAL_FACTOR_FOR_OPEN_INTEREST_MULTIPLIER.
Calcul des valeurs d'impact des prix ne tiennent pas compte des frais et des effets résultant de l'impact des prix lui-même, pour la plupart des cas, l'effet sur le calcul de l'impact des prix doit être faible
Il est rare mais possible que la valeur d'une piscine devienne négative, cela peut se produire puisque le FactPooLamount et le PNL en attente sont soustraits de la valeur des jetons dans la piscine
En raison de la différence d'impact de prix de position positif et négatif, il peut y avoir une accumulation de montants de jetons virtuels dans le pool d'impact de position qui affecterait le prix des jetons de marché, le pool d'impact de position devrait être progressivement distribué si nécessaire
L'inventaire virtuel suit la quantité de jetons dans les pools, il faut s'assurer que les jetons de chaque groupement sont du même type et avoir les mêmes décimales, c'est-à-dire que les longs jetons à travers les pools du groupe devraient avoir les mêmes décimales, les jetons courts entre les pools Dans le groupe devrait avoir les mêmes décimales, en supposant que l'USDC a 6 décimales et Dai a 18 décimales, des marchés comme ETH-USDC, Eth-Dai ne devrait pas être groupé
Les identifiants virtuels doivent être définis avant la création du marché / la liste blanche de jeton, s'il est réglé après le commerce pour le jeton / le marché, le suivi ne serait pas précis et peut devoir être ajusté
For L2s with sequencers, there is no contract validation to check if the L2 sequencer is active, oracle keepers should stop signing prices if no blocks are being created by the sequencer, if the sequencer resumes regular operation, the oracle keepers should sign prices for the derniers blocs en utilisant les derniers prix récupérés
Dans le cas où un séquenceur L2 est en panne, il peut empêcher les dépôts en positions pour éviter les liquidations
Pour les transactions qui peuvent être exécutées entièrement à l'aide de flux de prix sur chaîne, il peut être possible de profiter des prix périmés en raison de la latence des prix ou de la baisse de la chaîne, l'utilisation des aliments de prix en chaîne devrait être temporaire et les aliments de latence faibles devraient être utilisé à la place une fois que tous les jetons sont pris en charge
Block Re-Orgs pourrait permettre à un utilisateur d'annuler rétroactivement une commande après l'exécution si le prix ne se déplaçait pas favorablement pour l'utilisateur, il faut prendre soin de traiter cette affaire si l'utilisation des contrats sur des chaînes où des ré-orgs longs sont possibles
La mise à jour et l'annulation des commandes pourraient être à l'avant pour empêcher l'exécution des commandes, cela ne devrait pas être un problème si la probabilité de réussite est inférieure ou égale à 50%, si la probabilité est supérieure à 50%, les frais et L'impact des prix doit être ajusté pour s'assurer que la stratégie n'est pas rentable, l'ajustement des frais d'interface utilisateur ou une remise de référence pourrait également être utilisé pour provoquer des annulations de commande
En cas de temps d'arrêt de la blockchain ou de l'Oracle, les ordonnances peuvent être exécutées à des prix considérablement différents ou ne peuvent pas exécuter si le prix acceptable de l'ordre ne peut pas être rempli
Il y a une dépendance à la précision de l'horodatage du bloc parce que les prix d'Oracle sont validés par rapport à cette valeur, pour les blockchains où les nœuds de blockchain ont un certain contrôle sur l'horodatage, il faut prendre soin de définir l'Oracletimestampad ajustement à une valeur qui rendrait la manipulation de la manipulation de la manipulation de la manipulation de la manipulation de la manipulation de la manipulation de la manipulation de la manipulation de la manipulation de l'Oracletimest horodatage non rentable
La fonction de décalage GLV peut être exploitée en augmentant temporairement l'utilisation sur un marché qui a généralement une faible utilisation. Une fois que le gardien exécute le changement, l'attaquant peut abaisser l'utilisation à ses niveaux normaux. Les frais de position et l'impact des prix doivent être configurés d'une manière qui rend cette attaque suffisamment coûteuse pour couvrir la perte de GLV.
Dans GLV, il peut y avoir des marchés GM qui sont au-dessus de leur maximum de PnltopoolfactorForTraders. Si MaxPNLFACTORFORDEPOSITS de ce marché GM est plus élevé que maxpnlfactorforTraders, le marché GM est plus bas pendant les dépôts, une fois que les commerçants auront réalisé leurs bénéfices plafonnés. L'utilisateur malveillant peut observer un marché GM dans une telle condition et déposer dans le GLV contenant afin de gagner des ADL qui suivront bientôt. Pour éviter ce maxpnlfactorfordEposits, devrait être inférieur ou égal à maxpnlfactorfortraders.
Il est techniquement possible que la valeur marchande devienne négative. Dans ce cas, le GLV serait inutilisable jusqu'à ce que la valeur marchande devienne positive.
Les jetons GM pourraient devenir illiquides en raison d'un facteur PNL élevé ou d'une USD réservée élevée. Les utilisateurs peuvent déposer des jetons GM illiquides dans GVL et retirer la liquidité d'un marché différent, laissant le GLV avec des jetons illiquides. Les paramètres GlvmaxmarkettokenBalanceUSD et GlvmaxmarketKBalanceamount devraient expliquer le risque d'un marché pour éviter d'avoir trop de jetons GM à partir d'un marché risqué.
scripts/verifyFallback.ts
peuvent être utilisés pour vérifier les contratsnpx hardhat verify
, par la suite, tous les contrats de marché devraient être vérifiés car le code source serait le même Si de nouveaux contrats sont ajoutés, ce qui peut entraîner une différence de prix, par exemple des jetons de marché entre les anciens et les nouveaux contrats, il faut prendre soin de désactiver les anciens contrats avant que les nouveaux contrats ne soient activés
Tout protocole externe qui utilise le contrat du lecteur ou les calculs potentiellement dépassés pour les prix doivent être rappelés d'utiliser les derniers contrats et calculs, par exemple
Il est recommandé de publier le meilleur effort Changelog documentant les changements importants dont les intégrations devraient être conscientes, par exemple si un champ est ajouté à une structure transmise dans une fonction de rappel, ce changement peut ne pas être évident pour les intégrations
Si les contrats sont utilisés pour soutenir les marchés synthétiques des actions, il faut veiller à ce que
Les contrats avec le rôle "Contrôleur" ont accès à des fonctions importantes telles que la définition des valeurs de la forme de données, à cause de cela, il faut veiller à ce que ces contrats ne disposent pas de fonctions ou de fonctions génériques qui peuvent être utilisées pour modifier des valeurs importantes
Des tests doivent être ajoutés pour les différents types de marché, par exemple les marchés de spot uniquement, les marchés de jeton simples
La commande des valeurs dans l'événement pour les rappels ne doit pas être modifiée sauf si nécessaire, car les contrats de rappel peuvent faire référence aux valeurs par un index fixe
Notez que si une structure transmise dans les rappels est modifiée, par exemple, dépôt, retrait, structures de commande, cela entraînerait les fonctions des contrats de rappel s'attendant à ce que la structure précédente cesse de fonctionner, à cause de cela, les changements de structures devraient être mis en évidence aux intégrations
Si le système de référence est utilisé, l'OrderHandler doit avoir accès à la mise à jour du code de référence pour les commerçants
Les dépôts, les retraits et les commandes peuvent être annulés si les exigences spécifiées dans la demande ne peuvent pas être remplies, par exemple, le montant MIN. Vérifiez où les fonds et les remboursements de gaz seront envoyés à l'annulation pour vous assurer qu'il correspond aux attentes.
Les ordres de position de diminution peuvent produire deux jetons au lieu d'un seul jeton, au cas où l'échange de position de diminution échoue, il est également possible que la quantité de sortie et la garantie ne soient pas suffisantes pour couvrir les frais, ce qui fait que l'ordre ne soit pas exécuté
S'il y a une grande propagation, il est possible que l'ouverture / la fermeture d'une position puisse modifier considérablement le prix Min et Max du jeton de marché, cela ne devrait pas être manipulable d'une manière rentable
Les modifications des valeurs de configuration telles que Funding_factor, stable_funding_factor, emprunter_factor, skip_browing_fee_for_smaller_side, emprunter_fee_receiver_factor, pourraient entraîner des frais supplémentaires pour les utilisateurs, il pourrait également entraîner un changement dans le prix des jecens du marché, les utilisateurs pourraient également entraîner un changement du prix des jetons du marché des jecens du marché, les utilisateurs pourraient également entraîner un changement dans le prix des jetons du marché des jecens du marché,
Si Trader PNL est plafonné en raison de Max_PNL_FACTOR_FOR_TRADERS, le pourcentage de bénéfices payés aux traders peut différer en fonction de la commande du moment
Les données de l'événement peuvent être transmises aux contrats de rappel, l'ordre des paramètres dans l'événementData sera tenté d'être inchangé, de sorte que les params peuvent être accessibles par index, pour la sécurité, la clé du param la valeur attendue
Certains paramètres tels que Order.sizelta et Order.InitialCollateraldeltaamount peuvent être mis à jour pendant l'exécution, les valeurs mises à jour ne peuvent pas être transmises au contrat de rappel
Lors de la création d'un contrat de rappel, le contrat de rappel peut avoir besoin de la liste blanche du dépôt, de l'ordre de l'ordre ou du retrait-handleur, il convient de noter que de nouvelles versions de ces gestionnaires peuvent être déployées à mesure que un nouveau code est ajouté aux gestionnaires, il est également possible pour deux gestionnaires de Existent temporairement en même temps, par exemple, OrderHandler (1), OrderHandler (2), pour cette raison, le contrat de rappel devrait être en mesure de la liste blanche et d'accepter simultanément des rappels à partir de plusieurs dépôts, des Handrandlers et Massacres
Pour les contrats de rappel au lieu de maintenir une liste blanche séparée pour les dépôts, les Handleurs, les Handleurs, une solution possible consisterait à valider le rôle du MSG.Sender dans le Rolestore, par exemple RoleStore.hasRole(msg.sender, Role.CONTROLLER)
, ce serait ce serait Vérifiez que le MSG.Sender est un gestionnaire valide
Si l'utilisation de contrats tels que l'échangerOrouter, Oracle ou Reader note que leurs adresses changeront à mesure que une nouvelle logique est ajoutée
Si des contrats tels que l'échangeoir, l'oracle ou le lecteur sont mis à jour, un effort doit être fait pour maintenir les paramètres de fonction identiques, cependant, cela peut ne pas toujours être possible, par exemple si une nouvelle propriété de commande doit être prise en charge, l'échangeur devra être changé
Le Rolestore et le DataTastore pour les déploiements ne devraient pas changer, s'ils sont modifiés, une migration de fonds des contrats précédents aux nouveaux contrats sera probablement nécessaire
Bien que le code ait été structuré pour minimiser le risque de réentrance en lecture seule, il faut prendre soin de se prémunir contre cette possibilité
Les wagons de jetons peuvent survenir dans les comptes des détenteurs de jetons GM, l'intégration des contrats détenant des jetons GM doit être en mesure de réclamer ces jetons, sinon les jetons seraient verrouillés, la mise en œuvre exacte pour cela variera en fonction du contrat d'intégration, une possibilité est de permettre la réclamation de jetons qui ne sont pas des jetons de marché, cela peut être vérifié à l'aide de la valeur Keys.MARKET_LIST
Les transferts d'ETH sont envoyés avec native_token_transfer_gas_limit pour la limite de gaz, si le transfert échoue en raison de gaz insuffisants ou d'autres erreurs, l'ETH est envoyé comme Weth à la place
Les comptes peuvent recevoir ETH pour ADLS / Liquidations, si le compte ne peut pas recevoir d'ETH, alors Weth serait envoyé à la place
L'impact positif des prix est plafonné par la quantité de jetons dans les pools d'impact et en fonction des valeurs configurées
L'impact négatif des prix peut être plafonné par des valeurs configurées
Si l'impact des prix négatifs est plafonné, le montant supplémentaire serait conservé dans le pool de garantie réclamable, cela doit être réclamé manuellement en utilisant l'échangeur.
Les frais de financement positifs doivent être réclamés manuellement en utilisant la fonction échangeur.claimFundingFees
Les récompenses d'affiliation doivent être réclamées manuellement à l'aide de la fonction échangeur.
Les marchés ou les fonctionnalités peuvent être désactivés
L'exécution continuera même si un rappel revient
Assurez-vous que les rappels ont suffisamment de gaz
Les sous-comptes peuvent créer, mettre à jour et annuler toute commande pour un compte
Les sous-comptes peuvent dépenser WNT et garantie à partir du compte
Les frais d'interface utilisateur peuvent être modifiés
Les remises de référence peuvent être modifiées
Les fonds pour les adresses sur liste noire seront conservés dans le protocole
Le jeton d'index n'est pas toujours garanti d'être le long jeton
Les taux de frais changent selon qu'il y a un impact positif ou négatif
Considérez le facteur PNL lors de l'estimation du prix GM
Manipuler les annulations de dépôt
Assurez-vous que seuls les gestionnaires avec le rôle du contrôleur peuvent appeler les fonctions de rappel AfterDepositeXecution et AfterdepositCancellation
Assurer que seule l'exécution de dépôt correct peut appeler les fonctions de rappel
Considérez les marchés avec le même jeton long et court, les échanges ne sont pas pris en charge pour ces marchés
Considérez l'impact des prix positifs et négatifs
Il y a une période d'annulation de demande pour un retard configuré où les demandes de dépôt ne peuvent pas être annulées
Les montants de production sont soumis à l'impact des prix et aux frais
Les dépôts ne sont pas autorisés au-dessus du max_pnl_factor_for_deposits
Le premier dépôt sur n'importe quel marché doit aller au récepteur_for_first_deposit
Deux sorties minimales doivent être utilisées pour les retraits
Gérer les annulations de retrait
Assurez-vous que seuls les gestionnaires avec le rôle du contrôleur peuvent appeler les fonctions de rappel AfterwithDrawaleXecution et AfterwithTrawalalCancellation
Assurer que seule l'exécution de retrait correcte peut appeler les fonctions de rappel
Considérez les marchés avec le même jeton long et court, les échanges ne sont pas pris en charge pour ces marchés
Considérez l'impact des prix positifs et négatifs
Il y a une période d'annulation de demande pour un retard configuré où les demandes de retrait ne peuvent pas être annulées
Les montants de production sont soumis à l'impact des prix et aux frais
Les retraits ne sont pas autorisés au-dessus du max_pnl_factor_for_withrawals
Gérer les annulations de commande
Les liquidations et les ADL peuvent déclencher le contrat de rappel enregistré
Les ordres peuvent devenir gelés
Assurez-vous que seuls les gestionnaires avec le rôle du contrôleur peuvent appeler les fonctions de rappel AfterOrDeReXecution, AfterOrderCancellation et AfterOrderOrder
Assurez-vous que l'exécution d'ordre correct peut appeler les fonctions de rappel
Considérez les marchés avec le même jeton long et court, les échanges ne sont pas pris en charge pour ces marchés
Considérez l'impact des prix positifs et négatifs
Les contrats de rappel enregistrés peuvent être modifiés
Il y a une période d'annulation de demande pour un retard configuré où les demandes de commande ne peuvent pas être annulées
Les montants de production sont soumis à l'impact des prix et aux frais
Le pool d'impact de position est distribué aux fournisseurs de liquidités au fil du temps
Si vous tentez de calculer l'impact des prix, l'inventaire virtuel doit être consulté
Trader PNL est plafonné au-dessus du max_pnl_factor_for_traders
L'impact négatif des prix peut être plafonné sur les baisses de position
La diminution de l'ordre sizelta et collateraldelta seront mise à jour automatiquement si elles sont supérieures à la position que la position peut gérer
Considérez la validation de la bossie-caractéristique de la position
Considérez la réduction des waptypes
Considérez le montant minimum
Les références sont toujours versées pendant la liquidation
Il est possible que les postes aient aucune garantie
Les positions avec une taille zéro ne peuvent pas exister
Pour compiler les contrats:
npx hardhat compile
Pour exécuter tous les tests :
npx hardhat test
export NODE_OPTIONS=--max_old_space_size=4096
peut être nécessaire pour exécuter des tests.
Pour imprimer les métriques:
npx ts-node metrics.ts
Pour imprimer la couverture des tests:
npx hardhat coverage