[TIL] Part2 - DAY49 Solidity - TEST10, TEST8리뷰, ERC1155, 비트코인 백서읽기

박동우·2023년 5월 30일

블록체인 스쿨 3기

목록 보기
46/72

[TIL] 2023-05-30 DAY49


Solidity

GIT 주소 : https://github.com/dowoo303/SOLIDITY


오늘 배운것들

  1. TEST10 시작
  2. TEST8 리뷰
    1) 코드 리뷰
    2) bytes형 비교 및 uint변환
  3. ERC1155
  4. 비트코인 백서읽기

각종 팁

  1. 프론트에서 solidity로 넘겨줄 때 자료를 쉽게 넘겨줄 수 있는 방법이 있다면 전처리 후 넘겨주면되기 때문에 solidity에서 모든 작업을 생각하는 것이 아닌전체적인 맥락에서 생각할 필요가 있다. 예를 들면 숫자형과 문자형을 섞어서 받는 경우 프론트에서 받아서 js에서 toString을 해준 후 solidity에 넘겨주면 solidity에서 할일이 많이 줄어든다.
    -> 요약: 한 섹터에서 모든 작업을 할 필요는 없다.
  2. bytes1은 uint8이랑, bytes2는 uint16이랑 변환이 가능하다.
  3. string을 bytes1으로 바꾸는 두가지 방법: bytes1(string) = abi.encodePacked(string)[0]
    -> 차이점: abi를 사용하면 다양한 자료형을 한번에 묶어서 bytes로 표현이 가능하다.
  4. 백서
    1) 비트코인의 아웃풋은 최대 2개다.(UTXO 중 일부인 1개는 상대방에게, 1개는 나에게)
    2) 개인공개키 쌍을 이용하여 검증과 거래가 가능하기 때문에 전통거래에서는 불가능했던 모든 거래 공개가 가능해졌다.

회고

  1. 부산에서는 노트북으로 수업을 들으니까 좀 불편하네..
  2. 질문을 할 때는 그 사람의 위치나 상황을 파악해야할 뿐 아니라 질문이 명확해야한다. 예를 들면 그 사람의 인터뷰나 강연 등을 보고 내가 이해한 부분과 이해하지 못한 부분들을 정확히 이해하고 내가 이해하지 못한 궁금했던 점들을 묻는게 좋은 질문이다.(좋은 질문은 그 사람에게 좋은 인상을 남길 수 있다)



💻 Solidity 코딩

✅ TEST8 리뷰

배열에서는 ==와 같은 비교가 불가능하다.

🟥 TEST8 코드

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;


contract Q8 {
    uint[] numbers = [1,2,3,4];
    string[] letters = ["a", "b"];

    // 로또 번호 입력, 맞추는기능 - 유저가 로또 번호를 입력하는 기능, 로또 번호를 맞추는 기능
    function setLotto(uint[] calldata _numbers, string[] calldata _letters) public payable {
        require(msg.value==0.05 ether);
        uint fit = isSameNumber(_numbers) + isSameLetter(_letters);
        getPrize(fit);
    }
    
    function getPrize(uint _n) private /*public으로 하면 자선사업가*/ {
        if(_n==6) {
            payable(msg.sender).transfer(1 ether);
        } else if(_n==5) {
            payable(msg.sender).transfer(0.75 ether);
        } else if(_n==4) {
            payable(msg.sender).transfer(0.25 ether);
        } else if(_n==3) {
            payable(msg.sender).transfer(0.1 ether);
        }
    }

    // 숫자배열 비교하기 - 각 자리 for돌려서 count 세기기
    function isSameNumber(uint[] calldata _myNumber) public view returns(uint) {
        uint count;
        for(uint i=0; i<numbers.length; i++) {
            if(numbers[i]==_myNumber[i]) {
                count++;
            }
        }
        return count;
    }

    function isSameLetter(string[] calldata _myLetter) public view returns(uint) {
        uint count;
        for(uint i=0; i<letters.length; i++) {
            if(letterCompare(letters[i], _myLetter[i])) {
                count++;
            }
        }
        return count;
    }

    // 문자배열 비교하기 - keccak256(abi.encodePacked(문자열)) 이용해서 비교 후 위와 같이 for돌려서 count 갱신
    function letterCompare(string memory _a, string calldata _b) public pure returns(bool) {
        return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
    }
}





