Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions GUIDELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@

Some standards (e.g. ERC-20) use present tense, and in those cases the
standard specification is used.

* Interface names should have a capital I prefix.

```solidity
Expand All @@ -141,7 +141,7 @@
* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted.

* Custom errors should be declared following the [EIP-6093](https://eips.ethereum.org/EIPS/eip-6093) rationale whenever reasonable. Also, consider the following:

* The domain prefix should be picked in the following order:
1. Use `ERC<number>` if the error is a violation of an ERC specification.
2. Use the name of the underlying component where it belongs (eg. `Governor`, `ECDSA`, or `Timelock`).
Expand All @@ -153,3 +153,17 @@
4. Declare the error in an extension if the error only happens in such extension or child contracts.

* Custom error names should not be declared twice along the library to avoid duplicated identifier declarations when inheriting from multiple contracts.

* In some cases arithmetics value should be written in specific formats

Check failure on line 157 in GUIDELINES.md

View workflow job for this annotation

GitHub Actions / codespell

arithmetics ==> arithmetic

* Memory locations should be written in hex format: `mload(64)` → `mload(0x40)`

* Memory offset should be written in hex format: `mstore(add(ptr, 32), value)` → `mstore(add(ptr, 0x20), value)`

* [Exception] for trivially small values, such as 1 or 2, decimal format can be accepted `ptr := add(ptr, 1)`

* Memory length should be written in hex format: `keccak(ptr, 85)` → `keccak(ptr, 0x55)`

* [Exception] in call/staticcall/delegatecall, decimal zero can be used if both the location and the length are zero.

* Bits offset used in shifts should be written in decimal format: `shl(0x80, value)` → `shl(128, value)`
28 changes: 14 additions & 14 deletions contracts/account/utils/draft-ERC7579Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ library ERC7579Utils {
Mode mode
) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) {
return (
CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0)),
ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 1)),
ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 6)),
ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 10))
CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0x00)),
ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0x01)),
ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 0x06)),
ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 0x0a))
);
}

Expand All @@ -146,9 +146,9 @@ library ERC7579Utils {
function decodeSingle(
bytes calldata executionCalldata
) internal pure returns (address target, uint256 value, bytes calldata callData) {
target = address(bytes20(executionCalldata[0:20]));
value = uint256(bytes32(executionCalldata[20:52]));
callData = executionCalldata[52:];
target = address(bytes20(executionCalldata[0x00:0x14]));
value = uint256(bytes32(executionCalldata[0x14:0x34]));
callData = executionCalldata[0x34:];
}

/// @dev Encodes a delegate call execution. See {decodeDelegate}.
Expand All @@ -163,8 +163,8 @@ library ERC7579Utils {
function decodeDelegate(
bytes calldata executionCalldata
) internal pure returns (address target, bytes calldata callData) {
target = address(bytes20(executionCalldata[0:20]));
callData = executionCalldata[20:];
target = address(bytes20(executionCalldata[0:0x14]));
callData = executionCalldata[0x14:];
}

/// @dev Encodes a batch of executions. See {decodeBatch}.
Expand All @@ -180,17 +180,17 @@ library ERC7579Utils {
uint256 bufferLength = executionCalldata.length;

// Check executionCalldata is not empty.
if (bufferLength < 32) revert ERC7579DecodingError();
if (bufferLength < 0x20) revert ERC7579DecodingError();

// Get the offset of the array (pointer to the array length).
uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0:32]));
uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0x00:0x20]));

// The array length (at arrayLengthOffset) should be 32 bytes long. We check that this is within the
// buffer bounds. Since we know bufferLength is at least 32, we can subtract with no overflow risk.
if (arrayLengthOffset > bufferLength - 32) revert ERC7579DecodingError();
if (arrayLengthOffset > bufferLength - 0x20) revert ERC7579DecodingError();

// Get the array length. arrayLengthOffset + 32 is bounded by bufferLength so it does not overflow.
uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 32]));
uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 0x20]));

// Check that the buffer is long enough to store the array elements as "offset pointer":
// - each element of the array is an "offset pointer" to the data.
Expand All @@ -200,7 +200,7 @@ library ERC7579Utils {
//
// Since we know bufferLength is at least arrayLengthOffset + 32, we can subtract with no overflow risk.
// Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32` does not overflow.
if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 32 < arrayLength * 32)
if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 0x20 < arrayLength * 0x20)
revert ERC7579DecodingError();

