상세 컨텐츠

본문 제목

The Uniswap V3 Smart Contracts

Blockchain/DeFi

by Yongari 2023. 4. 12. 22:06

본문

 

유니스왑 V3 스마트 컨트랙트 문서에 오신 것을 환영합니다.

이 페이지에는 유니스왑 V3 스마트 컨트랙트에 대한 가이드와 기술 문서가 포함되어 있습니다. 이 문서를 사용하여 V3 프로토콜 스마트 컨트랙트에 대해 배우고 온체인 통합을 개발할 수 있습니다.

가이드
유니스왑 프로토콜을 처음 사용하는 경우, 기본 개념부터 시작하는 것이 좋습니다.
그런 다음 로컬 환경을 설정하고 첫 번째 스왑을 실행할 수 있습니다.

참고자료
더 자세히 알아보려면 기술 참조 문서를 읽어보세요.

리소스

Installation

To interact with the V3 SDK we recommend installing though npm:

npm i --save @uniswap/v3-sdk
npm i --save @uniswap/sdk-core
 

@uniswap/v3-sdk

⚒️ An SDK for building applications on top of Uniswap V3. Latest version: 3.9.0, last published: 9 months ago. Start using @uniswap/v3-sdk in your project by running `npm i @uniswap/v3-sdk`. There are 169 other projects in the npm registry using @unisw

www.npmjs.com

 

 

Background

유니스왑과 통합하기 전에, 유니스왑을 처음 사용하시는 분들은 몇 가지 중요한 개발자 웹3.0 개념, 예시의 구조, SDK 개념에 대한 다음의 배경 정보를 검토하는 것이 도움이 될 수 있습니다.

Providers

블록체인과의 통신은 일반적으로 공급자와 로컬 스마트 컨트랙트 모델 및 해당 ABI를 통해 이루어집니다.

이를 위해 예시에서는 ethers.js 라이브러리를 사용합니다. 공급자를 인스턴스화하려면 데이터 소스가 필요합니다. 예시에서는 두 가지 옵션을 제공합니다:

JSON RPC URL: 이더리움 메인넷이나 로컬 포크로 직접 작업하는 경우, infura와 같은 제품은 다양한 체인 및 테스트넷에 대한 JSON RPC URL을 제공합니다. 이 예제에서는 이더리움 메인넷만 사용하겠습니다.

지갑 확장: 지갑 브라우저 확장 프로그램에 연결하는 경우, 이러한 지갑은 자바스크립트 창 객체에  .ethereum으로 소스를 직접 삽입합니다. 이 객체는 사용자의 지갑에 대한 정보를 표시하고 연결된 체인과 통신할 수 있는 기능을 제공합니다. 이 예시에서 중요한 점은, 이 객체를 ethers.js와 함께 사용하여 공급자를 구성할 수 있다는 것입니다.

 

 

Uniswap's Runnable Examples

각 가이드에는 예제와 상호작용하기 위한 기본 UI를 제공하기 위해 React를 사용해 실행 가능한 예제가 함께 제공되고 구동됩니다. 각 예제는 로컬 블록체인에서 실행하거나 이더리움 메인넷에 직접 연결하는 등 관련 옵션을 제공합니다. 또한 두 환경 모두에 연결할 수 있는 지갑 확장자를 사용할 수도 있습니다.

입력 및 환경 설정은 각 예제의 config.ts에서 구성되며, 간단한 설정과 구성이 가능합니다.

 

Developing and Testing

코드를 테스트하려면 이더리움 메인넷의 로컬 포크를 활용하는 것이 좋습니다. 쉽게 테스트할 수 있도록 각 예시에는 테스트 지갑으로 로컬 체인을 실행할 수 있는 빠른 시작이 포함되어 있습니다. 추가 테스트를 위해 지갑 확장을 사용하고 로컬 체인에 연결하는 것도 권장합니다. 마지막으로, 원하는 경우 각 예제를 이더리움 메인넷에서 실행할 수 있습니다. 전체 개발 지침은 각 코드 예제의 README.md에서 확인할 수 있습니다.

 

Utility Libraries

각 예제는 예제의 libs/ 폴더에 있는 단일 파일에 집중되어 있으며, 각 가이드와 README에 진입 포인트가 명시되어 있습니다.
가이드가 SDK의 핵심 기능에 집중할 수 있도록 각 예제의 libs 폴더에서 추가 기본 빌딩 블록을 찾을 수 있습니다. 이러한 파일에서 내보낸 기능은 각 예제에 필요한 최소한의 기능이며 프로덕션 사용을 위한 완전한 라이브러리가 아닙니다. 여기에는 핵심 개념에 방해가 될 수 있는 토큰, ABI, 블록체인 주소에 대한 정의와 같은 핵심 상수를 저장하는 것도 포함됩니다. 다음은 여러분이 만나게 될 도움이 되는 라이브러리의 요약입니다.

Provider Utilities

