개요
이번 시간에는 이더리움의 
Solidity를 활용해서 간단한 스마트 계약을 만들어 보는 시간을 가져보도록 할게요. 유언을 스마트 계약으로 처리하는 것은 블록체인을 잘 활용할 수 있는 실사용사례 중 하나일 수 있는데요. 왜냐하면 변호사나 은행 같은 중개인 없어도 계약 내용에 따라 자동 실행이 가능하고, 블록체인의 투명성과 위변조 불가한 특징을 동시에 활용할 수 있기 때문이에요. 오늘 내용은 스마트 계약이 처리되기 위한 기본 구성을 익혀나가는 것이 목적이기 때문에, 가볍게 봐주시면 될 것 같아요. 그리고 
Java와 Javascript의 문법을 알고 있으면 쉽게 따라오실 수 있을거라 생각해요!준비
일단 인터넷에서 Remix IDE를 활용해서 Solidity 계약을 가상으로 테스트 할 수 있는 공간이 있는데요. 
Remix IDE - Solidity 계약 에디터
위의 링크를 클릭하고 들어와서 사용하면 되요. 간단한 사용법과 구성소개는 다른 블로그글로 정리해서 향후에 첨부 하도록 할게요. 
파일 생성 하기

일단 위 링크를 타고 들어와보시면 사진과 같이 VScode같은 편집기가 나올거에요. 설명을 드리자면 Remix IDE 웹 기반 통합 개발환경인데 스마트 계약을 만드는 온라인 작업실이라고 보면 좋겠네요. 
여기서 왼쪽 파일 목록에서 새 파일로 유언을 뜻하는 
will.sol 이라는 파일을 생성해볼게요. 여기서 sol은 solidity파일 확장자 이름이고 여기서 스마트 계약을 작성할 수 있어요.  계약 객체 생성하기
파일을 생성했으면 기본적으로 작성해줘야 하는 
보일러 플레이트 코드가 있는데요. 한 번 아래와 같이 작성해 볼까요? // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Will {
 
}위의 코드같이 모든 솔리디티 코드에는 스마트 계약을 작성할 때 갖춰야 될 세가지 기본 요소라고 보면 좋은데요. 하나씩 설명드릴게요. 
- // SPDX-License-Identifier: MIT
이 주석은 SPDX 라이선스를 명시하는 역할을 하는데요. 코드 배포시 법적 문제를 방지하기 위해 필요한데, 없으면 솔리디티 컴파일러의 경고가 발생해요.
- pragma solidity ^0.8.0;
이 부분은 컴파일러의 버전을 명시하는 역할을 하는데요. 
솔리디티 컴파일러 버전 0.8.0 이상에서 컴파일 되어야 한다는 뜻이에요- contract Will { }
여기서 
Java의 class 같이  Solidity에서는contract 키워드를 사용해서 객체를 생성할 수 있어요. 바로 이 contract 객체가 블록체인에 배포될 스마트 계약이에요!
계약속성 정의하기
이제 유언장 계약에 대한 속성을 정의해줘야 하는데요. 유언에는 유언을 하는 사람,  그리고 사망 여부가 있으면 계약 주체를 정의할 수 있겠죠? 그럼 아래와 같이 작성해 볼게요. 
contract Will {
    address owner;
    bool deceased;
}- address onwer;
address 라는 것은 solidity를 처음 공부하신다면 생소한 타입이실텐데요. 이건 이더리움의 계정 주소를 저장하기 위한 전용타입이라고 보시면 되요.- bool deceased;
bool 은 Java를 할 때와 마찬가지로 불리언이겠죠? ㅎAddress 타입Address 타입은 솔리디티에서 매우 중요한 타입이에요. 이 타입으로 다른 컨트렉트와 상호작용하고 이 객체의 메소드로 여러가지 행동을 할 수 있어요. 
- .balance(속성)
address 타입에서 가장 많이 사용되는 속성으로 이더리움 잔액을 보여줘요. 
- .transfer()(메소드)
이더를 전송할 때 사용하는 메소드에요. 전송에 실패하면 에러를 던지고 revert까지 내장되어 있어요. 
- .call()(메소드)
이 메소드는 다른 특정함수를 호출하는 기능인데요. 이것으로도 이더를 전송할 수 있지만, 특징으로는 에러를 던지지 않고 
false를 반환하기 때문에, 꼭 성공여부를 체크해줘야 해요. 그래서 
transfer보다 좀 더 유연하게 사용하고 받는 쪽이 복잡한 로직을 사용할 수 있게 사용할 수 있어서 현재는 표준처럼 사용되고 있어요. 계약 생성자 작성하기
그럼 자바와 마찬가지로 생성자가 필요합니다. 이 생성자는 네트워크에 배포가 될 때 딱 한번 실행이 되는 거에요. 
contract Will {
    address owner;
    bool deceased;
    constructor() payable {
        owner = msg.sender;
        deceased = false;
    }
}- constuctor() payable{}
생성자 정의는 자바랑 같은 데, 여기 payable이란 단어가 있어요. 이는 함수가 실행이 될 때 이더를 받을 수 있다는 뜻이에요. 
payable로 선언되지 않은 함수에 이더를 보내면 트랜잭션을 실패하게되요.- owner = msg.sender
여기서 또 새로운 
msg 라는 변수를 확인할 수 있는데요. msg 역시 Solidity에서 사용되는 특수 글로벌 변수라고 생각하시면 될거 같아요. 이 변수는 현재 실행 중인 함수를 호출한 트랜잭션 또는 메시지에 대한 정보를 담고 있는 객체라고 보면 되요.  그래서 트랙잭션을 호출한 계정 주소를 owner에 할당하해서 계약 소유자를 설정하는 거죠!- deceased = false;
생성시에는 유산을 남기려는 분이 살아계시니 바로 유산이 전송이 되지 않겠죠. 미래 시점에 deceased가 true로 트리깅이 되면 계약을 실행할 수 있게끔 속성을 정의한거에요.
가족 지갑 설정하기
이번엔 유산을 받을 가족들의 지갑을 설정해줘야 되겠죠? 여기 Will 이라는 유산 계약에서는 가족 지갑을 받을 배열  데이터 타입만 만들어 놓고, 나중에 계약 소유자가 호출해서 추가할 수 있게 만들어 줄거에요. 
address payable[] familyWallets; mapping(address => uint) inheritance;
- address payable[] familyWallets;
address type의 배열을 만드는 데, 유산을 나눠줄 때 받는 사람들의 주소가 이더를 받을 수 있는 주소여야 하기 때문에  
payable[] 배열로 설정해줘야 되요. - mapping(address => uint) inheritance;
이건 
inheritance라는 map 타입을 설정하는 것인데요. 지갑 주소에 따라 얼마만큼의 유산을 정할 것인지 정보를 담는 그릇이라고 생각하시면 되요.상속액 설정하기
이제 계약을 소유한 계약자가 가족 지갑에 따라 상속액을 정할 수 있는 함수를 만들어 줄 것인데요. javaScript의 
function이랑 문법이 비슷해요! 그럼 상속액 설정과 상속액을 지급하는 함수, 그리고 사망시에 상속액이 지급되는 함수를 만들어보죠!setInheritance() - 상속자별 상속액 설정 함수
function setInheritance(address payable wallet,uint amount) public {
    familyWallets.push(wallet);
    inheritance[wallet] = amount;
}- function setInheritance(address payable wallet,uint amount) public
기존 javaScript 함수와 같이 정의해서 사용하며 되요! 여기서는 
public 지시어로 누구나 이 함수를 호출할 수 있게 되요. 하지만 사실, 누구나 이 함수를 호출하면 안되겠죠? 그 부분은 아래에서 추가적으로 설명해볼게요.  또 상속액을 설정하기 위해서는 지급가능한 주소와, 상속액을 매개변수로 받아야 겠죠? 그래서 위와 같이 매개변수를 설정했어요!- familyWallets.push(wallet); inheritance[wallet] = amount;
familyWallets은 배열이니까 push로 지갑을 추가할수 있겠죠? 그리고 inheritance mapping 타입에 주소와 상속액을 mapping 시켜요! payout() - 상속액 지급 함수
function payout() private {
    for (uint i = 0; i < familyWallets.length; i++) {   
        familyWallets[i].transfer(inheritance[familyWallets[i]]);
    }
}- function payout() private
마찬가지로 이 
payout() 함수로 제일 중요한 유산을 지급하는 행동이 일어나게 되는 것인데요. 하지만 이 함수를 아무나 실행되면 안되고 그리고 외부에 드러나지 않고 이 계약 안에서만 호출되게끔 private설정도 한것이에요. - for (uint i = 0; i < familyWallets.length; i++)
for 반복문은 자바랑 사용하는 방식이 같아요. 
i를 설정할 때  타입을 지정해주는 것만 유의하면 될거 같아요.  내부 로직에는 transfer로 각 지갑과 연동된 상속액에 따라 지급할 수 있게끔 설정했어요. 그리고  젤 처음 
uint 는 정수타입인데, u가 붙은 이유는 Unsgined Interger 로서 부호가 없는 정수(음수 x)라는 뜻이에요.hasDeceased()- 사망시 실행되는 함수 설정
function hasDeceased() public {
      deaceased = true;
      payout();
}- 함수가 실행되면 deaceased를 true로 업데이트하고payout()메서드가 실행이 되면서 자동으로 유산을 지급하는 계약이 트리거가 되는거에요. 그리고 이렇게 완성이 된 것같지만, 치명적인 오류가 존재해요. 즉 현재 코드로서는 아무나 이 계약을 실행할 수 있다는 것이 문제이죠. 그래서 생소하겠지만함수 수정자를 만들어야 해요.
함수 수정자 설정하기
함수 수정자(
modifier)는 자바에서 AOP(Aspect-Oriented Programming)과 비슷한 역할을 하는 Solidity만의 문법인데요. 비즈니스 로직에서 분리된 공통 관심사를 설정할 수가 있는 것이죠! 여기서는 함수를 실행하는 사람이 계약 소유자인지 체크하기 위해서 사용된다 거나, 계약이 실행되기 위한 조건을 체크하는 용도로 사용이 되어요! modifier onlyOwner- 계약소유자 본인 체크 수정자
modifier onlyOwner() {
		require(msg.sender == owner);
		_;
}- modifier onlyOwner()
이렇게 modifier를 사용하면 이 함수는 함수수정자로 사용할 수 있어요.
- require(msg.sender == owner);
여기서 사용된 
require는 if문의 역할이랑 같은 역할을 해요.  즉 이 조건이 맞으면 로직을 계속 진행할 수 있게 되는거죠. 그럼 다음 로직이 _(언더스코어)의 영역에 들어와서 실행되게 되는거에요. 이 언더스코어는 플레이스 홀더 같은 역할을 한다고 생각하면 좋겠네요.  modifier mustBeDeceased- 유언자의 사망여부 체크
modifier hasDeceased() {
		require(deceased == true);
		_;
}- 그럼 이 hasDeceased함수에서도deceased가true인지 체크하고 상태가 확인이 되면 다음 로직으로 넘어간다라고 이해가 되겠죠?
함수 수정자 적용하기
함수 수정자를 사용하는 방법은 간단해요!
modifier함수 수정자 적용
function setInheritance(address payable wallet,uint amount) public onlyOwner{
    familyWallets.push(wallet);
    inheritance[wallet] = amount;
}   
function payout() private mustBedeceased{
    for(uint i = 0; i < familyWallets.length; i++) {
        familyWallets[i].transfer(inheritance[familyWallets[i]]);
    }
}
function hasDeceased() public onlyOwner {
    deceased = true;
    payout();
}이렇게 함수의 중괄호가 시작되기 전에 함수수정자 명을 넣어주면 되요. 그럼 
setInheritance는 오직 계약 소유자만 실행할 수 있고, payout은 계약소유자가 반드시 사망상태여야 지급이 되는 조건이 되는거에요. 그리고 사망상태가 일어나면 계약소유자만이 hasDeceased 를 실행해서 사망상태를 변경할 수 있는 거죠. 전체 코드 확인
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Will {
    address owner;
    bool deceased;
    constructor() payable {
        owner = msg.sender;
        deceased = false;
    }
    address payable[] familyWallets;
    mapping(address => uint) inheritance;
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }
    modifier mustBedeceased() {
        require(deceased == true);
        _;
    }
    function setInheritance(address payable wallet,uint amount) public onlyOwner{
        familyWallets.push(wallet);
        inheritance[wallet] = amount;
    }   
    function payout() private mustBedeceased{
        for(uint i = 0; i < familyWallets.length; i++) {
            familyWallets[i].transfer(inheritance[familyWallets[i]]);
        }
    }
    function hasDeceased() public onlyOwner {
        deceased = true;
        payout();
    }
}배포하기
이제 필요한 로직은 다 작성했어요. 그럼 컴파일을 해보도록 할게요. 
배포전 컴파일하기

