> For the complete documentation index, see [llms.txt](https://docs.klaybank.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.klaybank.org/protocol/functions/flashloan/undefined.md).

# 개발 가이드

이 장에서는 플래시론을 활용하여 개발하는 방법 및 동작 방식을 알아보기위해 가장 간단한 형태의 예시와 함께 설명합니다. 아래의 가이드에서 설명의 편의를 위해 플래시론을 활용해 개발할 컨트랙트를 **A컨트랙트**라 표기하도록 하겠습니다.

**A컨트랙트는** 클레이 뱅크의 LendingPool 컨트랙트와 상호작용하게 됩니다. 플래시론을 통한 코드의 진행순서는 다음과 같습니다.

1\. 플래시론을 활용할 상황이 생겼을 때 개발자가 컨트랙트의 특정 함수를 호출합니다. 여기서는 예시로 `exampleFlashLoanCall` 을 호출했다고 가정합니다. 즉 **A컨트랙트**에는 `exampleFlashLoanCall` 함수가 구현되어 있습니다.

2\. `exampleFlashLoanCall` 함수에서 필요한 자산 과 양을 설정하여 **LendingPool 컨트랙트** 에 FlashLoan을 요청하는 `flashLoan` 함수를 호출합니다. 파라미터에 대한 설명은 [여기](#flashloan)를 참고해주세요.

```solidity
interface ILendingPool{
    function flashLoan(
        address receiverAddress,
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata modes,
        address onBehalfOf,
        bytes calldata params,
        uint16 referralCode
      ) external;
} 
```

3\. **LendingPool 컨트랙트**는 **A컨트랙트**가 요청한 금액만큼 자산을 전달합니다.

4\. **LendingPool 컨트랙트**는 **A컨트랙트**의 `executeOperation` 함수를 호출합니다. `executeOperation` 는 `IFlashLoanReceiver` 에 정의되어있으며 플래시론을 활용할 컨트랙트는 이 인터페이스를 반드시 구현해야합니다. 각 파라미터에대한 설명은 [여기](#iflashloanreceiver)를 참고해주세요.

```solidity
interface IFlashLoanReceiver {
    function executeOperation(
      address[] calldata assets,
      uint256[] calldata amounts,
      uint256[] calldata premiums,
      address initiator,
      bytes calldata params
    ) external returns (bool);
}
```

즉 **A컨트랙트**가 실제로 자산을 빌려 동작을 수행하는 코드는 `executeOperation` 함수 내에서 수행되게 됩니다. `executeOperation` 함수는 내부에서 자산을 활용한 뒤 반드시 상환해야할 양(`amounts` + `premium`) 만큼의 자산(토큰) 을 보유하고 있어야 합니다. 또한 **LendingPool 컨트랙트**가 회수해 갈 수 있도록 상환해야할 양 이상 토큰을 **LendingPool 컨트랙트**에 approve 해주어야 합니다.

**5. LendingPool 컨트랙트** 는 마지막으로 `amounts` + `premium` 만큼의 토큰을 **A컨트랙트** 로부터 회수(transferFrom) 해옵니다.

위의 1\~5 까지의 동작중에 예외가 발생하거나 특히

* 4\. 에서 **A컨트랙트** 가 false를 리턴하는경우
* 5\. 에서 **LendingPool 컨트랙트**가 자산이 회수가 불가능한 경우

모든 실행이 취소됩니다.

따라서 대출자(Borrower)는 담보 없이 자산을 빌릴 수 있고, 대여자(Depositor)는 위험성 없이 수수료를 얻을 수 있습니다.

지금까지의 과정을 도식으로 보면 아래와 같습니다.

![플래시론 흐름도 ](https://1588138884-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSEmzO32OosXLfHq4LKuJ%2Fuploads%2FIOC5CKyHhU7wDJIhMxWV%2Fimage.png?alt=media\&token=e799b37d-43a7-461e-9094-8ffe879b14db)

### 파라미터 설명(flashLoan)

아래는 `flashLoan` 함수를 호출하기위한 파라미터와 이에대한 설명입니다.

```solidity
interface ILendingPool{
    function flashLoan(
        address receiverAddress,
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata modes,
        address onBehalfOf,
        bytes calldata params,
        uint16 referralCode
      ) external;
}
```

* `address receiverAddress` : 플래시론을 통해 대출을 발생시켰을 때 자산을 받아가고, `executeOperation` 가 구현되어있는 주소입니다. 이 예제에서는 **A컨트랙트**가 `receiverAddress`가 됩니다.
* `address[] calldata assets` : 대출 받을 자산의 목록입니다.
* `uint256[] calldata amounts` : 대출 받을 자산의 양 목록입니다.
* `uint256[] calldata modes` : 대출 받을 자산들에 대해 대출 모드를 설정합니다. 현재 클레이뱅크의 대출모드는 0만 지원하며 나머지 타입은 추후 지원 예정입니다. 모드는 다음과 같습니다.
  * 0 : 즉시 상환을 의미합니다. 플래시론을 통해 빌린 자산은 트랜잭션 종료와 함께 반드시 상환되어야 합니다. 그렇지 않은경우 실패합니다.
* `address onBehalfOf` : 대출모드가 0이아닐때 사용됩니다. 현재는 값이 무시되므로 `msg.sender` 를 입력하셔도 무방합니다.
* `bytes calldata params` : **LendingPool** 컨트랙트가 `executeOperation` 을 통해 사용자 **A컨트랙트**를 호출할때 넘겨줄 파라미터를 지정할 수 있습니다.
* `uint16 referralCode` : 특정상황에 레퍼럴 구분자로 이용하기 위한 파라미터입니다. 일반 사용시에는 0을 입력하면 됩니다.

### 파라미터 설명(IFlashLoanReceiver)

아래는 `executeOperation` 함수를 호출하기위한 파라미터와 이에대한 설명입니다.

```solidity
interface IFlashLoanReceiver {
    function executeOperation(
      address[] calldata assets,
      uint256[] calldata amounts,
      uint256[] calldata premiums,
      address initiator,
      bytes calldata params
    ) external returns (bool);
}
```

* `address[] calldata assets` : 대출한 자산 목록을 의미합니다.
* `uint256[] calldata amounts` : 대출한 금액 목록을 의미합니다.
* `uint256[] calldata premiums` : 대출한 자산에 대한 수수료가 반영된 금액 목록을 의미합니다. 즉 `amount` + `premium` 만큼을 상환해야합니다.
* `address initiator` : 플래시론을 호출한 주소를 나타냅니다.
* `bytes calldata params` : 플래시론을 호출할때 넘겨준 파라미터 데이터를 나타냅니다

### 예시 컨트랙트

아래는 지금까지 설명했던 **A컨트랙트**의 예시입니다.

```solidity
contract AContract is IFlashLoanReceiver {
// 랜딩풀은 클레이 뱅크의 Lending Pool 주소를 활용해야합니다.
// 또는 클레이 뱅크의 Address Provider를 통해 Lending Pool 주소를 얻어올 수 있습니다.
    ILendingPool public LENDING_POOL; 

    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata params
    )
        external
        override
        returns (bool)
    {
        // 실제 자산을 획득한 뒤 수행할 코드는 여기에 작성하면 됩니다.
        // 파라미터로 넘어온 assets와 amounts를 활용해 코드를 진행합니다.
        // 필요시에 initiator 주소도 활용할 수 있습니다. ( 함수호출자 검증 등 )

        // 특별히 부채생성 모드로 실행하지않은경우 함수 종료시점에 자산을 반환해야합니다.
        // 아래 예시는 클레이뱅크의 Lending Pool 컨트랙트가 자산을 가져갈 수 있도록 토큰에 Approve를 진행해줍니다.
        for (uint i = 0; i < assets.length; i++) {
	    uint amountToRepay = amounts[i].add(premiums[i]);
	    IKIP7(assets[i]).approve(address(LENDING_POOL), amountToRepay);
	}

	/*

	이 부분에 flashloan을 이용해 수행하고자하는 로직을 작성합니다.

	*/ 

	// 로직전개중 트랜잭션을 취소하고싶을때 가스비 최소화를 위해 false를 리턴할 수 있습니다.
	// 일반적인 성공 상황에서는 true를 리턴해주면 됩니다.
	return true;
    }

    function exampleFlashLoanCall() public {
        address receiverAddress = address(this);
        address[] memory assets = new address[](2);
        assets[0] = address(0xcee8faf64bb97a73bb51e115aa89c17ffa8dd167); // KUSDT
        assets[1] = address(0x5c74070fdea071359b86082bd9f9b3deaafbe32b); // KDAI

        uint256[] memory amounts = new uint256[](2);
        amounts[0] = 1000000; // 1 KUSDT
        amounts[1] = 1 ether; // 1 KDAI

        // 0 = 부채 생성 X 즉시 상환 모드
        uint256[] memory modes = new uint256[](2);
        modes[0] = 0;
        modes[1] = 0;

        address onBehalfOf = address(this);
        bytes memory params = "";
        uint16 referralCode = 0;

        LENDING_POOL.flashLoan(
            receiverAddress,
            assets,
            amounts,
            modes,
            onBehalfOf,
            params,
            referralCode
        );
    }
}
```

### 더 알아보기

플래시론을 활용할때 클레이뱅크 **LedingPool 컨트랙트** 의 `flashLoan` 함수를 호출하고 `executeOperation` 를 구현하는 것들이 모두 하나의 컨트랙트 (예시에서는 **A컨트랙트**) 일 필요는 없습니다.

필요에 따라서 일반 계정(EOA)에서 `flashLoan` 를 호출하고 `receiverAddress` 에 `executeOperation` 를 구현한 컨트랙트 주소(예시에서는 **A컨트랙트**)를 기입해도 무방합니다. 또한 또다른 컨트랙트인 **B컨트랙트**에서 호출할수도 있습니다. 각각 모두 `msg.sender`가 달라짐을 유의합니다.

위와같이 누구나 `flashLoan` 을 호출하여 다른 컨트렉트의 `executeOperation` 을 호출할 수 있으므로 [griefing](https://ethereum.stackexchange.com/questions/92391/explain-griefing-attack-on-aave-flash-loan/92457#92457)공격을 조심해야합니다. 해당 공격은 다음과 같이 이루어질 수 있습니다.

* A컨트랙트에 자산(토큰)을 가지고있고 플래시론을 위해 `executeOperation()` 이 구현되어있는경우
* B컨트랙트가 `flashloan()` 에 `receiverAddress` 파라미터로 A컨트랙트 주소를 넣고 실행할 수 있습니다.
* 이 경우 A컨트랙트의 `executeOperation()` 가 실행 될 것이고, 클레이뱅크의 LendingPool은 A컨트랙트로부터 자산 회수를 시도합니다.
* A컨트랙트에 자산이 있기때문에 자산회수가 성공하게되고 A컨트랙트 코드에 따라 자산손실이 발생할 수 있습니다.

이 공격을 막기위해서 `executeOperation` 함수에 적절한 방어로직(initiator 화이트리스팅, 자산 전,후 비교 require문 등..)을 충분히 고려하는것을 권장합니다.&#x20;

### 활용방안

클레이 뱅크의 플래시론을 활용하여 순간 큰 자산이 필요할 때 기능을 수행할 수 있습니다.

* 클레이튼 내 DEX내에서의 큰 규모의 차액거래(Arbitrage) 기회가 생겼을때 활용하여 차액을 획득할 수 있으며
* 클레이뱅크 뿐만아니라 다른 대출 프로토콜들의 청산기회가 생겼을때 없는 자산을 빌려 청산을 진행하고 청산 보너스를 얻을 수 있습니다.

이 외 한 트랜잭션내에 큰 규모의 자산을 빌려 이득을 취할수 상황이 있다면 플래시론을 활용하여 큰 이익을 얻을 수 있습니다.
