Skip to content

feat(week-01): complete counter and quiz assignment#16

Closed
minij02 wants to merge 2 commits intoBay-17th:mainfrom
minij02:minij02/week-01
Closed

feat(week-01): complete counter and quiz assignment#16
minij02 wants to merge 2 commits intoBay-17th:mainfrom
minij02:minij02/week-01

Conversation

@minij02
Copy link

@minij02 minij02 commented Feb 12, 2026

과제 제출 정보

주차: Week 01

과제 유형:

  • 이론 (Theory Quiz)
  • 개발 (Dev Assignment)

구현 내용

  • Counter.sol 스마트 계약 구현: Solidity 0.8.26 컴파일러를 활용하여 기초적인 상태 변경 로직(increment, decrement, reset) 완성
  • 예외 처리 및 보안: decrement 함수 실행 시 0 미만으로 감소하는 상황을 방지하기 위해 require 문을 통한 에러 핸들링 구현
  • 이론 퀴즈 풀이: 이더리움 상태 머신, EOA/CA 계정 구조, 가스(Gas) 시스템의 경제적/기술적 역할 등 10개 문항 답변 완료

배운 점 (What I Learned)

이번 주에 배운 것 (2-3가지)

  1. 상태 머신과 네트워크 합의
  • 이더리움을 하나의 거대한 상태 머신(State Machine)으로 정의하는 관점을 배웠습니다. 이는 분산 네트워크 환경에서 각 노드들이 - P2P 통신을 통해 동일한 상태 전이 결과에 도달해야 하는 분산 합의(Consensus) 문제와 직결됨을 이해했습니다.
    특히 EVM이 결정론적(Deterministic)으로 설계된 이유를 네트워크 상의 모든 노드가 동일한 입력에 대해 동일한 출력(상태)을 보장하여 데이터 정합성을 유지하기 위함이라는 네트워크 설계 원칙과 연결지어 학습했습니다.
  1. 가스 시스템과 알고리즘 복잡도
  • 시간/공간 복잡도가 스마트 계약에서는 단순히 성능의 문제가 아니라 실제 경제적 비용(Gas)으로 환산된다는 점이 인상적이었습니다.
  • 무한 루프를 방지하여 'Halting Problem' 경제적 제약으로 해결하는 방식과, 스토리지 접근(SSTORE) 등 특정 작업의 가스 소모량이 왜 더 높게 책정되었는지를 데이터 접근 오버헤드 관점에서 분석해 보았습니다.
  1. EOA/CA 구조
  • 개인키를 직접 보유하지 않는 CA가 외부 트랜잭션 없이 스스로 연산을 시작할 수 없는 구조적 제약을 '디지털 서명의 유무'라는 보안 관점으로 재해석하며 계정 모델의 차이를 명확히 이해했습니다.

어려웠던 점과 해결 방법

어려웠던 점:
NULL (이번 과제에서는 없었습니다)

해결 방법:
WSL 환경에서의 PATH 우선순위 충돌로 인한 실행 파일 경로 문제를 hash -r 및 ~/.bashrc 수정을 통해 해결했습니다.

질문 사항


체크리스트

테스트

  • forge build 성공
  • forge test 모든 테스트 통과

제출 규칙

  • 브랜치명이 {username}/week-{XX} 형식
  • .env 파일이 커밋에 포함되지 않음
  • 커밋 메시지가 규칙을 따름

@ahwlsqja
Copy link
Member

리뷰

정말 고생하셨습니다 ㅎㅎ

개발 과제

increment, decrement, reset 모두 정확합니다.

퀴즈

10문제 + 이론 모두 정확합니다.
답변 퀄리티가 매우 높습니다!! 특히 각 문제마다 왜에 대한 설명이 충실하고,
상태 변수의 Storage/Memory 가스비 차이까지 언급한 부분이 정말 좋았습니다.

인상적인 부분

WSL PATH 충돌을 hash -r로 해결한 것도 좋습니다. 블로그나 그런곳에 포스팅해도 좋을거 같아요
알고리즘 복잡도 = 가스비라는 연결도 정확합니다.
과제 퀼리티가 정말 좋았습니다! 기대가 됩니다 민주님 ㅎㅎ

@ahwlsqja ahwlsqja closed this Feb 12, 2026
Comment on lines +13 to +14
/// @dev mapping은 key(address) => value(uint256) 형태의 저장소입니다
mapping(address => uint256) public balances;

Check failure

Code scanning / Slither

Uninitialized state variables High

