# Security

> **Security is always our top priority at Krystal. We've implemented comprehensive external and internal security measures to ensure that our users can enjoy using Krystal with complete peace of mind.**

## **External Audit**

We recently conducted a thorough audit with Code4rena, involving 1,137 lines of code, 6 security researchers, and 10 days of rigorous analysis. Five medium-severity and five low-severity issues were identified by the researchers and resolved by Krystal team. Below is a summary for medium-severity issues found and actions:

<table><thead><tr><th>Risk</th><th width="93">Severity</th><th>Explanation</th><th>Action</th></tr></thead><tbody><tr><td>Wrong logic in <code>Auto-Compound</code>: Doesn’t allow for Swap token</td><td>Medium</td><td><code>Auto-Compound</code> action allows for compounding your gains into liquidity. It additionally allows for swaps in the middle. There is a faulty condition though, which is never effective.</td><td>Fixed</td></tr><tr><td>The signatures are replayable</td><td>Medium</td><td>User signed orders can be replayed</td><td>The <code>onlyRole(OPERATOR_ROLE)</code> privilege required to exploit this in the smart contract mitigates the risk. No further action needed.</td></tr><tr><td><code>_deductFees()</code> is incompatible with tokens that revert on zero value transfers</td><td>Medium</td><td>All main functionality risks reverting with tokens that revert on zero value transfers, via a transfer in Common._deductFees().</td><td>Fixed</td></tr><tr><td>The Protocol breaks the Allowance Mechanism of the NFTs</td><td>Medium</td><td>The approved entities may lose the right to control the NFT after making a transaction</td><td>There are 2 options to authorize Automation: : <code>setApprovalForAll</code> or <code>onERC721Received</code>. Krystal is already using <code>onERC721Received</code> - the safer option for users. No further action needed.</td></tr><tr><td>Swapping logic would be broken for some supported tokens</td><td>Medium</td><td>Swapping logic would be broken for some supported tokens</td><td>Fixed</td></tr></tbody></table>

The detailed report can be found in the link below:

{% embed url="<https://code4rena.com/reports/2024-06-krystal-defi>" %}

## **Internal Measures**

We've implemented four key measures to ensure that even Krystal's developers cannot exploit the system or access user funds.

### <mark style="color:red;">**Access Control**</mark> <a href="#access-control" id="access-control"></a>

*#limit\_fee #pause #multi\_sig*

The Krystal `V3 Automation` smart contract is operated and guarded by three distinct roles: **`Admin`**, **`Withdrawer`**, and **`Operator`**. Each role has specific responsibilities and limitations, enhancing the overall safety and integrity of the system.

* The **`Admin`** role has the following capabilities:

  * Assign a wallet to be **`Operator`** or **`Withdrawer`**
  * Pause the smart contract to halt the executing orders
  * Set the ceiling fee taken in one execution

  *This role is maintained by a multi-sig wallet, requiring 5 out of 6 signatures to approve any action.*\\
* The **`Withdrawer`** role has one capability:

  * Withdraw the collected fee in the smart contract

  *Withdrawers cannot access any of the LP positions. This role is also managed by a multi-sig wallet with a different set of approvals to mitigate risks. Additionally, the Admin role can change the assigned wallets for this role.*\\
* The **`Operator`** role has one capability:

  * Manage users’ positions on their behalf, including depositing, withdrawing, and collecting fees from the pool

  *Operators are restricted to a limited set of actions necessary for rebalancing only. All actions are encapsulated in specific transactions (rebalances) to prevent unrestricted access to funds. This role is operated by multiple Externally Owned Accounts (EOA) to handle multiple orders simultaneously. Operators can be added or removed by the Admin role.*

### <mark style="color:red;">**Sign & Verify**</mark> <a href="#sign-and-verify" id="sign-and-verify"></a>

*#verification*

The smart contracts only run the settings by the owner; even Krystal devs won’t be able to change those settings

Since **`Operator`** would deposit, withdraw & collect liquidity assets, and swap according to the user’s intentions on their behalf, Krystal will ask users to sign their order off-chain and then verify this signature once again on the smart contract.

* Users will sign their order configurations using **EIP-712: Typed structured data hashing and signing**. These signatures will be securely stored by Krystal:

{% code lineNumbers="true" %}

```
{
    "chainId": 42161,
    "nfpmAddress": "0xc36442b4a4522e871399cd717abdd847ab11fe88",
    "tokenId": "2008812",
    "orderType": "ORDER_TYPE_REBALANCE",
    "config": {
        "rangeOrderConfig": {
            "action": {
                "maxGasProportion": "0",
                "swapSlippage": "0",
                "withdrawSlippage": "0"
            },
            "condition": {
                "gteTickAbsolute": 0,
                "lteTickAbsolute": 0,
                "zeroToOne": false
            }
        },
        "rebalanceConfig": {
            "autoCompound": {
                "action": {
                    "feeToPrincipalRatioThreshold": "922337203685477632",
                    "maxGasProportion": "970925927575628544"
                }
            },
            "rebalanceAction": {
                "liquiditySlippage": "184467440737095520",
                "maxGasProportion": "970925927575628544",
                "priceOffsetAction": {
                    "baseToken": 0,
                    "priceLowerOffset": "0",
                    "priceUpperOffset": "0"
                },
                "swapSlippage": "184467440737095520",
                "tickOffsetAction": {
                    "tickLowerOffset": 102,
                    "tickUpperOffset": 100
                },
                "tokenRatioAction": {
                    "tickWidth": 0,
                    "token0Ratio": "0"
                },
                "type": "ACTION_TYPE_PERCENTAGE"
            },
            "rebalanceCondition": {
                "priceOffsetCondition": {
                    "baseToken": 0,
                    "gtePriceOffset": "0",
                    "ltePriceOffset": "0"
                },
                "sqrtPriceX96": "79214759379423715127847",
                "tickOffsetCondition": {
                    "gteTickOffset": 4,
                    "lteTickOffset": 7
                },
                "timeBuffer": 3600,
                "tokenRatioCondition": {
                    "gteToken0Ratio": "0",
                    "lteToken0Ratio": "0"
                },
                "type": "CONDITION_TYPE_PERCENTAGE"
            },
            "recurring": true
        }
    },
    "signatureTime": 1713927796
}
```

{% endcode %}

* When the Operator calls the V3 Automation smart contract to execute a function, it includes the signature and order configuration. The smart contract then verifies that the signer matches the position owner.:

```
function execute(ExecuteParams calldata params) public payable onlyRole(OPERATOR_ROLE) whenNotPaused() {
        address userAddress = _recover(params.userConfig, params.orderSignature);
        require(userAddress == params.userAddress);
        _execute(params);
 }
```

### <mark style="color:red;">**Canceling orders**</mark> <a href="#canceling-orders" id="canceling-orders"></a>

*#cancel*

Smart contract settings ensure that users retain full control over their positions and automation, even if Krystal’s servers are inaccessible.

In case of system malfunctions or failures, users can directly interact with the smart contract. By using the `cancelOrder` method with the order configuration and signature, users can cancel their orders, preventing the `Operator` from executing them.

{% hint style="info" %}
In any case, the fund is safe on-chain even when our server is down or malfunctioning.
{% endhint %}

```

function cancelOrder(Order calldata order, bytes calldata orderSignature) external {
    _validateOrder(order, orderSignature, msg.sender);
    _cancelledOrder[keccak256(orderSignature)] = true;
    emit CancelOrder(msg.sender, order, orderSignature);
}

function isOrderCancelled(bytes calldata orderSignature) external view returns (bool) {
    return _cancelledOrder[keccak256(orderSignature)];
}

function _validateOrder(Order memory order, bytes memory orderSignature, address actor) internal view {
    address userAddress = _recover(order, orderSignature);
    require(userAddress == actor);
    if (_cancelledOrder[keccak256(orderSignature)]) {
        revert OrderCancelled();
    }
}
```

### <mark style="color:red;">**Revoke**</mark> <a href="#revoke" id="revoke"></a>

***#revoke***

Users can call the `NonfungiblePositionManager` smart contract using the `setApprovalForAll(V3 Automation Address, false)` method to revoke permission for V3 Automation. Once revoked, Krystal will no longer be able to execute their orders.[<br>](https://docs.krystal.app/transparency/fees)