assembly ("memory-safe") {
Expand Down
8 changes: 4 additions & 4 deletions contracts/proxy/Clones.sol
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,9 @@ library Clones {
* function should only be used to check addresses that are known to be clones.
*/
function fetchCloneArgs(address instance) internal view returns (bytes memory) {
bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
bytes memory result = new bytes(instance.code.length - 0x2d); // revert if length is too short
assembly ("memory-safe") {
extcodecopy(instance, add(result, 32), 45, mload(result))
extcodecopy(instance, add(result, 0x20), 0x2d, mload(result))
}
return result;
}
Expand All @@ -280,11 +280,11 @@ library Clones {
address implementation,
bytes memory args
) private pure returns (bytes memory) {
if (args.length > 24531) revert CloneArgumentsTooLong();
if (args.length > 0x5fd3) revert CloneArgumentsTooLong();
return
abi.encodePacked(
hex"61",
uint16(args.length + 45),
uint16(args.length + 0x2d),
hex"3d81600a3d39f3363d3d373d3d3d363d73",
implementation,
hex"5af43d82803e903d91602b57fd5bf3",
Expand Down
12 changes: 6 additions & 6 deletions contracts/token/ERC20/utils/SafeERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,13 @@ library SafeERC20 {
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0, 0x44, 0, 0x20)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0, returndatasize())
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
Expand Down Expand Up @@ -224,13 +224,13 @@ library SafeERC20 {
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0, 0x64, 0, 0x20)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0, returndatasize())
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
Expand Down Expand Up @@ -260,13 +260,13 @@ library SafeERC20 {
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0, 0x44, 0, 0x20)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0, returndatasize())
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
Expand Down
2 changes: 1 addition & 1 deletion contracts/utils/Bytes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ library Bytes {
* if the buffer is all zeros.
*/
function clz(bytes memory buffer) internal pure returns (uint256) {
for (uint256 i = 0; i < buffer.length; i += 32) {
for (uint256 i = 0; i < buffer.length; i += 0x20) {
bytes32 chunk = _unsafeReadBytesOffset(buffer, i);
if (chunk != bytes32(0)) {
return Math.min(8 * i + Math.clz(uint256(chunk)), 8 * buffer.length);
Expand Down
20 changes: 10 additions & 10 deletions contracts/utils/Create2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,22 @@ library Create2 {
assembly ("memory-safe") {
let ptr := mload(0x40) // Get free memory pointer

// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |---------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |---------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 0x55) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
addr := and(keccak256(start, 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
}
10 changes: 5 additions & 5 deletions contracts/utils/LowLevelCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ library LowLevelCall {
bytes memory data
) internal view returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0, 0x40)
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
Expand All @@ -72,7 +72,7 @@ library LowLevelCall {
/// @dev Performs a Solidity function call using a low level `delegatecall` and ignoring the return data.
function delegatecallNoReturn(address target, bytes memory data) internal returns (bool success) {
assembly ("memory-safe") {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0, 0)
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}

Expand All @@ -86,7 +86,7 @@ library LowLevelCall {
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ("memory-safe") {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0, 0x40)
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
Expand All @@ -104,7 +104,7 @@ library LowLevelCall {
assembly ("memory-safe") {
result := mload(0x40)
mstore(result, returndatasize())
returndatacopy(add(result, 0x20), 0, returndatasize())
returndatacopy(add(result, 0x20), 0x00, returndatasize())
mstore(0x40, add(result, add(0x20, returndatasize())))
}
}
Expand All @@ -113,7 +113,7 @@ library LowLevelCall {
function bubbleRevert() internal pure {
assembly ("memory-safe") {
let fmp := mload(0x40)
returndatacopy(fmp, 0, returndatasize())
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/utils/RelayedCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ library RelayedCall {
mstore(add(fmp, 0x46), 0x60145f375f5f601436035f345f3560601c5af13d5f5f3e5f3d91604557fd5bf3)
mstore(add(fmp, 0x26), 0x331460133611166022575f5ffd5b60143603)
mstore(add(fmp, 0x14), address())
mstore(add(fmp, 0), 0x60475f8160095f39f373)
mstore(add(fmp, 0x00), 0x60475f8160095f39f373)
let initcodehash := keccak256(add(fmp, 0x16), 0x50)

// compute create2 address
Expand All @@ -120,7 +120,7 @@ library RelayedCall {
// is relayer not yet deployed, deploy it
if iszero(extcodesize(relayer)) {
if iszero(create2(0, add(fmp, 0x16), 0x50, salt)) {
returndatacopy(fmp, 0, returndatasize())
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
}
Expand Down
8 changes: 4 additions & 4 deletions contracts/utils/ShortStrings.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ library ShortStrings {
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
if (bstr.length > 0x1f) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
Expand All @@ -63,7 +63,7 @@ library ShortStrings {
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
string memory str = new string(0x20);
assembly ("memory-safe") {
mstore(str, len)
mstore(add(str, 0x20), sstr)
Expand All @@ -76,7 +76,7 @@ library ShortStrings {
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
if (result > 0x1f) {
revert InvalidShortString();
}
return result;
Expand All @@ -86,7 +86,7 @@ library ShortStrings {
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
if (bytes(value).length < 0x20) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
Expand Down
2 changes: 1 addition & 1 deletion contracts/utils/cryptography/SignatureChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ library SignatureChecker {
mstore(add(ptr, 0x24), 0x40)
mcopy(add(ptr, 0x44), signature, add(length, 0x20))

let success := staticcall(gas(), signer, ptr, add(length, 0x64), 0, 0x20)
let success := staticcall(gas(), signer, ptr, add(length, 0x64), 0x00, 0x20)
result := and(success, and(gt(returndatasize(), 0x19), eq(mload(0x00), selector)))
}
}
Expand Down
16 changes: 8 additions & 8 deletions contracts/utils/structs/Checkpoints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ library Checkpoints {
uint256 pos
) private pure returns (Checkpoint256 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), mul(pos, 2))
mstore(0x00, self.slot)
result.slot := add(keccak256(0x00, 0x20), mul(pos, 2))
}
}

Expand Down Expand Up @@ -420,8 +420,8 @@ library Checkpoints {
uint256 pos
) private pure returns (Checkpoint224 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
mstore(0x00, self.slot)
result.slot := add(keccak256(0x00, 0x20), pos)
}
}

Expand Down Expand Up @@ -623,8 +623,8 @@ library Checkpoints {
uint256 pos
) private pure returns (Checkpoint208 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
mstore(0x00, self.slot)
result.slot := add(keccak256(0x00, 0x20), pos)
}
}

Expand Down Expand Up @@ -826,8 +826,8 @@ library Checkpoints {
uint256 pos
) private pure returns (Checkpoint160 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
mstore(0x00, self.slot)
result.slot := add(keccak256(0x00, 0x20), pos)
}
}
}
Loading