diff --git a/README.md b/README.md index ac3e86c..1803a86 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,22 @@ A barebones implementation of a gasback contract that implements [RIP-7767](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7767.md). -## Suggested deployment for OP stack chains +## Suggested setup for OP stack chains + +### Requirements + +- The `baseFeeVault` is deployed at `0x4200000000000000000000000000000000000019`. +- The `WITHDRAWAL_NETWORK` of the `baseFeeVault` is set to `1`. + +### Via script + +See `script/Delegate7702.s.sol` for an automated script that can help you deploy. + +This script requires you to have the private key of the `baseFeeVault` recipient in your environment. + +For more information on how to run a foundry script, see `https://getfoundry.sh/guides/scripting-with-solidity`. + +### Manual steps 1. Deploy the `gasback` contract which will be used as an implementation via EIP-7702. @@ -13,7 +28,7 @@ A barebones implementation of a gasback contract that implements [RIP-7767](http `900000000000000000` - `setGasbackMaxBaseFee(uint256)` `115792089237316195423570985008687907853269984665640564039457584007913129639935` - - `setBaseFeeVault(address)` + - `setbaseFeeVault(address)` `0x4200000000000000000000000000000000000019` 4. Put or leave some ETH into the EOA `RECIPIENT`, which will be the actual `gasback` contract. diff --git a/lib/forge-std b/lib/forge-std index 1714bee..77041d2 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 1714bee72e286e73f76e320d110e0eaf5c4e649d +Subproject commit 77041d2ce690e692d6e03cc812b57d1ddaa4d505 diff --git a/script/Delegate7702.s.sol b/script/Delegate7702.s.sol new file mode 100644 index 0000000..3e1feeb --- /dev/null +++ b/script/Delegate7702.s.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {Script} from "forge-std/Script.sol"; +import "../src/Gasback.sol"; + +contract Delegate7702Script is Script { + function run() external { + uint256 privateKey = uint256(vm.envBytes32("PRIVATE_KEY")); + + address gasbackImplementation = _deployWithNicks(type(Gasback).creationCode); + address deployer = vm.addr(privateKey); + + vm.signAndAttachDelegation(gasbackImplementation, privateKey); + bytes memory code = deployer.code; + require(code.length > 0, "Not delegation detected"); + + vm.startBroadcast(privateKey); + Gasback(payable(deployer)).setGasbackRatioNumerator(900000000000000000); + vm.stopBroadcast(); + + vm.startBroadcast(privateKey); + Gasback(payable(deployer)).setGasbackMaxBaseFee(type(uint256).max); + vm.stopBroadcast(); + + vm.startBroadcast(privateKey); + Gasback(payable(deployer)).setBaseFeeVault(0x4200000000000000000000000000000000000019); + vm.stopBroadcast(); + } + + /// @dev Returns the address deployed via Nick's factory with salt `bytes32(0)`. + /// If the contract has already been deployed, skips deploying it. + function _deployWithNicks(bytes memory code) internal returns (address) { + address nicks = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + address instance = _predictDeterministicAddress(keccak256(code), 0, nicks); + if (instance.code.length != 0) return instance; + (bool success,) = nicks.call(abi.encodePacked(bytes32(0), code)); + require(success && instance.code.length != 0, "Deployment via Nick's failed."); + return instance; + } + + /// @dev Returns the address when a contract with initialization code hash, + /// `hash`, is deployed with `salt`, by `deployer`. + /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly. + function _predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer) + internal + pure + returns (address predicted) + { + /// @solidity memory-safe-assembly + assembly { + // Compute and store the bytecode hash. + mstore8(0x00, 0xff) // Write the prefix. + mstore(0x35, hash) + mstore(0x01, shl(96, deployer)) + mstore(0x15, salt) + predicted := keccak256(0x00, 0x55) + mstore(0x35, 0) // Restore the overwritten part of the free memory pointer. + } + } +} diff --git a/src/Gasback.sol b/src/Gasback.sol index 4010381..6962189 100644 --- a/src/Gasback.sol +++ b/src/Gasback.sol @@ -77,27 +77,31 @@ contract Gasback { /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Withdraws ETH from this contract. - function withdraw(address to, uint256 amount) public onlySystemOrThis { + function withdraw(address to, uint256 amount) public onlySystemOrThis returns (bool) { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) { revert(0x00, 0x00) } } + return true; } /// @dev Sets the numerator for the gasback ratio. - function setGasbackRatioNumerator(uint256 value) public onlySystemOrThis { + function setGasbackRatioNumerator(uint256 value) public onlySystemOrThis returns (bool) { require(value <= GASBACK_RATIO_DENOMINATOR); _getGasbackStorage().gasbackRatioNumerator = value; + return true; } /// @dev Sets the max base fee. - function setGasbackMaxBaseFee(uint256 value) public onlySystemOrThis { + function setGasbackMaxBaseFee(uint256 value) public onlySystemOrThis returns (bool) { _getGasbackStorage().gasbackMaxBaseFee = value; + return true; } /// @dev Sets the base fee vault. - function setBaseFeeVault(address value) public onlySystemOrThis { + function setBaseFeeVault(address value) public onlySystemOrThis returns (bool) { _getGasbackStorage().baseFeeVault = value; + return true; } /// @dev Guards the function such that it can only be called either by