# Core System Contract

## Treasury Contract

```
0x1Ee7E501039E0bd75475DD9da69EE744951CaB8B
```

Treasury Contract는 라운드의 확장 및 축소 상태를 결정하고 KAI의 신규 발행, bKAI 상환 등 중앙은행과 같은 중심적인 역할을 합니다.

**\[주요 역할]**

* PriceOracle에서 제공되는 KAI의 가격에 따른 확장/축소 상태 결정
* 확장/축소/부스트 결과에 따른 에어드랍 비율 결정
* 확장 상태에서 KAI 신규 발행 및 분배
* bKAI 상환을 위한 KAI 보유 및 지급

다음은 확장 상태에서 KAI 추가 발행을 위해 Mint 하는 Code 입니다.

```
function allocateSeigniorage() external onlyOneBlock checkCondition checkEpoch checkOperator {
        _updateKAIPrice();
        previousRoundKAIPrice = getKAIPrice(); // KAI 가격을 얻어옴
        uint256 kaiSupply = IERC20(kai).totalSupply().sub(seigniorageSaved);
        if (round < bootstrapRounds) { // 초기 21라운드는 3% 고정
            _sendToBoardRoom(kaiSupply.mul(bootstrapSupplyExpansionPercent).div(10000));
        } else {
            if (previousRoundKAIPrice > kaiPriceOne) { // KAI 가격이 $1 초과하면 확장
uint256 bkaiSupply = IERC20(bkai).totalSupply();
                uint256 _percentage = previousRoundKAIPrice.sub(kaiPriceOne).mul(seigniorageExpansionRate).div(10000);
                uint256 _savedForBKAI;
                uint256 _savedForBoardRoom;
                // bKAI 의 발행량 이상으로 Treasury 가 KAI 를 보유한 경우 일반적인 확장 진행
                if (seigniorageSaved >= bkaiSupply.mul(bkaiDepletionFloorPercent).div(10000)) 
                    uint256 _mse = maxSupplyExpansionPercent.mul(1e14);
                    if (_percentage > _mse) {
                        _percentage = _mse;
                    }
                    _savedForBoardRoom = kaiSupply.mul(_percentage).div(1e18);
                } else {
                    // bKAI 의 발행량 만큼 Treasury 가 보유하고 있지 않다면, 이는 Debt Phase 로 전환되어 더 많은 KAI 가 Treasury 에 적립됨
                    _percentage = maxSupplyExpansionPercentInDebtPhase.mul(1e14);
                    uint256 _seigniorage = kaiSupply.mul(_percentage).div(1e18);
                    _savedForBoardRoom = _seigniorage.mul(seigniorageExpansionFloorPercent).div(10000);
                    _savedForBKAI = _seigniorage.sub(_savedForBoardRoom);
                    if (mintingFactorForPayingDebt > 0) {
                        _savedForBKAI = _savedForBKAI.mul(mintingFactorForPayingDebt).div(10000);
                    }
                }
                if (_savedForBoardRoom > 0) {
                    // 보드룸으로 KAI 생성 요청
                    _sendToBoardRoom(_savedForBoardRoom);
                }
                if (_savedForBKAI > 0) {
                    seigniorageSaved = seigniorageSaved.add(_savedForBKAI);
                    IKAIAsset(kai).mint(address(this), _savedForBKAI);
                    emit TreasuryFunded(now, _savedForBKAI);
                }
            }
        }
        // 바이백 펀드 KAI 생성
        if (previousRoundKAIPrice > kaiPriceOne) {
            uint256 _buyBackRate = previousRoundKAIPrice.sub(kaiPriceOne).mul(buyBackFundExpansionRate).div(10000);
            uint256 _maxBuyBackRate = maxBuyBackFundExpansion.mul(1e14);
            if (_buyBackRate > _maxBuyBackRate) {
                _buyBackRate = _maxBuyBackRate;
            }
            uint256 _savedForBuyBackFund = kaiSupply.mul(_buyBackRate).div(1e18);
            if (_savedForBuyBackFund > 0) {
                IKAIAsset(kai).mint(address(buyBackFund), _savedForBuyBackFund);
                emit BuyBackFunded(now, _savedForBuyBackFund);
            }
        }
        if (allocateSeigniorageSalary > 0) {
            IKAIAsset(kai).mint(address(admin), allocateSeigniorageSalary);
        }
    }

```

