contract QUIZ2 {
struct User {
bytes32 hash;
uint attempts;
}
mapping(string => User) ID_PW;
function getHash(string memory _ID, string memory _PW) public pure returns(bytes32) {
return keccak256(abi.encodePacked(_ID, _PW));
}
function userInfo(string memory _ID) public view returns(string memory, User memory){
return (_ID, ID_PW[_ID]);
}
// * 로그인 기능 - ID, PW를 넣으면 로그인 여부를 알려주는 기능
function logIn(string memory _ID, string memory _PW) public returns(bool){
// * 비밀번호 5회 이상 오류시 경고 메세지 기능 - 비밀번호 시도 회수가 5회되면 경고 메세지 반환
require(ID_PW[_ID].attempts < 5, "Too much attempts");
if(ID_PW[_ID].hash == getHash(_ID, _PW)) {
ID_PW[_ID].attempts = 0;
return true;
} else {
ID_PW[_ID].attempts++;
return false;
}
}
// * 회원가입 기능 - 새롭게 회원가입할 수 있는 기능
function signIn(string memory _ID, string memory _PW) public{
// * 회원가입시 이미 존재한 아이디 체크 여부 기능 - 이미 있는 아이디라면 회원가입 중지
require(ID_PW[_ID].hash == 0x0000000000000000000000000000000000000000000000000000000000000000, "Provided ID is already being used");
// require(ID_PW[_ID].hash == "", "Provided ID is already being used");
ID_PW[_ID].hash = getHash(_ID, _PW);
}
// * 회원탈퇴 기능 - 회원이 자신의 ID와 PW를 넣고 회원탈퇴 기능을 실행하면 관련 정보 삭제
function signOut(string memory _ID, string memory _PW) public {
require(ID_PW[_ID].hash == getHash(_ID, _PW));
// require(logIn(_ID, _PW) == true); // 추후 수정
delete ID_PW[_ID];
}
}
contract REQUIRE {
/* 실습가이드
1. 5, 15 각각 Require()에 넣어보기
2. onlyAlice에 alice 한번, bob 한번 input 값으로 넣어보기
*/
//10보다 작은 3의배수.(REQUIRE에는 조건문만 들어가야 한다.)
function Require1(uint _n) public pure returns(uint) {
//메세지를 넣을 수 있다.
require(_n<10, "input should be lower than 10");
return _n*3;
}
function getName(string memory _name) public pure returns(bytes32) {
return keccak256(abi.encodePacked(_name));
}
function onlyAlice(string memory _name) public pure returns(bool) {
require(getName(_name) == 0x9c0257114eb9399a2985f8e75dad7600c5d89fe3824ffa99ec1c3eb8bf3b0501);
return true;
}
}
if문과 require의 차이
require
예시
contract REQUIRE2 {
function getBool() public pure returns(bool) {
bool _a;
return _a;
}
function Require1() public pure returns(uint) {
uint _a=1;
bool b;
require(b, "Error"); // 통과못함
return _a;
}
function Require2() public pure returns(uint) {
uint _a=1;
bool b;
return _a;
require(b, "Error"); // Unrecheable code
}
uint a = 1;
function getA() public view returns(uint) {
return a;
}
function Require3() public {
bool c;
a = 5;
require(c, "error"); // a를 5로 바꾼 것도 전부다 다시 revert (원래 상태로 복구) 시킴.
}
function Require3_2() public {
bool c;
a = 5;
require(!c, "error"); // a를 5로 바꾼 것도 전부다 다시 revert (원래 상태로 복구) 시킴.
}
function setAasFive() public {
a =5;
}
// require 타 함수 호출
function Require4() public {
bool c;
setAasFive(); // a의 값을 5로 설정하는 외부 함수
require(c, "error"); // 외부함수도 모두 revert
}
//require가 어디까지 뒤집을 수 있는지를 확인하고 싶어서 작성된 코드들.
// require 조건 2개
function Require5(uint _n) public pure returns(bool) {
require(_n%5==0 && _n>10, "Nope");
return true;
}
// if문 안의 require
function Require6(uint _a) public pure returns(uint) {
if(_a%3==0) {
require(_a%3!=0, "nope");
} else if(_a%3==1) {
return _a%3;
} else {
return _a%3;
}
}
}
REQUIRE의 위치가 어디에 들어가느냐에 따라서 실행되는 범위가 어떻게 되는지 알아보기 위해 여러 방법을 사용.
uint가 bytes형태로 변하지 못하는 이유.
abi.encodepacked는 uint를 bytes로 변경할 수 있는 과정을 도와준다.
if문안에 Require를 넣어 코드가 끝까지 실행되지 않도록 막을 수 있다.
Require 안 조건에 "!" 가 들어가면 반대가 되기때문에 조건에 부합하지 않았을 때도 실행된다.
contract CONSTRUCTOR {
uint a;
uint b;
constructor() {
a = 7;
b = 4;
}
function setA() public {
a = 5;
}
function getA() public view returns(uint) {
return a;
}
function getB() public view returns(uint) {
return b;
}
}
//인풋값을 받는것.
contract CONSTRUCTOR2 {
uint a;
constructor(uint _a) {
a = _a;
}
function getA() public view returns(uint) {
return a;
}
}
// 인풋을 두개 받을 수 있다.
contract CONSTRUCTOR3 {
struct Student {
string name;
uint number;
}
Student s;
constructor(string memory _name, uint _number) {
s = Student(_name, _number);
}
function getStudent() public view returns(Student memory) {
return s;
}
}
// 안에 if나 else를 넣을 수 있다.
contract CONSTRUCTOR4 {
uint a;
constructor(uint _a) {
if(_a>5) {
a = _a;
} else {
a = _a*2;
}
}
function getA() public view returns(uint) {
return a;
}
}
contract CONSTRUCTOR5 {
/*
1. 1번 지갑으로 배포, value는 10eth로
2. 배포 후 지갑 잔고 확인
3. 2번 지갑으로 deposit() 1eth // 3,4,5번 지갑으로 똑같이 실행
4. 지갑 잔고 확인 후, 2번 지갑으로 trnasferTo 시도, _to의 지갑 주소는 6번 지갑 금액은 5eth
5. 1번 지갑으로 transferTo 시도, _to의 지갑 주소는 6번 지갑 금액은 5eth
6. 2번 지갑으로 withdraw 함수 시도, 1번 지갑으로 withdraw 함수 시도
*/
address payable owner;
constructor() payable {
payable(this).transfer(msg.value);// 배포할 때 msg.value 만큼 contract에게 바로 입급.
owner = payable(msg.sender); // 배포하는 지갑주소가 바로 owner로 설정.
}
function getOwner() public view returns(address) {
return owner;
}
// 특정 지갑주소에 특정 금액만큼 보내는 함수.(contract가 _to에게 _amount를 보냄)
function transferTo(address payable _to, uint _amount) public {
require(msg.sender == owner, "only owner can transfer asset");
_to.transfer(_amount);
}
receive() external payable{}// 일반 거래(별도의 호출되는 함수 없을때)시 해당 contract가 돈을 받을 수 있게 해주는 함수.
// contract에 돈을 받는 함수.(contract가 msg.value만큼 돈을 받는 함수)
function deposit() public payable returns(uint){
return msg.value;
}
// withdraw는 돈을 보내는 함수.(contract가 owner에게 전액 돈을 보내는 함수. owner 입장에서는 전액 인출)
function withdraw() public {
require(msg.sender == owner, "only owner can transfer asset");
owner.transfer(address(this).balance);
}
// contract가 owner에게 _amount만큼 보내는 함수.
function withdraw2(uint _amount) public {
require(msg.sender == owner, "only owner can transfer asset");
owner.transfer(_amount); //(_amount * 10**18) 이렇게 eth 단위로도 사용할 수 있음.
}
// ether도 넣을 수 있음.
function withdraw3() public {
require(msg.sender == owner, "only owner can transfer asset");
owner.transfer(1 ether);
}
}
contract MODIFIER {
uint a;
modifier lessThanFive() {
require(a<5, "should be less than five");
_;// 함수가 실행되는 시점.(자기를 호출한 함수의 코드.)
}
function aPlus() public {
a++;
}
function aMinus() public {
a--;
}
function getA() public view returns(uint) {
return a;
}
function doubleA() public lessThanFive {
a = a*2;
}
function plusTen() public lessThanFive {
a += 10;
}
}
contract MODIFIER2 {
/*
실습가이드
1. setAasTwo()로 a 값 2로 만들기
2. setA() 실행 후 결과 확인, getA()로 A 값 확인
3. setAasTwo()로 a 값 다시 2로 만들기
4. setA2() 실행 후 결과 확인, getA()로 A 값 확인
*/
uint a;
modifier plusOneBefore() {
a++;
_;
}
modifier plusOneAfter() {
_;
a++;
}
function setA() public plusOneBefore returns(string memory) {
if(a>=3) {
return "A";
} else {
return "B";
}
}
function setA2() public plusOneAfter returns(string memory) {
if(a>=3) {
return "A";
} else {
return "B";
}
}
function getA() public view returns(uint) {
return a;
}
function setAasTwo() public {
a = 2;
}
}
contract MODIFIER3 {
/*
실습가이드
1. setAasTwo()로 a 값 2로 만들기
2. setA() 실행 후, getB2() 실행해서 결과 보기
*/
uint a;
string b;
string[] b2;
modifier plusOneBefore {
_;
a++;
_;
}
function setA() public plusOneBefore {
if(a>=3) {
b = "A";
b2.push(b);
} else {
b = "B";
b2.push(b);
}
}
function getA() public view returns(uint) {
return a;
}
function getB() public view returns(string memory) {
return b;
}
function getB2() public view returns(string[] memory) {
return b2;
}
function setAasTwo() public {
a = 2;
}
}
a++; 언더바; / 언더바; a++;
_; 를 여러번 적용해서 사용할수도 있다.
contract MODIFIER4 {
struct Person {
uint age;
string name;
}
Person P;
modifier overTwenty(uint _age, string memory _criminal) {
require(_age >20, "Too young");
require(keccak256(abi.encodePacked(_criminal)) != keccak256(abi.encodePacked("Bob")), "Bob is criminal. She can't buy it");
_;
}
function buyCigar(uint _a, string memory _name) public pure overTwenty(_a, _name) returns(string memory) {
return "Passed";
}
function buyAlcho(uint _a, string memory _name) public pure overTwenty(_a, _name) returns(string memory) {
return "Passed";
}
function buyGun(uint _a, string memory _name) public pure overTwenty(_a, _name) returns(string memory) {
return "Passed";
}
function setP(uint _age, string memory _name) public {
P = Person(_age, _name);
}
function getP() public view returns(Person memory) {
return P;
}
function buyCigar2() public overTwenty(P.age, P.name) view returns(string memory) {
return "Passed";
}
function buyAlcho2() public overTwenty(P.age, P.name) view returns(string memory) {
return "Passed";
}
function buyGun2() public overTwenty(P.age, P.name) view returns(string memory) {
return "Passed";
}
}
Modifier4~6은 어렴풋이 이해함. (이걸 이해했다고 표현하는게 맞나?)
mutex = 화장실, 예시) 누군가 들어가면 다른사람은 못들어옴.
Require : 분명 들었는데.. 잘모르겠다.. 테스트에서도 제대로 사용을 못했다.
constructor : 기초에서는 어렵지 않다고 생각했는데 응용으로 넘어가니까 좀 헷갈렸다. 그래도 이론적인건 이해를 좀 했다고 생각했는데 써보라고 하면 못쓸 것 같다.
Modifier : 왜 써야하는지는 알겠는데 역시나 응용 넘어가니까 너무 헷갈린다. 특히 언더바가 왔다갔다하고 여기갔다 저기갔다 하니까 이건 내가 칠수있으려면 좀 걸릴것 같다;
테스트3 : 오늘 테스트를 또 봤다. 역시나 엉망이였다. 사실 나한테는 테스트는 아직 무리다; 그것보다는 뿌수기를 빨리 해봐야겠다.