관리 메뉴

멍개의 연구소

[ethereum] solidity - address 관리방법(address, address payabl 타입) 본문

블록체인

[ethereum] solidity - address 관리방법(address, address payabl 타입)

멍개. 2022. 8. 27. 16:23

이번글에서는 solidity로 개발한 스마트 컨트랙트에서 다른 계정으로 이더를 전송하는 방법에 대해서 알아보겠습니다. 이번글도 0.5 버전을 기준으로 작성됩니다. 물론 이전 버전과 어떤 차이가 있는지도 함께 알아보겠습니다.

먼저, 컨트랙트에서 다른 계정으로 이더를 전송하기 위해서는 컨트랙트에서 이더를 보유하고 있어야 합니다. 즉, 다른 계정으로부터 이더를 전송받아야 하는데 전송 받는방법 부터 알아보겠습니다.

· 이더 전송받는 방법

pragma solidity ^0.5;

contract address05 {
    function () external payable{
        
    }
}

solidity에서는 이름이 없는 함수를 fallback 함수라고 하는데 fallback 함수에 external과 payable 옵션을 붙여주어 해당 컨트랙트가 외부 계정으로부터 돈을 입금받을 수 있도록 합니다. payable은 외부 계정으로부터 이더를 받으면 호출되는 함수입니다. 만약  payable 키워드가 존재하지 않는다면 해당 컨트랙트는 외부 계정으로부터 이더를 전송받지 못하게 됩니다. 

추가적으로 external은 외부에서만 호출할 수 있는 함수를 의미합니다. 즉 해당 컨트랙트 내부에서는 해당 함수를 호출할 수 없음을 의미하고 있고 0.5 버전부터는 fallback 함수는 external을 강제하고 있습니다.

· 0.5에서 이더 전송방법

0.5부터는 이더를 전송하기 위해서는 address payable을 이용해야 합니다. 이전 버전에서는 address 타입에서 send와 transfer를 제공하여 바로 사용할 수 있었지만 0.5 버전부터는 address 타입도 address payable 타입으로 변환을 해야 정상적으로 전송이 가능해집니다.

// address payable to == address(uint160(to))

pragma solidity ^0.5;

contract address05 {
    function () external payable{
        
    }
    
    function oldSend(address to, uint value) public {
        to.send(value * (10 ** 18));
    }
    
    function newSend(address payable to, uint value) public {
        to.transfer(value * (10 ** 18));
    }
    
    function newSendTypeConvert1(address to, uint value) public {
        address payable convertedTo= address(uint160(to));
        convertedTo.send(value * (10 ** 18));
    }
    
    function newSendTypeConvert3(address to, uint value) public {
        address(uint160(to)).send(value * (10 ** 18));
    }
}

이전 버전처럼 사용하면 앞의 이미지처럼 에러가 발생하게 됩니다. address payable로 변환을 해야 정상적으로 컴파일이 됩니다. 

address payable은 address(uint160())으로 변환해주면 됩니다. 또한 msg.sender로 가져오는 address도 address payable 타입입니다.

function giveBack() internal {
    msg.sender.transfer(msg.value);
}

msg.sender로 가져온 address는 address payable 타입이기 때문에 변환없이 transfer를 사용할 수 있습니다. 또한 msg.sender로 transfer 하기 위해서는 internal 형태의 함수이거나 payable 타입의 함수여야 합니다. 

추가적으로 0.5 부터는 send가 아닌 transfer 사용을 권장하고 있습니다.

● 이더전송 테스트 해보기

// address payable to == address(uint160(to))

pragma solidity ^0.5;

contract address05 {
    function () external payable{}
    
    function newSend(address payable to, uint value) public {
        to.transfer(value * (10 ** 18));
    }
    
    function newSendTypeConvert1(address to, uint value) public {
        address payable convertedTo= address(uint160(to));
        convertedTo.send(value * (10 ** 18));
    }
    
    function newSendTypeConvert3(address to, uint value) public {
        address(uint160(to)).send(value * (10 ** 18));
    }
    
    function getBalance(address to) view public returns(uint) {
        return address(to).balance;
    }
    
    function giveBack() internal {
        msg.sender.transfer(msg.value);
    }
}

앞의 코드로 배포를 합니다.

※ 배포정보

배포 네트워크 : ropsten network
컨트랙트 배포 address(EOA) : 0x98e748f1d7b17e9f99210044a609cfbfe7604f0d
배포된 컨트랙트 address(CA): 0xbe649afefd32c806a4668d3fc0800d929a400f63

이더스캔을 통해서도 배포된 컨트랙트의 자세한 정보를 확인할 수 있습니다. 

· 배포된 컨트랙트로 이더전송

5이더를 배포된 컨트랙트에 전송해줍니다.

 

배포한 컨트랙트에서 getBalance() 함수에 이더 보유를 확인할 컨트랙트 주소를 인자로 전달하여 호출하거나 이더스캔에서 확인을 할 수 있습니다. 참고로 이더리움은 decimals이 18이기 때문에 1000000000000000000 wei가 1ether가 됩니다.

· 컨트랙트에 있는 이더 외부계정에 전송

전송받을 계정 : 0x74537181C008e71BB3Fb6E4F4780f04A3470f551

현재 컨트랙트에 존재하는 이더리움중 일부를 해당 계정으로 전송해보겠습니다.

트랜잭션을 발생 시키고 해단 트랜잭션이 block에 포함될 때까지 기다린 후 이더스캔을 접속하여 확인하면 이더 전송이 된 것을 확인할 수 있습니다.

transaction의 경우는 지갑을 통해서 주고 받은 이더가 표시되고 컨트랙트 내부에서 전송이 발생된 경우는 internal Txns에서 몇 이더를 전송했는지 확인 가능합니다.

이더를 전송받은 계정또한 이더스캔에서 확인 가능합니다.

metamask 지갑에서도 확인 가능합니다.

 
0.5 버전에서는 이더를 전송하기 위해서는 address payable을 사용하여 전송하게 되는데 좀 더 신경써서 전송하라는 의미인 것 같습니다.
Comments