BTC
ETH
HTX
SOL
BNB
시장 동향 보기
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

곡선에 대한 짧은 이야기: 가장 강력한 스테이블코인 교환 프로토콜

이 기사는 약 6844자로, 전체를 읽는 데 약 10분이 소요됩니다
효율적이고 간결한 자동 시장 조성 거래소 풀 프로토콜인 Curve는 DeFi 분야에서 매우 낮은 슬리피지(slippage)를 자랑합니다.
AI 요약
펼치기
효율적이고 간결한 자동 시장 조성 거래소 풀 프로토콜인 Curve는 DeFi 분야에서 매우 낮은 슬리피지(slippage)를 자랑합니다.

소개

소개

StableSwap

첫 번째 레벨 제목

StableSwap은 백서에서 Curve가 설계하고 제안한 안정적인 통화 거래 모델로, 매우 낮은 거래 미끄러짐과 무제한 유동성을 제공할 수 있습니다.

보조 제목

StableSwap 모델의 CFMM(Constant Function Market Maker Curve)은 다음과 같습니다.

디자인 컨셉은 일정 금액의 낮은 슬리피지와 일정 제품의 무한한 유동성이라는 특징을 가진 일정 금액과 일정 제품의 두 가지 시장 조성 모델의 융합을 기반으로 합니다.

보조 제목

도출하다

총 n개의 스테이블 코인이 있다고 가정하면 다음과 같습니다.

단순화하기 위해 위의 두 공식을 결합하면 공식 (1)을 얻을 수 있습니다.

특징

보조 제목

Basepool

특징

베이스풀은 커브에서 런칭한 기본 거래소 풀로 가장 대표적인 것이 3개의 스테이블 코인 DAI, USDC, USDT로 구성된 3풀입니다.

베이스풀 계약은 기본 StableSwap 트랜잭션 모델을 구현합니다.

보조 제목

@pure
@internal
def _get_D(_xp: uint256[N_COINS], _amp: uint256) -> uint256:
   """
  D invariant calculation in non-overflowing integer operations
  iteratively
  A * sum(x_i) * n**n + D = A * D * n**n + D**(n+1) / (n**n * prod(x_i))
  Converging solution:
  D[j+1] = (A * n**n * sum(x_i) - D[j]**(n+1) / (n**n prod(x_i))) / (A * n**n - 1)
  """
   S: uint256 = 0
   Dprev: uint256 = 0
   for _x in _xp:
       S += _x
   if S == 0:
       return 0
   D: uint256 = S
   Ann: uint256 = _amp * N_COINS
   for _i in range(255):
       D_P: uint256 = D
       for _x in _xp:
           D_P = D_P * D / (_x * N_COINS)  # If division by 0, this will be borked: only withdrawal will work. And that is good
       Dprev = D
       D = (Ann * S / A_PRECISION + D_P * N_COINS) * D / ((Ann - A_PRECISION) * D / A_PRECISION + (N_COINS + 1) *D_P)
       # Equality with the precision of 1
       if D > Dprev:
           if D - Dprev <= 1:
               return D
       else:
           if Dprev - D <= 1:
               return D
   # convergence typically occurs in 4 rounds or less, this should be unreachable!
   # if it does happen the pool is borked and LPs can withdraw via `remove_liquidity`
   raise

매개변수 계산

동일한 알고리즘이 _get_y 함수에서도 y 값을 계산하는 데 사용됩니다.

@view
@internal
def _get_y(i: int128, j: int128, x: uint256, _xp: uint256[N_COINS]) -> uint256:
   """
  Calculate x[j] if one makes x[i] = x
  Done by solving quadratic equation iteratively.
  x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
  x_1**2 + b*x_1 = c
  x_1 = (x_1**2 + c) / (2*x_1 + b)
  """
   # x in the input is converted to the same price/precision
   assert i != j       # dev: same coin
   assert j >= 0       # dev: j below zero
   assert j < N_COINS  # dev: j above N_COINS
   # should be unreachable, but good for safety
   assert i >= 0
   assert i < N_COINS
   A: uint256 = self._A()
   D: uint256 = self._get_D(_xp, A)
   Ann: uint256 = A * N_COINS
   c: uint256 = D
   S: uint256 = 0
   _x: uint256 = 0
   y_prev: uint256 = 0
   for _i in range(N_COINS):
       if _i == i:
           _x = x
       elif _i != j:
           _x = _xp[_i]
       else:
           continue
       S += _x
       c = c * D / (_x * N_COINS)
   c = c * D * A_PRECISION / (Ann * N_COINS)
   b: uint256 = S + D * A_PRECISION / Ann  # - D
   y: uint256 = D
   for _i in range(255):
       y_prev = y
       y = (y*y + c) / (2 * y + b - D)
       # Equality with the precision of 1
       if y > y_prev:
           if y - y_prev <= 1:
               return y
       else:
           if y_prev - y <= 1:
               return y
   raise