Mint된 후 \_sendToBoardRoom function 을 통해 Boardroom Contract 및 Team Fund에게 KAI가 분배됩니다.

```
function _sendToBoardRoom(uint256 _amount) internal {
        IKAIAsset(kai).mint(address(this), _amount);
        // 10%의 물량은 팀펀드로 적립되며, 해당 물량은 마케팅 및 운영비로 사용됨
        if (teamFundSharedPercent > 0) {
            uint256 _teamFundSharedAmount = _amount.mul(teamFundSharedPercent).div(10000);
            IERC20(kai).transfer(teamFund, _teamFundSharedAmount);
            emit TeamFundFunded(now, _teamFundSharedAmount);
            _amount = _amount.sub(_teamFundSharedAmount);
        }
        IERC20(kai).safeApprove(boardroom, 0);
        IERC20(kai).safeApprove(boardroom, _amount);
        // 보드룸에 나머지 물량을 보내서 단일예치자들에게 배분
        IBoardroom(boardroom).allocateSeigniorage(_amount);
        emit BoardroomFunded(now, _amount);
    }

```

## Boardroom Contract

```
0x931579Fa23580CB2214fBE89aB487f6AEDE8a352
```

Boardroom Contract는 sKAI 단일 예치를 관리하고 확장 상태에서 Treasury Contract로 부터 받은 KAI를 sKAI 단일 예치 사용자에게 분배하는 일반 은행과 같은 역할을 합니다.

\[주요 역할]

* sKAI 단일 예치
* 추가 발행된 KAI 분배
* 발행된 vKAI 분배

## BBFund Contract - Buyback Fund

```
0x451033434Fb739a538DA0a77d3DcA23Bf0801255
```

bKAI를 통한 KAI의 $ 1 페깅 알고리즘의 보완 장치로 다음 라운드 예상 가격(TWAP)이 $ 1미만일때 KAI를 바이백해서 가격을 안정화할 수 있습니다. KAI 유통량 및 바이백 펀드 현황에 따라 바이백된 KAI가 소각될 수 있습니다.

바이백 펀드 조성은 KAI, vKAI로 진행되며 KUSDT, KDAI로 변환해서 적립합니다.

\[주요 기능]

* KAI 가격이 $ 1 초과일때 KAI -> KUSDT 또는 KAI -> KDAI 교환
* KAI 가격이 $ 1 미만일때 KUSDT -> KAI 또는 KDAI -> KAI교환

Buyback Fund Contract는 Transfer function이 불가능하며 오직 KAI 가격 유지를 위한 Sell, Buy, Burn function으로만 구성되어 있습니다.

```
function setKAIPriceToSell(uint256 _priceToSell) external onlyStrategist {
        require(_priceToSell > 1.0 ether, "out of range"); // 1불을 초과해야 매도 가능
        kaiPriceToSell = _priceToSell;
}
 
function setKAIPriceToBuy(uint256 _priceToBuy) external onlyStrategist {
        require(_priceToBuy < 1.0 ether, "out of range"); // 1 불 미만일 때 매수 가능
        kaiPriceToBuy = _priceToBuy;
}

function forceSell(address _buyingToken, uint256 _amount) external onlyStrategist {
        require(getKAIUpdatedPrice() >= kaiPriceToSell, "price is too low to sell");
        _swapToken(kai, _buyingToken, _amount);
}
 
function forceBuy(address _sellingToken, uint256 _amount) external onlyStrategist {
        require(getKAIUpdatedPrice() <= kaiPriceToBuy, "price is too high to buy");
        _swapToken(_sellingToken, kai, _amount);
}
 
function _swapToken(address _inputToken, address _outputToken, uint256 _amount) internal {
        if (_amount == 0) return;
        uint256 _maxAmount = maxAmountToTrade[_inputToken];
 
        if (_maxAmount > 0 && _maxAmount < _amount) {
            _amount = _maxAmount;
        }
 
        address[] memory _path;
        IERC20(_inputToken).safeIncreaseAllowance(address(klayswapFactory), _amount);
        IKlayswapFactory(klayswapFactory).exchangeKctPos(_inputToken, _amount, _outputToken, 1, _path);
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.kaiprotocol.fi/kai-protocol/protocol-and-mechanisms/core-smart-contract/core-system-contract.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
