메타 트랜잭션(ERC-2771)이란 무엇인가?
모든 Ethereum 트랜잭션은 gas를 사용하며, 트랜잭션을 보내는 주체는 소비되는 gas를 지불할 만큼 충분한 Ether를 보유하고 있어야 합니다. 이 때문에 신규 사용자는 dapp을 사용하기 전에 먼저 Ether를 구매해야 하는데(이는 상당히 부담스러운 일일 수 있습니다), 이는 사용자 온보딩에 있어 큰 장벽이 됩니다.
이른바 "메타 트랜잭션"은 사용자를 대신해 gas 수수료를 지불할 수 있게 해주는 방법입니다.
하지만 이러한 솔루션들 중 다수는 Account Abstraction(ERC-4337) 인프라로 전환하고 있는데, 이는 더 많은 기능을 갖춘, 더 유망하고 정교한 gas 추상화 방식이기 때문입니다.
메타 트랜잭션이란 무엇인가?
메타 트랜잭션의 개념은 간단합니다. Relayer라 불리는 제3자가 사용자를 대신해 트랜잭션을 전송하고 gas 수수료를 지불하는 것입니다.
사용자는 실행할 트랜잭션에 대한 정보를 담은 메시지(가급적 EIP-712를 준수하는)에 서명합니다.
서명된 메시지는 Relayer에게 전달되며, Relayer는 자신이 대가를 받을 수 있는지 여부(이는 선택 사항일 수 있으며 자세한 내용은 뒤에서 다룹니다)를 검증하고, gas 수수료를 지불할 자금이 충분한지 확인한 뒤, 네이티브 트랜잭션에 서명하여 실행을 위해 제출할 책임을 갖습니다.
OpenZepplin의 Relayer를 예로 들어 메타 트랜잭션을 살펴보겠습니다.

메타 트랜잭션 요청은 어떻게 생겼는가?
샘플 메타 트랜잭션 메시지는 다음과 같이 생겼습니다...

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

메타 트랜잭션 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)를 검증하는 온체인 스마트 컨트랙트입니다.
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;
}검증이 성공하면, MinimalForwarder는 적절한 calldata와 함께 요청된 컨트랙트를 호출함으로써 트랜잭션을 실행합니다.
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);
}바로 이 지점에서 메타 트랜잭션의 단점이 드러나는데, MinimalForwarder가 호출하는 컨트랙트가 MinimalForwarder로 하여금 사용자를 대신해 자신을 호출할 수 있도록 허용해야 하기 때문입니다.
ERC-2771이란 무엇인가?
마지막으로, 호출이 의도한 target 컨트랙트에 도달하면, Relayer의 트랜잭션 안에 중첩되어 있는 원래 사용자(msg.sender)와 calldata(msg.data)를 알아낼 수 있어야 합니다. 이 과정을 표준화하기 위해 ERC2771이 제안되었습니다.
OpenZepplin은 스마트 컨트랙트 개발자가 MinimalForwarder가 전송한 데이터로부터 의도된 msg.sender와 msg.data를 손쉽게 추출할 수 있도록 ERC2771Context라는 유틸리티 컨트랙트를 제공합니다.
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
}모든 스마트 컨트랙트가 메타 트랜잭션을 읽는 방법을 알고 있어야 하기 때문에, 이미 배포된 컨트랙트에 이를 구현하는 것은 어려운 일이며 버그가 발생할 수도 있습니다!
그 외에도 많은 메타 트랜잭션 인프라 서비스가 존재하지만, 이들 모두 target 컨트랙트가 _msg.sender_와 _msg.data_를 추론하기 위해 EIP-712 또는 EIP-2771 기반 컨트랙트를 상속받을 것을 요구합니다.
이 표준은 훌륭하지만, 소급 적용이 불가능합니다. 바로 이런 이유로 ERC-4337이 만들어졌으며, 대부분의 ERC-2771 솔루션들을 대체해나가고 있습니다.
자주 묻는 질문
메타 트랜잭션이란 무엇인가?
메타 트랜잭션은 Relayer라 불리는 제3자가 사용자를 대신해 트랜잭션을 전송하고 gas 수수료를 지불할 수 있게 함으로써, 사용자가 앱과 상호작용하기 전에 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 유틸리티 컨트랙트입니다.
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, 조건부 로직 같은 기능을 구성할 수 있습니다.
관련 개요
지갑2026년 9월 2일
Agent Wallets: AI 에이전트를 위한 세션 및 권한 모델
AI 에이전트가 개인 키를 보유하지 않고도 범위가 지정되고 취소 가능한 지갑 액세스 권한을 얻는 방법: 세션, 위임 서명, 즉시 취소.
지갑2026년 7월 29일
Cursor에 프라이빗 키를 붙여넣지 마세요: 코딩 에이전트에게 지갑을 부여하는 방법
코딩 에이전트에게 키는 주지 않고 지갑만 부여하세요. Alchemy CLI가 제공하는 에이전트 지갑이 범위가 제한된 세션을 사용해 .env에 프라이빗 키 없이도 에이전트가 트랜잭션을 실행할 수 있도록 하는 방법을 소개합니다.
지갑2026년 6월 24일
크립토 번들러(bundler)란?
크립토 번들러(bundler)는 배칭, MEV, 롤업, 토큰 런칭, 계정 추상화 전반에서 여러 트랜잭션 또는 오퍼레이션을 하나의 온체인 제출로 결합합니다.

블록체인 매직을 만드세요
Alchemy는 가장 강력한 Web3 개발자 제품 및 도구를 리소스, 커뮤니티, 그리고 전설적인 지원과 결합합니다.