provider.ts는 ethers.js의 기본 사항과 지갑 확장 기능 연결을 공급자, 지갑 주소, 트랜잭션 전송 기능에 대한 추상화된 보기로 래핑합니다. 또한 구성 외부에서 코드를 변경하지 않고도 예제에서 실행하려는 구성 환경을 추상화할 수 있도록 도와줍니다.

 

Wallet Utilities

wallet.ts는 지갑(확장 프로그램을 통해 연결되었든 코드/설정에서 정의되었든)의 잔액과 기타 필수 정보를 쿼리할 수 있는 기능을 제공합니다.

 

Pool Information
pool.ts에는 관련 가이드의 필수/핵심 사항이 아닌 경우 풀 정보에 대한 기본 쿼리가 포함되어 있습니다.

 

Display Utilities

conversion.ts는 통화 금액을 처리할 때 사람이 읽을 수 있는 가격을 표시하는 데 도움이 되는 표시 및 가벼운 수학 래퍼를 제공합니다(일반적으로 원시 숫자로 저장되며 정밀도를 위해 소수점 자릿수는 별도로 표시됨).

 

Notable SDK Structures and Concepts

SDK로 작업할 때 몇 가지 디자인 선택 사항과 그 필요성을 이해하는 것이 도움이 될 수 있습니다. 아래에서 몇 가지 중요한 개념을 확인할 수 있습니다.

 

ABI's

다른 사람이 스마트 컨트랙트와 상호작용할 수 있도록 각 컨트랙트는 ABI(애플리케이션 바이너리 인터페이스)를 노출합니다. 이는 블록체인에 정의되어 있으므로 자바스크립트 함수에 올바른 정의가 제공되도록 해야 합니다. ABI는 다양한 SDK에서 제공되며 필요에 따라 가져올 수 있습니다. 일부 예제에서는 필요에 따라 ABI를 직접 정의합니다.

 

CurrencyAmount and JSBI

암호화폐 애플리케이션은 종종 매우 적은 수의 토큰으로 작동합니다. 따라서 높은 정밀도가 매우 중요합니다. 정밀도를 유지하기 위해 CurrencyAmount 클래스는 정확한 값을 분수로 저장하고 웹 전반의 호환성을 위해 JSBI를 활용합니다. 이러한 금액을 사용자에게 보기 좋게 표시하려면 때때로 추가 작업이 필요합니다.

Currency

Currency 클래스는 기본 통화(ETH)와 ERC20 토큰을 모두 나타낼 수 있습니다. 통화는 상대적 가치가 다양하므로 통화 클래스를 사용하면 애플리케이션에서 통화의 주소, 기호 및 이름과 함께 각 통화에 필요한 소수점 수를 정의할 수 있습니다.

 

Getting a Quote

Introduction

이 가이드는 유니스왑 프로토콜에서 토큰 쌍의 현재 호가를 구하는 방법을 다룹니다. 이는 유니스왑 코드 예제 저장소에 있는 호가 계산 코드 예제를 기반으로 합니다. 이 예제를 실행하려면 예제의 README를 확인하고 설정 지침을 따르세요.

 

이 예시에서는 quoteExactInputSingle을 사용하여 USDC - WETH 쌍에 대한 호가를 얻겠습니다. 입력은 토큰 인, 토큰 아웃, 입력 금액 및 수수료입니다.

수수료 입력 매개변수는 스왑 시점에 범위 내 유동성 전체에 분배된 스왑 수수료를 나타냅니다. 이는 풀의 식별자 중 하나이며, 다른 식별자는 토큰 인과 토큰 아웃입니다.

가이드에서 다룰 예정입니다:

1. 풀의 배포 주소 계산하기
2. 풀 컨트랙트 참조 및 메타데이터 가져오기
3. 쿼터 컨트랙트 참조 및 견적 받기

가이드가 끝나면 웹 애플리케이션에서 버튼 하나만 누르면 주어진 입력 토큰 쌍과 입력 토큰 금액에 대한 견적을 가져올 수 있어야 합니다.

이 가이드에서는 다음과 같은 유니스왑 패키지가 사용됩니다:

The core code of this guide can be found in quote.ts

Computing the Pool's deployment address

USDC - WETH 풀 콘트랙트와 상호작용하려면 먼저 배포 주소를 계산해야 합니다. SDK는 이를 위한 유틸리티 메서드를 제공합니다:

Computing the Pool's address
const currentPoolAddress = computePoolAddress({
  factoryAddress: POOL_FACTORY_CONTRACT_ADDRESS,
  tokenA: CurrentConfig.tokens.in,
  tokenB: CurrentConfig.tokens.out,
  fee: CurrentConfig.tokens.poolFee,
})

각 유니스왑 V3 풀은 3가지 특성(토큰 인, 토큰 아웃, 수수료)으로 고유하게 식별되므로, 풀팩토리 컨트랙트의 주소와 함께 이를 사용하여 USDC - ETH 풀의 주소를 계산합니다. 이러한 매개변수는 이미 구성 파일에 정의되어 있습니다:

