From 5da6f18b5c1d3ece316e84d143b0a041bbccd199 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Wed, 5 Jul 2023 19:58:52 +0300 Subject: [PATCH 1/5] feat: initial eip712 ref --- docs/contracts/eip712-steth.md | 81 ++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/docs/contracts/eip712-steth.md b/docs/contracts/eip712-steth.md index 38a953b9f..fda1ae342 100644 --- a/docs/contracts/eip712-steth.md +++ b/docs/contracts/eip712-steth.md @@ -7,3 +7,84 @@ EIP712StETH is a special helper contract for `stETH` that enables support for [ERC-2612 compliant signed approvals](https://eips.ethereum.org/EIPS/eip-2612). The contract is responsible for the permit signatures preparation. + +## View methods + +### domainSeparatorV4() + +Returns the domain separator to build a EIP712-compatible signature for the stETH token. + +```sol +function domainSeparatorV4(address _stETH) returns (bytes32) +``` + +### hashTypedDataV4() + +Returns the hash of a fully encoded EIP712-compatible message for this domain. + +```sol +function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32) +``` + +#### Parameters + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------- | +| `_stETH` | `address` | Address of the deployed `stETH` token | +| `_structHash` | `bytes32` | Address of the deployed `stETH` token | + +### eip712Domain() + +Returns the fields and values required to build a domain separator on the client's side. + +The method is akin the proposed one in [ERC-5267](https://eips.ethereum.org/EIPS/eip-5267) with a difference of not returning the unused fields at all. + +```sol +function eip712Domain(address _stETH) returns ( + string memory name, + string memory version, + uint256 chainId, + address verifyingContract +) +``` + +#### Parameters + +| Name | Type | Description | +| ---------- | --------- | -------------------------------------- | +| `_stETH` | `address` | Address of the deployed `stETH` token | + +#### Returns + +| Name | Type | Description | +| ----------------- | ---------- | ----------------------------- | +| `name` | `string` | name of the token | +| `version` | `string` | version of the token | +| `chainId` | `uint256` | chain identifier | +| `verifyContract` | `address` | address of the token contract | + +:::note +If the proper `_stETH` [deployed](/deployed-contracts) address passed then returns: + +- ("Liquid staked Ether 2.0", "2", 1, 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) for Mainnet. +- ("Liquid staked Ether 2.0", "2", 5, 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F) for Görli. +::: + +The method is supposed to be used on the client's (e.g. wallet or widget) side facilitating a domain separator construction: + +```js +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, + ] + ) + ) +} +``` From abda03769cf961dd0ccbc6d45e281a5e09d1ffe4 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Fri, 7 Jul 2023 19:05:55 +0300 Subject: [PATCH 2/5] fix: more improvements on the helper's purpose --- docs/contracts/eip712-steth.md | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/contracts/eip712-steth.md b/docs/contracts/eip712-steth.md index fda1ae342..cba83066c 100644 --- a/docs/contracts/eip712-steth.md +++ b/docs/contracts/eip712-steth.md @@ -3,24 +3,37 @@ - [Source code](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.8.9/EIP712StETH.sol) - [Deployed contract](https://etherscan.io/address/0x8F73e4C2A6D852bb4ab2A45E6a9CF5715b3228B7) -EIP712StETH is a special helper contract for `stETH` that enables support -for [ERC-2612 compliant signed approvals](https://eips.ethereum.org/EIPS/eip-2612). +`EIP712StETH` is a special helper contract for `stETH` that is required to fully support + [ERC-2612 compliant signed approvals](https://eips.ethereum.org/EIPS/eip-2612). -The contract is responsible for the permit signatures preparation. +## Why helper + +The original [`Lido/StETH`](/contracts/lido) contract is implemented in Solidity `0.4.24` while this helper is +implemented in Solidity `0.8.9`. A newer compiler version allows accessing the current network's chain id +(via the [`block.chainid`](https://docs.soliditylang.org/en/v0.8.9/units-and-global-variables.html#block-and-transaction-properties) +globally available variable). The latter is required by [EIP-155](https://eips.ethereum.org/EIPS/eip-155) to +prevent replay attacks (i.e., an attacker captures a valid network transmission and then retransmits it on another network fork, +for example, using a valid testnet signature on mainnet later). Finally, the `EIP-155` compliance is required to secure the `ERC-2612` signed approvals. ## View methods ### domainSeparatorV4() -Returns the domain separator to build a EIP712-compatible signature for the stETH token. +Returns the EIP712-compatible hashed [domain separator](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator) +which is valid for the `stETH` token permit signatures. The domain separator helps to prevent a signature meant for one dApp +from working in another (i.e., prevents a signature collision in a broad sense). ```sol function domainSeparatorV4(address _stETH) returns (bytes32) ``` +See also the [`eip712Domain()`](/contracts/eip712-steth#eip712domain) method that can be used to construct a domain separator +from the `StETH`-specific fields on the client's side (e.g., inside a dApp or a wallet). + ### hashTypedDataV4() Returns the hash of a fully encoded EIP712-compatible message for this domain. +The method can be used to validate the input data against the provided `v, r, s` secp256k1 components. ```sol function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32) @@ -33,6 +46,9 @@ function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32) | `_stETH` | `address` | Address of the deployed `stETH` token | | `_structHash` | `bytes32` | Address of the deployed `stETH` token | +See the [StETHPermit.permit()](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.4.24/StETHPermit.sol#L99-L112) +implementation for a particular use case. + ### eip712Domain() Returns the fields and values required to build a domain separator on the client's side. @@ -88,3 +104,8 @@ function makeDomainSeparator(name, version, chainId, verifyingContract) { ) } ``` + +## Useful external links + +- [The Magic of Digital Signatures on Ethereum](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7) +- [ERC-2612: The Ultimate Guide to Gasless ERC-20 Approvals](https://medium.com/frak-defi/erc-2612-the-ultimate-guide-to-gasless-erc-20-approvals-2cd32ddee534) From ea27c485f97f3f34a3ff58d5087ff95df57edd46 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Sat, 8 Jul 2023 08:48:11 +0300 Subject: [PATCH 3/5] fix: paraphrase eip712steth --- docs/contracts/eip712-steth.md | 59 +++++++++++++--------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/docs/contracts/eip712-steth.md b/docs/contracts/eip712-steth.md index cba83066c..5b8abd176 100644 --- a/docs/contracts/eip712-steth.md +++ b/docs/contracts/eip712-steth.md @@ -3,37 +3,27 @@ - [Source code](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.8.9/EIP712StETH.sol) - [Deployed contract](https://etherscan.io/address/0x8F73e4C2A6D852bb4ab2A45E6a9CF5715b3228B7) -`EIP712StETH` is a special helper contract for `stETH` that is required to fully support - [ERC-2612 compliant signed approvals](https://eips.ethereum.org/EIPS/eip-2612). +`EIP712StETH` serves as a dedicated helper contract for `stETH`, crucial for complete support of [ERC-2612 compliant signed approvals](https://eips.ethereum.org/EIPS/eip-2612). -## Why helper +## Why This Helper Is Needed -The original [`Lido/StETH`](/contracts/lido) contract is implemented in Solidity `0.4.24` while this helper is -implemented in Solidity `0.8.9`. A newer compiler version allows accessing the current network's chain id -(via the [`block.chainid`](https://docs.soliditylang.org/en/v0.8.9/units-and-global-variables.html#block-and-transaction-properties) -globally available variable). The latter is required by [EIP-155](https://eips.ethereum.org/EIPS/eip-155) to -prevent replay attacks (i.e., an attacker captures a valid network transmission and then retransmits it on another network fork, -for example, using a valid testnet signature on mainnet later). Finally, the `EIP-155` compliance is required to secure the `ERC-2612` signed approvals. +The original [`Lido/StETH`](/contracts/lido) 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`](https://docs.soliditylang.org/en/v0.8.9/units-and-global-variables.html#block-and-transaction-properties). The chain id is mandatory for signature inclusion as per [EIP-155](https://eips.ethereum.org/EIPS/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 +## View Methods ### domainSeparatorV4() -Returns the EIP712-compatible hashed [domain separator](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator) -which is valid for the `stETH` token permit signatures. The domain separator helps to prevent a signature meant for one dApp -from working in another (i.e., prevents a signature collision in a broad sense). +This method returns the EIP712-compatible hashed [domain separator](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator), 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). ```sol function domainSeparatorV4(address _stETH) returns (bytes32) ``` -See also the [`eip712Domain()`](/contracts/eip712-steth#eip712domain) method that can be used to construct a domain separator -from the `StETH`-specific fields on the client's side (e.g., inside a dApp or a wallet). +Also, consider the [`eip712Domain()`](/contracts/eip712-steth#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. ### hashTypedDataV4() -Returns the hash of a fully encoded EIP712-compatible message for this domain. -The method can be used to validate the input data against the provided `v, r, s` secp256k1 components. +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. ```sol function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32) @@ -41,19 +31,16 @@ function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32) #### Parameters -| Name | Type | Description | -| --------------- | --------- | -------------------------------------- | -| `_stETH` | `address` | Address of the deployed `stETH` token | -| `_structHash` | `bytes32` | Address of the deployed `stETH` token | +| Name | Type | Description | +| ------------ | --------- | ------------------------------------- | +| `_stETH` | `address` | Address of the deployed `stETH` token | +| `_structHash`| `bytes32` | Hash of the data structure | -See the [StETHPermit.permit()](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.4.24/StETHPermit.sol#L99-L112) -implementation for a particular use case. +For a specific use case, see the [StETHPermit.permit()](https://github.com/lidofinance/lido-dao/blob/master/contracts/0.4.24/StETHPermit.sol#L99-L112) implementation. ### eip712Domain() -Returns the fields and values required to build a domain separator on the client's side. - -The method is akin the proposed one in [ERC-5267](https://eips.ethereum.org/EIPS/eip-5267) with a difference of not returning the unused fields at all. +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](https://eips.ethereum.org/EIPS/eip-5267), with the only difference being that it doesn't return unused fields. ```sol function eip712Domain(address _stETH) returns ( @@ -66,27 +53,27 @@ function eip712Domain(address _stETH) returns ( #### Parameters -| Name | Type | Description | -| ---------- | --------- | -------------------------------------- | -| `_stETH` | `address` | Address of the deployed `stETH` token | +| Name | Type | Description | +| -------- | --------- | ------------------------------------- | +| `_stETH` | `address` | Address of the deployed `stETH` token | #### Returns | Name | Type | Description | | ----------------- | ---------- | ----------------------------- | -| `name` | `string` | name of the token | -| `version` | `string` | version of the token | -| `chainId` | `uint256` | chain identifier | -| `verifyContract` | `address` | address of the token contract | +| `name` | `string` | Name of the token | +| `version` | `string` | Version of the token | +| `chainId` | `uint256` | Chain identifier | +| `verifyingContract`| `address` | Address of the token contract | :::note -If the proper `_stETH` [deployed](/deployed-contracts) address passed then returns: +Provided the correct `_stETH` [deployed](/deployed-contracts) address, it returns: - ("Liquid staked Ether 2.0", "2", 1, 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84) for Mainnet. - ("Liquid staked Ether 2.0", "2", 5, 0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F) for Görli. ::: -The method is supposed to be used on the client's (e.g. wallet or widget) side facilitating a domain separator construction: +This method facilitates domain separator construction on the client's side, such as in a wallet or widget: ```js function makeDomainSeparator(name, version, chainId, verifyingContract) { @@ -105,7 +92,7 @@ function makeDomainSeparator(name, version, chainId, verifyingContract) { } ``` -## Useful external links +## Useful External Links - [The Magic of Digital Signatures on Ethereum](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7) - [ERC-2612: The Ultimate Guide to Gasless ERC-20 Approvals](https://medium.com/frak-defi/erc-2612-the-ultimate-guide-to-gasless-erc-20-approvals-2cd32ddee534) From 25bf57e2a4460d592a01efd4367207c3002c8953 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 10 Jul 2023 14:49:33 +0300 Subject: [PATCH 4/5] fix: review suggestions by @folkyatina --- docs/contracts/eip712-steth.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/contracts/eip712-steth.md b/docs/contracts/eip712-steth.md index 5b8abd176..62c16b412 100644 --- a/docs/contracts/eip712-steth.md +++ b/docs/contracts/eip712-steth.md @@ -7,23 +7,23 @@ ## Why This Helper Is Needed -The original [`Lido/StETH`](/contracts/lido) 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`](https://docs.soliditylang.org/en/v0.8.9/units-and-global-variables.html#block-and-transaction-properties). The chain id is mandatory for signature inclusion as per [EIP-155](https://eips.ethereum.org/EIPS/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. +The original [`Lido/StETH`](/contracts/lido) 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`](https://docs.soliditylang.org/en/v0.8.9/units-and-global-variables.html#block-and-transaction-properties). The chain id is mandatory for signature inclusion as per [EIP-155](https://eips.ethereum.org/EIPS/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`](https://eips.ethereum.org/EIPS/eip-2612) signed approvals. ## View Methods ### domainSeparatorV4() -This method returns the EIP712-compatible hashed [domain separator](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator), 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). +This method returns the `EIP712`-compatible hashed [domain separator](https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator), 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). ```sol function domainSeparatorV4(address _stETH) returns (bytes32) ``` -Also, consider the [`eip712Domain()`](/contracts/eip712-steth#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. +Also, consider the [`eip712Domain()`](/contracts/eip712-steth#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`](https://docs.metamask.io/wallet/how-to/sign-data/#use-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. +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. ```sol function hashTypedDataV4(address _stETH, bytes32 _structHash) returns (bytes32) From c32365cec55a3df0e10e58f956c682d2f9ec1d50 Mon Sep 17 00:00:00 2001 From: Eugene Mamin Date: Mon, 10 Jul 2023 14:54:26 +0300 Subject: [PATCH 5/5] doc: add Metamask sign data link --- docs/contracts/eip712-steth.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contracts/eip712-steth.md b/docs/contracts/eip712-steth.md index 62c16b412..bfcb32a6f 100644 --- a/docs/contracts/eip712-steth.md +++ b/docs/contracts/eip712-steth.md @@ -96,3 +96,4 @@ function makeDomainSeparator(name, version, chainId, verifyingContract) { - [The Magic of Digital Signatures on Ethereum](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7) - [ERC-2612: The Ultimate Guide to Gasless ERC-20 Approvals](https://medium.com/frak-defi/erc-2612-the-ultimate-guide-to-gasless-erc-20-approvals-2cd32ddee534) +- [Metamask sign-data](https://docs.metamask.io/wallet/how-to/sign-data/#use-eth_signtypeddata_v4)