// 파라미터 값이 없는 경우
modifier 모디파이어명{
revert 나 require
_;
}
// 파라미터 값이 있는 경우
modifier 모디파이어명(파라미터){
revert 나 require
_;
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract lec27{
modifier onlyAdults2(uint256 _age){
require(_age>18,"You are not allowed to pay for the cigarette");
_;
}
function BuyCigarette2(uint256 _age) public onlyAdults2(_age) returns(string memory){
return "Your payment is scceeded";
}
}
여기서는 modifier인 onlyAdults2는 uint256 타입인 _age 파라미터를 받음.
이 _age를 받고 18세 미만이라면 require를 통해서 에러를 발생시킴.
즉, Buycigarette2 _age 라는 파라미터 값을 onlyAdults2 라는 모디파이어에 _age 넣어준 것.
그러면, Buycigarette2(uint256 _age) 는 실질적으로 이렇게 작동하게 됨.
function BuyCigarette2(uint256 _age) public returns(string memory){
require(_age>18,"You are not allowed to pay for the cigarette");
return "Your payment is scceeded";
}
Payable은 코인과 상호작용(송금)시 필요한 키워드.
즉, send, trnafer, call을 이용하여, 이더를 보낼때 Payable이라는 키워드가 필요.
이 Payable은 주로 함수,주소,생성자에 붙여서 사용됨.
// SPDX-Lisence-Identifier: GPL-3.0
pragma solidity ^0.8.13;
import "hardhat/console.sol";
contract Counter {
address payable public owner;
constructor() payable {
owner = payable(msg.sender);
}
function deposit() public payable {
}
function NotpayableDepisit() public {
}
function withdraw() public payable {
uint amount = address(this).balance;
console.log(amount / 1 ether,"ETH");
(bool success, ) = owner.call{value: amount}("");
require(success, "Failed to send Other.");
}
function transfer(address payable _to, uint _amount) public {
(bool success,) = _to.call{value: _amount*(1 ether)}("");
require(success, "Failed to send Other.");
}
}
msg.value는 송금보낸 코인의 값. 호출자의 Address를 가져옴
1.send : 2300 gas를 소비, 성공여부를 true 또는 false로 리턴한다
2.transfer : 2300 gas를 소비, 실패시 에러를 발생
3.call : 가변적인 gas 소비 (gas값 지정 가능), 성공여부를 true 또는 false로 리턴. 재진입(reentrancy) 공격 위험성 있음, 2019년 12월 이후 call 사용을 추천.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 < 0.9.0;
contract lec32 {
event howMuch(uint256 _value);
function sendNow(address payable _to) public payable{
bool sent = _to.send(msg.value); // return true or false
require(sent,"Failed to send either");
emit howMuch(msg.value);
}
function transferNow(address payable _to) public payable{
_to.transfer(msg.value);
emit howMuch(msg.value);
}
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 Ether");
emit howMuch(msg.value);
}
}
balance
balance는 해당 특정 주소의 현재 이더의 잔액을 나타 냅니다.
주소.balance 와 같은 형태로 사용합니다.
msg.sender
msg.sender 는 스마트컨트랙과 상호 작용하는 주체.
pragma solidity >=0.7.0 < 0.9.0;
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 payable _to) 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는 스마트 컨트랙과 상호작용하는 주체를 나타내기에, 이점을 이용해서
require관 연계하여 특정 주소를 가진 주체에게만 특정 함수를 사용할 수 있도록 권한을 부여 할 수 있다.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
contract MobileBanking{
address owner;
constructor() payable{
owner = msg.sender;
}
modifier onlyOwner{
require(msg.sender == owner, "Only Owner!");
_;
}
event SendInfo(address _msgSender, uint256 _currentValue);
event MyCurrentValue(address _msgSender, uint256 _value);
event CurrentValueOfSomeone(address _msgSender, address _to,uint256 _value);
function sendEther(address payable _to) public onlyOwner 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 onlyOwner {
emit MyCurrentValue(msg.sender, msg.sender.balance);
}
function checkUserMoney(address _to) public onlyOwner {
emit CurrentValueOfSomeone(msg.sender,_to ,_to.balance);
}
}
fallback
Fallback은 함수지만, 어떠한 전달 인자, return 값도 가지지 않음
특징
1. 먼저 무기명 함수, 이름이 없는 함수입니다.
2. external 필수
3. payable 필수
4. 존재하지 않는 함수를 호출할 때 FallBack이 자동으로 호출됨
5. Ether가 Contract로 바로 Send 될 때 Call 됨
(receive, msg.data가 없는 경우)
receive: 순수하게 이더만 받을때 작동 합니다.
fallback: 함수를 실행하면서 이더를 보낼때, 불려진 함수가 없을 때 작동합니다.
기본형 : 불려진 함수가 특정 스마트 컨트랙이 없을때 fallback 함수가 발동 합니다.
fallback() external {
}
payable 적용시 : 이더를 받고 나서도 fallaback 함수가 발동합니다.
fallback() external payable {
}
receive() external payable{
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 < 0.9.0;
contract Bank{
event JustFallback(address _from,string message);
event RecevieFallback(address _from,uint256 _value ,string message);
event JustFallbackWIthFunds(address _from,uint256 _value ,string message);
//~0.6
// function() external payable {
// emit JustFallbackWIthFunds(msg.sender, msg.value,"JustFallback is called");
// }
//0.6~
// fallback() external {
// emit JustFallback(msg.sender,"JustFallback is called");
// }
// receive() external payable {
// emit RecevieFallback(msg.sender, msg.value,"RecevieFallback is called");
// }
//
fallback() external payable {
emit JustFallbackWIthFunds(msg.sender, msg.value,"JustFallbackWIthFunds is called");
}
}
contract You{
//receve()
function DepositWithSend(address payable _to) public payable{
bool success = _to.send(msg.value);
require(success, "Failled" );
}
function DepositWithTransfer(address payable _to) public payable{
_to.transfer(msg.value);
}
function DepositWithCall(address payable _to) public payable{
// ~ 0.7
// (bool sent, ) = _to.call.value(msg.value)("");
// require(sent,"Failed to send either");
//0.7 ~
(bool sent, ) = _to.call{value: msg.value}("");
require(sent, "Failled" );
}
//fallback()
function JustGiveMessage(address payable _to) public payable{
(bool success, ) = _to.call("HI");
require(success, "Failled" );
}
//To the fallback() with Funds
function JustGiveMessageWithFunds(address payable _to) public payable{
(bool success,) = _to.call{value:msg.value}("HI");
require(success, "Failled" );
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
contract add{
event JustFallback(string _str);
function addNumber(uint256 _num1, uint256 _num2) public pure returns(uint256){
return _num1 + _num2;
}
fallback() external {
emit JustFallback("JustFallback is called");
}
}
contract caller{
event calledFunction(bool _success, bytes _output);
//1. 송금하기
function transferEther(address payable _to) public payable{
(bool success,) = _to.call{value:msg.value}("");
require(success,"failed to transfer ether");
}
//2. 외부 스마트 컨트랙 함수 부르기
function callMethod(address _contractAddr,uint256 _num1, uint256 _num2) public{
(bool success, bytes memory outputFromCalledFunction) = _contractAddr.call(
abi.encodeWithSignature("addNumber2(uint256,uint256)",_num1,_num2)
);
require(success,"failed to transfer ether");
emit calledFunction(success,outputFromCalledFunction);
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
contract add{
uint256 public num = 0;
event Info(address _addr,uint256 _num);
function plusOne() public {
num = num + 1;
emit Info(msg.sender,num);
}
}
contract caller{
uint256 public num = 0;
function callNow(address _contractAddr) public payable{
(bool success,) = _contractAddr.call(abi.encodeWithSignature("plusOne()"));
require(success,"failed to transfer ether");
}
function delcateCallNow(address _contractAddr) public payable{
(bool success,) = _contractAddr.delegatecall(abi.encodeWithSignature("plusOne()"));
require(success,"failed to transfer ether");
}
}
enum 은사람이 읽을수 있게, 사용자/개발자에 의해 정의된 상수세트 타입.
한개의 enum당 256개까지 저장이 되며, 0 부터 255까지 부여됨.
(uint8 = 0~255(2^8-1))
상수세트이기에 enum은 uint로 변환해서 사용이 가능
// SPDX-Lisence-Identifier: GPL 3.0
pragma solidity ^0.8.13;
contract Example {
enum Status{
Pending,
Shipped,
Accepted,
Rejected,
Canceled
}
Status public status;
function get() public view returns(Status) {
return status;
}
function set(Status _status) public {
status = _status;
}
function cancel() public {
status = Status.Canceled;
}
function reset() public{
delete status;
}
}
library: 기존에 만들던 스마트 컨트랙과 다른 종류의 스마트 컨트랙
이점
1. 재사용 : 블록체인에 라이브러리가 배포되면, 다른 스마트 컨트랙들에 적용가능.
2. 가스 소비 줄임 : 라이브러리는 재사용가능 한 코드, 즉 여러개의 스마트 컨트랙에서 공통으로 쓰이는 코드를 따로 라이브러리 통해서 배포 하기에, 다른 스마트 컨트랙에 명시를 해주는것이 아니라, 라이브러리를 적용만 하면 되기에 가스 소비량을 줄일 수 있다. 왜냐하면, 가스는 스마트 컨트랙의 사이즈/길이에 영향을 많이 받기 때문이다.
3.데이터 타입 적용: 라이브러리의 기능들은 데이터 타입에 적용할 수 있기에, 좀 더 쉽게 사용할 수 있다.
제한사항
1. fallback 함수 불가: fallback 함수를 라이브러리 안에 정의를 못 하기에, 이더를 갖고 있을 수 없습니다.
2. 상속 불가
3. payable 함수 정의 불가
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
library SafeMath{
function add(uint8 a, uint8 b) internal pure returns (uint8) {
require(a+b >= a , "SafeMath: addition overflow");
return a + b;
}
}
contract lec40{
using SafeMath for uint8;
uint8 public a;
function becomeOverflow(uint8 _num1,uint8 _num2) public {
// a = _num1.add(_num2);
a = SafeMath.add(_num1 ,_num2);
}
}
솔리디티 파일 한개당 스마트 컨트랙트를 한개씩 넣는다면, 여러개의 솔리디티 파일이 생길것이다.
그렇다면, 스마트 컨트랙끼리 이어 줄려면, 서로의 솔리디티 파일의 위치를 잘 알아야한다.
이럴때 필요한것이 import 입니다.
스마트 컨트랙트든, library 든 import 를 통해서 위치를 명시해주ㅜㄴ다.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/docs-v3.x/contracts/math/SafeMath.sol";
contract lec41 {
using SafeMath for uint256;
uint public a;
uint public maximum = ~uint256(0); // ==2**256-1; // 2**256 == 2^256
function becomeOverflow(uint _num1, uint _num2) public {
a = _num1.add(_num2);
}
}