V2 백서 분석

유니스왑 V2란?

유니스왑이 투자를 받고나서 2020년 5월에 새로 컨트랙트를 개발했다. 그렇게 배포한 것이 유니스왑 V2이다. 기존의 단점을 해결했다.

V1 pair

V1에서는 토큰 pair를 만들 때 ERC-20 토큰과 이더리움을 서로 pair로 만들어서 사용했다.

Token exchange contract 가 전부 ERC-20과 이더리움 pair로 이루어져 있었다. 이더리움을 bridge currency로 사용했다.

  • 어떤 사람이 두 스테이블 코인 DAI와 USDT를 pair로 만들고 싶은데 유니스왑에서는 반드시 이더리움을 bridge로 써야 한다.

  • DAI-ETH pair와 USDT-ETH pair를 만들어야 한다.

  • 이더리움을 무조건 들고 있어야 한다.

  • 이 사람은 스테이블 코인만을 pool로 제공하고 싶었는데 어쩔 수 없이 이더리움을 제공함으로 인해서 이더리움 가격이 떨어졌을 때 impermanent loss가 발생한다.

V2 pair

ERC-20 토큰과 ERC-20토큰을 가지고 pair를 만들 수 있게 변경했다.

  • DAI-USDT pair를 생성 가능

  • 이더리움을 보유하지 않아도 되기 때문에 impermanent loss가 방지된다.

하지만 ERC-20과 이더리움 간의 pair도 생성을 해줘야 한다.

그렇기 때문에 예외 케이스가 생기고 코드 양이 배로 늘어난다.

이를 막기 위해서 V2에서는 이더리움을 쓰지 않고 Wrapped ETH라고 하는 이더리움을 ERC-20 토큰 형태로 wrapping한 WETH를 사용한다.

V2에서는 무조건 ERC-20 표준을 가지는 두 토큰을 pair로 만들어서 사용한다.

→ 코드가 간단해지고 수수료가 적게 든다. (이 토큰이 이더리움인지 ERC-20인지 판단하는 로직이 사라지기 때문에)

거래 수수료 변경

V1에서는 거래 수수료 0.3%를 LP들이 가지고 있는 토큰의 지분만큼 분배해줬다.

V2에서는 0.25%만을 지급하고 0.05%는 프로토콜 fee로 따로 걷는다.

0.05%의 프로토콜 수수료는 유니스왑 토큰인 UNI 홀더들에게 제공된다.

Price oracle

유니스왑에서 거래되는 토큰의 교환비가 시중에서 거래되는 토큰의 교환비와 매우 유사하다, 거의 일치한다라는 논문이 발표가 되었다. 이 논문을 근거로 유니스왑에서 거래되는 토큰 비율을 가격 정보로 사용하는 로직을 V2에 넣어놨다.

유니스왑을 price oracle로 사용하게 되면 공격자가 나타날 수 있다. 다량의 토큰을 교환하거나 pool에 집어넣는다거나 해서 정보를 왜곡시킬 수 있다. 그러면 다른 컨트랙트들이 피해를 볼 수 있기 때문에 가격 정보를 그냥 반영하지 않고 과거부터 현재까지 쭉 이어지는 가격 변화들을 가격이 유지된 시간만큼 곱해서 가격을 결정한다. 이렇게 하면 가격이 급격하게 변동하지 않는다.

유니스왑에서 두 토큰의 교환 비율을 정할 때 정수로 딱 떨어지지 않는다. 그런데 Solidity는 소수를 표현할 수 있는 데이터 타입을 지원하지 않는다. 그래서 소수를 표현할 수 있는 새로운 데이터 타입을 정의해서 사용한다. 256-bit 자료형을 사용한다. 첫 112-bit는 정수형을 사용, 그 뒤 112-bit는 소수점 자리수를 위해 사용, 나머지 32-bit는 그 가격이 유지되는 시간을 표현하기 위해서 사용한다.

주소 변경

V2에서는 두 토큰 pair에 대한 주소를 변경할 수 있는 로직을 넣어놨다.

