솔리디티 문법

CHOYEAH·2023년 10월 23일
0
post-thumbnail

컨트랙트 구조


pragma solidity ^0.4.23; // 컴컴파파일러의 버젼

contract Mycontract { // 컨트랙트명
  unit count; // 상태변수, 컨트랙트 저장소에 영구히 저장됨

	constructor() public { // 생성자
			// ...
  }

	 				     함수이름         매개변수          함수타입       리턴타입
	function numOfStudents(address _teacher) public view retunrs(uint) { // 함수
			// ...
	}
}

상속


is 키워드를 사용하며 여러개를 상속받을 경우 “,” 쉼표 키워드를 사용하여 추가

contract MyNft is ERC721URIStorage, ERC721Enumerable {
...

만약 상속받은 객체들에 동일한 함수가 있다면 나중에 상속받은 객체들부터 검색되어 사용된다.

//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract Seller{
    address private seller;
    string private location;

    constructor(address _seller){
        seller = _seller;
    }

    function getSeller() public view returns(address){
        return seller;
    }
}

contract Car{
    string private type_; // <-- 예약어라 "_" 붙임
    uint8 private door;
    uint private price;

    constructor(string memory _type, uint8 _door, uint _price) {
        type_ = _type;
        door = _door;
        price = _price;
    }

    function getDoor() public view returns(uint8) {
        return door;
    }

    function getPrice() public view virtual returns(uint) { // <-- virtual 키워드를 사용하면 자식 클래스에서 오버라이드 할 수 있음
        return price;
    }
}

contract Benz is Car("suv", 4, 10000), Seller(0x592Ee9A3d490352cF3357b729e399C2B43f9126b) {
    string private model;
    address private owner;
    uint private premium;

    constructor(string memory _model, uint _premium){
        model = _model;
        owner = msg.sender;
        premium = _premium;
    }

    function getModel() public view returns(string memory) {
        return model;
    }

    function getPrice() public view override returns(uint) { // <-- 같은 이름의 부모 클래스 함수를 override 키워드로 오버라이드함
        return premium;
    }

    function getCarPrice() public view returns(uint) { 
        return super.getPrice(); // <-- 부모 클래스의 함수를 호출할때는 super 키워드를 사용
    }
}

접근 제어자


타입외부상속내부
externalOXX
internalXOO
publicOOO
privateXXO

external

  • 외부 컨트랙에서만 호출 가능
  • 상태변수는 external 사용 불가
pragma solidity ^0.4.23;

contract Mycontract {
  unit external count; // 상태변수에는 external 사용불가

	constructor() public { 
			// ...
  }

	function numOfStudents(address _teacher) public view retunrs(uint) {
			test(); // 컨트랙 내부에서 사용 불가
	}

	function test() external {
			// ...
	}
}

constract YourContract {
		MyContract myContract;

		function callTest() public {
				myContract.test(); // 외부 컨트랙이므로 test() 호출 가능
		}
}

internal

  • 컨트랙 내부 호출 가능
  • 상속받은 컨트랙도 호출 가능
  • 상태변수는 디폴트로 internal
pragma solidity ^0.4.23;

contract Mycontract {
  unit count;

	constructor() public { 
			// ...
  }

	function numOfStudents(address _teacher) public view retunrs(uint) {
			test(); // 컨트랙 내부에서 호출 가능
	}

	function test() internal {
			// ...
	}
}

constract YourContract is MyContract { // is MyContract ← 상속을 의미
		function callTest() public {
				test(); // 상속받은 컨트랙에서도 test() 호출 가능
		}
}

public

  • 컨트랙트 내부 호출 가능
  • 상속받은 컨트랙도 호출 가능
  • 외부 컨트랙도 호출 가능
  • 상태변수에 public 접근제어자를 명시하면 컴파일러에서 자동적으로 해당 변수의 Getter 함수를 만들어준다.
pragma solidity ^0.4.23;

contract Mycontract {
  unit public count;

	constructor() public { 
			// ...
  }

	function numOfStudents(address _teacher) public view retunrs(uint) {
			test(); // 컨트랙 내부에서 호출 가능
	}

	function test() public {
			// ...
	}
}

constract YourContract is MyContract { // is MyContract ← 상속을 의미
		function callTest() public {
				test(); // 상속받은 컨트랙에서도 test() 호출 가능
		}
}

constract HisContract {
		MyContract myContract;

		function callTest() public {
				myContract.test(); // 외부 컨트랙에서도 test() 호출 가능
		}
}

private

  • 컨트랙 내부만 호출 가능
pragma solidity ^0.4.23;

contract Mycontract {
  unit public count;

	constructor() public { 
			// ...
  }

	function numOfStudents(address _teacher) public view retunrs(uint) {
			test(); // 컨트랙 내부에서 호출 가능
	}

	function test() public {
			// ...
	}
}

constract YourContract is MyContract {
		function callTest() public {
				test(); // 상속받은 컨트랙에서는 test() 호출 불가
		}
}

constract HisContract {
		MyContract myContract;

		function callTest() public {
				myContract.test(); // 외부 컨트랙에서도 test() 호출 불가
		}
}

함수 타입 제어자


타입설명가스 비용
view데이터 read-only없음
pure1) 데이터 읽지 않음 2) 인자 값만 활용해서 반환 값 정함없음
constant0.4.17 버전 이전에는 view/pure 대신 쓰임없음
payable함수가 ETH를 받을 수 있게 함있음

view

  • read-only, 읽기 전용 함수
  • 가스 비용 없음
uint numOfStudents;

function getNumOfStudents() public view returns (uint) {
		return numOfStudents;
}

블록체인에 저장된 numOfStudents만 리턴하는 읽기 전용 함수.

numOfStudents를 수정하거나 삭제할 수 없음

pure

  • 데이터 읽지 않음
  • 인자 값만 활용해서 반환 값 정함
  • 가스 비용 없음
function multiply(uint x, uint y) public pure returns (uint) {
		return x * y;
}

constant

  • 0.4.17 버전 이전에는 view 와 pure를 대신해서 쓰임. 즉, constant는 이전에 view처럼 쓰였었는데 버전업이 되면서 view와 pure로 대체되었다.
  • 그런이유로 요새는 constant를 거의 안쓴다고함
uint numOfStudents

function getNumOfStudents() public constant returns (uint) {
		return numOfStudents;
}

payable

  • 함수가 ETH를 받을 수 있게 함. 즉, 함수가 이더를 받야할때 사용하는 타입 제어자.
  • 가스 비용 있음
function buy() public payable {
		require(10000 = msg.value);
		transferEther(msg.sender);
}

msg.value는 송신자가 이더를 얼마나 보냈는지 wei 값으로 맵핑되어있다.

값 타입


bool

분류타입
Booleanbooltrue / false
bool x = false;

int, uint

분류타입
정수형int8 bit ~ 256 bit
정수형uint8 bit ~ 256 bit
// int
// int == int256                  
// 양수와 음수 모두 사용가능
// 사용할 숫자 범위가 파악이 가능하면 되도록 비트를 지정해줘서 사용하는것이 최적화 부분에서 좋음 
int32 x = -27467               
int x = -27456

// uint 
// uint == uint256            
// 양수만 사용가능              
// 사용할 숫자 범위가 파악이 가능하면 되도록 비트를 지정해줘서 사용하는것이 최적화 부분에서 좋음 
uint256 = 24557867
uint = 24557867

adress

분류타입
주소형address20 byte 값 이더리움 계정 주소
// adress 타입은 balance, transfer 두 개의 멤버를 소유한다.
// balance: 해당 계정의 잔액
// transfer: 해당 계정으로 이더 전송

adress x = 0x123;             

function send() public {
		if (x.balance < 10) {
				x.transfer(10);
    }
} 

byte

분류타입
고정된 크기의 byte 배열byte1 byte ~ 32 byte
//  byte == bytes1    

// 바이트 타입
// 솔리디티는 스트링에 최적화되어있지 않고 32바이트 문자열에 최적화 되어있다.
// 따라서 문자를 저장할때는 hex로 변환해서 저장
// 32바이트를 넘기지 않는 길이라면 바이트 타입을 사용한다.
bytes32 x = “0x68656c6f20776f726c64”;

// 스트링타입
// 32바이트를 초과할때는 스트링 타입을 쓴다.
// 스트링 타입은 바이트 타입보다 가스 비용이 더 요구된다.
bytes32 x = “hello world”; 

bytes / string

분류타입
동적인 크기의 byte 배열bytes무한
// bytes/string은 값 타입이 없다.
bytes[] names;

enum

분류타입
열거형enum이름 { value1, value2}
// enum은 사용자 정의 타입 중 하나
// 값을 정수형으로 리턴함

enum Direction { Right, Left} // 인덱스 0: Right, 1: Left
Direction direction;

function getDirection() public return (uint) {
		return uint(direction); // Direction의 인덱스를 리턴, 인덱스는 0 부터 시작됨
}

function setDirection(uint newDirection) public {
		direction = Direction(newDirection); // 매개변수를 받은 숫자를 인자로 사용해 값을 지정
}
자료형ex1ex2범위비고
booltrue / false
int8int8 public data = -13-2^7 ~2^7 -1, -128 ~ 128
uint8uint8 public data = 10~2^8 -1 , 255양수만 가능
int (int256)int public data = -222222222-2^255 ~2^255 -1
uint (uint256)uint public data = 222220~2^256 -1양수만 가능
string내부적으로 바이트 값으로 저장이됨
bytes- 데이터가 들어오는 범위가 어느정도인지 가늠되지 않아서 가변적으로 메모리를 사용하려할 때 bytes를 사용
bytes{숫자}bytes32 public tx = hex”0x5da17b4d19e21ddf5136fe2188a5a92c51a4f868597a0c618537f102a7c548f9”bytes20 public address = hex”0xFa0CaCa91a26F421813503f577cD95f115CFdf41”~bytes32- byte 값이 고정되어 있는 경우에는 숫자를 붙여 고정된 범위를 사용, 주소값을 쓸때 bytes20, 트랜잭션 해시 값을 쓸때bytes32를 사용
addressaddress public wallet = “0xFa0CaCa91a26F421813503f577cD95f115CFdf41”bytes20과 동일하다고 볼 수 있음, hex를 안 붙여도 됨

솔리디티에서는 float 타입이 없어 소수점을 사용할 수 없음, 외부에서 처리해줘야 함

  • string과 bytes
    • String은 유니코드 단위, 즉 2byte단위
    • byte는 1byte단위
    • string은 인코딩이 되어 있어서 다른 것으로 전환할때 깨지기 쉽지만 별다른 처리가 필요 없다는 점이 장점
    • byte는 인코딩이 안된 binary라서 깨지지는 않지만 해당 byte가 어떤 방식으로 인코딩되어야 할지 정확하게 알고 있어야 하고 그것을 문자열로 변환 해주어야 하기 때문에 번거로운 단점이 있음

참조 타입: 데이터 위치


  • storage
    • 변수를 블록체인에 영구히 저장 (ex: 하드디스크)
    • 상태변수는 디폴트로 storage (함수 밖의 변수들이 상태변수)
  • memory
    • 임시 저장 변수 (ex: RAM)
    • 매개변수와 리턴 값은 디폴트로 memory
    • 컨트랙이 종료될때 증발
contract MyContract {

		uint[] ages; // storage

														   // [11, 22, 33]
		function learnDataLocation(uint[] memory newAges) public returns (uint a) {
				// newAge memory 배열을 ages storage 배열에 복사.
				// ages 값: [11, 22, 33]
				ages = newAges; 

				// int, uint, bool과 같은 기본 타입들은 함수안에 로컬 변수로 선언되었을때 memory
				uint16 myAge = 44; 

				// 배열은 함수안에 로컬 변수로 쓰일때 storage
				// studentAges는 ages를 가리키는 포인터
				// studentAges 값: [11, 22, 33]
				uint[] studentAges = ages; 
																	  
				// studentAges 배열의 첫 번째 인덱스를 44로 바꿈
				// studentAges 값: [44, 22, 33]
				// ages 값: [44, 22, 33]
				studentAges[0] = myAge;
	
				// 44를 리턴 변수에 대입, a는 메모리
				a = studentAges[0];
	
				return a;
		}
}	

참조타입: 배열


  • 정적 배열
    • 사이즈 고정
    • ex) uint[5] fixedArray;
  • 동적 배열
    • 사이즈 무한대
    • ex) uint[] dynamicArray;
contract MyContract {

		uint[] myArray; // 동적배열, 함수 밖 상태변수는 디폴트로 storage
	  uint8[3] d = [1, 2, 3]; // 정적배열,  함수 밖 상태변수는 디폴트로 storage

		function learnArrays() public {

				// 배열은 로컬(지역) 변수로 쓸때 디폴트 storage 인데
				// memory 지시어를 통해 강제로 memory로 변경
				uint256[] memory a = new uint256[](5); // 배열 사이즈 5로 지정
				bytes32[] memory b = new bytes32[](10); // 배열 사이즈 10으로 지정
				// 메모리 배열은 사이즈를 다시 정하지 못함을 유의

				// a 배열 첫 번째 인덱스 숫자 1 대입
				a[0] = 1;
				
				// a 배열 두 번째 인덱스 숫자 2 대입
				a[1] = 2;

				// 배열의 사이즈를 3으로 고정 
				// 함수안에서 [1, 2, 3] 리터럴 초기화
				// 함수 안에서 리터럴로 배열 초기화시 무조건 memory로 지정시켜야함, 안그러면 에러 발생
				uint8[3] memory c = [1, 2, 3];
				
				// 함수 안의 리터럴 초기화인데 memory로 지정시키지 않았으므로 에러가 발생됨 
				// 4라인처럼 함수 밖에서 리터럴로 배열 초기화시에는 memory 선언 안해도됨
				uint8[3] d = [1, 2, 3];

				// 동적 배열에는 push() 멤버 메소드 사용 가능
				// 또한 push()는 storage만 가능하고 memory는 사용 불가
				myArray.push(5);
				
				// length() 멤버 메소드는 storage, memory 둘 다 사용 가능
				uint myArrayLength = myArray.length; // 1 대입 
		}
}	

참조타입: 구조체


  • struct
    • 필요한 자료형들을 가지고 새롭게 정의하는 사용자 정의 타입
contract MyContract {

		struct Student {
			string studentName;
			string gender;
			uint age;
		}

		Student[] students;
		
		function addStudent(string _name, string _gender, uint _age) public {

			// 상태변수 students 배열에 새로운 Student 입력
			students.push(Student(_name, _gender, _age));

			// storage에 저장하는 새로운 Student 선언
			// 상태변수 students 배열의 첫 번째 인덱스 값 대입
			// storage로 선언되었기 때문에 상태 변수를 가르키는 포인터 역할
			Student storage updateStudent1 = student[0];

			// updateStudent1의 age 필드 55로 변경
			// 결과적으로 상태변수 students 배열의 첫 번째 인덱스의 age 필드를 55로 변경함
			updateStudent1.age = 55;

			// memory에 저장하는 새로운 Student 선언
			// 상태변수 students 배열의 첫 번째 인덱스 값 대입
			// memory로 선언됐기 때문에 값의 복사
			Student memory updateStudent2 = students[0];

			// updateStudent2의 age 필드를 20으로 변경
			// 결과적으로는 updateStudent2의 age 필드를 20으로 변경함
			updateStudent2.age = 20;

			// memory 배열의 값을 상태변수에 직접적으로 대입해주면 students 값은 영구히 변경
			students[0] = updateStudent2;
		}
}	

참조타입: 매핑


  • 문법
    • mapping(_KeyType ⇒ _ValueType)
  • 설명
    • key, value를 쌍으로 저장하는 자바의 Map과 유사
    • KeyType: 동적배열, 열거형, 구조체, 매핑 타입을 제외하고 다른 모든 타입들 다 가능
    • ValueType: 매핑 포함 모든 타입 다 가능
contract MyContract {
		//      키 타입     밸류 타입    변수명
		mapping(address => uint256) balance;
	
		function learnMapping() public {

				// msg.sender는 현재 이 함수를 불러오는 계정 주소를 뜻한다
				balance[msg.sender] = 100;
				balance[msg.sender] += 100; // 값의 변경도 가능

				// balance 매핑타입 변수의 밸류타입이 uint256이기 때문에
				// balance 밸류값을 받기 위해서
				// currentBalance의 타입을 uint256으로 지정
				uint256 currentBalance = balance[msg.sender];
		}
}	
contract MyContract2 {
		
		struct Student {
			string studentName;
			string gender;
			uint age;
		}

		mapping(uint256 => Student) studentInfo;
	
		function setStudentInfo(uint _studentId, string memory _name, string memory _gender, uint _age) public {
				
				// 매개변수 _studentId(예: 1234)를 mapping 변수 studentInfo의 키값으로 사용
				// 1234 키값의 특정 Student 구조체 정보를 불러온다
				Student storage student = studentInfo[_studentId];

				student.studentName = _name;
				student.gender = _gender;
				student.age = _age;
		}
		
		// 솔리디티에서 아직까지는 리턴값으로 구조체를 지원하지 않음
		function getStudentInfo(uint256 _studentId) view public returns (string memory, string memory, uint) {
					
					// 매개변수로 받은 키값으로(1234) 맵핑된 value값인 Student를 리턴
					return (studentInfo[_studentId].studentName
								, studentInfo[_studentId].gender
								, studentInfo[_studentId].age);
		}
}

기타


  • 변수의 값을 바꾸는 함수 호출은 트랜잭션을 호출시키지만 변수의 값을 가져오는 함수는 트랜잭션 없이 값만 읽어온다
  • 자주쓰는 화폐 단위
    • wei: 가장 작은 단위
    • 1wei * (10**18) == 1eth
    • 솔리디티에서는 wei 단위로 화폐를 처리함
      uint wei = 1 wei;
      uint eth = wei * (10**18);
      // or
      uint eth = 1000000000000000000
      // or
      uint eth = 1 ether;
      
    • gwei == wei * (10**9)

loop


  • for
    uint8 sum = 0;
    for(uint8 i=1; i < 11; i++) {
    	sum += 1;
    }
  • while
    uint8 sum = 0;
    uint8 i = 1;
    while(i<11) {
    	sum +1;
    	i++;
    }
  • dowhile
    uint8 sum = 0;
    uint8 i = 1;
    
    do{
    	sum += 1;
    	i++;
    }while(i<11)	
  • break
    uint8 sum = 0;
    for(uint8 i=1; i < 11; i++) {
    	sum += 1;
    	if(sum > 10){
    		break;
    	}
    }
  • continue
    uint8 sum = 0;
    for(uint8 i=1; i < 11; i++) {
    
    	if(i == 5){
    		continue;
    	}
    	sum += 1;
    }

Block Property


//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;

contract BlockProperty{
    uint public basefee = block.basefee;
    uint public chainid = block.chainid;
    address payable public coinbase = block.coinbase;
    uint public difficulty = block.difficulty;
    uint public gaslimit = block.gaslimit;
    uint public blockNumber = block.number;
    uint public timestamp = block.timestamp;
}

테스트 넷이라 메인넷이랑 차이가 있을 수 있음

블록 프로퍼티로 랜덤 넘버 구하기

//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;

contract BlockProperty2{

    function generateRandom() public view returns(uint8) {
        // 내장 함수인 keccak256()을 사용하여 SHA3계열 해쉬 알고리즘을 사용할 수 있다.
        // 파라메터는 바이트 값으로 넣어줘야 하기 때문에 abi.encodePacked()라는 내장 함수를 이용한다.
        // uint256()값은 너무 크기 때문에 %251 연산을 통해서 251보다 작은 값이 나오도록 하였다.
        // 블록 정보가 업데이트될때마다 다른 값이 출력되게된다.
        uint8 number = uint8(uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty)))%251);
        return number;
    }
}

transaction property


//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract TransactionProperty{

    // 남은 가스를 확인 가능, 이를 통해 트랜잭션을 계속 진행할지 말지를 결정할때 사용 할 수 있음.
    uint public gasLeft = gasleft();

    // 트랜잭션 함수를 호출할때 데이터 값(Input Data)이 들어가게되는데, 그 데이터 값을 확인할 수 있음
    bytes public msgData = msg.data;

    // 트랜잭션을 요청한 계정 주소
    address public sender = msg.sender;

    // 함수를 호출할때 함수의 MethodID 값이 인풋 데이터에 들어가게 되는데 그 바이트 코드 값을 리턴한다.
    bytes4 public sig = msg.sig;

    // 사용자가 전송한 이더의 양을 리턴, payable 함수 안에서 확인 가능
    uint public msgValue = msg.value;
}
//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract TransactionProperty2{

    // 요청한 사용자 주소를 저장하는 경우 
    mapping(address=>uint) private orderList;
    function newOrderList() external payable {
        orderList[msg.sender] = msg.value;
    }

    // 사용자가 호출한 함수를 확인하는 경우 
    // MethodID는 함수명을 keccak256() 해시 함수의 인자로 전달하여 해시한 후 바이트 값으로 바꾼것이다.
    // 파라메터가 있는 함수의 경우 추가적인 데이터를 조합한다.
		function newCheckFunction() public pure returns(bool){
        bytes4 selector = bytes4(keccak256("newCheckFunction()"));
        return selector == msg.sig;
    }
}

