Contract로 다른 Contract 함수 호출하면 msg.sender는 어떻게 될까? [ TIL / Solidity ]

알락·2023년 2월 7일
0

이더리움

목록 보기
16/16
post-thumbnail

프로젝트 진행 중에 우리가 만든 컨트랙트에서 ERC20을 다뤄야하는 일이 생겼다. 컨트랙트에서 유저가 이용하는 ERC20 토큰을 위임받아서 대신 지불을 할 수 있게 만들어야 했다. 하지만 이 기획은 결국 수정되었다. 해당 컨트랙트 내에서 ERC20의 함수를 실행시켜 원래 토큰의 주인의 토큰을 가져와 사용하는 것과, 이 컨트랙트가 나중에 지불하게 될 일정양의 토큰을 위임받게하는 것이 불가능했기 때문이다.

이런 이유는 ERC20 컨트랙트 내에 중요한 로직이 msg.sender라는 글로벌 상태값을 통해서 이루어지기 때문이다. 대부분 입문용으로 사용하는 OpenZeppelin 라이브러리가 제공하는 ERC20 솔리디티 파일에서도 확인할 수 있듯이, msg.sender가 토큰을 소유한 본인이어야 함수 내 명령문들이 실행될 수 있게 로직이 짜여져있다.

그리고 msg.sender는 함수가 실해될 때마다 바뀐다. 즉, 해당 트랜잭션을 최초에 발생시킨 누군가만이 msg.sender가 될 수 있는 것이 아니라는 것이다.

이는 다음의 예시를 통해서 확인할 수 있다.

msg.sender 예시

[Sender Contract]

// SPDX-License-Identifier: MIT
// address: 0xd9145CCE52D386f254917e481eB44e9943F39138

pragma solidity ^0.8.6;

contract Sender{
    function showSender() public view returns (address) {
        return address(msg.sender);
    }
}

Sender 컨트랙트의 showSender 메소드는 실행시키면 msg.sender의 주소값을 반환한다.

[SenderCaller Contract]

// SPDX-License-Identifier: MIT
// address: 0x358AA13c52544ECCEF6B0ADD0f801012ADAD5eE3

pragma solidity ^0.8.6;

import './Sender.sol';

contract SenderCaller{
    Sender sender = Sender(0xd9145CCE52D386f254917e481eB44e9943F39138);

    function showSender() public view returns(address){
        address addr = sender.showSender();

        return addr;
    }
}

SenderCaller 컨트랙트는 위에서 예시로 들었던 Sender 컨트랙트를 내부 상태값으로 가지고 와 사용을 한다. 그래서 SenderCallershowSender 내부적으로 Sender에서 정의한 showSender의 결과값을 반환한다.

구조는 트랜잭션 발생자 -> SenderCaller -> Sender의 순으로 실행되게 된다.

SenderCaller.showSender()의 결과

결국 최종적으로 트랜잭션 발생자가 SenderCaller.showSender()를 실행한 결과로 확인할 수 있는 값은 SenderCaller의 주소값이다. 트랜잭션 발생자가 Sender.showSender()를 실행하면 트랜잭션 발생자 본인의 주소값을 확인할 수 있다.

profile
블록체인 개발 공부 중입니다, 프로그래밍 공부합시다!

0개의 댓글