무지개곰
article thumbnail

openGSN과 openzeppelin의 Defender를 공부하며 user들이 gas fee를 지불하지 않고 사용할 target이 되는 contract에 ERC2771Context를 상속하여 사용하였습니다. ERC-2771은 무엇이고, ERC-2771은 무엇인지 알아보겠습니다.

목차

ERC-2771이란?

ERC-2771Context란?

ERC-2771은 왜 등장하였는가?

예시 코드


ERC-2771이란?

기존의 사용자가 스마트 계약과 상호작용을 할 때 gas비용을 지불하여야 하기에 gas 비용이라는 진입 문턱이 있었습니다. 하지만 ERC-2771은 가스 비용을 지불하지 않고도 메타 트랜잭션을 수행할 수 있는 방법을 제공하는 스마트 계약의 표준입니다. 이를 통해 사용자는 자신의 지갑에서 가스를 지불하지 않고도 스마트 계약을 상호작용할 수 있습니다.


ERC-2771Context란?

ERC-2771Context는 ERC-2771을 기반으로 한 메타 트랜잭션 처리를 위한 스마트 계약 컨텍스트 인터페이스입니다. ERC-2771이 제공하는 기능에 _msgData() 함수가 추가되었습니다. 이 함수는 메타 트랜잭션의 데이터를 반환합니다. 반환되는 데이터에는 계약을 호출한 외부 컨트랙트에서 전달한 매개 변수나 추가 정보가 포함될 수 있어 데이터를 해석하여 사용할 수 있습니다.


ERC-2771은 왜 등장하였는가?

위에서 말씀드렸다시피 ERC-2771은 기존의 사용자 지갑에서 스마트 계약과 상호작용할 때 발생하는 가스 비용 문제를 해결하기 위해 등장하였습니다. 이전에는 사용자가 스마트 계약에 직접 트랜잭션을 전송하며 가스를 지불해야 했습니다. 하지만 ERC-2771을 사용하면  _trustedForwarder라는 private 한 불변 변수에 EIP712로 생성한 forwarder contract 주소를 입력하여 신뢰할 수 있는 forwarder를 통하여 메타 트랜잭션을 실행시켜 가스 비용 없이 사용자가 contract와 상호작용할 수 있게 설정할 수 있습니다.

forwarder를 생성하는 EIP712란?

 

[Solidity] EIP-712란?

OpenGSN과 Openzeppelin의 defender를 공부하며 알게 된 forwarder contract가 EIP712를 상속받고 있는 것을 보았습니다. EIP712는 무엇인지 어떠한 역할인지 알아보도록 하겠습니다. 목차 EIP-712란? EIP-712의 장점

rainbow96bear.tistory.com


예시 코드

아래의 코드는 openzeppelin에서 제공하는 ERC-2771Context입니다.

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.9;

import "../utils/Context.sol";

/**
 * @dev Context variant with ERC2771 support.
 */
abstract contract ERC2771Context is Context {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable _trustedForwarder;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(address trustedForwarder) {
        _trustedForwarder = trustedForwarder;
    }

    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
        return forwarder == _trustedForwarder;
    }

    function _msgSender() internal view virtual override returns (address sender) {
        if (isTrustedForwarder(msg.sender)) {
            // The assembly code is more direct than the Solidity version using `abi.decode`.
            /// @solidity memory-safe-assembly
            assembly {
                sender := shr(96, calldataload(sub(calldatasize(), 20)))
            }
        } else {
            return super._msgSender();
        }
    }

    function _msgData() internal view virtual override returns (bytes calldata) {
        if (isTrustedForwarder(msg.sender)) {
            return msg.data[:msg.data.length - 20];
        } else {
            return super._msgData();
        }
    }
}

isTrustedForwarder : 매개변수로 받은 forwarder 주소가 신뢰할 수 있는 forwarder인지 확인하고 bool 값으로 반환합니다.

_msgSender : Context 컨트랙트에서 오버라이딩되어 현재 메서드 호출의 발신자를 반환합니다. 발신자가 포워더인 경우 어셈블리코드를 사용하여 calldata에서 발신자 주소를 추출하고 그렇지 않은 경우 부모 컨트랙트의 기본으로 돌아가 메서드 호출의 발신자를 반환합니다.

_msgData : _msgSender와 마찬가지로 Context 컨트랙트에서 오버라이딩되어 현재 호출의 calldata를 반환하고 발신자가  forwarder의 경우 calldata의 마지막 20바이트를 제거하고 그렇지 않은 경우 부모 컨트랙트의 기본 구현으로 되돌립니다. 제거되는 calldata의 마지막 20바이트는 포워더의 주소를 나타내며 실제 메타 트랜잭션의 발신자 주소는 그 이전의 데이터에 포함되어 있습니다. 

'BlockChain > solidity' 카테고리의 다른 글

[Solidity] EIP-712란?  (0) 2023.07.02
[Solidity] ERC20 Permit이란?  (0) 2023.06.17
[Solidity] ERC-1155란?  (0) 2023.05.18
[Solidity] ERC-721이란?  (0) 2023.05.18
[Solidity] ERC20이란? (ERC20 토큰 발행)  (0) 2023.05.14
profile

무지개곰

@무지개곰

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!