Skip to content

Commit

Permalink
πŸ“ Documentation (#659)
Browse files Browse the repository at this point in the history
Co-authored-by: melancholicxxx <[email protected]>
Co-authored-by: 0xlgtm <[email protected]>
  • Loading branch information
3 people authored Dec 24, 2024
1 parent e1cb33a commit 2d85958
Show file tree
Hide file tree
Showing 85 changed files with 22,538 additions and 2 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[![NPM][npm-shield]][npm-url]
[![CI][ci-shield]][ci-url]
[![Solidity][solidity-shield]][solidity-ci-url]
[![Docs][docs-shield]][docs-url]

Gas optimized Solidity snippets.

Expand All @@ -22,6 +23,10 @@ To install with [**Hardhat**](https://github.com/nomiclabs/hardhat):
npm install solady
```

## Documentation

https://vectorized.github.io/solady

## Contracts

The Solidity smart contracts are located in the `src` directory.
Expand Down Expand Up @@ -158,3 +163,6 @@ This repository is inspired by or directly modified from many sources, primarily

[solidity-shield]: https://img.shields.io/badge/solidity-%3E=0.8.4%20%3C=0.8.28-aa6746
[solidity-ci-url]: https://github.com/Vectorized/solady/actions/workflows/ci-all-via-ir.yml

[docs-shield]: https://img.shields.io/badge/docs-%F0%9F%93%84-blue
[docs-url]: https://vectorized.github.io/solady
Empty file added docs/.nojekyll
Empty file.
172 changes: 172 additions & 0 deletions docs/accounts/erc1271.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# ERC1271

ERC1271 mixin with nested EIP-712 approach.




<b>Inherits:</b>

- `utils/EIP712.sol`


<!-- customintro:start --><!-- customintro:end -->

## Constants

### _PERSONAL_SIGN_TYPEHASH

```solidity
bytes32 internal constant _PERSONAL_SIGN_TYPEHASH =
0x983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de
```

`keccak256("PersonalSign(bytes prefixed)")`.

## ERC1271 Operations

### isValidSignature(bytes32,bytes)

```solidity
function isValidSignature(bytes32 hash, bytes calldata signature)
public
view
virtual
returns (bytes4 result)
```

Validates the signature with ERC1271 return,
so that this account can also be used as a signer.

### _erc1271IsValidSignatureNowCalldata(bytes32,bytes)

```solidity
function _erc1271IsValidSignatureNowCalldata(
bytes32 hash,
bytes calldata signature
) internal view virtual returns (bool)
```

Returns whether the `hash` and `signature` are valid.
Override if you need non-ECDSA logic.

### _erc1271UnwrapSignature(bytes)

```solidity
function _erc1271UnwrapSignature(bytes calldata signature)
internal
view
virtual
returns (bytes calldata result)
```

Unwraps and returns the signature.

### _erc1271IsValidSignature(bytes32,bytes)

```solidity
function _erc1271IsValidSignature(bytes32 hash, bytes calldata signature)
internal
view
virtual
returns (bool)
```

Returns whether the `signature` is valid for the `hash.

### _erc1271IsValidSignatureViaSafeCaller(bytes32,bytes)

```solidity
function _erc1271IsValidSignatureViaSafeCaller(
bytes32 hash,
bytes calldata signature
) internal view virtual returns (bool result)
```

Performs the signature validation without nested EIP-712 if the caller is
a safe caller. A safe caller must include the address of this account in the hash.

### _erc1271IsValidSignatureViaNestedEIP712(bytes32,bytes)

```solidity
function _erc1271IsValidSignatureViaNestedEIP712(
bytes32 hash,
bytes calldata signature
) internal view virtual returns (bool result)
```

ERC1271 signature validation (Nested EIP-712 workflow).
This uses ECDSA recovery by default (see: `_erc1271IsValidSignatureNowCalldata`).
It also uses a nested EIP-712 approach to prevent signature replays when a single EOA
owns multiple smart contract accounts,
while still enabling wallet UIs (e.g. Metamask) to show the EIP-712 values.
Crafted for phishing resistance, efficiency, flexibility.
__________________________________________________________________________________________
Glossary:
- `APP_DOMAIN_SEPARATOR`: The domain separator of the `hash` passed in by the application.
Provided by the front end. Intended to be the domain separator of the contract
that will call `isValidSignature` on this account.
- `ACCOUNT_DOMAIN_SEPARATOR`: The domain separator of this account.
See: `EIP712._domainSeparator()`.
__________________________________________________________________________________________
For the `TypedDataSign` workflow, the final hash will be:
```solidity
keccak256(\x19\x01 β€– APP_DOMAIN_SEPARATOR β€–
hashStruct(TypedDataSign({
contents: hashStruct(originalStruct),
name: keccak256(bytes(eip712Domain().name)),
version: keccak256(bytes(eip712Domain().version)),
chainId: eip712Domain().chainId,
verifyingContract: eip712Domain().verifyingContract,
salt: eip712Domain().salt
}))
)
```
where `β€–` denotes the concatenation operator for bytes.
The order of the fields is important: `contents` comes before `name`.
The signature will be `r β€– s β€– v β€– APP_DOMAIN_SEPARATOR β€–
contents β€– contentsDescription β€– uint16(contentsDescription.length)`,
where:
- `contents` is the bytes32 struct hash of the original struct.
- `contentsDescription` can be either:
a) `contentsType` (implicit mode)
where `contentsType` starts with `contentsName`.
b) `contentsType β€– contentsName` (explicit mode)
where `contentsType` may not necessarily start with `contentsName`.
The `APP_DOMAIN_SEPARATOR` and `contents` will be used to verify if `hash` is indeed correct.
__________________________________________________________________________________________
For the `PersonalSign` workflow, the final hash will be:
```solidity
keccak256(\x19\x01 β€– ACCOUNT_DOMAIN_SEPARATOR β€–
hashStruct(PersonalSign({
prefixed: keccak256(bytes(\x19Ethereum Signed Message:\n β€–
base10(bytes(someString).length) β€– someString))
}))
)
```
where `β€–` denotes the concatenation operator for bytes.
The `PersonalSign` type hash will be `keccak256("PersonalSign(bytes prefixed)")`.
The signature will be `r β€– s β€– v`.
__________________________________________________________________________________________
For demo and typescript code, see:
- https://github.com/junomonster/nested-eip-712
- https://github.com/frangio/eip712-wrapper-for-eip1271
Their nomenclature may differ from ours, although the high-level idea is similar.
Of course, if you have control over the codebase of the wallet client(s) too,
you can choose a more minimalistic signature scheme like
`keccak256(abi.encode(address(this), hash))` instead of all these acrobatics.
All these are just for widespread out-of-the-box compatibility with other wallet clients.
We want to create bazaars, not walled castles.
And we'll use push the Turing Completeness of the EVM to the limits to do so.

### _erc1271IsValidSignatureViaRPC(bytes32,bytes)

```solidity
function _erc1271IsValidSignatureViaRPC(
bytes32 hash,
bytes calldata signature
) internal view virtual returns (bool result)
```

Performs the signature validation without nested EIP-712 to allow for easy sign ins.
This function must always return false or revert if called on-chain.
Loading

0 comments on commit 2d85958

Please sign in to comment.