그림처럼 상단에 컴파일 버튼이 있는데요. 코드에 이상이 없으면 왼쪽에 초록색 불이 들어올거에요. 그럼 배포 사전준비는 완료가 되었어요. 하지만 컴파일 단계에서 에러가 많이 나기 떄문에, 디버깅을 해야할 수도 있겠죠. 그래도 디버깅이 프로그래머의 일이고 그게 프로그래머를 성장시키는 것 같아요 ㅎ
배포 및 트랜잭션 탭

사진 처럼 왼쪽 바를 확인해보면 
이더리움모양 아이콘이 있을거에요. 클릭해보면 배포 설정을 할 수 있는 곳이 나오는데요. 일단 차례로 설명을 드리자면, - ENVIRONMENT: Remix VM
이는 연결된 블록체인 환경을 말해요. Remix VM 은 실제 돈이 들지 않는, 내장된 가상의 테스트용 블로체인이에요. (Prague는 버전이름이에요)
- ACCOUNT
여길 클릭해보면 많은 지갑 주소가 나오고 각 얼마마큼의 이더가 있는지 확인할 수 있어요. 이건 진짜 이더가 아니라 테스트용 이더에요. 여기서 선택한 주소로 배포를 하게 되면 계약의 주인이 되는 거죠.
- GAS LIMIT
이더리움에서 스마트 컨트랙트를 실행하려면 가스비라는 수수료를 내야하는데요. 이건 하나의 계산 비용으로 이더리움 네트워크 채굴자에게 일을 시키는 것과 같은거에요. 복잡한 작업일 수록 더 많은 가스가 필요해요! 만약 
Esimated Gas를 선택하고 배포를 하게 되면, Remix VM이 견적을 내서 자동으로 Gas한도값을 설정하게 되요, 직접 설정하고 싶다면 수기로 Custom에서 조절할 수 있어요. 예전 코로나 코인 불장 때, 이더리움이 엄청 비쌀때는 이 계산비용이 너무 비싸기도 했어요. 그래서 한도를 미리 알고 실행하고, 너무 많은 비용을 방지하고자 한도를 설정할 수 있는거에요. 
- VALUE
여기엔 이 계약 소유자가 계약을 배포할 때, 얼만큼의 이더를 할당할 건지 정하는 곳이라고 보면 되요. 이제 여기에 할당된 이더 기준으로 유산이 나눠지게 되는거죠. 
단위를 보면 
Wei 라는 단위를 볼수있는데 이더를 잘게 쪼갠 토큰 단위에요. 10의 18승의 Wei가 모여야 1 ETH가 되어요!배포하기
그럼 이제 
ACCOUNT에 100ETH가 할당되어 있으니까, 이 계약에는 30ETH를 설정하고 배포하도록 할게요!
사진처럼 
VALUE에 30 Ether를 맞추고 Deploy 버튼을 눌러주세요.
그럼 콘솔창으로 한번 와보시면, 이렇게 파란 체크가 확인 도리 거에요. 그럼 성공적으로 배포가 된거에요. 그리고 이 안에는 다양한 정보를 담고 있어요. 