Configuration Parameters
tokens: {
  in: USDC_TOKEN,
  amountIn: 1000,
  out: WETH_TOKEN,
  fee: FeeAmount.MEDIUM,
},

 

Referencing the Pool contract and fetching metadata

이제 USDC - 이더리움 풀의 배포 주소를 얻었으므로, 이더 컨트랙트의 인스턴스를 구성하여 상호작용할 수 있습니다:

 

Setting up a reference to the Pool contract
const poolContract = new ethers.Contract(
  currentPoolAddress,
  IUniswapV3PoolABI.abi,
  getProvider()

컨트랙트를 구성하려면 컨트랙트의 주소, ABI, 그리고 우리를 위해 RPC 호출을 수행할 공급자를 제공해야 합니다. 유니스왑 V3 프로토콜의 핵심 스마트 컨트랙트가 들어 있는 @uniswap/v3-core 패키지를 통해 컨트랙트의 ABI에 액세스할 수 있습니다:

 

Uniswap V3 Pool smart contract ABI
import IUniswapV3PoolABI from '@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool

컨트랙트에 대한 참조를 구성했으므로 이제 공급자를 통해 해당 메서드에 액세스할 수 있습니다. 일괄 프로미스 호출을 사용합니다. 이 접근 방식은 상태 데이터를 순차적으로 쿼리하지 않고 동시에 쿼리하여, 두 블록에 걸쳐 순차 쿼리를 실행할 경우 반환될 수 있는 동기화되지 않은 데이터를 방지합니다:

 

이러한 메서드의 반환값은 Quoter fetching 함수의 입력값이 됩니다.

이 예제에서는 가져오는 메타데이터가 입력에 이미 존재합니다. 이 가이드에서는 메타데이터를 가져오는 방법을 보여주기 위해 이 정보를 먼저 가져오는데, 향후 가이드에서 자세히 설명할 예정입니다.

 

 

 

Referencing the Quoter contract and getting a quote

풀 컨트랙트에서 했던 것처럼, 쿼터 컨트랙트와 상호작용하기 위해서는 쿼터 컨트랙트에 대한 이더 컨트랙트 인스턴스를 구성해야 합니다:

Setting up a reference to the Quoter contract
const quoterContract = new ethers.Contract(
  QUOTER_CONTRACT_ADDRESS,
  Quoter.abi,
  getProvider()
)

 

유니스왑 V3 프로토콜의 주변 스마트 콘트랙트를 보유하고 있는 @uniswap/v3-periphery 패키지를 통해 콘트랙트의 ABI에 접근할 수 있습니다:

Uniswap V3 Quoter smart contract ABI
import Quoter from '@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json'

 

이제 Quoter 계약을 사용하여 견적을 받을 수 있습니다.

이상적인 세계에서는 쿼터 함수가 뷰 함수가 되어 최소한의 가스 비용으로 온체인에서 매우 쉽게 쿼리할 수 있을 것입니다. 그러나 유니스왑 V3 쿼터 컨트랙트는 원하는 데이터를 반환하기 위해 되돌릴 수 있도록 설계된 상태 변경 호출에 의존합니다. 즉, 쿼터를 호출하는 것은 매우 비싸며 온체인에서 호출해서는 안 됩니다.

이 문제를 해결하기 위해 ethers.js 컨트랙트 인스턴스에서 제공하는 callStatic 메서드를 사용할 수 있습니다. 이는 상태 변경 트랜잭션을 이더리움 노드에 제출하지만, 트랜잭션을 실행하는 대신 노드에 상태 변경을 시뮬레이션하도록 요청하는 유용한 메서드입니다. 그러면 스크립트는 시뮬레이션된 상태 변경의 결과를 반환할 수 있습니다:

 

Getting Quotes from the Quoter contract
const quotedAmountOut = await quoterContract.callStatic.quoteExactInputSingle(
  poolConstants.token0,
  poolConstants.token1,
  poolConstants.fee,
  fromReadableAmount(
    CurrentConfig.tokens.amountIn,
    CurrentConfig.tokens.in.decimals
  ).toString(),
  0
)

 

 

 

호출 결과는 호가 스왑에 대해 받게 되는 출력 토큰의 수입니다.

quoteExactInputSingle은 견적자가 제공하는 4가지 메서드 중 하나에 불과하다는 점에 유의해야 합니다:

quoteExactInputSingle - 스왑하고자 하는 금액이 주어지면 단일 풀의 스왑에 대한 견적을 생성합니다.
quoteExactInput - 스왑하려는 금액이 주어지면 여러 풀에 걸친 스왑에 대한 인출 금액에 대한 견적을 생성합니다.
quoteExactOutputSingle - 인출하고자 하는 금액이 주어지면 단일 풀에 대한 스왑의 인출 금액에 대한 견적을 생성합니다.
quoteExactOutput - 인출하고자 하는 금액이 주어지면 여러 풀에 걸친 스왑에 대한 인입 금액에 대한 견적을 생성합니다.

 

 

관련글 더보기