OpenGSN과 Openzeppelin의 defender를 공부하며 알게 된 forwarder contract가 EIP712를 상속받고 있는 것을 보았습니다. EIP712는 무엇인지 어떠한 역할인지 알아보도록 하겠습니다.
목차
EIP-712란?
EIP-712의 장점
예시 코드
EIP-712란?
EIP-712는 Typed Structured Data로 구조화된 데이터에 대한 해싱과 서명 검증을 위한 표준입니다. 이 표준은 메시지 형식을 사전에 정의하고, 이를 해싱하여 고유한 메시지 해시를 생성합니다. 이로써 구조화된 데이터의 무결성을 보장하고, 서명 검증을 통해 메시지의 인증과 권한 부여를 신뢰할 수 있게 합니다. 이러한 검증과 무결성을 이용하기 위하여 forwarder에 상속합니다.
EIP-712의 장점
데이터의 무결성 : EIP-712은 데이터를 해싱하여 무결성을 보장합니다. 데이터가 변경되면 해시값도 변경되므로 데이터의 위변조를 검사할 수 있습니다.
서명 검증 : EIP-712를 통해 서명된 메시지를 검증할 수 있으며, 메시지를 생성한 주소를 확인할 수 있습니다.
이러한 장점을 이용하여 스마트 계약 간의 통신, 오프체인 서비스와의 상호작용, 탈중앙화된 식별 시스템에 이용할 수 있습니다.
예시 코드
아래의 코드는 openzeppelin에서 제공하는 EIP712 contract입니다.
pragma solidity ^0.8.8;
import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
}
_domainSeparatorV4 : 현재 체인의 domainSeparator를 반환합니다. 이 메서드는 캐시 된 캐시 된 domainSeparator 값을 반환하며, 체인 ID가 변경되면 캐시 된 값을 무효화하여 보안을 강화합니다.
_buildDomainSeparator : domainSeparator를 구성하기 위한 내부 함수입니다. _TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this) 값을 사용하여 domainSeparator를 생성합니다.
_hashTypedDataV4 : 이미 해싱된 구조체에 대한 EIP-712 메시지의 해시값을 반환합니다. domainSeparator와 구조체 해시를 조합하여 타입화된 데이터의 해시를 계산합니다. 계산되어 나온 해시는 ECDSA의 recover의 함수와 함께 사용하여 메시지의 서명을 복원할 수 있습니다.
eip712Domain : 이 메서드는 EIP-5267 인터페이스에 정의된 함수로, 도메인과 관련된 정보를 반환합니다. 반환되는 정보는 메시지의 도메인을 식별하고, 체인 ID 및 관련 컨트랙트 주소등의 정보를 제공하여 메시지의 유효성을 검증하는 데 사용할 수 있습니다.
'BlockChain > solidity' 카테고리의 다른 글
[Solidity] ERC-2771이란? (ERC-2771Context란?) (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 |