이렇게 내용을 보시면 
Transaction Hash랑 block hash를 확인할 수 있어요. Transaction Hash는 방금 배포한 계약에 대한 지문이라 할수있고, Block Hash는 해당 계약이 어떤 블록에 기록이 되었는지 나타내는 거에요. 그리고 아래 gas부분에 계약에 대한 비용과 실행에 대한 비용을 합쳐서 총 gas 비용이 얼마나 나왔는지를 보여주죠. 유산 정해주기
이제 배포까지 완료가 되었고, 유산을 살아있을 때 정해줘야 겠죠? 왼쪽 바 아래에 보시면 
Deployed Contracts라는 항목을 확인할 수 있어요. 여기서 배포된 계약의 함수를 실행할 수 있는데요, 보시면 아까 public 된 함수만 실행될 수 있는 것을 확인할 수 있어요. 
그럼 빨간 네모 부분에 
setInheritance 함수의 드롭다운을 내려보면 매개변수를 입력할 수 있는 곳이 나와요. 
여기에 자식들의 지급가능한 지갑 주소와 amount에 유산을 지정해줘야 겠죠? 지급 가능한 주소를 알려면 상단에 지갑 리스트에서 가져올수 있어요!

AMOUNT항목의 드롭다운을 클릭해보면 여러 지갑과 얼마나 이더가 있는지 확인할 수 있어요. 젤 위에 주소는 현재 로그인된 지갑 주소라고 보면 될 것 같고, 다른 주소를 복사해서 매개변수에 넣어줄게요. 
사진처럼 다른 주소로 변경하고 
copy account 아이콘을 누르면 복사가 되어요. 
이렇게 매개변수를 이렇게 넣어주고 Transact를 실행하면 되는데, 주의해야할 것은 Transact를 할 수 있는 사람은 계약을 만든사람만 가능하기 때문에 (우리가 그렇게 설정했엇죠?) 로그인된 지갑 주소를 변경하고 실행해주셔야되요!