유동성

보조 제목

@external
@nonreentrant('lock')
def add_liquidity(_amounts: uint256[N_COINS], _min_mint_amount: uint256) -> uint256:
   """
  @notice Deposit coins into the pool
  @param _amounts List of amounts of coins to deposit
  @param _min_mint_amount Minimum amount of LP tokens to mint from the deposit
  @return Amount of LP tokens received by depositing
  """
   assert not self.is_killed  # dev: is killed
   amp: uint256 = self._A()
   old_balances: uint256[N_COINS] = self.balances
   # Initial invariant
   D0: uint256 = self._get_D_mem(old_balances,유동성
   lp_token: address = self.lp_token
   token_supply: uint256 = CurveToken(lp_token).totalSupply()
   new_balances: uint256[N_COINS] = old_balances
   for i in range(N_COINS):
       if token_supply == 0:
           assert _amounts[i] > 0  # dev: initial deposit requires all coins
       # balances store amounts of c-tokens
       new_balances[i] += _amounts[i]
   # Invariant after change
   D1: uint256 = self._get_D_mem(new_balances,Curve pool의 유동성 추가는 Uniswap이 거래 쌍을 추가해야 하는 두 자산과 다르며, basepool은 풀에 특정 자산만 추가할 수 있습니다.
   assert D1 > D0
   # We need to recalculate the invariant accounting for fees
   # to calculate fair user's share
   D2: uint256 = D1
   fees: uint256[N_COINS] = empty(uint256[N_COINS])
   mint_amount: uint256 = 0
   if token_supply >amp) #hunya# 초기 상태 D0
       # Only account for fees if we are not the first to deposit
       fee: uint256 = self.fee * N_COINS / (4 * (N_COINS - 1))
       admin_fee: uint256 = self.admin_fee
       for i in range(N_COINS):
           ideal_balance: uint256 = D1 * old_balances[i] / D0
           difference: uint256 = 0
           new_balance: uint256 = new_balances[i]
           if ideal_balance > new_balance:
               difference = ideal_balance - new_balance
           else:
               difference = new_balance - ideal_balance
           fees[i] = fee * difference / FEE_DENOMINATOR
           self.balances[i] = new_balance - (fees[i] * admin_fee / FEE_DENOMINATOR)
           new_balances[i] -= fees[i]
       D2 = self._get_D_mem(new_balances,amp) #hunya# 이론 D1 유동성 추가 후
0: #hunya# 취급수수료를 차감하기 위해 유동성을 추가한 것은 처음이 아니다
   else:
       self.balances = new_balances
       mint_amount = D1  # Take the dust if there was any
   assert mint_amount >= _min_mint_amount, "Slippage screwed you"
   # Take coins from the sender
   for i in range(N_COINS):
       if _amounts[i] > 0:
           # "safeTransferFrom" which works for ERC20s which return bool or not
           _response: Bytes[32] = raw_call(
               self.coins[i],
               concat(
                   method_id("transferFrom(address,address,uint256)"),
                   convert(msg.sender, bytes32),
                   convert(self, bytes32),
                   convert(_amounts[i], bytes32),
              ),
               max_outsize=32,
          )
           if len(_response) > 0:
               assert convert(_response, bool)  # dev: failed transfer
           # end "safeTransferFrom"
   # Mint pool tokens
   CurveToken(lp_token).mint(msg.sender, mint_amount)
   log AddLiquidity(msg.sender, _amounts, fees, D1, token_supply + mint_amount)
   return mint_amount

Metapool

amp) #hunya# 취급수수료 차감 후 D2

