# 2장: 쉘(Shell) 만들기 및 커널 공개

이 장에서는 **쉘**을 구축하여 커널을 보호하는 방법을 배웁니다. 쉘의 강도를 초기화하고 이를 감소시키는 <kbd>hit</kbd> 함수를 구현할 것입니다. 또한, <kbd>look()</kbd> 함수를 추가하여 <kbd>requiredCracked</kbd> modifier를 사용하여 쉘이 완전히 깨진 후에만 커널을 볼 수 있도록 합니다.

예상 소요 시간: 약 10분

## 쉘 정의하기

쉘은 Walnut의 내구성을 결정합니다. 쉘에는 강도(<kbd>shellStrength</kbd>)라는 정수 값이 있으며, 이는 쉘이 깨지기 전까지 견딜 수 있는 타격 횟수를 나타냅니다.\
쉘을 정의하고 생성자에서 초기화합니다:

```solidity
uint256 shellStrength; // Walnut 쉘의 강도

constructor(uint256 _shellStrength, suint256 _kernel) {
    shellStrength = _shellStrength; // 초기 쉘 강도 설정
    kernel = _kernel; // 커널 초기화
}
```

***

## **hit 함수 추가하기**

각 타격마다 Walnut의 쉘 강도가 감소하며, 이는 보호 쉘에 손상이 가는 것을 시뮬레이션합니다.\
이것은 커널을 공개하는 데 중요합니다. **쉘이 완전히 깨져야 커널에 접근할 수 있습니다:**

```solidity
// 타격 이벤트를 기록
event Hit(address indexed hitter, uint256 remainingShellStrength);

// Walnut 쉘을 타격하는 함수
function hit() public {
    shellStrength--; // 쉘 강도 감소
    emit Hit(msg.sender, shellStrength); // 타격 이벤트 기록
}

// 쉘이 깨지지 않았는지 확인하는 modifier
modifier requireIntact() {
    require(shellStrength > 0, "SHELL_ALREADY_CRACKED");
    _;
}
```

***

## **여기서 일어나는 일은?**

* **`requireIntact` modifier**:\
  이 modifier는 쉘이 이미 깨졌다면 함수가 호출되지 않도록 보장합니다 (`shellStrength == 0`).\
  따라서 쉘이 깨진 후에는 불필요한 호출을 방지합니다. 이제 이 modifier를 `shake` 함수에 추가하여 쉘이 깨진 후에도 `shake`가 호출되지 않도록 할 수 있습니다:

```solidity
function shake(suint256 _numShakes) public requireIntact {
    kernel += _numShakes; // 차폐된 매개변수를 사용하여 커널 값을 증가시킴
    emit Shake(msg.sender); // shake 이벤트 기록
}
```

* **쉘 감소:**\
  `hit` 함수 호출마다 쉘 강도(`shellStrength`)가 1씩 감소합니다.
* **액션 기록:**\
  `Hit` 이벤트는 타격한 사람의 주소(<kbd>msg.sender</kbd>)와 **남은 쉘 강도**를 기록합니다.

***

## **커널 공개하기**

이제 쉘의 내구성 및 쉘을 깨는 기능을 구현했으므로, 새로운 조건을 도입할 수 있습니다. **커널은 쉘이 완전히 깨졌을 때만 공개**되어야 합니다.\
현재는 커널 값에 접근할 방법이 없지만, 쉘 강도가 감소하는 방식을 이용하여 커널을 볼 수 있는 조건을 적용할 수 있습니다.\
특히:

* 쉘이 intact(손상되지 않음)일 때는 커널을 숨겨둡니다.
* 쉘 강도가 **0**이 되면(즉, 쉘이 깨지면) 커널을 공개할 수 있습니다.

이 조건을 강제하려면, **`look()`** 함수를 생성하여 쉘이 완전히 깨졌을 때만 커널 값을 반환하도록 합니다.

다음과 같이 `look()`을 `requireCracked` modifier와 함께 정의합니다:

```solidity
// 쉘이 완전히 깨졌을 때 커널을 공개하는 함수
function look() public view requireCracked returns (uint256) {
    return uint256(kernel); // 커널을 표준 uint256으로 반환
}

// 커널을 공개하기 전에 쉘이 완전히 깨졌는지 확인하는 modifier
modifier requireCracked() {
    require(shellStrength == 0, "SHELL_INTACT"); // 쉘이 깨지지 않으면 커널을 공개할 수 없음
    _;
}
```

***

### **여기서 일어나는 일은?**

* **조건을 통한 접근 제한**:\
  `requireCracked` modifier는 `look()`이 **쉘 강도(`shellStrength`)가 0**일 때만 호출될 수 있도록 보장합니다. 즉, Walnut이 완전히 깨졌을 때만 커널을 볼 수 있습니다.
* **커널 공개**:\
  조건이 충족되면 `look()`은 커널의 **비차폐된 값**을 반환합니다.
* **조기 접근 방지**:\
  쉘이 깨지기 전에 `look()`이 호출되면 함수는 "SHELL\_INTACT" 오류와 함께 실패합니다.

***

### **`hit`, `shake`, `look` 함수가 포함된 업데이트된 컨트랙트**

```solidity
// SPDX-License-Identifier: MIT License
pragma solidity ^0.8.13;

contract Walnut {
    uint256 shellStrength; // Walnut 쉘의 강도
    suint256 kernel; // 숨겨진 커널 (Walnut 내부의 숫자)

    // 이벤트
    event Hit(address indexed hitter, uint256 remainingShellStrength); // Walnut이 타격당했을 때 기록
    event Shake(address indexed shaker); // Walnut이 흔들렸을 때 기록

    // 생성자: 쉘 강도와 커널 초기화
    constructor(uint256 _shellStrength, suint256 _kernel) {
        shellStrength = _shellStrength; // 쉘 강도 초기화
        kernel = _kernel; // 커널 초기화
    }

    // Walnut을 타격하여 쉘 강도를 감소시키는 함수
    function hit() public requireIntact {
        shellStrength--; // 쉘 강도 감소
        emit Hit(msg.sender, shellStrength); // 타격 이벤트 기록
    }

    // Walnut을 흔들어 커널 값을 증가시키는 함수
    function shake(suint256 _numShakes) public requireIntact {
        kernel += _numShakes; // 주어진 횟수만큼 커널을 증가
        emit Shake(msg.sender); // shake 이벤트 기록
    }
    
    // 쉘이 완전히 깨졌을 때 커널을 공개하는 함수
    function look() public view requireCracked returns (uint256) {
        return uint256(kernel); // 커널을 표준 uint256으로 반환
    }
    
    // 쉘이 완전히 깨졌는지 확인하는 modifier
    modifier requireCracked() {
        require(shellStrength == 0, "SHELL_INTACT"); // 쉘이 깨지지 않으면 커널을 공개할 수 없음
        _;
    }
    
    // 쉘이 깨지지 않았는지 확인하는 modifier
    modifier requireIntact() {
        require(shellStrength > 0, "SHELL_ALREADY_CRACKED");
        _;
    }
}
```


---

# 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://clairetranslation.gitbook.io/seismic-docs-kr/undefined-2/undefined-2/undefined/2-shell.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.
