소유 가능한 컨트랙트 Ownable
컨트랙트를 소유 가능하게 하는 방법이 있다.
즉, 컨트랙트를 대상으로 특별한 권리를 가지는 소유자를 생성시킬 수 있다.
OpenZeppelin 솔리디티 라이브러리에 있는
Ownable 컨트랙트는 DApp에서 사용할 수 있는 안전한 스마트 컨트랙트의 라이브러리이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0)); OwnershipTransferred(owner, newOwner); owner = newOwner; } } | cs |
위의 코드에 있는 함수는 다음과 같이 실행된다.
1. 생성자 Ownable()은 컨트랙트와 동일한 이름을 가진,생략할 수 있는 특별한 함수이며 다른 언어와 같이
이 함수는 컨트랙트가 생성될 때 딱 한 번만 실행된다.
2. 컨트랙트가 생성되면 컨트랙트의 생성자가 owner에 msg.sender(컨트랙트 배포자)를 대입한다.
3. 특정한 함수들에 대해 오직 소유자만 접근 가능하도록 onlyOwner 제어자를 추가한다.
4. 해당 컨트랙트의 소유권을 옮겨준다.
1 2 3 4 5 | modifier onlyOwner() { require(msg.sender == owner); _; } | cs |
1 2 3 4 5 6 7 | contract MyContract is Ownable { event LaughManiacally(string laughter); function likeABoss() external onlyOwner { LaughManiacally("Muahahahaha"); } } | cs |
likeABoss함수를 보면 onlyOwner이 있다. onlyOwner 제어자가 호출되면 require로 owner인지 확인하게 되고
owner가 맞다면 _;을 통해 likeABoss 함수로 되돌아가고 해당 함수(likeABoss)를 실행하게 된다.
보통은 require를 이용하여 함수 실행전에 체크를 할 수 있지만, onlyOwner의 경우에는, 함수에 이 제어자를 추가하면 오직 컨트랙트의 소유자(자네가 배포했다면 자네겠지)만이 해당 함수를 호출할 수 있다.
** 소유자가 컨트랙트에 특별한 권한을 가지는 일이 종종 필요할 수 있지만 코드를 악용하면 심각한 문제가 될 수 있다.
따라서 이러한 DApp을 피하기 위해서는 개발자가 제공하는 소스 코드를 잘 분석하고 잠재적 위험이있는지 확인하는 습관이 필요하고 개발자는 소비자에게 이러한 위험이 없게 믿고 쓸 수 있도록 해야 DApp 생태계가 밝아진다.
Payable 제어자 및 컨트랙트에서 ETH 거래
payable 함수는 솔리디티에서 이더리움을 거래할 수 있게 해주는 제어자이다.
단적인 예로 함수를 실행하는 동시에 컨트랙트에 일정 페이를 지불하도록 하는 방식을 만들 수 있다는 것이다.
1 2 3 4 5 6 7 8 | contract OnlineStore { function buySomething() external payable { // 함수 실행에 0.001이더가 보내졌는지 확실히 하기 위해 확인: require(msg.value == 0.001 ether); // 보내졌다면, 함수를 호출한 자에게 디지털 아이템을 전달하기 위한 내용 구성: transferThing(msg.sender); } } | cs |
require와 msg.value를 통해 컨트랙트로 ETH가 얼마나 보내진 지 확인이 가능하게 된다.
만약 함수가 payable로 표시되지 않았는데 ETH를 보내려 한다면, 함수에서 자네의 트랜잭션을 거부할 것이다.
특정 컨트랙트로 ETH를 보내게 되면 해당 컨트랙트의 이더리움 지갑에는 이더가 저장될 것이다.
이 컨트랙트에 있는 ETH를 가져오기 위한 방법을 한번 알아보자.
1 2 3 4 5 | contract GetPaid is Ownable { function withdraw() external onlyOwner { owner.transfer(this.balance); } } | cs |
onlyOwner 제어자에 의해 소유자가 확인되면 owner.transfer(this.balance)를 통해 컨트랙트 내의 ETH를 인출 할 수 있다.
이때 balance는 ETH의 총합을 의미하고 this는 현재 컨트랙트를 의미한다.
1 2 | uint itemFee = 0.001 ether; msg.sender.transfer(msg.value - itemFee); | cs |
만약 초과분의 ETH를 줬다면 반환기능도 만들 수 있다.
오버플로우
uint256으로 만들어진 변수는 2^256이지만 결국 오버플로우는 존재하게 된다.
단적인 사례를 한번 보자.
https://m.blog.naver.com/715fas/221261325892
이렇게 불안정한 DApp을 만들면 애꿎은 사용자만 피해를 보게 된다.
따라서 OpenZeppelin에서 오버플로를 막아주는 라이브러리 SafeMath를 제공해주고 있으니 참고해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | library SafeMath { function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; assert(c / a == b); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } | cs |
따라서 우리는 num이라는 변수에서 num++대신 num = num.add(1);로 변경시켜 오버플로우에 안전해질 수 있다.
'Applied > Blockchain' 카테고리의 다른 글
Sollidity 토큰 Contract 예제문 (0) | 2018.05.04 |
---|---|
Solidity 기초 예제코드 및 분석- 3 (0) | 2018.05.02 |
이더리움 가스(Ethereum Gas) (2) | 2018.05.01 |
Solidity 프로그래밍 기초 - 1 (2) | 2018.04.30 |
블록체인 멤풀(Blockchain Mempool) (0) | 2018.04.28 |