잘 따라오셨다면 다음과 같은 내용을 확인할 수 있어요. 복사한 주소에 10
wei (단위가 안나오는데, ETH는 1000000000000000000wei인데 10이면 10wei입니다.)가 저장 된 것을 확인할 수 있어요. 이건 실제 돈을 보낸게 아니라 얼마의 유산을 줄 지 설정한 거에요. 그럼 이번에 읽으시는 독자님이 다른 주소를 하나더 추가해서 유산을 한번 설정해주실래요? 

저는 이렇게 다른 주소에는 얼마인지 정확하게는 알 수 없지만, 1ETH보다는 작은 금액을 설정해서 유산 금액을 설정했어요. (단위측정기가 있으면 좋겠다는 생각이 드네요. 얼마나 많은 사람들이 실수를 할까요?)
사망시 유산 지급 실행 ㅠ (아니 사망했는데 어떻게 실행?!)
자 이제 계약소유자가 자식들에게 유산의 양도 설정을 했고, 이제 사망하는 일만 남았네요 ㅠ. hasDeceased라는 함수가 실행이 되면, 제일 먼저 계약소유자인지 확인하고 
payout()을 실행하게 되겠죠. 남은 작업은 간단해요. hasDeceased를 클릭하면 됩니다. 그럼 또 궁금한게 생기죠. 아니 계약 소유자가 사망했는 데 어떻게 클릭하냐??? 그것을 해결하는 방법은 세가지 정도가 있어요. 
- 유언 집행인 지정
미리 신뢰할 수 있는 변호사나, 가족 대표를 선정해서 지갑주소에 집행인으로 등록 해놓는 거에요. 그럼 사망시에 클릭하면 되겠죠?
- 스위치 방식
이 방식은 살아있을 때, ‘내가 아직 살아있다’라고 유효기간을 연장하는 방법이에요. 시간 내에 이를 내가 증명하지 않으면 사망했다라고 간주하고 실행이 되게 하는 방법이에요. 
- 오라클 서비스 사용
체인링크와 같은 
오라클 서비스를 사용하는 방법도 있어요. 이 서비스를 이용하면 현실 세계의 사망자 명부 데이터를 블록체인으로 가져올 수 있거든요. 그럼 컨트렉트가 이 계약 소유자가 사망 명부에 있는지 주기적으로 체크를 하고 오라클이 true를 반환하면 실행되게 하는 방법이에요. 블록체인과 현실세계를 결합할 수 있는 중요한 서비스인거죠.그럼 이제 실행해볼까요? 

