본문 바로가기
⛓️ Web3

솔리디티 문해력 특강_ 2강

by meLR 2023. 9. 5.

디사이퍼에서 진행한 솔리디티 문해력 특강을 개인적으로 기록으로 남기기 위해 정리한 글입니다.

해당 특강은 아래 링크에서 확인 가능합니다. 강의를 진행해주신 안수찬님께 감사드립니다.

 

안수찬님 블로그 : https://solidity.ansuchan.com/

디사이퍼 솔리디티 문해력 특강 유튜브 : https://www.youtube.com/playlist?list=PLOY0jYV3zWiElk6lAXhuyRJ8dMDqelU_r    


// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;


contract Counter {
    event Reset(address owner, uint lastValue);

    uint public value;
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    function increment() public payable {
        require(msg.value == 1 ether, "Costs: 1 Ether is required.");
        value = value + 1;
    }

    function reset() public {
        require(msg.sender == owner, "OnlyOwner: Ownership is required.");
        emit Reset(msg.sender, value);
        value = 0;
    }

    function withdraw() public {
        require(msg.sender == owner);
        payable(owner).transfer(address(this).balance);
    }
}

 

👉 어떤 데이터가 들어갈지 어떤 가시성을 가질지 생각해보자

  • TX = 1) Invocation 2) Payment

1은 트랜잭션에 데이터가 있는가? 2는 이더 전송을 하는가?

 

1. DATA

  • value : private
  • owner : public

기본적으로 컨트랙트를 생성한 사람에게 권한을 주지않는다! → 누가 만들었는지를 그렇기에 저장해야한다.

 

2. ACTIONS

  • getValue : public
  • increment : public, payable
  • reset : public , Owner 만 호출 가능
  • withdraw : Owner 만 호출 가능

3. EVENTS

  • Reset 기록

🧑‍💻 실습

uint private value =0;

function getValue() public view returns (uint){
    return value;
}

 function increment() public payable {
    require(msg.value == 1 ether, "1 Ether");
    value += 1;
}

 

 

함수 종류

 

view

함수밖의 변수들을 볼수있을 때 하지만 변경은 불가능 하다.

 

pure

함수밖의 변수들을 볼수도 없고 변경도 불가능 하다.

 

payable

이더를 사용해야할때 사용된다. 하지만 꼭 지불 해야하는것은 아니다

 

error 다루기

 

assert

가스를 모두 소비 후 조건이 false면 에러를 발생시킨다. 하지만 0.8.1 이후 버전부터는 가스를 환불해준다.

내부 오류테스트하고 불변성을 확인하는 경우에만 assert를 사용해야한다 그리고 panic 유형의 에러를 발생시킨다.

 

revert

조건없이 에러를 발생 시키고 가스를 환불 해준다.

 

require

조건이 false면 에러를 발생시키고 가스를 환불해준다.

 

constructor

  • constructor는 컨트랙트가 배포 될때 실행된다. 그리고 단하나의 constuctor만 컨트랙트에 존재해야한다.
  • visibility는 internal 이거나 public이어야 한다

또한 상속 받을 때 다음 두가지 방법으로 상속 받을수있다.

contract Lion is Animal(4, true) {}
contract Animal {

    string name;
    uint feet;
    bool canSwim;

    constructor(string memory _name, uint _feet, bool _canSwim) {
        name = _name;
        feet = _feet;
        canSwim = _canSwim;
    }
}contract Lion is Animal {

    constructor(string memory _name)
        Animal(_name, 4, true)
    {
        // ...
    }
}

 

이더를 보내는 메소드

 

send

2300gas를 소모하고 성공여부를 true/false값을 반환한다.

 

call

원하는 gas값을 지정하여 소모할수 있고 성공여부를 true/false값을 반환한다.

 

transfer

2300gas를 소모하고 에러를 발생시킨다.

 


event

트랜잭션이 완료되면 트랜잭션에 대한 트랜잭션 영수증이 발급되게 되는데 트랜잭션 영수증은 이 트랜잭션의 행위에 관한 정보들을 가지고 있는 로그 엔트리를 가진다 event는 이러한 로그 엔트리를 만드는 고수준 객체이다.

이때 정보는 스토리지에 저장되지 않고 트랜잭션 로그에 저장이 된다. 그리고 블록에 저장된다는 것도 특징이다.

이때 indexed를 쓰면 필터링이 가능해진다.

contract Test {
    uint private value =0;
    address public owner;
     constructor(){
         owner = msg.sender; //컨트랙트 배포 할때 owner값에 배포한 사람의 주소 할당
     } 
			
			//event 선언
	   event Reset(address owner, uint currentValue);
	
	   function reset() public {
	       require(msg.sender==owner);
				//Reset한 내용을 블록에 저장하기에 쉽게 조회가능하다
	       emit Reset(msg.sender,value);
	       value = 0;
	   }

    function getValue() public view returns (uint){
        return value;
    }

     function increment() public payable {
        require(msg.value == 1 ether, "1 Ether");
        value += 1;
    }

    function withdraw() public {
        require(msg.sender == owner);
				// owner를 이더 받을수 있게 변환후 이 컨트랙트 이더 잔고를 모두 컨트랙트 배포자에게 송금
        payable(owner).transfer(address(this).balance);
    }
}

modifier

함수를 동작을 변경 시킬때 사용되는 것으로 실행 전후로 어떤 기능을 추가할수있다.

modifier onlyOwner(){
    require(msg.sender==owner, "Only owner");
    _;
}


function reset() public onlyOwner {
    emit Reset(msg.sender,value);
    value = 0;
}

 

Inheritance

다른 컨트랙트 기능을 그대로 사용하고 싶을때 사용한다.

 

mapping

키와 밸류 값을로 저장하는 구조체

//mapping으로 다룬 ENS 기본 개념 

mapping (string=>address) public names;

function register(string memory _name, address _address) public {
    if(names[_name]==address(0)){
        names[_name] = _address;
    }
}//매핑되어있는 이름이 없다면 새로운 이름을 주소에 등록 시켜주는 함수