require, modifiyer, assert, revert


require()

//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract Modifier{
    
    uint public minPrice = 10000;  
    mapping (address=>int) public orderList;

   
    function test1() public payable{
        // 전송 금액이 minPrice 보다 클 경우에만 진행이 계속 될 수 있다.
        // 조건이 참일 경우에만 진행된다.
				// 실행할때까지 발견할 수 없는 유효 조건 검사를 위해 사용된다.
				// 조건에 통과하지 못한다면 에러메세지와 함께 에러를 발생시키고 트랜잭션을 롤백 후 가스비가 환불된다.
        require(msg.value > minPrice, "에러 메세지를 정의");
        orderList[msg.sender] = msg.value;
    }
}

modifier

//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract Modifier{
    
    uint public minPrice = 10000;  
    mapping (address=>int) public orderList;

    // 앞선 test1 함수의 기능을 아래와 같이 modifier를 사용하여 구현할 수 있다.
		// 하나의 모디파이어를 공통으로 사용할때 유용하다.
    modifier checkMinPrice() {
        require(msg.value > minPrice);
        _; // <-- 이 부분의 의미는 위 조건을 실행 후 다음 코드를 이어나간다는 의미라고 볼 수 있다.
    }
    function test2() public payable checkMinPrice{ //<-- 모디파이어를 적용
        orderList[msg.sender] = msg.value;  
    }
}

assert()

//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract Assert{
    
    // require문과의 차이점은 에러 메세지를 사용하지 않고 단순히 조건만 체크한다는 점이다.
    // 조건을 통과하지 못할 경우 에러를 발생시키고 
		// 트랜잭션으로 인해 지금까지 변경된 state를 rollback 시키고
    // 사용자가 제공한 가스 프라이스를 되돌려준다. (0.8.0 이하는 환불 안됨)
		// assert는 개발을 할때 내부 오류를 테스트하고 불변성을 확인하는 경우에 사용한다고한다.
    function order() public payable{
        assert(msg.value != 0);
    }
}

revert()

function order() external {
      // revert는 조건 없이 에러를 발생시키고 state 롤백, 가스비 환불
      // if/else 문과 함께 사용됨.
      revert("Error msg");
  }

보통 require나 revert를 사용하고 assert는 개발을 할때 내부 오류를 테스트하고 불변성을 확인하는 경우에 사용한다고한다.

  • 참고링크
[[solidity] Error Handling (assert, require, revert)](https://velog.io/@imysh578/solidity-Error-Handling-assert-require-revert)

try catch


//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

contract Math {

    function plus(uint a, uint b) external returns(uint) {
        return a + b;
    }
}

contract TryCatch{
    
   Math math = new Math();
   address payable temp_address = "0x592Ee9A3d490352cF3357b729e399C2B43f9126b";

   function callOtherContract(address to) external {
       
       // try catch는 다른 컨트랙트를 쓸때만 사용 가능하다
       try math.plus(6, 4) returns(uint plusResult) {
           (temp_address).transfer(plusResult);
       }catch{
           revert();
       }
   }
}

custom error


//SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0 <0.9.0;
import "hardhat/console.sol";

//error ZeroCheckError(); // <-- 컨트랙트 바깥쪽에서도 사용 가능하다

contract CustomError{
    
		// require, revert를 쓰다보면 에러 문구를 반복적으로 사용하게되는데 이럴때 custom error를 사용하면 유용하다.
    error ZeroCheckError(); // <-- 컨트랙트 안쪽에서도 바깥쪽에서도 사용 가능하다

    mapping (address=>uint) public testMap;

    function test1() external payable{
       if(msg.value < 1000){
            revert ZeroCheckError();
       }
       testMap[msg.sender] = msg.value;
    }

    function test2() external payable{
       if(msg.value < 2000){
            revert ZeroCheckError();
       }
    }
}

profile
Move fast & break things

0개의 댓글