[DiFi] Swap Contract

wrld_worthy·2023년 6월 15일
0

DeFi

목록 보기
2/5

Token Swap

swapExactTokensForTokens

일정 수량의 토큰을 다른 토큰으로 스왑(input을 고정)
amountIn ( 토큰을 몇개를 내겠다. ex) 100)
amountOutMin ( 최소한 몇개는 받아야 되겠다. )
특정 토큰을 100개를 줄테니 그 만큼 다른 토큰으로 교환할 때

swapTikensForExactTokens

특정 수량의 토큰을 얻기 위해 스왑(output을 고정)
amountOut ( B토큰을 이 만큼 받겠다. )
amountInMax ( amountOut만큼 얻는데 드는 비용은 amountInMax보다는 적어야 한다. )
B토큰을 얻고 싶은데 A토큰이 몇개 필요하는지 모르고 B토큰을 100개를 받으려고 할 때.

path

토큰 스왑 경로
ex) [ETH, USDT, USDC]
이더리움 토큰을 통해 이더리움을 USDT로 바꾸고, USDT를 USDC로 바꿔서 받겠다는 뜻이 됨.
이런 식으로 PATH를 넘겨줌으로 최적의 경로를 통해 최대한 토큰 손실이 없이 토큰 교환을 수행할 수 있도록 함.

Swap Path

스왑패스는 토큰 스왑 순서를 나타내는 정보인데, 이 path를 어떻게 설정하냐에 따라서 최종적으로 수령할 수 있는 토큰의 수량이 달라진다.

AB, BC, CA 유동성 풀이 있고. 각각의 비율이 존재한다. 유저가 토큰 스왑을 진행할 때, A 10개로 C토큰을 받으려고 한다. swap path를 [A-B-C]로 설정했다면, 스왑 요청을 Router로 보내게 되는데,
일단 AB LP에서 A10개를 주고 B를 100개 받게 된다. 그다음 BC풀에 B를 100개를 주고 C를 100개 받게 되고, 이대로 유저에게 준다.
A 10개 -> B 100개 -> C 100개 의 순서대로 스왑이 이루어지는 것을 볼 수 있다.
하지만 [A-C]로 swap path를 설정하게 된다면, Router는 AC LP에 A를 10개를 주게 되고 C 80개를 받게 된다.
즉, swap path를 어떻게 설정하느냐에 따라 최종적으로 받을 수 있는 토큰의 개수가 달라진다.
(이 예시는 복잡한 계산을 제외하고 단순히 swap path에 따른 수량 변화를 보여주기 위함이다.)

Swap Contract

function swapExactTokenToToken(uint amountIn, address[] calldata path) external { // 주는 토큰에 대한 스왑함수
        // [A-B-C..] A토큰이 스왑할 토큰이기 때문에 path의 첫째 값이 inputToken이 된다.
        address inputToken = path[0];

        // transferFrom으로 inputToken을 받아온다.
        IERC20(inputToken).transferFrom(msg.sender, address(this), amountIn);

        approveToken(inputToken, ROUTER);

        // Swap
        IUniswapV2Router01(ROUTER).swapExactTokensForTokens(amountIn, 0, path, msg.sender, block.timestamp + 10);
    }

    function swapTokenToExactToken(uint amountOut, uint amountInMax, address[] calldata path) external { // 돌려받는 토큰에 대한 스왑 함수.
        uint[] memory amountsIn = IUniswapV2Router01(ROUTER).getAmountsIn(amountOut, path);
        uint amountIn = amountsIn[0];
        require(amountInMax >= amountIn, "exceed amountInMax");

        address inputToken = path[0];

        IERC20(inputToken).transferFrom(msg.sender, address(this), amountIn);

        approveToken(inputToken, ROUTER);
        IUniswapV2Router01(ROUTER).swapTokensForExactTokens(amountOut, amountIn, path, msg.sender, block.timestamp + 10);
    }

    function swapExactKlayToToken(address[] calldata path) payable external {
        require(path[0] == WKLAY, "invalid path");
        require(msg.value > 0, "zero msg.value");
        IUniswapV2Router01(ROUTER).swapExactETHForTokens{value: msg.value}(0, path, msg.sender, block.timestamp + 10);
    }

    function swapKlayToExactToken(uint amountOut, address[] calldata path) payable external {
        require(path[0] == WKLAY, "invalid path");
        require(msg.value > 0, "zero msg.value");
        uint[] memory amountsIn = IUniswapV2Router01(ROUTER).getAmountsIn(amountOut, path);
        IUniswapV2Router01(ROUTER).swapETHForExactTokens{value: amountsIn[0]}(amountOut, path, msg.sender, block.timestamp + 10);

        // return remaining KLAY
        if (msg.value > amountsIn[0]){
            (bool success,) = (msg.sender).call{value: msg.value - amountsIn[0]}(new bytes(0));
            require(success, "fail to trasfer KLAY");
        }
    }

0개의 댓글