diff --git a/src/FraxTest.sol b/src/FraxTest.sol index 3216238..5cc8962 100644 --- a/src/FraxTest.sol +++ b/src/FraxTest.sol @@ -8,6 +8,7 @@ import { Strings } from "./StringsHelper.sol"; abstract contract FraxTest is VmHelper, Test { /// @notice Differential State Storage uint256[] internal snapShotIds; + uint256 currentSnapShotId; function()[] internal setupFunctions; /// @notice EIP-1967 Slots @@ -22,6 +23,7 @@ abstract contract FraxTest is VmHelper, Test { if (snapShotIds.length == 0) _; for (uint256 i = 0; i < snapShotIds.length; i++) { uint256 _originalSnapshotId = vm.snapshot(); + // currentSnapShotId = snapShotIds[i]; if (!vm.revertTo(snapShotIds[i])) { revert VmDidNotRevert(snapShotIds[i]); } diff --git a/src/FrxTransparentProxy.sol b/src/FrxTransparentProxy.sol new file mode 100644 index 0000000..5204f65 --- /dev/null +++ b/src/FrxTransparentProxy.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: ISC +pragma solidity >=0.8.0; + +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +// ==================================================================== +// | ______ _______ | +// | / _____________ __ __ / ____(_____ ____ _____ ________ | +// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | +// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | +// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | +// | | +// ==================================================================== +// ====================== FrxTransparentProxy ========================= +// ==================================================================== + +contract FrxTransparentProxy is TransparentUpgradeableProxy { + constructor( + address _logic, + address _initialAdmin, + bytes memory _data + ) TransparentUpgradeableProxy(_logic, _initialAdmin, _data) {} + + // ================================================================ + // ~~~~~~~~~~~~~~~~~~~~~~~~~~ Extension ~~~~~~~~~~~~~~~~~~~~~~~~~~ + // ================================================================ + + /// @notice Low level function to read arbitrary slots from the proxy + /// @param slot The slot to read + /// @return data The bytes32 data that is stored on that slot + /// @dev Ensure that `0x53e1edcb` does not result in selector clash on + /// The implementation contract + function readArbitrary(bytes32 slot) public view returns (bytes32 data) { + assembly { + data := sload(slot) + } + } + + /// @notice Silence compiler warnings + receive() external payable { + _fallback(); + } +} diff --git a/test/TestFrxProxy.t.sol b/test/TestFrxProxy.t.sol new file mode 100644 index 0000000..cf190f0 --- /dev/null +++ b/test/TestFrxProxy.t.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: ISC +pragma solidity >=0.8.0; + +import "../src/FraxTest.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { FrxTransparentProxy } from "src/FrxTransparentProxy.sol"; + +contract TestFrxTransparentProxy is FraxTest { + address instance; + FrxTransparentProxy frxUsdProxy; + IERC20 frxUsd; + + function setUp() public { + vm.createSelectFork("https://rpc.frax.com", 16_557_873); + vm.etch( + address(0xC2A4), /// The Unicode character 'ยค' encoded in UTF-8 and represented as hex + hex"11" + ); + instance = address(new FrxTransparentProxy(address(0xC2A4), address(0xC2A4), hex"")); + vm.etch(0xFc00000000000000000000000000000000000001, instance.code); + frxUsdProxy = FrxTransparentProxy(payable(0xFc00000000000000000000000000000000000001)); + frxUsd = IERC20(0xFc00000000000000000000000000000000000001); + } + + function testReadImplementationSlot() public { + bytes32 impl = frxUsdProxy.readArbitrary(IMPLEMENTATION_SLOT); + assertEq({ + a: address(uint160(uint256(impl))), + b: 0x00000aFb5e62fd81bC698E418dBfFE5094cB38E0, + err: "// THEN: Implementation not as expected" + }); + } + + function testReadAdminSlot() public { + bytes32 admin = frxUsdProxy.readArbitrary(ADMIN_SLOT); + console.logBytes32(admin); + assertEq({ + a: address(uint160(uint256(admin))), + b: 0xfC0000000000000000000000000000000000000a, + err: "// THEN: Admin not as expected" + }); + } + + function testReadBalanceData() public { + /// Derive the balance slot + bytes32 balanceSlot = keccak256(abi.encode(0x31562ae726AFEBe25417df01bEdC72EF489F45b3, 0)); + bytes32 balance = frxUsdProxy.readArbitrary(balanceSlot); + assertEq({ a: uint256(balance), b: 879.253786510845295473e18, err: "// THEN: balance not as expected" }); + } +} diff --git a/test/TestMultipleSetup.t.sol b/test/TestMultipleSetup.t.sol index c9f6a23..4a97794 100644 --- a/test/TestMultipleSetup.t.sol +++ b/test/TestMultipleSetup.t.sol @@ -4,7 +4,8 @@ pragma solidity >=0.8.0; import "../src/FraxTest.sol"; contract TestMultipleSetup is FraxTest { - uint256 value; + uint256 public value; + uint256 public runsPassed; function initializeValueOne() public { value = 25; @@ -23,9 +24,19 @@ contract TestMultipleSetup is FraxTest { setupFunctions.push(initializeValueTwo); setupFunctions.push(initializeValueThree); addSetupFunctions(setupFunctions); + vm.makePersistent(address(this)); } - function testFailAssertValue() public useMultipleSetupFunctions { - assertEq(value, 5); + function revertIfNotFive(uint256 value) public { + if (value != 5) revert(); + else revert("Run Passed"); + } + + /// @notice Should fail if value is not 5, should fail differently if + /// value == 5 + function testAssertValue() public useMultipleSetupFunctions { + if (value != 5) vm.expectRevert(); + else vm.expectRevert(bytes("Run Passed")); + this.revertIfNotFive(value); } }