SimpleStorage.balances is never initialized. It is used in:
- SimpleStorage.getBalance(address)
Comment on lines +87 to +110
/// - 상태(balances) 업데이트는 나중에 수행
/// - 외부 호출 중에 재귀적으로 withdraw() 호출 가능
function withdraw(uint256 amount) public {
// ========================================
// Checks (검증) - 이 부분은 올바름
// ========================================
// 잔액이 충분한지 확인
require(balances[msg.sender] >= amount, "Insufficient balance");
// ========================================
// ❌ 위험: Interactions (상호작용) 먼저!
// ========================================
// call()로 ETH 전송 - 이 시점에서 공격자의 receive()가 실행됨
// 공격자의 receive()가 다시 withdraw()를 호출하면
// balances[msg.sender]는 아직 그대로이므로 검증을 통과함
(bool success,) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
// ========================================
// ❌ 위험: Effects (상태변경) 나중에!
// ========================================
// 이 줄에 도달하기 전에 위의 call()에서 재진입이 발생하면
// 공격자는 balances가 업데이트되기 전에 반복 출금 가능
balances[msg.sender] -= amount;

Check failure

Code scanning / Slither

Reentrancy vulnerabilities High

Reentrancy in Vault.withdraw(uint256):
External calls:
- (success,None) = msg.sender.call{value: amount}()
State variables written after the call(s):
- balances[msg.sender] -= amount
Vault.balances can be used in cross function reentrancies:
- Vault.balances
- Vault.deposit()
- Vault.withdraw(uint256)
Comment on lines +6 to +70
/// @dev mapping, event, payable 함수를 학습합니다.
contract SimpleStorage {
// ============================================================
// 상태 변수 (State Variables)
// ============================================================
/// @notice 각 주소별 잔액을 저장합니다
/// @dev mapping은 key(address) => value(uint256) 형태의 저장소입니다
mapping(address => uint256) public balances;
// ============================================================
// 이벤트 (Events)
// ============================================================
/// @notice 입금 시 발생하는 이벤트
/// @param user 입금한 사용자 주소 (indexed로 검색 가능)
/// @param amount 입금한 금액 (wei 단위)
event Deposited(address indexed user, uint256 amount);
/// @notice 출금 시 발생하는 이벤트
/// @param user 출금한 사용자 주소 (indexed로 검색 가능)
/// @param amount 출금한 금액 (wei 단위)
event Withdrawn(address indexed user, uint256 amount);
// ============================================================
// 읽기 함수 (View Functions)
// ============================================================
/// @notice 특정 사용자의 잔액을 조회합니다
/// @param user 조회할 사용자 주소
/// @return 해당 사용자의 잔액 (wei 단위)
function getBalance(address user) public view returns (uint256) {
return balances[user];
}
// ============================================================
// 쓰기 함수 (State-Changing Functions)
// ============================================================
/// @notice ETH를 입금합니다
/// @dev msg.value는 함수 호출 시 전송된 ETH 양입니다
function deposit() public payable {
// TODO: 입금 로직을 구현하세요
// 1. balances[msg.sender]에 msg.value를 더합니다
// 2. Deposited 이벤트를 발생시킵니다
//
// 힌트:
// balances[msg.sender] += msg.value;
// emit Deposited(msg.sender, msg.value);
}
/// @notice ETH를 출금합니다
/// @param amount 출금할 금액 (wei 단위)
/// @dev 잔액이 충분한지 확인 후, ETH를 전송합니다
function withdraw(uint256 amount) public {
// TODO: 출금 로직을 구현하세요
// 1. 사용자의 잔액이 amount 이상인지 확인합니다 (require 사용)
// 2. balances[msg.sender]에서 amount를 뺍니다
// 3. msg.sender에게 ETH를 전송합니다
// 4. Withdrawn 이벤트를 발생시킵니다
//
// 힌트:
// require(balances[msg.sender] >= amount, "Insufficient balance");
// balances[msg.sender] -= amount;
// payable(msg.sender).transfer(amount);

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract SimpleStorage has payable functions:
- SimpleStorage.deposit()
But does not have a function to withdraw the ether
Comment on lines +77 to +136
/// @dev ReentrancyGuard 사용 시: contract VaultSecure is ReentrancyGuard
contract VaultSecure {
// ============================================
// 상태 변수
// ============================================
/// @dev 사용자별 예치금 잔액
mapping(address => uint256) public balances;
// ============================================
// 이벤트
// ============================================
/// @dev 입금 시 발생하는 이벤트
event Deposited(address indexed user, uint256 amount);
/// @dev 출금 시 발생하는 이벤트
event Withdrawn(address indexed user, uint256 amount);
// ============================================
// 외부 함수
// ============================================
/// @notice ETH를 Vault에 예치합니다
/// @dev msg.value만큼 예치하고 Deposited 이벤트를 발생시킵니다
///
/// TODO: deposit() 함수를 구현하세요
/// - msg.value를 balances[msg.sender]에 추가
/// - Deposited 이벤트 발생
///
/// 힌트: Vault.sol의 deposit()과 동일하게 구현하면 됩니다
function deposit() public payable {
// TODO: 구현하세요
}
/// @notice 예치한 ETH를 출금합니다
/// @param amount 출금할 ETH 양 (wei 단위)
///
/// TODO: withdraw(uint256 amount) 함수를 구현하세요
/// - 재진입 공격에 안전하게 구현
/// - CEI 패턴 또는 ReentrancyGuard 사용
///
/// 필수 요소:
/// 1. 잔액 확인 (require)
/// 2. 잔액 차감 (balances 업데이트)
/// 3. ETH 전송 (call)
/// 4. Withdrawn 이벤트 발생
///
/// CEI 패턴 사용 시 순서: Checks -> Effects -> Interactions
/// ReentrancyGuard 사용 시: nonReentrant modifier 추가
function withdraw(uint256 amount) public {
// TODO: 구현하세요
}
// ============================================
// View 함수
// ============================================
/// @notice Vault의 총 잔액을 반환합니다
/// @return Vault 컨트랙트가 보유한 ETH 총량 (wei)

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract VaultSecure has payable functions:
- VaultSecure.deposit()
But does not have a function to withdraw the ether
Comment on lines +57 to +70
/// @notice deposit 함수가 Deposited 이벤트를 발생시키는지 확인합니다
function test_Deposit_EmitsEvent() public {
// Arrange: user가 호출하도록 설정
vm.prank(user);
// vm.expectEmit: 다음 호출에서 특정 이벤트가 발생할 것을 예상
// (checkTopic1, checkTopic2, checkTopic3, checkData)
// true = 해당 항목을 검증함
vm.expectEmit(true, false, false, true);
// 예상되는 이벤트 (비교 대상)
emit SimpleStorage.Deposited(user, 1 ether);
// Act: 1 ETH 입금 - 이 호출에서 이벤트가 발생해야 함

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low test

Comment on lines +132 to +143
simpleStorage.withdraw(2 ether);
}
/// @notice withdraw 함수가 Withdrawn 이벤트를 발생시키는지 확인합니다
function test_Withdraw_EmitsEvent() public {
// Arrange: 먼저 2 ETH 입금
vm.prank(user);
simpleStorage.deposit{value: 2 ether}();
// 다음 호출에서 Withdrawn 이벤트 예상
vm.expectEmit(true, false, false, true);
emit SimpleStorage.Withdrawn(user, 1 ether);

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low test

Comment on lines +87 to +110
/// - 상태(balances) 업데이트는 나중에 수행
/// - 외부 호출 중에 재귀적으로 withdraw() 호출 가능
function withdraw(uint256 amount) public {
// ========================================
// Checks (검증) - 이 부분은 올바름
// ========================================
// 잔액이 충분한지 확인
require(balances[msg.sender] >= amount, "Insufficient balance");
// ========================================
// ❌ 위험: Interactions (상호작용) 먼저!
// ========================================
// call()로 ETH 전송 - 이 시점에서 공격자의 receive()가 실행됨
// 공격자의 receive()가 다시 withdraw()를 호출하면
// balances[msg.sender]는 아직 그대로이므로 검증을 통과함
(bool success,) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
// ========================================
// ❌ 위험: Effects (상태변경) 나중에!
// ========================================
// 이 줄에 도달하기 전에 위의 call()에서 재진입이 발생하면
// 공격자는 balances가 업데이트되기 전에 반복 출금 가능
balances[msg.sender] -= amount;

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low

Reentrancy in Vault.withdraw(uint256):
External calls:
- (success,None) = msg.sender.call{value: amount}()
Event emitted after the call(s):
- Withdrawn(msg.sender,amount)
Comment on lines +146 to +154
}
/// @notice 입금 시 Deposited 이벤트가 발생하는지 테스트
/// @dev 예상: Deposited(alice, 1 ether) 이벤트 발생
function test_Deposit_EmitsDepositedEvent() public {
// Arrange
// 이벤트 발생 예상 설정
vm.expectEmit(true, false, false, true);
emit Deposited(alice, 1 ether);

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low test

Comment on lines +212 to +221
"ETH should be transferred to user after withdraw"
);
}
/// @notice 출금 시 Withdrawn 이벤트가 발생하는지 테스트
/// @dev 예상: Withdrawn(alice, 1 ether) 이벤트 발생
function test_Withdraw_EmitsWithdrawnEvent() public {
// Arrange
vm.prank(alice);
vault.deposit{value: 3 ether}();

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants