Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
Next Next commit
add a TranscientStorage library, and a transcient variant of Reentran…
…cyGuard
  • Loading branch information
Amxx committed Mar 13, 2024
commit 747bd76d8738faf98778d88891ab2513c45f6801
50 changes: 50 additions & 0 deletions contracts/mocks/TranscientReentrancyMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {TranscientReentrancyGuard} from "../utils/TranscientReentrancyGuard.sol";
import {ReentrancyAttack} from "./ReentrancyAttack.sol";

contract TranscientReentrancyMock is TranscientReentrancyGuard {
uint256 public counter;

constructor() {
counter = 0;
}

function callback() external nonReentrant {
_count();
}

function countLocalRecursive(uint256 n) public nonReentrant {
if (n > 0) {
_count();
countLocalRecursive(n - 1);
}
}

function countThisRecursive(uint256 n) public nonReentrant {
if (n > 0) {
_count();
(bool success, ) = address(this).call(abi.encodeCall(this.countThisRecursive, (n - 1)));
require(success, "ReentrancyMock: failed call");
}
}

function countAndCall(ReentrancyAttack attacker) public nonReentrant {
_count();
attacker.callSender(abi.encodeCall(this.callback, ()));
}

function _count() private {
counter += 1;
}

function guardedCheckEntered() public nonReentrant {
require(_reentrancyGuardEntered());
}

function unguardedCheckNotEntered() public view {
require(!_reentrancyGuardEntered());
}
}
55 changes: 55 additions & 0 deletions contracts/utils/TranscientReentrancyGuard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import { TranscientStorage } from "./TranscientStorage.sol";

/**
* @dev Variant of {ReentrancyGuard} that uses transcient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*/
abstract contract TranscientReentrancyGuard {
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();

/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}

function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}

// Any calls to nonReentrant after this point will fail
TranscientStorage.store(ReentrancyGuardStorageLocation, true);
}

function _nonReentrantAfter() private {
TranscientStorage.store(ReentrancyGuardStorageLocation, false);
}

/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return TranscientStorage.loadBool(ReentrancyGuardStorageLocation);
}
}
91 changes: 91 additions & 0 deletions contracts/utils/TranscientStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/TranscientStorage.js.

pragma solidity ^0.8.24;

/**
* @dev Library for reading and setting transcient storage.
*
* Note: This library only works on networks where EIP-1153 is available.
*/
library TranscientStorage {
/**
* @dev Returns the transcient slot `slot` as a `address`.
*/
function loadAddress(bytes32 slot) internal view returns (address r) {
/// @solidity memory-safe-assembly
assembly {
r := tload(slot)
}
}

/**
* @dev Returns the transcient slot `slot` as a `bool`.
*/
function loadBool(bytes32 slot) internal view returns (bool r) {
/// @solidity memory-safe-assembly
assembly {
r := tload(slot)
}
}

/**
* @dev Returns the transcient slot `slot` as a `bytes32`.
*/
function loadBytes32(bytes32 slot) internal view returns (bytes32 r) {
/// @solidity memory-safe-assembly
assembly {
r := tload(slot)
}
}

/**
* @dev Returns the transcient slot `slot` as a `uint256`.
*/
function loadUint256(bytes32 slot) internal view returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := tload(slot)
}
}

/**
* @dev Store `value` in the transcient slot `store`.
*/
function store(bytes32 slot, address value) internal {
/// @solidity memory-safe-assembly
assembly {
tstore(slot, value)
}
}

/**
* @dev Store `value` in the transcient slot `store`.
*/
function store(bytes32 slot, bool value) internal {
/// @solidity memory-safe-assembly
assembly {
tstore(slot, value)
}
}

/**
* @dev Store `value` in the transcient slot `store`.
*/
function store(bytes32 slot, bytes32 value) internal {
/// @solidity memory-safe-assembly
assembly {
tstore(slot, value)
}
}

/**
* @dev Store `value` in the transcient slot `store`.
*/
function store(bytes32 slot, uint256 value) internal {
/// @solidity memory-safe-assembly
assembly {
tstore(slot, value)
}
}
}
10 changes: 9 additions & 1 deletion hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const { argv } = require('yargs/yargs')()
compiler: {
alias: 'compileVersion',
type: 'string',
default: '0.8.20',
default: '0.8.24',
},
src: {
alias: 'source',
Expand All @@ -36,6 +36,11 @@ const { argv } = require('yargs/yargs')()
type: 'boolean',
default: false,
},
evm: {
alias: 'evmVersion',
type: 'string',
default: 'cancun',
},
// Extra modules
coverage: {
type: 'boolean',
Expand Down Expand Up @@ -78,6 +83,7 @@ module.exports = {
enabled: withOptimizations,
runs: 200,
},
evmVersion: argv.evm,
viaIR: withOptimizations && argv.ir,
outputSelection: { '*': { '*': ['storageLayout'] } },
},
Expand All @@ -90,11 +96,13 @@ module.exports = {
'*': {
'code-size': withOptimizations,
'unused-param': !argv.coverage, // coverage causes unused-param warnings
2394: false, // 'transcient-storage'
default: 'error',
},
},
networks: {
hardhat: {
hardfork: argv.evm,
allowUnlimitedContractSize,
initialBaseFeePerGas: argv.coverage ? 0 : undefined,
},
Expand Down
Loading