Contratos para Sintéticos GMX.
Esta seção fornece uma visão geral de como o sistema funciona.
Para uma visão geral técnica, consulte a seção mais abaixo.
Os mercados suportam negociações à vista e perp, eles são criados especificando um token de garantia longo, um token de garantia curto e um token de índice.
Exemplos:
Os provedores de liquidez podem depositar o token de garantia longo ou curto, ou ambos, para cunhar tokens de liquidez.
O token de garantia longo é usado para garantir posições longas, enquanto o token de garantia curto é usado para garantir posições curtas.
Os provedores de liquidez assumem os lucros e perdas dos traders no mercado para o qual fornecem liquidez.
Ter mercados separados permite o isolamento do risco, os fornecedores de liquidez só estão expostos aos mercados em que depositam, o que potencialmente permite listagens sem permissão.
Os comerciantes podem usar o token comprado ou vendido como garantia para o mercado.
Os contratos suportam os seguintes recursos principais:
Para evitar problemas iniciais, a maioria das ações requer duas etapas para serem executadas:
Os preços são fornecidos por um sistema oráculo fora da rede, que assina continuamente os preços com base no momento em que os preços foram consultados.
É assinado um preço mínimo e um preço máximo, o que permite incluir informações sobre spreads de compra e venda.
Os preços armazenados no contrato Oracle representam o preço de uma unidade do token usando um valor com 30 casas decimais de precisão.
Representar os preços desta forma permite que as conversões entre valores de tokens e valores fiduciários sejam simplificados, por exemplo, para calcular o valor fiduciário de um determinado número de tokens, o cálculo seria apenas: valor do token * preço oracle, para calcular o valor do token para um valor fiduciário seria: valor fiduciário / preço oracle.
As taxas de financiamento e o impacto nos preços mantêm as posições compradas/vendidas equilibradas, ao mesmo tempo que reduzem o risco de manipulação de preços.
Existem alguns guardiões e nós no sistema:
Existem alguns tipos principais de contratos:
Os contratos são separados nesses tipos para permitir a atualização gradual.
A maioria dos dados é armazenada usando o contrato DataStore.
*Os contratos storeUtils armazenam dados de estrutura usando o DataStore, o que permite que novas chaves sejam adicionadas às estruturas.
EnumberableSets são usados para permitir que listas de pedidos e listas de posições sejam facilmente consultadas por interfaces ou detentores. Isso é usado em indexadores, pois pode haver um atraso para que os indexadores sincronizem o bloco mais recente. Ter as listas armazenadas diretamente no contrato também ajuda a garantir que dados precisos possam ser recuperados e verificados quando necessário.
*Os contratos eventUtils emitem eventos usando o emissor de eventos, os eventos são generalizados para permitir que novos valores-chave sejam adicionados aos eventos sem exigir uma atualização de ABIs.
Abreviação de GMX Liquidity Vault: um invólucro de vários mercados com os mesmos tokens longos e curtos. A liquidez é automaticamente reequilibrada entre os mercados subjacentes com base na utilização dos mercados.
Esta seção fornece uma descrição técnica dos contratos.
Os mercados são criados usando MarketFactory.createMarket
, isso cria um MarketToken e armazena uma estrutura Market.Props no MarketStore.
O MarketToken é usado para acompanhar a participação dos provedores de liquidez no pool de mercado e para armazenar os tokens para cada mercado.
A qualquer momento, o preço de um MarketToken é (worth of market pool) / MarketToken.totalSupply()
, a função MarketUtils.getMarketTokenPrice
pode ser usada para recuperar esse valor.
O valor do pool de mercado é a soma de
Os depósitos adicionam tokens longos/curtos ao pool do mercado e emitem MarketTokens para o depositante.
As solicitações de depósitos são criadas chamando ExchangeRouter.createDeposit, especificando:
As solicitações de depósito são executadas usando DepositHandler.executeDeposit, se o depósito foi criado no timestamp n
, ele deverá ser executado com os preços do oracle após o timestamp n
.
A quantidade de MarketTokens a serem cunhados, antes das taxas e do impacto no preço, é calculada como (worth of tokens deposited) / (worth of market pool) * MarketToken.totalSupply()
.
As retiradas queimam MarketTokens em troca de tokens longos/curtos do pool de um mercado.
As solicitações de saques são criadas chamando ExchangeRouter.createWithdrawal, especificando:
As solicitações de saque são executadas usando WithdrawalHandler.executeWithdrawal, se o saque foi criado no timestamp n
, deverá ser executado com os preços do oracle após o timestamp n
.
A quantidade de tokens longos ou curtos a serem resgatados, antes das taxas e do impacto no preço, é calculada como (worth of market tokens) / (long / short token price)
.
Os tokens longos e curtos de um mercado podem ser trocados entre si.
Por exemplo, se o mercado ETH/USD tiver WETH como token longo e USDC como token curto, WETH pode ser enviado ao mercado para ser trocado por USDC e USDC pode ser enviado ao mercado para ser trocado por WETH.
As solicitações de ordem de troca são criadas chamando ExchangeRouter.createOrder, especificando:
O valor da saída de swap, antes das taxas e do impacto no preço, (amount of tokens in) * (token in price) / (token out price)
.
As solicitações de ordens de swap de mercado são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, deverá ser executada com os preços do oráculo após o timestamp n
.
Ordens de swap passivas que devem ser executadas quando o valor de saída corresponder ao valor mínimo de saída especificado pelo usuário.
As solicitações de ordem de swap de limite são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, ela deverá ser executada com preços oracle após o timestamp n
.
Abra ou aumente uma posição criminosa longa / curta.
As solicitações de ordem de aumento de mercado são criadas chamando ExchangeRouter.createOrder, especificando:
As solicitações de ordem de aumento de mercado são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, deverá ser executada com os preços do oráculo após o timestamp n
.
Ordens passivas de aumento de posição que devem ser executadas quando o preço do token de índice corresponder ao preço aceitável especificado pelo usuário.
Exemplo de posição longa: se o preço atual do token de índice for $ 5.000, uma ordem de aumento de limite pode ser criada com preço aceitável de $ 4.990, a ordem pode ser executada quando o preço do token de índice for <= $ 4.990.
Exemplo de posição curta: se o preço atual do token de índice for US$ 5.000, uma ordem de aumento de limite pode ser criada com preço aceitável de US$ 5.010, a ordem pode ser executada quando o preço do token de índice for >= US$ 5.010.
As solicitações de ordem de aumento de limite são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, ela deverá ser executada com os preços do oracle após o timestamp n
.
Fechar ou diminuir uma posição criminosa comprada/vendida.
As solicitações de ordem de redução de mercado são criadas chamando ExchangeRouter.createOrder, especificando:
As solicitações de ordem de redução de mercado são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, deverá ser executada com os preços do oráculo após o timestamp n
.
Ordens passivas de posição decrescente que devem ser executadas quando o preço do token de índice corresponder ao preço aceitável especificado pelo usuário.
Exemplo de posição longa: se o preço atual do token de índice for US$ 5.000, uma ordem de redução de limite pode ser criada com preço aceitável de US$ 5.010, a ordem pode ser executada quando o preço do token de índice for >= US$ 5.010.
Exemplo de posição curta: se o preço atual do token de índice for $ 5.000, uma ordem de redução de limite pode ser criada com preço aceitável de $ 4.990, a ordem pode ser executada quando o preço do token de índice for <= $ 4.990.
As solicitações de ordem de diminuição de limite são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, ela deverá ser executada com os preços do oracle após o timestamp n
.
Ordens passivas de posição decrescente que devem ser executadas quando o preço do token de índice ultrapassa o preço aceitável especificado pelo usuário.
Exemplo de posição longa: se o preço atual do token de índice for $ 5.000, uma ordem de redução de stop loss pode ser criada com preço aceitável de $ 4.990, a ordem pode ser executada quando o preço do token de índice for <= $ 4.990.
Exemplo de posição curta: se o preço atual do token de índice for US$ 5.000, uma ordem de redução de stop loss pode ser criada com preço aceitável de US$ 5.010, a ordem pode ser executada quando o preço do token de índice for >= US$ 5.010.
As solicitações de ordem de redução de stop-loss são executadas usando OrderHandler.executeOrder, se a ordem foi criada no timestamp n
, ela deve ser executada com os preços do oráculo após o timestamp n
.
O preço da ETH é 5.000 e a ETH tem 18 casas decimais.
O preço de uma unidade de ETH é 5000 / (10 ^ 18), 5 * (10 ^ -15)
.
Para lidar com os decimais, multiplique o valor por (10 ^ 30)
.
O preço seria armazenado como 5000 / (10 ^ 18) * (10 ^ 30) => 5000 * (10 ^ 12)
.
Para otimização do gás, esses preços são enviados ao oráculo na forma de um valor multiplicador decimal uint8 e um valor de preço uint32.
Se o valor do multiplicador decimal for definido como 8, o valor uint32 seria 5000 * (10 ^ 12) / (10 ^ 8) => 5000 * (10 ^ 4)
.
Com esta configuração, os preços do ETH podem ter um valor máximo de (2 ^ 32) / (10 ^ 4) => 4,294,967,296 / (10 ^ 4) => 429,496.7296
com 4 casas decimais de precisão.
O preço do BTC é 60.000 e o BTC tem 8 casas decimais.
O preço de uma unidade de BTC é 60,000 / (10 ^ 8), 6 * (10 ^ -4)
.
O preço seria armazenado como 60,000 / (10 ^ 8) * (10 ^ 30) => 6 * (10 ^ 26) => 60,000 * (10 ^ 22)
.
Valor máximo dos preços BTC: (2 ^ 64) / (10 ^ 2) => 4,294,967,296 / (10 ^ 2) => 42,949,672.96
.
Decimais de precisão: 2.
O preço do USDC é 1 e o USDC tem 6 casas decimais.
O preço de uma unidade de USDC é 1 / (10 ^ 6), 1 * (10 ^ -6)
.
O preço seria armazenado como 1 / (10 ^ 6) * (10 ^ 30) => 1 * (10 ^ 24)
.
Valor máximo dos preços em USDC: (2 ^ 64) / (10 ^ 6) => 4,294,967,296 / (10 ^ 6) => 4294.967296
.
Decimais de precisão: 6.
O preço do DG é 0,00000001 e o DG tem 18 casas decimais.
O preço de uma unidade de DG é 0.00000001 / (10 ^ 18), 1 * (10 ^ -26)
.
O preço seria armazenado como 1 * (10 ^ -26) * (10 ^ 30) => 1 * (10 ^ 3)
.
Valor máximo dos preços DG: (2 ^ 64) / (10 ^ 11) => 4,294,967,296 / (10 ^ 11) => 0.04294967296
.
Decimais de precisão: 11.
A fórmula para calcular como o valor do multiplicador decimal deve ser definido:
Decimais: 30 - (decimais de token) - (número de decimais desejado para precisão)
Exemplo de cálculo para 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)
Exemplo de cálculo para 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)
A fórmula para o multiplicador é: 10 ^ (60 - dataStreamDecimals - tokenDecimals)
As taxas de financiamento incentivam o equilíbrio entre posições longas e curtas, o lado com os contratos em aberto maiores paga uma taxa de financiamento ao lado com os contratos em aberto menores.
As taxas de financiamento para o lado maior são calculadas como (funding factor per second) * (open interest imbalance) ^ (funding exponent factor) / (total open interest)
.
Por exemplo, se o fator de financiamento por segundo for 1/50.000, e o fator expoente de financiamento for 1, e os contratos longos em aberto forem $ 150.000 e os contratos em aberto curtos forem $ 50.000, então a taxa de financiamento por segundo para longos seria (1 / 50,000) * 100,000 / 200,000 => 0.00001 => 0.001%
.
A taxa de financiamento por segundo para shorts seria -0.00001 * 150,000 / 50,000 => 0.00003 => -0.003%
.
Também é possível definir um valor fundingIncreaseFactorPerSecond, o que resultaria na seguinte lógica de financiamento:
longShortImbalance
é calculado como [abs(longOpenInterest - shortOpenInterest) / totalOpenInterest] ^ fundingExponentFactor
longShortImbalance
atual for maior que o thresholdForStableFunding
, a taxa de financiamento aumentará em longShortImbalance * fundingIncreaseFactorPerSecond
longShortImbalance
atual for maior que thresholdForDecreaseFunding
e menor que thresholdForStableFunding
e a inclinação estiver na mesma direção do financiamento, a taxa de financiamento não mudarálongShortImbalance
atual for menor que thresholdForDecreaseFunding
e a inclinação estiver na mesma direção do financiamento, a taxa de financiamento diminuirá em fundingDecreaseFactorPerSecond
Como longShortImbalance > limiarForStableFunding, saveFundingFactorPerSecond deve aumentar em 0.0001% * 6% * 600 = 0.0036%
Como os comprados já estão pagando vendidos, a inclinação é a mesma e o longShortImbalance <limiarForStableFunding, saveFundingFactorPerSecond não deve mudar
Como longShortImbalance < limiarForDecreaseFunding, saveFundingFactorPerSecond deve diminuir em 0.000002% * 600 = 0.0012%
Como a inclinação está na outra direção, saveFundingFactorPerSecond deve diminuir em 0.0001% * 1% * 600 = 0.0006%
Observe que existem formas possíveis de manipular as taxas de financiamento, os fatores de financiamento devem ser ajustados para minimizar esta possibilidade:
Se longOpenInterest > shortOpenInterest e longShortImbalance estiverem dentro do limiteForStableFunding, um usuário que detenha uma posição curta poderá abrir uma posição longa para aumentar o longShortImbalance e tentar fazer com que a taxa de financiamento aumente. Num mercado ativo, deverá ser difícil prever quando uma posição curta oposta seria aberta por outra pessoa para obter o aumento da taxa de financiamento, o que deverá dificultar este jogo. Os fatores de financiamento também podem ser ajustados para ajudar a minimizar o benefício deste jogo. .
Se longOpenInterest > shortOpenInterest e longShortImbalance > limiarForStableFunding, um trader que detém uma posição longa poderia fazer várias pequenas negociações durante esse período para garantir que o fator de financiamento seja atualizado continuamente em vez de um valor maior ser usado durante toda a duração, isso deve minimizar o taxa de financiamento para posições longas, mas não deve diminuir a taxa de financiamento abaixo das taxas esperadas.
Há uma taxa de empréstimo paga aos provedores de liquidez, o que ajuda a evitar que os usuários abram posições longas e curtas para ocupar a capacidade do pool sem pagar quaisquer taxas.
As taxas de empréstimo podem usar um modelo de curva ou um modelo de torção.
Para usar o modelo de curva, as chaves a serem configuradas seriam BORROWING_FACTOR
e BORROWING_EXPONENT_FACTOR
, o fator de empréstimo por segundo seria calculado como:
// 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
Para usar o modelo kink, as chaves a serem configuradas seriam OPTIMAL_USAGE_FACTOR
, BASE_BORROWING_FACTOR
e ABOVE_OPTIMAL_USAGE_BORROWING_FACTOR
, o fator de empréstimo por segundo seria calculado como:
// 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)
}
Há também uma opção para definir um sinalizador skipBorrowingFeeForSmallerSide, o que resultaria na taxa de empréstimo para o lado menor sendo definida como zero. Por exemplo, se houver mais posições compradas do que vendidas e skipBorrowingFeeForSmallerSide for verdadeiro, a taxa de empréstimo para posições vendidas será zero.
O código para impacto no preço pode ser encontrado nos contratos /pricing
.
O impacto no preço é calculado como:
(initial USD difference) ^ (price impact exponent) * (price impact factor) - (next USD difference) ^ (price impact exponent) * (price impact factor)
Para swaps, o desequilíbrio é calculado como a diferença no valor dos tokens longos e dos tokens curtos.
Por exemplo:
price impact exponent
é definido como 2 e price impact factor
é definido como 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
Para ações de posição (posição de aumento/diminuição), o desequilíbrio é calculado como a diferença entre as posições em aberto compradas e vendidas.
price impact exponents
e price impact factors
são configurados por mercado e podem diferir para ações à vista e de posição.
Observe que este cálculo é o impacto do preço para a negociação de um usuário e não o impacto do preço no pool. Por exemplo, a negociação de um utilizador pode ter um impacto de 0,25% no preço, a próxima negociação por um valor muito pequeno pode ter um impacto de 0,5% no preço.
O objetivo do impacto no preço é:
Já os contratos utilizam um preço oráculo que seria um preço médio ou mediano de múltiplas exchanges de referência. Sem impacto nos preços, pode ser lucrativo manipular os preços nas bolsas de referência durante a execução de ordens nos contratos.
Este risco também estará presente se os valores do impacto positivo e negativo dos preços forem semelhantes, por essa razão o impacto positivo dos preços deve ser definido para um valor baixo em tempos de volatilidade ou movimentos irregulares de preços.
Para o impacto do preço nos aumentos/diminuições da posição, se o impacto negativo do preço for deduzido como garantia da posição, isso poderá levar a que a posição tenha uma alavancagem diferente daquela que o utilizador pretendia, pelo que em vez de deduzir a garantia o preço de entrada/saída da posição é ajustado com base no impacto do preço.
Por exemplo:
Se o token de índice for diferente do token comprado e vendido do mercado, então é possível que o valor do pool seja significativamente afetado pelo pool de impacto de posição, se o pool de impacto de posição for muito grande e o token de índice tiver um preço grande aumentar. Uma opção para reduzir gradualmente o tamanho do conjunto de impacto de posição pode ser adicionada se isso se tornar um problema.
O impacto do preço também é rastreado usando um valor de inventário virtual para posições e swaps, que rastreia o desequilíbrio de tokens em mercados semelhantes, por exemplo, ETH/USDC, ETH/USDT.
No caso de um grande movimento de preços, é possível que uma grande quantidade de posições sejam diminuídas ou liquidadas de um lado, causando um desequilíbrio significativo entre contratos em aberto longos e curtos, o que pode levar a valores de impacto de preços muito elevados. Para mitigar isso, um valor máximo do fator de impacto da posição pode ser configurado. Se o impacto atual no preço exceder o impacto negativo máximo no preço, qualquer excesso de garantia deduzido além do impacto negativo máximo no preço será mantido no contrato; se não for detectada manipulação de preço, essa garantia poderá ser liberada para o usuário. Quando o impacto negativo nos preços é limitado, pode ser rentável abrir e fechar imediatamente posições, uma vez que o impacto positivo nos preços pode agora ser superior ao impacto negativo limitado nos preços. Para evitar isso, o impacto máximo positivo no preço deve ser configurado para estar abaixo do impacto máximo negativo no preço.
Existem taxas de swap e taxas de posição configuráveis por mercado.
As taxas de execução também são estimadas e contabilizadas na criação de depósitos, saques e solicitações de ordens, para que os detentores possam executar transações a um custo líquido próximo de zero.
Se um mercado tiver stablecoins como token de garantia curta, ele deverá ser capaz de pagar integralmente os lucros curtos se a quantidade máxima de contratos em aberto não exceder a quantidade de stablecoins no pool.
Se um mercado tiver um token de garantia longo diferente do token de índice, os lucros longos podem não ser totalmente pagos se o aumento de preço do token de índice exceder o aumento de preço do token de garantia longo.
Os mercados têm um fator de reserva que permite que os contratos em aberto sejam limitados a uma percentagem do tamanho do pool, o que reduz o impacto dos lucros das posições curtas e reduz o risco de as posições longas não poderem ser totalmente pagas.
O preço de um token de mercado depende do valor dos ativos no pool e do PnL líquido pendente das posições abertas dos traders.
É possível que o PnL pendente seja limitado. Os fatores usados para calcular o preço do token de mercado podem diferir dependendo da atividade:
Keys.MAX_PNL_FACTOR_FOR_DEPOSITS: este é o limite do fator PnL ao calcular o preço do token de mercado para depósitos
Keys.MAX_PNL_FACTOR_FOR_WITHDRAWALS: este é o limite do fator PnL ao calcular o preço do token de mercado para retiradas
Keys.MAX_PNL_FACTOR_FOR_TRADERS: este é o limite do fator PnL ao calcular o preço do token de mercado para fechar uma posição
Esses diferentes fatores podem ser configurados para ajudar os provedores de liquidez a gerenciar riscos e incentivar depósitos quando necessário, por exemplo, o limite do PnL do trader ajuda a limitar o valor pelo qual o preço do token de mercado pode ser reduzido devido ao PnL do trader, o limite do PnL para depósitos e retiradas pode levar a um preço simbólico de mercado mais baixo para depósitos em comparação com retiradas, o que pode incentivar depósitos quando o PnL pendente é alto.
minCollateralFactor: determina a proporção mínima permitida de (garantia da posição) / (tamanho da posição)
maxPoolAmount: A quantidade máxima de tokens que podem ser depositados em um mercado
maxOpenInterest: O número máximo de contratos em aberto que podem ser abertos para um mercado
reserveFactor: determina a proporção máxima permitida de (valor dos tokens reservados para posições) / (tokens no pool)
maxPnlFactor: A proporção máxima de (PnL/valor de tokens no pool)
positionFeeFactor: Determina o valor percentual das taxas a serem deduzidas para ações de aumento/diminuição de posição, o valor da taxa é baseado na mudança no tamanho da posição
positionImpactFactor: Este é o "fator de impacto no preço" para posições descritas na seção "Impacto no preço"
maxPositionImpactFactor: Este é o "impacto máximo do preço" para posições descritas na seção "Impacto do preço"
positionImpactExponentFactor: Este é o valor do "expoente do impacto no preço" para ações de posição, descrito na seção "Impacto no preço"
swapFeeFactor: determina o valor percentual das taxas a serem deduzidas para swaps, o valor da taxa é baseado no valor do swap
swapImpactFactor: Este é o "fator de impacto no preço" descrito na seção "Impacto no preço"
swapImpactExponentFactor: Este é o valor do "expoente do impacto no preço" para depósitos e swaps, descrito na seção "Impacto no preço" acima
fundingFactor: Este é o valor do "fator de financiamento por segundo" descrito na seção "Taxas de financiamento"
empréstimoFactorForLongs: Este é o "fator de empréstimo" para posições longas descrito na seção "Taxas de empréstimo"
empréstimoFactorForShorts: Este é o "fator de empréstimo" para posições vendidas descritas na seção "Taxas de empréstimo"
empréstimoExponentFactorForLongs: Este é o "fator expoente de empréstimo" para posições longas descritas na seção "Taxas de empréstimo"
empréstimoExponentFactorForShorts: Este é o "fator expoente de empréstimo" para posições longas descritas na seção "Taxas de empréstimo"
As funções são gerenciadas no RoleStore, o RoleAdmin tem acesso para conceder e revogar qualquer função.
O RoleAdmin será o implementador inicialmente, mas deverá ser removido após a configuração das funções.
Após a configuração inicial:
Apenas o contrato Timelock deve ter a função RoleAdmin
Novas funções podem ser concedidas por administradores de timelock com atraso
Os valores do sistema só devem ser definidos usando o contrato Config
Nenhum EOA deve ter uma função de Controlador
Os responsáveis pela configuração e os administradores de timelock podem interromper a operação regular por meio da desativação de recursos, configuração incorreta de valores, inclusão de tokens maliciosos na lista de permissões, abuso do valor de impacto positivo no preço, etc.
Espera-se que o timelock multisig revogue as permissões de contas maliciosas ou comprometidas
Os detentores de ordens e os detentores de ordens congeladas poderiam potencialmente extrair valor através de pedidos de transações, execução atrasada de transações, execução de ADL, etc., isso será parcialmente mitigado com uma rede de detentores
Espera-se que os assinantes da Oracle relatem com precisão o preço dos tokens
Os tokens colaterais precisam estar na lista de permissões com um TOKEN_TRANSFER_GAS_LIMIT configurado
Tokens de rebase, tokens que alteram o saldo na transferência, com queima de tokens, tokens com retornos de chamada, por exemplo, tokens ERC-777, etc., não são compatíveis com o sistema e não devem ser colocados na lista de permissões
Os detentores de ordens podem usar preços de diferentes carimbos de data/hora para ordens limitadas com um swap, o que levaria a diferentes valores de produção
Espera-se que os detentores de pedidos validem se uma transação será revertida antes de enviá-la para minimizar o desperdício de gás
Os detentores de pedidos podem fazer com que as solicitações sejam canceladas em vez de executadas, executando a solicitação com gás insuficiente
Se uma transação de execução exigir uma grande quantidade de gás próximo ao limite máximo de gás do bloco, pode ser possível preencher blocos para evitar que a transação seja incluída em blocos
Em certas blockchains é possível que o detentor tenha controle sobre o tx.gasprice usado para executar uma transação que afetaria a taxa de execução paga ao detentor
As ordens podem ser impedidas de serem executadas por um usuário mal-intencionado, causando intencionalmente o desequilíbrio do mercado, resultando em um alto impacto no preço; isso deve ser caro e difícil de se beneficiar.
O impacto do preço pode ser reduzido através do uso de posições e swaps e negociação em mercados, cadeias, garfos, outros protocolos, isto é parcialmente mitigado com rastreamento de inventário virtual
Um usuário pode reduzir o impacto no preço usando posições de alta alavancagem, isso é parcialmente mitigado com o valor MIN_COLLATERAL_FACTOR_FOR_OPEN_INTEREST_MULTIPLIER
O cálculo dos valores de impacto dos preços não é responsável pelas taxas e os efeitos resultantes do impacto do preço em si, na maioria dos casos o efeito no cálculo do impacto dos preços deve ser pequeno
É raro, mas possível que o valor de uma piscina se torne negativo, isso pode acontecer, pois o impactoPoolamount e o PNL pendente são subtraídos do valor dos tokens na piscina
Devido à diferença no impacto positivo e negativo do preço da posição, pode haver um acúmulo de quantidades virtuais de token no pool de impacto da posição que afetaria o preço dos tokens de mercado, o pool de impacto de posição deve ser gradualmente distribuído, se necessário
O inventário virtual rastreia a quantidade de tokens nas piscinas, deve -se garantir que os tokens em cada agrupamento sejam do mesmo tipo e tenham as mesmas decimais, ou seja, os tokens longos nas piscinas do grupo devem ter os mesmos decimais, os tokens curtos nas piscinas No grupo deve ter os mesmos decimais, assumindo que o USDC tem 6 decimais e DAI tem 18 decimais, mercados como ETH-USDC, eth-Dai não devem ser agrupados
Os IDs virtuais devem ser definidos antes da lista de permissões de criação / token do mercado, se for definido após a negociação para o token / mercado, o rastreamento não seria preciso e pode precisar ser ajustado
Para L2s com sequenciadores, não há validação de contrato para verificar se o sequenciador L2 está ativo, o Oracle Keepers deve parar de assinar os preços se nenhum bloco estiver sendo criado pelo sequenciador, se o sequenciador retomar a operação regular, os detentores do Oracle devem assinar preços para o os mais recentes blocos usando os preços mais recentes buscados
Caso um seqüenciador L2 esteja inativo, pode impedir depósitos em posições para evitar liquidações
Para transações que podem ser executadas inteiramente usando feeds de preços na cadeia, pode ser possível tirar proveito dos preços obsoletos devido à latência de preços ou à cadeia estar inativa, o uso dos feeds de preços na cadeia deve ser temporário e os feeds de baixa latência devem ser usado em vez
Os reorgs de bloco podem permitir que um usuário cancelasse retroativamente um pedido após a execução de executada se o preço não se movesse favoravelmente para o usuário, deve-se tomar cuidado para lidar com esse caso se usar os contratos em correntes onde são possíveis reorgs longos
Atualização e cancelamento de ordens podem ser de frente para impedir a execução de pedidos, isso não deve ser um problema se a probabilidade de uma corrida bem-sucedida for menor ou igual a 50%, se a probabilidade for superior a 50%, taxas e taxas e O impacto do preço deve ser ajustado para garantir que a estratégia não seja lucrativa líquida, ajustando a taxa da interface do usuário ou desconto de referência poderia ser usado da mesma forma para causar cancelamentos de pedidos
Em caso de inatividade do blockchain ou Oracle, os pedidos podem ser executados a preços significativamente diferentes ou podem não ser executados se o preço aceitável da ordem não puder ser cumprido
Existe uma dependência da precisão do registro de data e hora do bloco, porque os preços do Oracle são validados em relação a esse valor, para blockchains onde os nós da blockchain têm algum controle sobre o registro de data e hora, deve -se tomar cuidado para definir ojustamento oracletimestampad Timestamp não lucrativo
O recurso de mudança de GLV pode ser explorado aumentando temporariamente a utilização em um mercado que normalmente possui baixa utilização. Uma vez que o goleiro execute a mudança, o invasor pode diminuir a utilização de volta aos seus níveis normais. As taxas de posição e o impacto do preço devem ser configurados de uma maneira que torne esse ataque caro o suficiente para cobrir a perda de GLV.
No GLV, pode haver mercados GM que estão acima de seus pnltopoolFactorForTraders máximos. Se o maxpnlFactorfordEposits deste mercado deste GM for maior que o MaxpnlFactorFortraders, o mercado de GM será avaliado mais baixo durante os depósitos do que uma vez que os comerciantes receberão seus lucros limitados. O usuário malicioso pode observar um mercado de GM em tal condição e depositar no GLV que o contém para ganhar com as ADLs que em breve se seguirão. Para evitar esse maxpnlFactorfordEposits, deve ser menor ou igual a maxpnlFactorFortraders.
É tecnicamente possível que o valor de mercado se torne negativo. Nesse caso, o GLV seria inutilizável até que o valor de mercado se torne positivo.
Os tokens GM podem se tornar ilíquidos devido ao alto fator PNL ou USD alta reservada. Os usuários podem depositar tokens GM ilíquidos na GVL e retirar a liquidez de um mercado diferente, deixando o GLV com tokens ilíquidos. Os parâmetros GLVMaxMarkTokenBalanceUSD e GlvMaxMarketTenyBayBalanceamount devem explicar o risco de um mercado para evitar ter muitos tokens GM de um mercado arriscado.
scripts/verifyFallback.ts
podem ser usados para verificar os contratosnpx hardhat verify
, depois todos os contratos de mercado devem ser verificados, pois o código -fonte seria o mesmo Se forem adicionados novos contratos que podem levar a uma diferença de preços, por exemplo, tokens de mercado entre os contratos antigos e novos, deve -se tomar cuidado para desativar os contratos antigos antes que os novos contratos sejam ativados
Quaisquer protocolos externos que usem o contrato do leitor ou cálculos potencialmente desatualizados para preços devem ser lembrados de usar os contratos e cálculos mais recentes, por exemplo, feeds de preços de link de cadeia para tokens GM
Recomenda -se publicar um melhor esforço Changelog documentando mudanças importantes sobre as quais as integrações devem estar cientes, por exemplo, se um campo for adicionado a uma estrutura que é transmitida a uma função de retorno de chamada, essa alteração pode não ser óbvia para integrações
Se os contratos forem usados para apoiar os mercados sintéticos de ações, deve -se tomar cuidado para garantir que as divisões de ações e alterações semelhantes possam ser tratadas
Contratos com a função "Controller" têm acesso a funções importantes, como definir valores de dados de dados, devido a isso, deve -se tomar cuidado para garantir que esses contratos não tenham funções ou funções genéricas que possam ser usadas para alterar valores importantes
Os testes devem ser adicionados para os diferentes tipos de mercado, por exemplo, apenas mercados, mercados de token único
A ordem dos valores nos dados do evento para retornos de chamada não deve ser modificada, a menos que seja estritamente necessário, pois os contratos de retorno de chamada podem referir os valores por um índice fixo
Observe que, se uma estrutura transmitida para retornos de chamada for alterada, por exemplo, depósito, retirada, estrutura de pedidos, isso causaria as funções dos contratos de retorno de chamada que espera que a estrutura anterior parasse de funcionar, devido a isso, as mudanças nas estruturas devem ser destacadas para integrações
Se o sistema de referência estiver sendo usado, o OrderHandler deve ter acesso para atualizar o código de referência para comerciantes
Depósitos, retiradas e ordens podem ser cancelados se os requisitos especificados na solicitação não puderam ser atendidos, por exemplo, o valor mínimo. Verifique para onde os fundos e os reembolsos de gás serão enviados para o cancelamento para garantir que ele corresponda às expectativas.
Diminuir as ordens de posição podem gerar dois tokens em vez de um único token, caso a troca de posição de diminuição falhe, também é possível que a quantidade de saída e a garantia não sejam suficientes para cobrir taxas, fazendo com que a ordem não seja executada
Se houver uma grande disseminação, é possível que abrir / fechar uma posição possa alterar significativamente o preço mínimo e máximo do token de mercado, isso não deve ser manipulável de uma maneira lucrativa
Alterações nos valores de configuração, como Financing_Factor, stable_funding_factor, empréstimo, skip_bororrowing_fee_for_smaller_side, empréstimo_fee_receiver_factor, pode levar a cobranças adicionais para os usuários, também pode resultar em uma alteração no preço do mercado tokens
Se o Trader PNL for limitado devido a max_pnl_factor_for_traders, a porcentagem de lucro paga aos comerciantes pode diferir dependendo da ordem de quando as posições são reduzidas / fechadas, pois a tampa é recalculada com base no estado atual do pool
Os dados do evento podem ser passados para contratos de retorno de chamada, a ordem dos parâmetros nos dados do evento será tentada para permanecer inalterada; portanto, os parâmetros podem ser acessados por índice, para segurança a chave do parâmetro ainda deve ser validada antes de usar para verificar se ele corresponde o valor esperado
Alguns parâmetros como Order.Sizedelta e Order.initialcollateraldeltaamount podem ser atualizados durante a execução, os valores atualizados não podem ser passados para o contrato de retorno de chamada
Ao criar um contrato de retorno de chamada, o contrato de retorno de chamada pode precisar de uma lista de depósito, deposithandler, OrderHandler ou retirada, deve -se notar que novas versões desses manipuladores podem ser implantadas à medida que o novo código é adicionado aos manipuladores, também é possível para dois manipuladores para Existe temporariamente ao mesmo tempo, por exemplo, OrderHandler (1), OrderHandler (2), devido a isso, o contrato de retorno de chamada deve ser capaz de colocar a lista de permissões e aceitar simultaneamente retornos de chamada de múltiplos DepositHandlers, Ordershandlers e Retirados
Para contratos de retorno de chamada em vez de manter uma lista de permissões separados para deposithandlers, OrderHandlers, retiradas, uma solução possível seria validar o papel do msg.sender no rolestore, por exemplo, RoleStore.hasRole(msg.sender, Role.CONTROLLER)
, isso seria Verifique se o msg.sender é um manipulador válido
Se o uso de contratos como o trocador, o Oracle ou o leitor observar que seus endereços mudarão à medida que a nova lógica é adicionada
Se contratos como o trocador, o Oracle ou o leitor forem atualizados, deve ser feito um esforço para manter os parâmetros da função iguais, no entanto, isso nem sempre é possível, por exemplo, se uma nova propriedade de pedido for suportada, o trocador. terá que ser alterado
O Rolestore e o DataStore para implantações não devem mudar, se forem alterados uma migração de fundos dos contratos anteriores para os novos contratos provavelmente serão necessários
Embora o código tenha sido estruturado para minimizar o risco de reentrância somente leitura, deve-se tomar cuidado para se proteger contra essa possibilidade
A Airdrops de token pode ocorrer nas contas dos titulares de token GM, integrando contratos que mantêm tokens GM devem poder reivindicar esses tokens, caso contrário os tokens seriam bloqueados, a implementação exata para isso variará dependendo do contrato de integração, uma possibilidade é permitir reivindicar a reivindicação de tokens que não são tokens de mercado, isso pode ser verificado usando o valor Keys.MARKET_LIST
As transferências ETH são enviadas com nativo_token_transfer_gas_limit para o limite de gás, se a transferência falhar devido a gás insuficiente ou outros erros, o ETH é enviado como Weth em vez
As contas podem receber ETH por ADLs / liquidações, se a conta não puder receber ETH, então Weth será enviado
O impacto positivo do preço é limitado pela quantidade de tokens nos pools de impacto e com base em valores configurados
O impacto negativo do preço pode ser limitado pelos valores configurados
Se o impacto negativo do preço for limitado, o valor adicional seria mantido no reivindicável pool colateral, isso precisa ser reivindicado manualmente usando o trocador. Função Claimcollateral
Taxas de financiamento positivas precisam ser reivindicadas manualmente usando o trocador.
As recompensas afiliadas precisam ser reivindicadas manualmente usando o trocador.
Mercados ou recursos podem ser desativados
A execução ainda continuará mesmo se um retorno de chamada reverter
Verifique se os retornos de chamada têm gás suficiente
As subcontas podem criar, atualizar e cancelar qualquer pedido para uma conta
As subcontas podem gastar Wnt e garantia da conta
As taxas da interface do usuário podem ser alteradas
Descontos de referência podem ser alterados
Os fundos para endereços na lista negra serão mantidos dentro do protocolo
O token do índice nem sempre é garantido como o token longo
Taxas mudam dependendo se há um impacto positivo ou negativo
Considere o fator PNL ao estimar o preço da GM
Lidar com cancelamentos de depósito
Certifique -se de que apenas os manipuladores com a função do controlador possam chamar as funções de retorno de chamada de AfterDepositExecution e AfterDepositCancellation
Certifique -se de que apenas a execução correta do depósito pode chamar funções de retorno de chamada
Considere mercados com o mesmo token longo e curto, os swaps não são suportados para esses mercados
Considere impacto positivo e negativo no preço
Há um período de cancelamento de solicitação para um atraso configurado, onde solicitações de depósito não podem ser canceladas
Os valores de saída estão sujeitos ao impacto do preço e às taxas
Depósitos não são permitidos acima do max_pnl_factor_for_deposits
O primeiro depósito em qualquer mercado deve ir para o receptor_for_first_deposit
Duas saídas mínimas devem ser usadas para saques
Lidar com cancelamentos de retirada
Certifique -se de que apenas os manipuladores com a função do controlador possam chamar as funções AfterWithDrawalexecution e AfterWithDrawalCancellation
Verifique se apenas a execução correta de retirada pode chamar funções de retorno de chamada
Considere mercados com o mesmo token longo e curto, os swaps não são suportados para esses mercados
Considere impacto positivo e negativo no preço
Há um período de cancelamento de solicitação para um atraso configurado, onde solicitações de retirada não podem ser canceladas
Os valores de saída estão sujeitos ao impacto do preço e às taxas
Os retirados não são permitidos acima do max_pnl_factor_for_withdrawals
Lidar com cancelamentos de pedidos
Liquidations e ADLs podem acionar o contrato de retorno de chamada salvo
Ordens podem ficar congeladas
Certifique -se de que apenas os manipuladores com a função do controlador possam chamar as funções de retorno de chamada após a encomenda, após a encomenda e o retorno de chamada após o encomenda
Certifique -se de que apenas a execução correta do pedido pode chamar funções de retorno de chamada
Considere mercados com o mesmo token longo e curto, os swaps não são suportados para esses mercados
Considere impacto positivo e negativo no preço
Os contratos de retorno de chamada salvos podem ser alterados
Há um período de cancelamento de solicitação para um atraso configurado, onde solicitações de pedido não podem ser canceladas
Os valores de saída estão sujeitos ao impacto do preço e às taxas
O pool de impacto da posição é distribuído aos provedores de liquidez ao longo do tempo
Se tentar calcular o impacto dos preços, o inventário virtual deve ser consultado
Trader PNL está coberto acima do max_pnl_factor_for_traders
O impacto negativo do preço pode ser limitado na posição diminuindo
Diminuir a ordem de Sizelta e Colatateralta será atualizada automaticamente se forem maiores que a posição pode lidar
Considere a validação WillPositionCollateralbesuficiente
Considere a diminuição do tipo de vista
Considere a quantidade de garantia mínima
As referências ainda são pagas durante a liquidação
É possível que as posições tenham zero garantia
Posições com tamanho zero não podem existir
Para compilar contratos:
npx hardhat compile
Para executar todos os testes:
npx hardhat test
export NODE_OPTIONS=--max_old_space_size=4096
pode ser necessário para executar testes.
Para imprimir métricas de código:
npx ts-node metrics.ts
Para imprimir cobertura de teste:
npx hardhat coverage