contract Q8_2 {
    string[] public letters;
    address owner;

    constructor() {
        owner = msg.sender;
    }

    // 숫자랑 문자랑 섞여있으니까 차라리 숫자를 문자로 바꿔서 한번에 처리하는것이 좋음(solidity로 자료를 넘기기전에 js에서 처리 후 받았다고 가정)
    function setTargetNumber(string[] memory _letters) public {
        require(owner == msg.sender);
        letters = _letters;
    }

    // 로또 번호 입력, 맞추는기능 - 유저가 로또 번호를 입력하는 기능, 로또 번호를 맞추는 기능
    function setLotto(string[] calldata _letters) public payable {
        require(msg.value==0.05 ether);
        uint fit = isSameLetter(_letters);
        getPrize(fit);
    }

    function getPrize(uint _n) private /*public으로 하면 자선사업가*/ {
        if(_n==6) {
            payable(msg.sender).transfer(1 ether);
        } else if(_n==5) {
            payable(msg.sender).transfer(0.75 ether);
        } else if(_n==4) {
            payable(msg.sender).transfer(0.25 ether);
        } else if(_n==3) {
            payable(msg.sender).transfer(0.1 ether);
        }
    }

    function isSameLetter(string[] calldata _myLetter) public view returns(uint) {
        uint count;
        for(uint i=0; i<letters.length; i++) {
            if(letterCompare(letters[i], _myLetter[i])) {
                count++;
            }
        }
        return count;
    }

    function letterCompare(string memory _a, string calldata _b) public pure returns(bool) {
        return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
    }
}




// string을 input으로 받아서 bytes1배열로 변경 후 순서를 sorting해주고 중간값을 구하여 a라는 string배열에 넣는다.
contract Q8_3 {
    // 로또 번호 설정 기능
    string[6] targetLetters;

    function setLotto(string[] memory _set1, string[] memory _set2, string[] memory _set3, string[] memory _set4, string[] memory _set5, string[] memory _set6) public {
        targetLetters[0] = string(abi.encodePacked(getMedian_Number(stringArrayToBytes1Array(_set1))));
        targetLetters[1] = string(abi.encodePacked(getMedian_Number(stringArrayToBytes1Array(_set2))));
        targetLetters[2] = string(abi.encodePacked(getMedian_Number(stringArrayToBytes1Array(_set3))));
        targetLetters[3] = string(abi.encodePacked(getMedian_Number(stringArrayToBytes1Array(_set4))));
        targetLetters[4] = string(abi.encodePacked(getMedian_Number(stringArrayToBytes1Array(_set5))));
        targetLetters[5] = string(abi.encodePacked(getMedian_Number(stringArrayToBytes1Array(_set6))));
    }

    function stringArrayToBytes1Array(string[] memory _a) public pure returns(bytes1[] memory) {
        uint _n = _a.length;
        bytes1[] memory _b = new bytes1[](_n);
        for(uint i=0; i<_n;i++) {
            _b[i] = abi.encodePacked(_a[i])[0];
        }
        return _b;
    }

    function bytesAverage(bytes1 a, bytes1 b) public pure returns(bytes1) {
        return bytes1((uint8(a) + uint8(b))/2);
    }
 
    function getMedian_Number(bytes1[] memory numbers) public pure returns(bytes1){
        uint _l = numbers.length;
        for(uint i=0;i<_l-1;i++) {
            for(uint j=i+1; j<_l ;j++) {
                if(numbers[i] < numbers[j]) {
                    (numbers[i], numbers[j]) = (numbers[j], numbers[i]);
                }
            }
        }
        if(_l %2 ==0) {
            return bytesAverage(numbers[_l/2-1], numbers[_l/2]);
        } else {
            return (numbers[_l/2]);
        }
    }

    // 로또 번호 입력, 맞추는기능 - 유저가 로또 번호를 입력하는 기능, 로또 번호를 맞추는 기능
    function setLotto(string[] calldata _letters) public payable {
        require(msg.value==0.05 ether);
        uint fit = isSameLetter(_letters);
        getPrize(fit);
    }

    function getPrize(uint _n) private /*public으로 하면 자선사업가*/ {
        if(_n==6) {
            payable(msg.sender).transfer(1 ether);
        } else if(_n==5) {
            payable(msg.sender).transfer(0.75 ether);
        } else if(_n==4) {
            payable(msg.sender).transfer(0.25 ether);
        } else if(_n==3) {
            payable(msg.sender).transfer(0.1 ether);
        }
    }

    function isSameLetter(string[] calldata _myLetter) public view returns(uint) {
        uint count;
        for(uint i=0; i<targetLetters.length; i++) {
            if(letterCompare(targetLetters[i], _myLetter[i])) {
                count++;
            }
        }
        return count;
    }

    function letterCompare(string memory _a, string calldata _b) public pure returns(bool) {
        return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
    }
}


