솔리디티에서 모든 call은 특정 주소의 다른 컨트랙트를 호출한다. 어떤 호출이냐에 따라 msg.sender가 바뀐다.
스마트 컨트랙트 A 안에 있는 Call을 통해 스마트 컨트랙트 B의 함수를 부른다고 하였을 때, B의 Storage를 변경 시키고 msg.sender는 컨트랙트 A의 주소가 된다.
예를 들어, Alice가 스마트 컨트랙트 A를 불렀을 때, 컨트랙트 A의 msg.sender는 Alice의 주소가 된다. 그리고 컨트랙트 B의 msg.sender는 Alice의 주소가 아니라, 컨트랙트 A의 주소가 나온다. Alice 때문에 컨트랙트 A에 있는 Call이 컨트랙트 B의 함수를 호출했기 때문에 컨트랙트 B의 msg.sender는 컨트랙트 A의 주소가 나온다.
여기서, 컨트랙트 A가 부른 컨트랙트 B의 함수가 num이라는 변수의 값을 1에서 3으로 변경한다면, num의 값은 3이 되고 num=3은 컨트랙트 B에 저장될 것이다.
Delegate call은 컨트랙트 A를 통해 컨트랙트 B를 호출할 시 B의 Storage를 변경하지 않고, B의 코드를 A에서 실행하는 것이다. msg.sender와 msg.value가 컨트랙트 A 호출시와 같고 변동되지 않는다.
Delegate call은 call과 다른점이 크게
컨트랙트 B의 msg.sender는 컨트랙트 A 주소가 아니라, Alice의 주소이다.
컨트랙트 B의 함수가 호출되어 num의 값은 3이 됐지만, 정작 num=3은 컨트랙트 A에 저장되어 있고 컨트랙트 B의 값은 그대로 1이다.
예를 들어, 컨트랙트 A와 컨트랙트 B를 배포하였다고 친다. 어느 날, num=3을 변경하는 함수가, num=5로 변경하고자 한다. 그런데, 스마트 컨트랙트는 한번 배포되어 블록체인에 올라간 이상 수정할 수 없다. 그렇다고 컨트랙트 A를 새로 배포한다면 기존 스마트 컨트랙트에 쌓인 정보들이 초기화된다. 또한, 주소도 바뀔 것이다.
여기서, Delegate call로 해결할 수있다. 컨트랙트 B의 주요 로직을 변경해서 새롭게 컨트랙트 B를 배포하는 것이다. 기존의 컨트랙트 A의 delegate call의 주소를 새롭게 짠 컨트랙트 B로 변경해주면 num=5인 함수를 쓸 수 있다. 즉, 컨트랙트 A에 저장되기 때문에 컨트랙트 A를 새로 배포한 것이 아니라서 데이터를 온전히 보장할 수 있다.