싸.우.게.
지금까지 다루었던 함수제어자들을 한 번 복습해보자!
함수가 언제, 어디서 호출될 수 있는지 제어한다.
private
: 컨트랙트 내부의 다른 함수들에서만 호출될 수 있음.internal
: internal 범위 + 해당 컨트랙트를 상속하는 컨트랙트에서도 호출될 수 있다.external
: 오직 컨트랙트 외부에서만 호출될 수 있다.public
: 내부, 외부 어디서나 호출될 수 있다.상태제어자는 블록체인과 상호작용 하는 방법에 대해 알려줬다.
view
: 해당 함수를 실행해도 어떤 데이터도 저장/변경되지 않음pure
: 해당함수가 어떤 데이터도 블록체인에 저장하지 않고 + 블록체인으로부터 아무 데이터도 읽지 않는 상태ex) onlyOwner
, aboveLevel
같이 우리가 정의한 제어자 !! modifier
로 함수처럼 선언했었음
modifier aboveLevel(uint _zombieId) {
require(zombies[_zombieId].level >= 2);
_;
}
이런 제어자들은 함수 하나에 다음과 같이 사용할 수 있다! 💥
function test() external view onlyOwner anotherModifier { /*...*/ }
이번 챕터에서는 새로운 함수 제어자를 하나 더 배웠다! 바로 payable
이다.
payable
제어자일반적인 웹서버에서 API 함수를 실행할 때는 함수 호출만으로 금융거래를 할 수는 없다. 👉🏻 일반적으로는 비트코인도 마찬가지다.
하지만 이더리움에서는 돈(이더), 데이터, 컨트랙트 코드 자체 모두가 이더리움 위에 있기 때문에 우리가 함수를 실행해서 컨트랙트에 돈을 지불할 수가 있다.
그럼 거꾸로, 특정 함수를 실행하기 위해서는 컨트랙트에 일정 금액을 지불하게 하는 것이 가능해지는 것이다. 🤩
예시를 보자 💨
contract OnlineStore {
function buySomething() external payable {
require(msg.value == 0.001 ether);
transferThing(msg.sender);
}
}
여기서, msg.value
는 컨트랙트로 이더가 얼마나 보내졌는지 확인하는 방법이고, ether
는 이더리움에 정의된 단위다.
참고로 프론트에서 아래와 같은 형식으로 보내준다고 한다.
// `OnlineStore`는 이더리움 위의 컨트랙트를 가리킨다고 가정한다.:
OnlineStore.buySomething({from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)})
value
필드를 보면 이더를 얼마나 보낼지 설정된 것을 알 수 있다. (호오~👀)
+) 위의 코드처럼 이더를 보내려면, 반드시 함수가
payable
로 선언돼있어야한다.payable
이 아닌 함수로 이더를 보내려고하면 함수 자체에서 트랜잭션을 거부한다.
레벨업하는 함수를 호출하려면 요금을 내야하도록 구현해보쟝🙂!
정답이다. 넘무 쉽다💗
contract ZombieHelper is ZombieFeeding {
uint levelUpFee = 0.001 ether;
function levelUp(uint _zombieId) external payable {
require(msg.value == levelUpFee);
zombies[_zombieId].level++;
}
//...
}
챕터1에서 컨트랙트에 이더를 보내는 방법을 배웠다. 그럼 이더를 보낸 다음에는 어떤 일이 일어날까?
우리가 컨트랙트로 이더를 보내면
👉🏻 해당 컨트랙트의 이더리움 계좌에 이더가 저장 되고
👉🏻 컨트랙트의 소유자가 onlyOwner
로 정의한 이더 인출 함수를 호출하여 이더를 가지게 된다!
인출함수는 다음처럼 만들 수 있다.
contract GetPaid is Ownable { // Ownable 컨트랙트를 import 했다면
function withdraw() external onlyOwner { // onlyOwner 사용
owner.transfer(this.balance); // owner 사용
}
}
balance
는 컨트랙트에 저장돼있는 전체 잔액이다. 만약 우리가 GetPaid
의 owner라면 withdraw()
를 호출해서 GetPaid
에 저장된 전체 잔액을 빼올 수 있는 것이다.
만약 owner가 아니라 transfer()
함수를 다른 주소에 붙이면?
👉🏻 맞다! 원하는 주소로 돈을 보낼 수 있다.
예를 들어, 누군가 한 아이템에 대해 초과 지불을 했다면, 이더를 msg.sender
로 되돌려주는 함수를 만들 수도 있다.
uint itemFee = 0.001 ether;
msg.sender.transfer(msg.value - itemFee);
1. withdraw 함수를 위의 예제처럼 만들어준다!
2. 가격은 물가에 따라 바뀔 수 있어야하므로 levelupFee를
변경하는 함수를 만든다: setLevelUpFee()
정답은 다음과 같습니당
function withdraw() external onlyOwner {
owner.transfer(this.balance);
}
function setLevelUpFee(uint _fee) external onlyOwner {
levelUpFee = _fee;
}
계속됩니당.