Initialization of liquidity token supply

  • S_minted : 새로 생성되는 LP 토큰

  • X_starting : X 토큰을 풀에 넣기 전의 수량

  • X_deposited : X 토큰을 풀에 넣은 수량

  • S_starting : X 토큰을 풀에 넣기 전에 원래 있던 LP 토큰의 양

새로 생성되는 LP 토큰의 양은 어떤 특정한 ERC-20 토큰의 (이 사람이 넣은 수량 / 전체 수량) 만큼 생성된다.

X-Y 간의 교환인데 왜 X만으로 계산하는가?

  • 두 토큰 중에 S_minted의 값이 더 작은 값이 되도록 하는 S_minted를 찾아서 생성을 해낸다.

  • X가 Y가 될 수도 있다.

토큰 pair를 처음 만들었을 경우 LP 토큰의 수량을 어떻게 결정하는가?

처음 생성할 경우 X_starting이 0이기 때문에 다른 공식을 따른다.

집어넣는 X, Y 토큰 수량의 곱의 루트 값이 새로 생기는 LP 토큰의 양이다. 기하평균값.

예시

ABC 토큰과 XYZ 토큰이 있다.

ABC-XYZ 교환 비율이 1:100이다.

initial deposit이 2ABC, 200XYZ 이다.

이때 depositor가 받는 LP 토큰의 양은 (2*200)^(1/2) = 20 이다.

처음 토큰 pair를 생성하는 사람은 그 LP 토큰을 온전히 갖지 못하고 수수료를 낸다.

그 수수료는 0번 주소로 전송되어서 영원히 묶이게 된다. (burn)

이렇게 하는 이유는 어떤 공격이 있을 수 있기 때문이다.

LP share는 최소 단위가 10^-18이다. 보통 ERC-20 토큰의 최소 단위랑 같다.

그런데 그 사람이 넣는 토큰 지분의 비중이 10^-18보다 작으면 LP share를 못 받는다. 이런 경우를 대비하기 위해 그 사람이 넣은 LP share의 10^-15만큼(10^-18의 1000배)의 LP token을 태워야 한다.

예를 들어 어떤 사람이 LP share하나의 가격을 100$로 맞추고 싶으면 그것의 1000배인 10만$에 해당하는 토큰이 없어진다.

그렇기 때문에 사람들이 초기에 돈을 넣을 때 너무 많이 집어넣지 않는다. 본인이 나중에 수수료를 받아서 얻을 수 있는 이득보다 태워지는 양이 더 많을 수 있기 때문이다.

프로토콜 fee

fee라는 것은 전체 LP 토큰 풀의 인플레이션에 비례해서 부과된다.

k : 두 토큰 수량의 곱

k_2 : 늘어난 LP 토큰의 양 (루트 X*Y)

k_1 : 늘어나기 전 LP 토큰의 양

사람들이 풀에 토큰을 더 많이 넣었다고 하면 k_2의 양이 k_1보다 크다.

이 인플레이션에서 프로토콜 fee로 0.05%를 가지고 간다.

이 수수료는 LP 토큰이 생성되거나 burn 될 때만 호출되어서 부과 된다.

s_1 : 기존에 있던 LP token 의 양

s_m : 프로토콜 fee로 가져가는 LP token의 양

ϕ : 수수료 비율

f_1,2 : 인플레이션 비율

이때 ϕ를 1/6로 잡았다.

위의 두 식을 합치면 다음 식을 유도할 수 있다.

ϕ에 1/6을 대입한 공식을 따라서 프로토콜이 정한 fee를 가져가는 사람에게 수여되는 LP 토큰의 양이 정해진다.

예시

100 DAI와 1 ETH가 존재하면 처음 LP token은 10개가 있다.

k_1 : 1* 100 = 100

s_1 : 10

이 상태에서 인플레이션이 돼서 96DAI와 1.5ETH가 됐다.

k_2 : 96 * 1.5

이 값들을 대입하면

s_m : 0.0286

0.0286 만큼을 프로토콜 fee로 가져간다.

Reference

Last updated