그러면 어떻게 할 수 있느냐? 바로 'Permit2'라고 하는 또 다른 컨트랙트에 송금 권한을 위임하는 것이다. 참고로 Permit2는 공공의 이익을 위해 유니스왑이 그냥 개발, 배포해준 컨트랙트임.
그러니까 내가 상호작용해야 하는 예치 컨트랙트가 있다면, 이렇게 작동하게 된다.
a.
Permit2 컨트랙트에 ERC20::approve를 type(uint256).max로 해버림. 근데 이게 더 이상 문제가 안 됨. 왜냐하면 Permit2는 돈을 마음대로 쓸 수 있는 함수가 없기 때문 (Permit2는 '믿을 만한' 컨트랙트임).
b.
유저인 내가 예치 컨트랙트의 pullToken()같은 함수를 나의 서명을 인자로 호출하게 된다. 그러면 그 예치 컨트랙트의 함수는 더 이상 ERC20::transferFrom(나, address(this), ...) 를 호출하지 않고, Permit2::permitTransferFrom(...)를 호출해준다.
그러면 Permit2는 가지고 있는 무한 allowance 덕분에 내부적으로 ERC20::transferFrom(나, address(예치컨트랙트), ...)를 불러줄 수 있음.
c.
b 단계의 서명은 '누가 누구에게 언제까지 얼마를 송금할 수 있는지'에 대한 정보를 담고 있음. Permit2::permitTransferFrom이 그 서명을 검증하고 유효하면 바로 송금해줌.
요약하자면 ERC20Permit을 상속하지 않는 토큰을 송금하는 건 더 이상 문제가 되지 않음. 유저는 Permit2라는 믿을만한 컨트랙트에게 모든 송금 권한을 위임하고, 송금이 필요할 때마다 호출하고자 하는 함수에 서명을 같이 보내면 서명 검증 후 바로 송금이 됨.
말고도 많은 문제를 해결해 주는데, 그건 걍 직접 확인.
세줄요약
1. ERC20::approve 직접 호출은 가장 원시적인 방법. allowance 무한으로 때려박지 않는 이상 항상 트잭 두 번 보내야 함.
2. ERC20Permit을 상속하는 토큰 컨트랙트를 사용한다면 오프체인 서명으로 approve와 원하는 custom logic을 한 트잭만에 실행할 수 있음.
3. Permit2로 처음에 approve를 한 번만 해주면 ERC20Permit을 상속하지 않는 토큰 컨트랙트도 ERC20Permit과 같이 한 트잭만에 송금하고 싶은 수량을 확인하고 custom logic을 실행시킬 수 있는 이점을 누릴 수 있음.
왜 중요한가
👉 개발자: 되도록이면 개발할때 1은 지양하세요. 두 번 트잭 보내는 건 옛날 메타..
👉 유저: 월렛에서 서명할 때 뭘 서명하는지, approve할 때 무엇을 approve하는지 알고 버튼 누르세요.