메타풀은 베이스풀의 확장에서 파생된 새로운 풀로, 새로운 스테이블 통화를 베이스풀의 LP 토큰에 고정하는 데 사용됩니다. 베이스풀 풀의 유동성 공급자는 베이스풀의 LP 토큰을 메타풀에 추가하여 다시 유동성을 추가할 수 있으며, 추가로 거래 수수료 수익을 얻을 수 있습니다.

메타풀 컨트랙트에서는 새로운 스테이블 통화와 기본 풀의 스테이블 통화가 간접적으로 결합되며, 서로 다른 스테이블 코인 간의 교환 기능을 제공함과 동시에 새로운 스테이블 통화의 위험도 어느 정도 분리한다.

보조 제목

@external
@nonreentrant('lock')
def exchange_underlying(i: int128, j: int128, _dx: uint256, _min_dy: uint256) -> uint256:
  ....
   # Use base_i or base_j if they are >= 0
   base_i: int128 = i - MAX_COIN
   base_j: int128 = j - MAX_COIN
   meta_i: int128 = MAX_COIN
   meta_j: int128 = MAX_COIN
   if base_i < 0:
       meta_i = i
   if base_j < 0:
       meta_j = j
   dy: uint256 = 0
  ...
스테이블 코인 교환
       old_balances: uint256[N_COINS] = self.balances
       xp: uint256[N_COINS] = self._xp_mem(rates[MAX_COIN], old_balances)
       x: uint256 = 0
메타풀 컨트랙트의 exchange_underlying 기능은 스테이블 코인 간의 상호 교환 기능을 구현합니다.
           x = xp[i] + dx_w_fee * rates[i] / PRECISION
base_i < 0 또는 base_j < 0인 경우: #hunya# 스왑에 메타 풀 토큰 포함
           # i is from BasePool
           # At first, get the amount of pool tokens
           base_inputs: uint256[BASE_N_COINS] = empty(uint256[BASE_N_COINS])
           base_inputs[base_i] = dx_w_fee
           coin_i: address = self.coins[MAX_COIN]
           # Deposit and measure delta
           x = ERC20(coin_i).balanceOf(self)
           Curve(base_pool).add_liquidity(base_inputs,if base_i < 0: #hunya# 입력 토큰은 메타 풀 토큰입니다.
           # Need to convert pool token to "virtual" units using rates
           # dx is also different now
           dx_w_fee = ERC20(coin_i).balanceOf(self) - x
           x = dx_w_fee * rates[MAX_COIN] / PRECISION
           # Adding number of pool tokens
           x += xp[MAX_COIN]
      ...
       # Withdraw from the base pool if needed
       if base_j >else: #hunya# 입력 토큰은 기본 풀 토큰입니다.
           out_amount: uint256 = ERC20(output_coin).balanceOf(self)
           Curve(base_pool).remove_liquidity_one_coin(dy, base_j,0) #hunya# 기본 풀 유동성 추가
           dy = ERC20(output_coin).balanceOf(self) - out_amount
       assert dy >= _min_dy, "Too few coins in result"
= 0: #hunya# 출력 토큰은 기본 풀 토큰입니다.
       # If both are from the base pool
       dy = ERC20(output_coin).balanceOf(self)
       Curve(base_pool).exchange(base_i, base_j, dx_w_fee, _min_dy)
       dy = ERC20(output_coin).balanceOf(self) - dy
  ...
   log TokenExchangeUnderlying(msg.sender, i, _dx, j, dy)
   return dy

else: #hunya# 순수 기본 풀 토큰 교환, 기본 풀 교환 기능을 직접 호출

요약하다

교환이 베이스풀 토큰과 메타풀 풀 토큰을 포함하는 경우 베이스풀의 LP를 통해 유동성을 추가하거나 제거하여 중간 프로세스가 수행되며, 베이스풀 토큰의 교환만 있는 경우에는 베이스풀의 교환 기능이 직접 호출됩니다. 교환.


Curve
안정적인 통화
Odaily 공식 커뮤니티에 가입하세요