실행을 하면 familyWallets에 등록된 유산들에게 지급을 실행합니다. 

거래가 완료되면 이렇게 거래 해시와 블록 해시를 확인할 수 있어요. 

왼쪽 Account탭에 확인해보면 잔고가 늘어난 지갑주소를 확인할 수 있어요. 다른 유산을 받은 주소는 10
wei였을 텐데 아마 거래 수수료가 유산보다 더 커서 계좌가 늘어난 것 처럼 보이지 않는 문제가 있었네요. ㅠ결론
자 이렇게 로컬 환경에서 계약을 설정하고 계약을 배포하고 실행하는 것까지 진행해 보았습니다. 아주 간단하게만 스마트 계약을 진행했기 때문에 그렇게 어렵게 느껴지지는 않았을 거라 생각해요. 하지만 이것으로 Web3.0 세계에 한 발짝 더 다가갈 수 있었을 거라 확신해요. 다 같이 공부하며 성장해보아요 🙂

![[Solidity] 유언 스마트 계약 만들어보기](/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fattachment%253A94c93052-dd63-4f3a-80b7-6af22500d58a%253A16.png%3Ftable%3Dblock%26id%3D2889c76c-6cb4-8056-8ad8-e48de41cebd3%26spaceId%3Db4216657-966f-4c29-ae8c-42f6c4adb66d&w=3840&q=75)