contract BytesCompare {
    bytes1 a = 0x12;
    bytes1 b = 0x23;

    function compare() public view returns(bool) {
        return b>a;
    }

    function compare2(bytes1 _a, bytes1 _b) public pure returns(bool) {
        return _b>_a;
    }
    // bytes1들끼리는 비교가 가능하다

    // bytes는 동적이리서 비교 불가!
    // function compare3(bytes memory _a, bytes memory _b) public pure returns(bool) {
    //     return _b>_a;
    // }

    // bytes1은 uint8로 변환가능능
    function bytes1ToUint(bytes1 _a) public pure returns(uint8) {
        return uint8(_a);
    }

    function uintToBytes1(uint8 _a) public pure returns(bytes1) {
        return bytes1(_a);
    }

    function bytesAdd() public view returns(bytes1) {
        return bytes1((uint8(a) + uint8(b))/2);
    }

}

🟥 TEST10 코드

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

/*
시험시간: 30분

흔히들 비밀번호 만들 때 대소문자 숫자가 각각 1개씩은 포함되어 있어야 한다 등의 조건이 붙는 경우가 있습니다. 그러한 조건을 구현하세요.

입력값을 받으면 그 입력값 안에 대문자, 소문자 그리고 숫자가 최소한 1개씩은 포함되어 있는지 여부를 알려주는 함수를 구현하세요.

*/


contract TEST10 {

     function bytestoBytesArray(bytes memory _bytes) public pure returns(bytes1[] memory) {
        bytes1[] memory _bytes1 = new bytes1[](_bytes.length);
        for(uint i=0; i<_bytes1.length; i++) {
            _bytes1[i] = _bytes[i];
        }
        return _bytes1;
    }

    function passWord(string memory _a) public returns(bool) {
        bool bigWord;
        bool smallWord;
        bool number;

        bytes1[] memory a = new bytes1[](bytes(_a).length);     // 길이만큼 자리 배정
        a = bytestoBytesArray(bytes(_a));
        

        for(uint i=0; i<a.length; i++) {
            if(abi.encodePacked(a[i]) <= abi.encodePacked(a[i]) && abi.encodePacked(a[i])<= 90) {
                bigWord = true;
            }
            if(97 <= abi.encodePacked(a[i]) && abi.encodePacked(a[i])<= 122) {
                smallWord = true;
            }
            if(48 <= abi.encodePacked(a[i]) && abi.encodePacked(a[i])<= 57) {
                number = true;
            }
        }

        return (bigWord && smallWord && number);  
    }

}

✅ ERC1155

ERC20, 721과 다르게 ERC1155는 코인을 1개만 관리하는 것이 아니라 여러개 관리가 가능하다.(그래서 _balances mapping이 이중mapping이다)

ERC20 - 코인 한개 관리
ERC721 - 멤버쉽
ERC1155 - 여러가지 코인 한번에 관리

거래를 일으켜주고 완성시켜주는 것은 노드


profile
HELLO!

0개의 댓글