Skip to main content

EIP712StETH

EIP712StETH serves as a dedicated helper contract for stETH, crucial for complete support of ERC-2612 compliant signed approvals.

Why This Helper Is Needed

The original Lido/StETH contract is implemented in Solidity 0.4.24, while this helper is implemented in Solidity 0.8.9. The newer compiler version enables access to the current network's chain id via the globally available variable block.chainid. The chain id is mandatory for signature inclusion as per EIP-155 to prevent replay attacks, wherein an attacker intercepts a valid network transmission and then rebroadcasts it on another network fork. Consequently, EIP-155 compliance is critical for securing ERC-2612 signed approvals.

View Methods

domainSeparatorV4()

This method returns the EIP712-compatible hashed domain separator, which is valid for stETH token permit signatures. The domain separator is essential in preventing a signature intended for one dApp from functioning in another (thereby averting a signature collision in a broader sense).

function domainSeparatorV4(address _stETH) returns (bytes32)

Also, consider the eip712Domain() method that can construct a domain separator from StETH-specific fields on the client's side, such as within a dApp or a wallet. For instance, Metamask relies on eth_signTypedData_v4, which requires a non-hashed domain separator being provided.

hashTypedDataV4()

This method returns the hash of a fully encoded EIP712-compatible message for this domain. The method can validate the input data against the provided v, r, s secp256k1 components.

function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32)

Parameters

NameTypeDescription
_stETHaddressAddress of the deployed stETH token
_structHashbytes32Hash of the data structure

For a specific use case, see the StETHPermit.permit() implementation.

eip712Domain()

This method returns the fields and values necessary to construct a domain separator on the client's side. The method resembles the one proposed in ERC-5267, with the only difference being that it doesn't return unused fields.

function eip712Domain(address _stETH) returns (
string memory name,
string memory version,
uint256 chainId,
address verifyingContract
)

Parameters

NameTypeDescription
_stETHaddressAddress of the deployed stETH token

Returns

NameTypeDescription
namestringName of the token
versionstringVersion of the token
chainIduint256Chain identifier
verifyingContractaddressAddress of the token contract
note

Provided the correct _stETH deployed address, it returns:

  • ("Liquid staked Ether 2.0", "2", 1, 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) for Mainnet.
  • ("Liquid staked Ether 2.0", "2", 5, 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F) for Görli.

This method facilitates domain separator construction on the client's side, such as in a wallet or widget:

function makeDomainSeparator(name, version, chainId, verifyingContract) {
return web3.utils.keccak256(
web3.eth.abi.encodeParameters(
['bytes32', 'bytes32', 'bytes32', 'uint256', 'address'],
[
web3.utils.keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
web3.utils.keccak256(name),
web3.utils.keccak256(version),
chainId,
verifyingContract,
]
)
)
}