diff --git a/src/Gatekeeper.sol b/src/Gatekeeper.sol index 285a15b..049a54b 100644 --- a/src/Gatekeeper.sol +++ b/src/Gatekeeper.sol @@ -22,15 +22,17 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard { using GovernancePacking for GovernancePacking.GovernancePayload; uint256 public constant BOUNTY_DIVISOR = type(uint32).max; - uint256 public constant MAX_ALLOWED_GAS_PRICE = 3e9; // 3 gwei - uint256 public constant EXISTENTIAL_DEPOSIT = 500 * 1e12; - uint256 public constant GAS_EXECUTION_BUFFER = 33805; + uint256 public constant EXISTENTIAL_DEPOSIT = 500 * 1e12; // 0.005 + uint256 public constant FULL_GAS_RESTORATION_TIME = 3600; // 1 hour + uint256 public constant MAX_ALLOWED_GAS_PRICE = 3e9; // 3 gwei + uint256 public constant GAS_EXECUTION_BUFFER = 21000 + 5969 + 50955; uint256 public constant REGISTRY_INDEX = 0; address public override staking; address public override deployer; address public override storageHistory; + uint256 private _lastVerificationTime; address private _previousAddress; bool private _initialized; @@ -109,6 +111,16 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard { return (publicKey, state.parity, state.session); } + function getCurrentGasPrice() public view returns (uint256) { + uint256 timePassed = block.timestamp - _lastVerificationTime; + + if (timePassed >= FULL_GAS_RESTORATION_TIME) { + return MAX_ALLOWED_GAS_PRICE; + } + + return FullMath.mulDiv(MAX_ALLOWED_GAS_PRICE, timePassed, FULL_GAS_RESTORATION_TIME); + } + function ghost(bytes32 receiver, uint256 amount) external override { if (msg.sender != staking) revert NotStaking(); if (amount < EXISTENTIAL_DEPOSIT) revert NonExistentAmount(); @@ -121,25 +133,24 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard { bytes calldata call, uint256 rx, uint256 s - ) external nonReentrant returns (bytes memory) { + ) external nonReentrant { uint256 gasStart = gasleft(); uint256 px = _extractPublicKey(call); bool validSignature = Verifier.verifyGhost(call, px, rx, s); if (!validSignature) revert BadSignature(); - (bool success, bytes memory data) = address(this).call(call); + (bool success,) = address(this).call(call); if (!success) revert ExecutionReverted(); - uint256 gasPrice = MAX_ALLOWED_GAS_PRICE < tx.gasprice ? MAX_ALLOWED_GAS_PRICE : tx.gasprice; - uint256 gasSpent = (gasStart - gasleft() + GAS_EXECUTION_BUFFER) * gasPrice; + uint256 currentGasPrice = getCurrentGasPrice(); + _lastVerificationTime = block.timestamp; + uint256 gasSpent = (gasStart - gasleft() + GAS_EXECUTION_BUFFER) * currentGasPrice; try IStaking(staking).phantomRefund(msg.sender, gasSpent, REGISTRY_INDEX) {} catch { emit VoluntaryVerification(msg.sender, gasSpent); } - - return data; } function recall( @@ -192,7 +203,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard { function govern( uint256 exodusSession, uint256 packed, - bytes calldata + bytes calldata call ) external { if (msg.sender != address(this)) revert NotGatekeeper(); @@ -201,7 +212,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard { StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession); - (bool success,) = payload.target.call(msg.data[132:]); + (bool success,) = payload.target.call(call); if (!success) revert ExecutionReverted(); } diff --git a/test/gatekeeper/GatekeeperRecall.t.sol b/test/gatekeeper/GatekeeperRecall.t.sol index a48083e..3c1dbad 100644 --- a/test/gatekeeper/GatekeeperRecall.t.sol +++ b/test/gatekeeper/GatekeeperRecall.t.sol @@ -92,6 +92,64 @@ contract GatekeeperRecallTest is Test { vm.stopPrank(); } + function test_gasPriceCorrectDuringRecall() public { + vm.startPrank(INITIALIZER); + Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper())); + gatekeeper.updatePublicKeyMetadata(0, 0xb5cd0d028a5e1b6a4eecb113b7e49c8176385eb77c8f134bc1db4bddd7654de6, 0); + vm.stopPrank(); + + vm.startPrank(ALICE); + uint256 aliceBalance = ftso.balanceOf(ALICE); + ftso.approve(address(staking), type(uint256).max); + staking.stake(aliceBalance, ALICE, false, true); + + uint256 ghostBalance = ghst.balanceOf(ALICE); + staking.ghost(bytes32(abi.encodePacked(ALICE)), ghostBalance); + vm.stopPrank(); + + vm.warp(block.timestamp + gatekeeper.FULL_GAS_RESTORATION_TIME() * 69); + + uint256 bobBalanceBeforeFirst = ghst.balanceOf(BOB); + uint256 priceBeforeFirst = gatekeeper.getCurrentGasPrice(); + assertEq(priceBeforeFirst, gatekeeper.MAX_ALLOWED_GAS_PRICE()); + assertEq(ghst.balanceOf(BOB), 0); + + vm.prank(BOB, BOB); + gatekeeper.verify( + hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000017508f1956a800000000000000000000000000000000000000000020000000000007a6980000000", + 0x883302783b7f3d253d5bdeb17f39117641acdf061bf3fe457cb505df6b17dfc1, + 0x8c3fc03b5cb738777ceec396ee8647f782d6670992f8f973de2dfc83379978d5 + ); + + uint256 bobBalanceAfterFirst = ghst.balanceOf(BOB); + assertGt(bobBalanceAfterFirst, bobBalanceBeforeFirst); + assertEq(gatekeeper.getCurrentGasPrice(), 0); + + vm.prank(BOB, BOB); + gatekeeper.verify( + hex"3137142600000000000000000000000000000000000000000000000000000000000000120000000000007a69010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000042b7ce50000000000000000000000000000000000000000000000000000000000", + 0xf1f4d62d27c3d0388b2298b621b23cd5791e1b97d4423ffc16b14e81ff0df97c, + 0xdbeed3eb94a829710147595c1b10f2ac6ec761c9721d8cc4711842c212ac517e + ); + + assertEq(ghst.balanceOf(BOB), bobBalanceAfterFirst); + assertEq(gatekeeper.getCurrentGasPrice(), 0); + + vm.warp(block.timestamp + gatekeeper.FULL_GAS_RESTORATION_TIME() / 2); + uint256 gasPriceRestored = gatekeeper.getCurrentGasPrice(); + assertEq(gasPriceRestored, gatekeeper.MAX_ALLOWED_GAS_PRICE() / 2); + + vm.prank(BOB, BOB); + gatekeeper.verify( + hex"31371426000000000000000000000000000000000000000000000000000000000000000d0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064e4e33ef800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000101010101010101010101010101010101010101000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000", + 0x0716f763060cfd52339544a203d0e156a42370b0e22d78ea9bf8766b0b66682b, + 0xc2da93948f869c5102992bd1cbd70ef5f821ff522305c69d113faf2e89570ce7 + ); + + assertGt(ghst.balanceOf(BOB), bobBalanceAfterFirst); + assertEq(gatekeeper.getCurrentGasPrice(), 0); + } + function test_recallChainWorks() public { vm.startPrank(INITIALIZER); Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper()));