플래시론을 활용한 아비트라지(2)
Overview
다음은 실제코드와 함께 플래시론을 이용하여 아비트라지를 하는 예제를 설명합니다.
본 예제에서는 클레이스왑과 클레임스왑에 존재하는 KUSDT↔KETH 페어간 아비트라지 기회를 포착하고 실행하는 방법 및 코드를 설명합니다.
아비트라지를 하기 위해서는,
플래시론을 활용하여 스왑하는 컨트랙트
기회를 포착하여 트랜잭션을 전송하는 봇
두가지가 필요합니다.
컨트랙트는 세개의 컨트랙트로 구성되어있으며 각각,
기회를 포착한 봇이 트랜잭션을 날려 시작점이 되는 컨트랙트 (A)
플래시론을 이용해 클레이스왑 → 클레임스왑 순서의 차액거래를 하는 컨트랙트 (B)
플래시론을 이용해 클레임스왑 → 클레이스왑 순서의 차액거래를 하는 컨트랙트 (C)
로 구성됩니다. 아래의 설명에서는 각 컨트랙트의 주소를 (A),(B),(C)로 표기하여 설명합니다.
Contract
Arbitrager Contract(A)는 아비트라지 기회를 포착후 Tx를 받는 허브역할을 하게됩니다.
contract Arbitrager {
ILendingPool LENDING_POOL;
IKlaySwapProtocol KLAYSWAP;
IClaimSwapRouter CLAIMSWAP;
...
function swapKlaySwapToClaimSwap(address tokenA, address tokenB, uint256 amount) public {
...
}
function swapClaimSwapToKlaySwap(address tokenA, address tokenB, uint256 amount) public {
...
}
...
}클레이스왑 → 클레임스왑 순서의 아비트라지를 수행하는 함수(swapKlaySwapToClaimSwap) 와 클레임스왑 → 클레이스왑 순서의 아비트라지를 수행하는 함수(swapClaimSwapToKlaySwap) 가 존재합니다. 각각 상황에 맞추어 호출하면 (B), (C) 컨트랙트를 호출하는 플래시론 동작을 수행합니다.
두가지의 함수중 swapClaimSwapToKlaySwap 를 기준으로 설명합니다.
swapClaimSwapToKlaySwap 는
KUSDT → KETH ( 클레임 스왑)
KETH → KUSDT ( 클레이 스왑)
과정의 아비트라지를 수행해주는 함수입니다. 따라서 플래시론을 통해 빌릴 토큰 파라미터인 assets 에 tokenA 주소를, amounts에 파라미터로 받은 amount를 넣고 플래시론을 실행해줍니다.
플래시론 인터페이스 및 파라미터 에 대한 설명은 여기 를 참조해주세요.
LENDING_POOL.flashLoan(...) 을 통해 플래시론을 실행해주고, 플래시론을 통해 로직을 수행할 컨트랙트인
ArbitragerClaimToKlaySwap 에 (C) 주소를 입력합니다.
위 코드는 ArbitragerClaimToKlaySwap 컨트랙트의 일부분입니다. 플래시론을 통해 대출이 실행되었을때 수행할 코드를 작성하기위해 IFlashLoanReceiver 를 상속 받습니다. ArbitragerClaimToKlaySwap 는 클레임스왑 → 클레이스왑의 아비트라지를 수행하는 컨트랙트입니다. 따라서 function executeOperation(...)에서 실질적인 아비트라지를 진행합니다. 빌린 자산인 asset[0] 가 tokenA, 파라미터로 넘어온 데이터인 params가 tokenB가 되게됩니다. 함수의 동작은 다음과같은 순서로 진행됩니다.
클레임 스왑의 getAmountsOut 과 클레이스왑의 estimate를 이용하여 거래를했을때 수익이 나는지 확인합니다.(
require(estimateOut2 > amounts[0]);)_swapClaimSwap를 통해 클레임스왑에서 A→B 토큰으로 교환을 하고_swapKlaySwap를 통해 클레이스왑에서 B→A 토큰으로 교환을 합니다.마지막으로 클레이뱅크에 빌린 자산을 돌려주기위해 approve 를 확인해주는
checkApprove함수를 실행합니다.
이로써 A→B→A 토큰 교환을 마치고 대출금액 및 플래시론 수수료를 상환한 뒤 남은 차액을 얻게됩니다.
swapKlaySwapToClaimSwap 를 사용하는 ArbitragerKlaySwapToClaim 컨트랙트역시 로직은 동일하며 순서만 다릅니다.
Arbitrage Bot
Arbitrage Bot의 전체 소스코드는 http://github.com/klaybank/arbitrager 에 업로드 되어있습니다.
먼저 봇 실행에 필요한 기본적인 Caver, BigNumber 및 컨트랙트의 ABI들을 추가해줍니다.
위에는 각 컨트랙트들의 주소를 나타내며, ArbitragerAddress의 경우 직접 배포한 컨트랙트의 주소가 위치하게 됩니다.
tryKUSDTAmount 는 한번 아비트라지를 시도할때 사용할 금액을 나타내며, 이 예시에서는 10,000 KUSDT를 기준으로 설명합니다.
매 블록마다 기회를 포착하기위해 소켓을 이용하며, 각 컨트랙트들을 ABI와 주소를 이용해 초기화해줍니다.
또한 아비트라지 트랜잭션을 보낼 EOA의 private key를 이용하여 키링을 설정해줍니다.
블록마다 아비트라지기회를 포착하고 실행하는 코드부분입니다.
부분에서 newBlockHeaders 를 subscribe하여 매 블록마다 이벤트를 받을 수 있도록 구성합니다. 이 subscribtion은 블록이 생성될때마다 async (error, result) => {...} 함수 콜백을 실행시켜줍니다.
따라서 콜백함수 내부에서 매 블록마다 클레이스왑 → 클레임스왑 에서 기회가 있는지, 클레임스왑 → 클레이스왑 에서 기회가 있는지 체크하게 됩니다.
콜백함수 내 위 코드는 클레이스왑 → 클레임스왑 에서의 KUSDT→KETH→KUSDT 경로의 아비트라지 기회가 있는지 포착합니다.
클레이 스왑에서 10,000 KUSDT를 KETH로 바꾼 예측값(estimateUsdtToETHKlayswap)를 구합니다. 이 예측값을 다시 이용하여 클레임 스왑에서 KETH를 KUSDT로 바꾼 예측값(estimateETHToUsdtClaimSwap) 를 구합니다.
이때 estimateETHToUsdtClaimSwap 의 값이 tryKUSDTAmount 보다 크다면 아비트라지 기회가 생긴 것 이므로, Contract 섹션에서 설명했던 arbitragerContract의 swapKlaySwapToClaimSwap 함수를 통해 플래시론 및 아비트라지를 수행하게 됩니다.
클레임스왑 → 클레이스왑 의 경우 역시 마찬가지로 클레임 스왑에서 10,000 KUSDT를 KETH로 바꾼 예측값(estimateUsdtToETHClaimSwap) 를 구합니다. 이 예측값을 다시 이용하여 클레이 스왑에서 KETH를 KUSDT로 바꾼 예측값(estimateETHToUsdtKlayswap) 를 구합니다. 그 후 과정은 arbitragerContract의 swapClaimSwapToKlaySwap를 이용하는 것 외에 이전 설명과 동일합니다.
마치며
아비트라지 기회는 위에서 언급한 클레이스왑↔클레임스왑 사이에만 존재하는것은 아닙니다. 또한 KUSDT↔KETH 페어 사이에서만 발생하는 것 역시 아닙니다. 다양한 Dex(클레이스왑, 클레임스왑, 팔라, UFO, …) 과 다양한 페어(KUSDT↔KETH, KLAY↔KUSDT, CLA↔KUSDT, …)를 이용하여 여러 기회를 포착할 수 있습니다.
따라서 봇 코드를 고도화 다양한 경로를 감시 및 아비트라지 할 수 있으며, 더욱 고도화 한다면 고정된 시도금액 ( 예시에서 10,000 KUSDT ) 이 아닌 더 큰 금액 또는 작은 금액으로 가변적으로 조절할 수 있습니다.
플래시론은 이러한 아비트라지 기회를 포착하고 실행할때, 무담보 대출을 실행하여 자본이 없거나 부족하더라도 아비트라지를 안정적으로 성공하도록 도와줍니다.
위 예시 코드에서는, Arbitrager contract에 쌓인 토큰을 꺼내는 함수 및 보안을 위한 사항들이 고려되어있지 않으므로 사용시에는 적절한 수정을 통해 사용하는 것을 권장합니다.
Last updated