BTC
ETH
HTX
SOL
BNB
Xem thị trường
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

Thảo luận ngắn gọn về Curve: Giao thức trao đổi Stablecoin mạnh mẽ nhất

Bài viết này có khoảng 6844 từ, đọc toàn bộ bài viết mất khoảng 10 phút
Curve, một giao thức nhóm trao đổi tạo thị trường tự động hiệu quả và ngắn gọn, là duy nhất trong lĩnh vực DeFi với độ trượt cực thấp.
Tóm tắt AI
Mở rộng
Curve, một giao thức nhóm trao đổi tạo thị trường tự động hiệu quả và ngắn gọn, là duy nhất trong lĩnh vực DeFi với độ trượt cực thấp.

Giới thiệu

Giới thiệu

StableSwap

tiêu đề cấp đầu tiên

StableSwap là một mô hình giao dịch tiền tệ ổn định được Curve thiết kế và đề xuất trong sách trắng, có thể cung cấp mức trượt giao dịch cực thấp và thanh khoản không giới hạn.

tiêu đề phụ

Đường cong nhà tạo lập thị trường hàm hằng số (CFMM) của mô hình StableSwap như sau:

Khái niệm thiết kế dựa trên sự kết hợp của hai mô hình tạo thị trường tổng không đổi và sản phẩm không đổi, có đặc điểm là độ trượt thấp của tổng không đổi và tính thanh khoản không giới hạn của sản phẩm không đổi

tiêu đề phụ

lấy được

Giả sử rằng có tổng cộng n đồng tiền ổn định, có:

Kết hợp 2 công thức trên để đơn giản ta được công thức (1)

đặc trưng

tiêu đề phụ

Basepool

đặc trưng

basepool là nhóm trao đổi cơ bản do Curve đưa ra. Phổ biến nhất là 3pool, bao gồm ba đồng tiền ổn định DAI, USDC và USDT

Hợp đồng basepool triển khai mô hình giao dịch StableSwap cơ bản

tiêu đề phụ

@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

Tính toán thông số

Thuật toán tương tự cũng được sử dụng trong hàm _get_y để tính giá trị 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

tính trôi chảy

tiêu đề phụ

@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,tính trôi chảy
   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,Việc bổ sung tính thanh khoản của nhóm Curve khác với hai tài sản mà Uniswap phải thêm các cặp giao dịch và nhóm cơ sở chỉ có thể thêm một tài sản nhất định vào nhóm
   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# trạng thái ban đầu 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# lý thuyết D1 sau khi thêm thanh khoản
0: #hunya# Đây không phải là lần đầu tiên thêm thanh khoản để trừ phí xử lý
   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 sau khi trừ phí xử lý

Metapool là một pool mới bắt nguồn từ việc mở rộng basepool, được sử dụng để neo đồng tiền ổn định mới vào mã thông báo LP của basepool. Nhà cung cấp thanh khoản của nhóm cơ sở có thể thêm mã thông báo LP của nhóm cơ sở vào metapool để thêm thanh khoản trở lại và kiếm thêm thu nhập từ phí giao dịch.

Trong hợp đồng metapool, đồng tiền ổn định mới và đồng tiền ổn định của nhóm cơ bản được kết hợp gián tiếp. Trong khi cung cấp chức năng trao đổi giữa các đồng tiền ổn định khác nhau, nó cũng phân tách rủi ro của đồng tiền ổn định mới ở một mức độ nhất định.

tiêu đề phụ

@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
  ...
Trao đổi tiền ổn định
       old_balances: uint256[N_COINS] = self.balances
       xp: uint256[N_COINS] = self._xp_mem(rates[MAX_COIN], old_balances)
       x: uint256 = 0
Hàm exchange_underlying trong hợp đồng metapool thực hiện chức năng trao đổi lẫn nhau giữa các đồng tiền ổn định
           x = xp[i] + dx_w_fee * rates[i] / PRECISION
nếu base_i < 0 hoặc base_j < 0: #hunya# hoán đổi bao gồm mã thông báo nhóm meta
           # 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,nếu base_i < 0: #hunya# mã thông báo đầu vào là mã thông báo nhóm meta
           # 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 >khác: #hunya# Mã thông báo đầu vào là mã thông báo nhóm cơ sở
           out_amount: uint256 = ERC20(output_coin).balanceOf(self)
           Curve(base_pool).remove_liquidity_one_coin(dy, base_j,0) #hunya# nhóm cơ sở thêm tính thanh khoản
           dy = ERC20(output_coin).balanceOf(self) - out_amount
       assert dy >= _min_dy, "Too few coins in result"
= 0: #hunya# mã thông báo đầu ra là mã thông báo nhóm cơ sở
       # 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

khác: #hunya# Trao đổi mã thông báo nhóm cơ sở thuần túy, gọi trực tiếp chức năng trao đổi nhóm cơ sở

tóm tắt

Nếu việc trao đổi liên quan đến mã thông báo basepool và mã thông báo nhóm metapool, quy trình trung gian sẽ được thực hiện bằng cách thêm hoặc xóa tính thanh khoản thông qua LP của nhóm cơ sở; nếu đó chỉ là việc trao đổi mã thông báo cơ sở, chức năng trao đổi của nhóm cơ sở sẽ được gọi trực tiếp cho trao đổi.


Curve
tiền tệ ổn định
Chào mừng tham gia cộng đồng chính thức của Odaily
Nhóm đăng ký:
https://t.me/Odaily_News
Nhóm trò chuyện:
https://t.me/Odaily_GoldenApe
Tài khoản chính thức:
https://twitter.com/OdailyChina