Solidity 기본 문법

CY·2022년 1월 18일
0

BlockChain

목록 보기
8/9

1) 전처리 구문

1-1. SPDX License Identifier

스마트 컨트랙트에 대한 신뢰를 높이고, 저작권과 같은 문제를 해소하기 위해 솔리디티 코드의 최상단에 SPDX 라이센스를 명시한다.

* SPDX 라이센스는 주석으로 표시 
// SPDX-License-Identifier: MIT

라이센스 리스트

1-2. Pragma

pragma는 특정 컴파일러의 버전을 표기할 때 사용한다.

* pragma는 일반적으로 파일의 최상단에 위치한다.

pragma solidity 0.8.7;

npm 버전 규칙

1-3. import

다른 언어들 처럼 필요한 파일들을 임포트 할 때 사용

import "파일이름";

// 임포트하는 파일을 symbolName이라는 이름으로 사용
import * as symbolName from "파일이름";  
import "파일이름" as symbolName;

// 파일의 일부분만 임포트 하는 경우
import {symbol1 as alias, symbol2} from "파일이름"; 

2) 컨트랙트 구조

2-1. 상태 변수

상태 변수는 값이 컨트랙트 스토리지에 영구적으로 저장되는 변수이다.

{데이터타입} {변수명}; // 변수명으로 선언
{데이터타입} {변수명} = {초기화할 값};  // 선언 및 초기화

--- example ---

pragma solidity ^0.8.7;

contract SimpleStorage {
    uint storedData; // 상태 변수 선언
    uint storedData = 20; // 상태 변수 선언 및 초기화
}

상태 변수 접근 수준

  • internal (default): 컨트랙트 및 해당 컨트랙트를 상속 받은 자식 컨트랙트만 사용할 수 있다.
  • public: 컨트랙트 내에서 뿐만 아니라 외부 컨트랙트나 클라이언트 코드에서도 상태 변수에 접근할 수 있다.
  • private: 동일한 컨트랙트 멤버만 프라이빗 상태 변수에 접근할 수 있다.

constant
constant를 통해 상태 변수를 상수로 선언하는 것도 가능하다.

pragma solidity ^0.8.7;

contract exmapleC {
    unit256 public constant maxLimit = 1000;
}

데이터 타입의 종류

a. 값형 데이터 타입

  • Bool - true / false
bool isOpen = true;
bool isSold = false;
  • 정수(int, uint)

부호(양수, 음수)가 있는 경우는 int,
0 이상의 값만 존재하는 경우 uint
int, uint 둘 다 뒤에 8의 배수를 붙여 크기를 비트 단위로 지정할 수도 있다.

int8 seoulTemp = -20
uint16 myAge = 30
  • 고정 바이트 배열

bytes1에서 bytes32까지의 고정된 크기의 배열을 선언할 수 있다.

bytes3 alphabets = 'abc'

alphabets[0] // 'a'
alphabets[1] // 'b'
alphabets[2] // 'c'
  • 주소

주소(address) 객체는 0x로 시작하고 최대 40자리의 16진수로 구성되는 문자열로 20바이트의 크기를 가진다.
주로 계정의 잔액을 반환하는 balance() 함수와 이더를 계정으로 전송하는 transfer() 함수에서 사용된다.

address yourAddress = 0x10abb5efEcdc01234f7b2384912398798E089Ab2;

0.8버전부터 단순 address 형식은 송금이 불가능한 주소값이다. 송금을 위해서는 뒤에 payable을 추가하여 지불이 일어날 수 있다는 점을 명시해줘야 한다.
address payable 형식에는 이더 송금을 위한 transfer()와 send() 함수 등이 내장되어 있다.

address addr1;
address payable p_addr1 = payable(addr1);

컨트랙트를 adress payable로 변환할 수도 있다.
만약 컨트랙트가 이더를 받을 수 있는 컨트랙트인 경우, address(컨트랙트)를 수행했을 때 address payable 형식의 주소값을 반환한다.

contract C  {  // 이더를 받을 수 있는 컨트랙트
	constructor () payable { }
} 
contract D { // 이더를 받지 않는 컨트랙트
	 constructor () { }
}

address payable addrC = address(C);  // address(C)는 adress payable 형식의 주소값을 반환한다

address addrD = address(D); // address(D)는 adress 형식의 주소값을 반환한다
address payable addrD_p = payable(addrD); // payable()을 사용해 address payable 형식의 주소값을 만들 수 있다.

  • 열거형(enum)
    특정 값들을 지정하고, 해당 집합에 있는 데이터만을 값으로 가지는 집합

// 해당 값들은 순서에 따라 0,1,2와 같이 0부터 1씩 올라가는 정수도 값으로 가짐
//0 : Bad   1 : Soso   2 : Great
enum EvalLevel { Bad, Soso, Great} 
EvalLevel kimcoding = EvalLevel.Bad

b. 참조형 데이터 타입

주소를 값으로 가지는 변수 타입

  • 배열(Array)

저장하고자 하는 데이터 형식에 []를 붙여 선언. uint8 형식의 배열을 만드는 경우 uint8[] 처럼 작성.

동적 배열 : uint[] {배열명} // 크기가 가변적
정적 배열 : uint[4] {배열명} // 크기가 고정
  • 문자열(String)
string name = 'tom';
  • 구조체(struct)
    구조체는 여러 데이터들을 포함하는 집합으로 임의의 사용자 정의 형식이다.
contract exmapleC {
	struct UserInfo {
	    address account;
	    string lastName;
	    string firstName;
	}
    
    	//구조체 추가하는 함수
    	function newUser (address newAddress, string newLastName, string newFirstName){
	    UserInfo memory newOne = UserInfo({account: newAddress, lastName: newLastName, firstName: newFirstName})
	}
}
  • 매핑(mapping)
    매핑은 javascript의 object와 같이 키-값 구조로 데이터를 저장할 때 사용하는 참조형 데이터이다.
    mapping({키 형식} => {값 형식}) {변수명} 의 형태로 선언한다.
mapping(address => int) public userAddress;

2-2. 글로벌 변수

솔리디티 언어 자체에 내장되어 있는 변수이다.

block

블록에 대한 정보를 가진 변수

  • blockhash(uint blocknumber): 주어진 블록의 해시를 bytes32 형태로 반환
  • 코인베이스: 블록의 채굴자 주소로 address 형식
    (velog의 오류로 코인베이스를 영어로 입력하면
    강제 비공개 처리되어 한글로 적음)
  • gaslimit: 블록의 가스 한도로 uint 형식
  • number: 블록의 번호로 uint 형식
  • timestamp: 블록 타임스탬프로 uint 형식

msg

컨트랙트를 시작한 트랜잭션 콜이나 메시지 콜에 대한 정보를 가지고 있다

  • gasleft(): 남아있는 가스의 양을 uint256 형태로 반환
  • data: 전체 콜데이터 본문으로bytes 형식
  • sender: 현재 호출을 수행하고 있는 메시지 발신자로 address 형식
  • gas: 남은 가스양으로 int 형식
  • value: 메시지와 함께 보낸 이더 금액으로 uint 형식

tx

트랜잭션 데이터를 가진 변수

  • gasprice : 트랜잭션 가스 비용으로 uint 형식
  • origin: 트랜잭션 발신자로 address 형식

This

현재 컨트랙트를 참조하는 변수로 컨트랙트의 주소로 암시적으로 변환

2-3. 함수

솔리디티에서는 다음과 같이 함수를 선언한다.

function 함수이름(파라미터형식1 파라미터1, 파라미터형식2 파라미터2, ...) { ... }

//함수가 값을 반환하는 경우 아래와 같이 선언
function 함수이름(파라미터,...) returns (반환 형식) { ... }

함수 접근 수준

  • external: 외부(external) 컨트랙트나 클라이언트 코드에서만 호출가능(내부에서는 불가)
  • public (default): 컨트랙트 내부, 외부 컨트랙트, 클라이언트 코드에서 모두 호출가능
  • internal: 컨트랙트 멤버 & 상속된 컨트랙트에서 호출가능
  • private : 컨트랙트 멤버만 호출가능

함수에서 view와 pure의 차이

view - 읽기 전용 함수. 스토리지의 자료를 읽을 수는 있지만 수정은 불가
pure - 스토리지의 변수를 읽거나 쓰지 않는 순수함수.

pragma solidity ^0.8.7;
contract exmapleC {

	unit256 public constant maxLimit = 1000;
  mapping(address => bool) public frozenAccount;
    
    
	function checkGas(uint256 amount) private pure returns (bool) {
	    if (amount < maxLimit) return true;
	    return false;
	}
	
	function validateAccount(address account) internal view  returns (bool) {
	   if (frozenAccount[account]) return true;
	   return false;
	}
}

constructor와 selfdestruct

constructor

컨트랙트가 생성될 때 생성자 함수가 실행되어 컨트랙트의 상태를 초기화

pragma solidity ^0.8.7;
contract exmapleC {

    address public account;
    
    constructor(address _account) internal {
        account = _account
    }
}

selfdestruct

selfdestruct 함수를 사용하여 컨트랙트를 소멸할 수 있다.

selfdestruct(컨트랙트 생성자의 주소);

함수 변경자(modifier)

함수를 선언할 때 modifier를 추가하여 함수가 실행되기 전, 요구 조건을 만족하는지 확인할 수 있다.
변경자를 작성할 때는 _; 를 사용하여 _; 를 기준으로
앞 부분은 함수 실행 전, 뒷 부분은 함수가 실행된 후에 적용되는 코드이다.

int public num = 0;
modifier changeNum {
	num++;  // 함수 실행 전 실행됨
	_;  // 함수 실행
	num--; // 함수 실행 후 실행됨
}

function func() public changeNum {
	if (num == 1) {
		// do something
	}
}

에러 핸들링

솔리디티에서 에러를 처리할 때는 assert, require, revert 함수를 사용한다.

  • revert : 해당 함수를 종료하고 에러를 return
  • require :설정한 조건이 참인지 확인하고, 조건이 거짓이면 에러를 return
  • assert : require처럼 조건을 확인하며 동작하지만, 사용하지 않은 가스를 호출자에게 반환하지 않고, 공급된 가스를 상태를 원래대로 되돌리는데 모두 사용

2-4. 상속

솔리디티의 contract 객체는 상속을 지원하며 다중 상속도 가능하다.

contract ChildContract is ParentContract1, ParentContract2, ParentContract3 {
  // ...
}

2-5. 이벤트

이벤트는 어떤 결과가 발생했을 때 해당 컨트랙트에서 dApp 클라이언트, 또는 다른 컨트랙트에게 전달하는 역할을 한다. 이벤트가 실행된 경우 트랜잭션에 기록된다.
event 키워드를 사용해 이벤트를 설정할 수 있으며,
emit 키워드를 사용해 이벤트를 실행한다.

contract coinTransfer {
	// event 이벤트명(파라미터유형1 파라미터1, 파라미터유형2 파라미터2, ...);
	event Transfer(address from, address to, uint256 value); 

	function transfer(address to, address amount) {
		//...
		
		// emit 이벤트명(인자1, 인자2 ...)
		emit Transfer(msg.sender, to, amount);
	}
}
profile
CY's StudyRoom

0개의 댓글