- Try/Catch
Try/catch는 프로그램을 종료시키지 않고 어떠한 대처를 할 수 있다.
- 정상 실행되므로 Try/catch내의 에러를 잡기가 힘들다
- 3가지 Catch가 존재한다
- Catch Error(string memory reason){ … } : revert나 require를 통해 생성된 에러 용도
- Catch panic(uint errorcode) { … } : assert를 통해 생성된 에러
0.8버전에는 없고 0.8.1버전 부터 존재
- Catch(bytesmemoryLowlevelData) { … } : low level error를 잡는다
3. 언제 사용되는지 ?
1) 외부 스마트 컨트랙트 함수를 부를 때 : 다른 스마트 컨트랙을 인스턴스화 해서, try/catch문이 있는 스마트 컨트랙의 함수를 불러와서 사용
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.7.0 <0.9.0;
contract math{
function division(uint256 _num1, uint256 _num2) public pure returns(uint256){
require(_num<10,"num1 shoud not be more than 10");
return _num1/_num2;
}
}
contract runner{
event catcherr(string _name, string _err);
event catchpanic(string _name,string _err);
event catchlowlevelerr(string _name,string _err);
math public mathinstance = new math();
function playtrycatch(uint256 _num1, uint256 _num2) public returns(uint256,bool){
try mathinstance.division(_num1,_num2) returns(uint256 value){
returns(value,true);
}
catch Error(string memory _err){
emit catcherr("revert/require",_err);
return(0,false)
}
catch Panic(uint256 _errorcode){
emit catchpanic("assert/panic",_errorcode);
return(0,false);
}
catch (bytes memory _errorcode){
emit catchlowlevelerr("lowlevelerror",_errorcode)
return(0,false);
}
}
}
2) 외부 스마트 컨트랙을 생성 할 때 : 다른 스마트컨트랙을 인스턴스화 할 때 쓴다.
contract character{
string private name;
uint private power;
constructor(string memory _name,uint256 _power){
name = _name;
power = _power;
}
}
contract runner{
event catchonly(string _name,string _err);
function playtrycatch(string memory _name,uint256 _power) public returns(bool successorfail){
try new character(_name,_power){
return(true);
}
catch{
emit catchonly("catch","error");
return(false)
}
}
Try 문 내에서의 revert와 같은 에러들은 잡히지 않는다.
3) 스마트컨트랙 내에서 함수를 부를 때
contract runner2{
function simple() public returns(uint256){
return 4;
}
function playtrycatch() public return(uint256,bool){
try this.simple() returns(uint256 value) {
return(value,true)
}
catch{
emit catchonly("catch","error");
return(0,false);
}
}
}
- Error handler
- Require
특정한 조건에 부합하지 않으면(false일 때) 에러를 발생시키고, gas를 환불 시켜준다.
function requirenow(uint256 _age) public pure{
Require(false,"occurred");
Require(_age>19,"you are not allowd to pay for the cigarette");
}
- Assert
Gas를 다 소비한 후, 특정한 조건에 부합하지 않으면 에러를 발생시킨다.
Gas는 환불이 안된다.
But 0.8버전부터는 가스환불 된다.(revert와 동일)
Panic(uint256)이라는 에러타입의 에러 발생
=> 에러 타입에 대해 정의되어 있다.
function assertnow() public pure{
// false 이므로 에러 발생
Assert(false);
// 주로 내부적 테스트 용도,
}
- Revert
조건없이 에러를 발생시키고, gas를 환불시켜준다.
function assertnow(uint256 _age) public pure{
//무조건 에러 발생하며 메세지를 남길수 있다.
revert("error ! ");
// 조건도 없이 에러가 나오므로 실용적이지 못하다 따라서 if와 함께 or require사용
If(_age<19)}
Revert("you are not allowed to pay for the cigarette");
}
}
이때는 revert에 대한 gas비용만 나간다.
- Function 리턴 값 변수 명시
function add(uint256 _num1, uint256 _num2) public pure returns(uint256){
uint256 total = _num1 + _num2;
return total;
}
function add(uint256 _num1, uint256 _num2) public pure returns(uint256 total){
total = _num1 + _num2;
return total;
}
명시할 시에 함수 내에서 따로 선언해줄 필요 없으며 여러 값을 리턴하는 경우에 더 편하다.
- Function Modifier
Revert나 require사용 시에 편하게 가능하다.
함수는 다르지만 require 조건이 같은 경우
contract modi{
modifier onlyAdults{
require(_age>18,"You are not allowd to pay for the cigarette");
//revert("You are not allowd to pay for the cigarette");
_; // 이 위치에 함수가 들어간다.
}
// return 되기 전에 revert문이 먼저 실행
function buyCigarette() public onlyAdults returns(string memory){
return "Your payment is succeeded";
}
}
- 이더 관련 함수
- Payable : 이더/토큰과 상호작용시 필요한 키워드
Send, transfer, call을 이용하여 이더를 보낼때 payable이라는 키워드가 필요하며 이 payable은 주로 함수, 주소, 생성자에 붙여서 사용된다.
+ msg.value = 송금보낸 코인의 값
1. Send
2300gas를 소비, 성공여부를 True 또는 False로 리턴, 에러를 보지 못한다는게 단점
function sendnow(address payable _to) public payable{
// 스마트컨트랙트 주소로도 이더를 받을수 있다.
//msg.value는 창에 입력하는 송금 금액
bool sent = _to.send(msg.value);
require(sent,"Failed to send ether");
emit howmuch(msg.value);
}
2. Call
가변적인 gas 소비(gas값 지정 가능), 성공여부를 true 또는 false로 리턴
재진입 공격 위험성 있음
function callnow(address payable _to) public payable{
// ~ 0.7
(bool sent, ) = _to.call.gas(1000).value(msg,value)("");
require(sent,"Failed to send either");
//0.7 ~
(bool sent, ) = _to.call{value:msg.value, gas:1000}("");
require(sent,"Failed to send either");
emit howmuch(msg.value);
}
3. Transfer
2300gas를 소비, 실패시 에러를 발생
function transfernow(address payable _to)public payable{
_to.transfer(msg.value);
emit howmuch(msg.value);
2019년 이스탄불 하드포크 후 가스 가격이 올랐고 2300가스로는 스마트컨트랙트 이용이 부족할수 있음 그래서 다시 call을 사용하게 됨
4. Balance
해당 특정 주소의 현재 갖고 있는 이더의 잔액을 나타낸다.
주소.balance와 같은 형태로 사용한다.
5. Msg.sender
contract MobileBanking{
event sendInfo(address _msgSender, uint256 _currentValue);
event mycurrentValue(address _msgSender, uint256 _value);
event currentValueOfSomeone(address _msgSender, address _to,uint256 _value);
function sendEther(address _to payable) public payable{
require(msg.sender.balance>msg.value, "Your balance is not enough");
_to.transfer(msg.value);
emit sendInfo(msg.sender,(msg.sender).balance);
}
function checkvalueNow() public{
emit mycurrentValue(msg.sender,msg.sender.balance);
}
function checkUserMoney(address _to) public{
emit currentValueOfSomeone(msg.sender,_to,_to.balance);
}
}
msg.sender 활용한 권한 부여
contract MobileBanking{
address owner;
//생성자에 payable 키워드를 통해 스마트컨트랙이 처음 배포될떄 이더를 받을수 있다
constructor () payable {
// 배포할 때 그 주소를 owner에 넣는다
owner = msg.sender;
}
event sendInfo(address _msgSender, address _msgReceiver,uint256 _currentValue);
event mycurrentValue(address _msgSender, uint256 _value);
event currentValueOfSomeone(address _msgSender, address _to,uint256 _value);
modifier onlyOwner{
require(msg.sender ==owner,"Only owner");
require(msg.sender.balance>msg.value, "Your balance is not enough");
_;
}
function sendEther(address payable _to) onlyOwner public payable{
_to.transfer(msg.value);
emit sendInfo(msg.sender,_to,(msg.sender).balance);
}
function checkvalueNow() public{
emit mycurrentValue(msg.sender,msg.sender.balance);
}
function checkUserMoney(address _to) public{
emit currentValueOfSomeone(msg.sender,_to,_to.balance);
}
}
'BlockChain' 카테고리의 다른 글
Solidity 취약점 카테고리화 (0) | 2022.01.11 |
---|---|
Solidity #5 (0) | 2022.01.10 |
Solidity #4 (0) | 2022.01.07 |
Solidity #3 (0) | 2022.01.06 |
Solidity #1 (0) | 2022.01.04 |