---
title: "메타 트랜잭션(ERC-2771)이란 무엇인가?"
description: "메타 트랜잭션을 소개하며, 가스비 문제와 이제 더 이상 최적의 해결책이 아닌 이유를 설명합니다."
---

# 메타 트랜잭션(ERC-2771)이란 무엇인가?

모든 Ethereum 트랜잭션은 gas를 사용하며, 트랜잭션을 보내는 주체는 소비되는 gas를 지불할 만큼 충분한 Ether를 보유하고 있어야 합니다. 이 때문에 신규 사용자는 dapp을 사용하기 전에 먼저 Ether를 구매해야 하는데\(이는 상당히 부담스러운 일일 수 있습니다\), 이는 사용자 온보딩에 있어 큰 장벽이 됩니다.

이른바 "메타 트랜잭션"은 사용자를 대신해 gas 수수료를 지불할 수 있게 해주는 방법입니다.

하지만 이러한 솔루션들 중 다수는 [Account Abstraction\(ERC-4337\) 인프라로 전환](http://www.alchemy.com/overviews/4337-vs-2771)하고 있는데, 이는 더 많은 기능을 갖춘, 더 유망하고 정교한 gas 추상화 방식이기 때문입니다.

## 메타 트랜잭션이란 무엇인가?

메타 트랜잭션의 개념은 간단합니다. Relayer라 불리는 제3자가 사용자를 대신해 트랜잭션을 전송하고 gas 수수료를 지불하는 것입니다.

사용자는 실행할 트랜잭션에 대한 정보를 담은 메시지\(가급적 EIP-712를 준수하는\)에 서명합니다.

서명된 메시지는 Relayer에게 전달되며, Relayer는 자신이 대가를 받을 수 있는지 여부\(이는 선택 사항일 수 있으며 자세한 내용은 뒤에서 다룹니다\)를 검증하고, gas 수수료를 지불할 자금이 충분한지 확인한 뒤, 네이티브 트랜잭션에 서명하여 실행을 위해 제출할 책임을 갖습니다.

OpenZepplin의 Relayer를 예로 들어 메타 트랜잭션을 살펴보겠습니다.

<ImageBlock
  src="https://media.alchemy.com/1703861042-meta-transactions.gif"
  alt="메타 트랜잭션 애니메이션 다이어그램: 사용자가 메시지에 서명하면 릴레이어가 이를 제출하고 가스비를 지불"
  width={720}
  height={405}
  caption="메타 트랜잭션 단계별 가이드"
/>

## 메타 트랜잭션 요청은 어떻게 생겼는가?

샘플 메타 트랜잭션 메시지는 다음과 같이 생겼습니다...

<ImageBlock
  src="https://media.alchemy.com/1703861080-sample-meta-transaction.jpeg"
  alt="NFT 민팅을 위한 샘플 메타 트랜잭션 메시지, from 주소와 call data 표시"
  width={1194}
  height={632}
  caption="샘플 메타 트랜잭션"
/>

위 메시지는 NFT를 민팅하며, from 주소 0x7099797...에 의해 서명됩니다.

메시지가 서명되면, 클라이언트\(또는 사용자\)는 메타 트랜잭션 요청\(아래 참조\)을 생성할 수 있습니다. 이는 Autotask로 POST 요청으로 전송되는데, Autotask는 호출되면 내부적으로 Relayer의 private key를 사용해 네이티브 트랜잭션에 서명하는 webhook입니다.

<ImageBlock
  src="https://media.alchemy.com/1703861109-meta-transaction-post-request.jpeg"
  alt="Autotask 릴레이어 웹훅으로 전송되는 메타 트랜잭션 POST 요청 페이로드"
  width={2264}
  height={726}
  caption="메타 트랜잭션 POST 요청"
/>

## 메타 트랜잭션 relayer란 무엇인가?

Relayer는 사용자의 gas 수수료를 대신 부담하기 위한 자금을 보유한 Ethereum 계정입니다. 이 계정의 private key는 provider 서버의 보안 vault에 저장됩니다.

개발자는 Relayer에 자금을 보내 사용자의 트랜잭션 수수료를 충당할 수 있습니다.

개발자는 원하는 만큼 여러 개의 Relayer를 생성할 수 있으며, 각 Relayer는 별도로 ETH를 충전해야 합니다.

OZ Relay는 Relayer 일시 정지, Whitelisted Addresses로부터의 요청 수락, Gas Price Capping을 지원합니다. 원한다면 더 많은 조건부 로직을 Autotask에 프로그래밍할 수 있습니다.

여기서 주의할 점은, 사용자가 정의한 트랜잭션이 이제 Relayer의 네이티브 트랜잭션의 data 필드 안에 들어있다는 것입니다. 메타 트랜잭션이란 바로 다른 트랜잭션 안에 들어있는 이 트랜잭션을 말합니다!

## 메타 트랜잭션에서 MinimalForwarder란 무엇인가?

지금까지는 온체인 검증이 전혀 이루어지지 않았습니다. 여기서 MinimalForwarder가 등장합니다.

MinimalForwarder는 사용자가 서명한 메시지의 유효성과 재사용 방지\(replay-protection\)를 검증하는 온체인 스마트 컨트랙트입니다.

<CodeSnippet code={`struct ForwardRequest {
    address from;
    address to;
    uint256 value;
    uint256 gas;
    uint256 nonce;
    bytes data;
}

function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {

    address signer = _hashTypedDataV4(
        keccak256(
            abi.encode(
                _TYPEHASH,
                req.from,
                req.to,
                req.value,
                req.gas,
                req.nonce,
                keccak256(req.data)
            )
        )
    ).recover(signature);

    return _nonces[req.from] == req.nonce && signer == req.from;

}`} language="text" theme="dark" />

검증이 성공하면, MinimalForwarder는 적절한 calldata와 함께 요청된 컨트랙트를 호출함으로써 트랜잭션을 실행합니다.

<CodeSnippet code={`function execute(ForwardRequest calldata req, bytes calldata signature)
        public
        payable
        returns (bool, bytes memory)
{
    require(verify(req, signature), "MinimalForwarder: signature does not match request");
    _nonces[req.from] = req.nonce + 1;

    (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(abi.encodePacked(req.data, req.from));

    // Validate that the relayer has sent enough gas for the call.
    // See
    if (gasleft() <= req.gas / 63) {
        // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since
        // neither revert or assert consume all gas since Solidity 0.8.0
        //
        /// @solidity memory-safe-assembly
        assembly {
            invalid()
        }
    }

    return (success, returndata);

}`} language="text" theme="dark" />

바로 이 지점에서 메타 트랜잭션의 단점이 드러나는데, MinimalForwarder가 호출하는 컨트랙트가 MinimalForwarder로 하여금 사용자를 대신해 자신을 호출할 수 있도록 허용해야 하기 때문입니다.

## ERC-2771이란 무엇인가?

마지막으로, 호출이 의도한 target 컨트랙트에 도달하면, Relayer의 트랜잭션 안에 중첩되어 있는 원래 사용자\(_msg.sender_\)와 calldata\(_msg.data_\)를 알아낼 수 있어야 합니다. 이 과정을 표준화하기 위해 [ERC2771](https://eips.ethereum.org/EIPS/eip-2771)이 제안되었습니다.

OpenZepplin은 스마트 컨트랙트 개발자가 MinimalForwarder가 전송한 데이터로부터 의도된 msg.sender와 msg.data를 손쉽게 추출할 수 있도록 [ERC2771Context](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol)라는 유틸리티 컨트랙트를 제공합니다.

<CodeSnippet code={`contract YourContract is ERC2771Context {
    constructor(MinimalForwarder forwarder, string memory uri_)
        ERC2771Context(address(forwarder))
    {}

    // Depending on whether the call is made by the \`MinimalForwarder\` or not the \`msg.sender\` and \`msg.data\` will be inferred accordingly

}`} language="text" theme="dark" />

모든 스마트 컨트랙트가 메타 트랜잭션을 읽는 방법을 알고 있어야 하기 때문에, 이미 배포된 컨트랙트에 이를 구현하는 것은 어려운 일이며 버그가 발생할 수도 있습니다!

그 외에도 많은 메타 트랜잭션 인프라 서비스가 존재하지만, 이들 모두 target 컨트랙트가 _msg.sender_와 _msg.data_를 추론하기 위해 EIP-712 또는 EIP-2771 기반 컨트랙트를 상속받을 것을 요구합니다.

이 표준은 훌륭하지만, 소급 적용이 불가능합니다. 바로 이런 이유로 ERC-4337이 만들어졌으며, 대부분의 ERC-2771 솔루션들을 대체해나가고 있습니다.

## 자주 묻는 질문

### 메타 트랜잭션이란 무엇인가?

메타 트랜잭션은 Relayer라 불리는 제3자가 사용자를 대신해 트랜잭션을 전송하고 gas 수수료를 지불할 수 있게 함으로써, 사용자가 [앱](https://www.alchemy.com/dapps/top/defi-dapps)과 상호작용하기 전에 Ether를 보유해야 하는 장벽을 없애줍니다.

### 메타 트랜잭션은 어떻게 작동하는가?

사용자는 트랜잭션 정보를 담은 메시지에 서명하며, 이는 Relayer에게 전달됩니다. Relayer는 요청을 검증하고, gas 수수료를 지불하며, 네이티브 트랜잭션에 서명해 블록체인 상에서 실행되도록 제출합니다.

### ERC-2771이란 무엇인가?

ERC-2771은 스마트 컨트랙트가 신뢰할 수 있는 forwarder를 통해 메타 트랜잭션을 수신할 때 원래 사용자와 calldata를 식별할 수 있도록 하는 표준으로, 올바른 msg.sender와 msg.data 추출을 보장합니다.

### 메타 트랜잭션에서 MinimalForwarder란 무엇인가?

MinimalForwarder는 사용자가 서명한 메시지의 진위 여부와 재사용 방지를 검증한 뒤, target 컨트랙트를 호출하여 트랜잭션을 실행하는 온체인 스마트 컨트랙트입니다.

### ERC2771Context란 무엇인가?

ERC2771Context는 스마트 컨트랙트 개발자가 MinimalForwarder가 전송한 메타 트랜잭션으로부터 의도된 msg.sender와 msg.data를 손쉽게 추출할 수 있도록 해주는 [OpenZeppelin](https://www.alchemy.com/dapps/openzeppelin) 유틸리티 컨트랙트입니다.

### ERC-2771 메타 트랜잭션의 한계는 무엇인가?

ERC-2771은 target 컨트랙트가 EIP-712 또는 EIP-2771 기반 컨트랙트를 상속받아 표준을 명시적으로 지원할 것을 요구하기 때문에, 이미 배포된 컨트랙트에 구현하기 어렵고 버그가 발생할 가능성이 있습니다.

### ERC-2771은 ERC-4337과 어떻게 비교되는가?

ERC-2771은 relayer와 forwarder를 통해 가스리스 트랜잭션을 가능하게 하지만, ERC-4337\(Account Abstraction\)은 소급 적용이 가능하고 기존 컨트랙트를 수정할 필요가 없기 때문에 대부분의 ERC-2771 솔루션을 대체해나가고 있습니다.

### 메타 트랜잭션에서 relayer는 어떤 역할을 하는가?

Relayer는 사용자의 gas 수수료를 대신 부담하는 Ethereum 계정으로, 그 private key는 provider 서버에 안전하게 저장되며, whitelisting, gas price capping, 조건부 로직 같은 기능을 구성할 수 있습니다.
