From 19cef112cdabea8f95781c5f739215f42082284d Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:23:50 -0500 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=91=B7=20pay=20contract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/Pay.sol | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/utils/Pay.sol diff --git a/src/utils/Pay.sol b/src/utils/Pay.sol new file mode 100644 index 00000000..eddd25eb --- /dev/null +++ b/src/utils/Pay.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.27; + +import {IWETH} from "src/interfaces/tokens/IWETH.sol"; + +/// @notice Pay contract for unwrapping WETH and sending it to a recipient +/// @author cmontecoding +contract Pay { + + /// @notice WETH contract + IWETH public WETH; + + /// @notice thrown when a call to transfer eth fails + error ETHTransferFailed(); + + constructor(address _weth) { + WETH = IWETH(_weth); + } + + /// @notice unwrap WETH and send it to a recipient + /// @param amount amount of WETH to unwrap + /// @param to recipient address + function unwrapAndPay(uint amount, address to) public { + WETH.transferFrom(msg.sender, address(this), amount); + WETH.withdraw(amount); + (bool success, ) = to.call{value: amount}(""); + if (success != true) { + revert ETHTransferFailed(); + } + } + + receive() external payable {} + +} \ No newline at end of file From b8ba06037379ab0d90a5b3531e05874ad13a7beb Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:24:16 -0500 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=91=B7=20add=20pay=20to=20engine=20?= =?UTF-8?q?and=20remove=20receive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Engine.sol | 17 +++++++++-------- src/interfaces/IEngine.sol | 3 --- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Engine.sol b/src/Engine.sol index da9a3a5c..0f5ce6ac 100644 --- a/src/Engine.sol +++ b/src/Engine.sol @@ -14,6 +14,7 @@ import {IERC20} from "src/interfaces/tokens/IERC20.sol"; import {IWETH} from "src/interfaces/tokens/IWETH.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {MulticallablePayable} from "src/utils/MulticallablePayable.sol"; +import {Pay} from "src/utils/Pay.sol"; import {SignatureCheckerLib} from "src/libraries/SignatureCheckerLib.sol"; import {Zap} from "src/utils/zap/Zap.sol"; @@ -85,6 +86,9 @@ contract Engine is /// @notice Zap contract Zap internal immutable zap; + /// @notice Pay contract + Pay internal immutable pay; + IWETH public immutable WETH; IERC20 public immutable USDC; @@ -133,12 +137,13 @@ contract Engine is address _sUSDProxy, address _pDAO, address _zap, + address payable _pay, address _usdc, address _weth ) { if ( _perpsMarketProxy == address(0) || _spotMarketProxy == address(0) - || _sUSDProxy == address(0) || _zap == address(0) + || _sUSDProxy == address(0) || _zap == address(0) || _pay == address(0) || _usdc == address(0) || _weth == address(0) ) revert ZeroAddress(); @@ -147,6 +152,7 @@ contract Engine is SUSD = IERC20(_sUSDProxy); zap = Zap(_zap); + pay = Pay(_pay); USDC = IERC20(_usdc); WETH = IWETH(_weth); @@ -155,9 +161,6 @@ contract Engine is pDAO = _pDAO; } - /// @notice Allows the contract to receive ETH when unwrapping WETH - receive() external payable {} - /*////////////////////////////////////////////////////////////// UPGRADE MANAGEMENT //////////////////////////////////////////////////////////////*/ @@ -570,10 +573,8 @@ contract Engine is address(this) ); - // Convert WETH to ETH and send to user - WETH.withdraw(unwrappedWETH); - (bool result,) = msg.sender.call{value: unwrappedWETH}(""); - if (result != true) revert ETHTransferFailed(); + WETH.approve(address(pay), unwrappedWETH); + pay.unwrapAndPay(unwrappedWETH, msg.sender); } function _depositCollateral( diff --git a/src/interfaces/IEngine.sol b/src/interfaces/IEngine.sol index b96a3c5e..1323272e 100644 --- a/src/interfaces/IEngine.sol +++ b/src/interfaces/IEngine.sol @@ -128,9 +128,6 @@ interface IEngine { /// and msg.value is less than specified amount error InsufficientETHDeposit(uint256 sent, uint256 required); - /// @notice thrown when a call to transfer eth fails - error ETHTransferFailed(); - /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ From 19e7c074d65f2946acaeee0b465c09b93099a414 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:25:48 -0500 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9C=85=20pay=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Pay.t.sol | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 test/Pay.t.sol diff --git a/test/Pay.t.sol b/test/Pay.t.sol new file mode 100644 index 00000000..84005be2 --- /dev/null +++ b/test/Pay.t.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.27; + +import {Bootstrap} from "test/utils/Bootstrap.sol"; +import {Pay} from "src/utils/Pay.sol"; +import {IWETH} from "src/interfaces/tokens/IWETH.sol"; + +contract PayTest is Bootstrap { + + Pay payLocal; + Pay payFork; + IWETH wethWrapped; + + function setUp() public { + vm.rollFork(BASE_BLOCK_NUMBER); + initializeBase(); + + wethWrapped = IWETH(weth); + payLocal = new Pay(weth); + payFork = Pay(pay); + } + + function test_unwrapAndPay_local() public { + uint amount = 100; + address to = address(1); + uint256 balanceBefore = to.balance; + + // setup + vm.deal(address(this), amount); + wethWrapped.deposit{value: amount}(); + wethWrapped.approve(address(payLocal), amount); + + // unwrap + payLocal.unwrapAndPay(amount, to); + assertEq(to.balance, balanceBefore + amount); + } + + function test_unwrapAndPay_local_fuzz(uint128 amount) public { + address to = address(1); + uint256 balanceBefore = to.balance; + + // setup + vm.deal(address(this), amount); + wethWrapped.deposit{value: amount}(); + wethWrapped.approve(address(payLocal), amount); + + // unwrap + payLocal.unwrapAndPay(amount, to); + assertEq(to.balance, balanceBefore + amount); + } + + function test_unwrapAndPay_withMaliciousReceiver() public { + uint amount = 100; + MaliciousReceiver maliciousReceiver = new MaliciousReceiver(); + address to = address(maliciousReceiver); + + // setup + vm.deal(address(this), amount); + wethWrapped.deposit{value: amount}(); + wethWrapped.approve(address(payLocal), amount); + + // Expect the ETHTransferFailed error + vm.expectRevert(Pay.ETHTransferFailed.selector); + payLocal.unwrapAndPay(amount, to); + } + + function test_unwrapAndPay_fork() public { + uint amount = 100; + address to = address(1); + uint256 balanceBefore = to.balance; + + // setup + vm.deal(address(this), amount); + wethWrapped.deposit{value: amount}(); + wethWrapped.approve(address(payFork), amount); + + // unwrap + payFork.unwrapAndPay(amount, to); + assertEq(to.balance, balanceBefore + amount); + } + + function test_unwrapAndPay_fork_fuzz(uint128 amount) public { + address to = address(1); + uint256 balanceBefore = to.balance; + + // setup + vm.deal(address(this), amount); + wethWrapped.deposit{value: amount}(); + wethWrapped.approve(address(payFork), amount); + + // unwrap + payFork.unwrapAndPay(amount, to); + assertEq(to.balance, balanceBefore + amount); + } + +} + +// Helper contract that rejects ETH transfers +contract MaliciousReceiver { + receive() external payable { + revert(); + } + + function onERC721Received(address, address, uint256, bytes calldata) + external + pure + returns (bytes4) + { + return 0x150b7a02; + } +} \ No newline at end of file From ccb1eb0d2d001dea69f30501465dc1f44b831158 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:26:19 -0500 Subject: [PATCH 04/14] =?UTF-8?q?=E2=9C=85=20update=20oracle=20test=20to?= =?UTF-8?q?=20revert=20again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/EIP7412.t.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/EIP7412.t.sol b/test/EIP7412.t.sol index 00ec279e..aeb6e645 100644 --- a/test/EIP7412.t.sol +++ b/test/EIP7412.t.sol @@ -44,12 +44,14 @@ contract FulfillOracleQuery is EIP7412Test { { uint256 preBalance = address(this).balance; + // refunds are not supported + vm.expectRevert("EIP7412MockRefund"); + engine.fulfillOracleQuery{value: AMOUNT}( payable(address(eip7412MockRefund)), signedOffchainData ); - assert(address(this).balance == preBalance - AMOUNT); - assert(address(engine).balance == AMOUNT); + assert(address(this).balance == preBalance); } function test_fulfillOracleQuery_revert(bytes calldata signedOffchainData) From 781e34c7cefbfd78b240ed8a52a0172e768c6cdf Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:27:15 -0500 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=9A=80=20add=20pay=20to=20deploy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/Deploy.s.sol | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 9a837ff5..fe2f810d 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -8,6 +8,7 @@ import {MulticallerWithSender} from "src/utils/MulticallerWithSender.sol"; import {BaseParameters} from "script/utils/parameters/BaseParameters.sol"; import {BaseSepoliaParameters} from "script/utils/parameters/BaseSepoliaParameters.sol"; +import {Pay} from "src/utils/Pay.sol"; // forge utils import {Script} from "lib/forge-std/src/Script.sol"; @@ -21,6 +22,7 @@ contract Setup is Script { address sUSDProxy, address pDAO, address zap, + address payable pay, address usdc, address weth ) public returns (Engine engine) { @@ -30,6 +32,7 @@ contract Setup is Script { _sUSDProxy: sUSDProxy, _pDAO: pDAO, _zap: zap, + _pay: pay, _usdc: usdc, _weth: weth }); @@ -56,6 +59,7 @@ contract DeployBase is Setup, BaseParameters { sUSDProxy: USD_PROXY_ANDROMEDA, pDAO: PDAO, zap: ZAP, + pay: PAY, usdc: USDC, weth: WETH }); @@ -78,6 +82,7 @@ contract DeployBaseSepolia is Setup, BaseSepoliaParameters { sUSDProxy: USD_PROXY_ANDROMEDA, pDAO: PDAO, zap: ZAP, + pay: PAY, usdc: USDC, weth: WETH }); @@ -99,3 +104,17 @@ contract DeployMulticallBase is Setup, BaseParameters { vm.stopBroadcast(); } } + +/// @dev steps to deploy and verify on Base: +/// (1) load the variables in the .env file via `source .env` +/// (2) run `forge script script/Deploy.s.sol:DeployPay --rpc-url $BASE_RPC_URL --etherscan-api-key $BASESCAN_API_KEY --broadcast --verify -vvvv` +contract DeployPay is Setup, BaseParameters { + function run() public { + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(privateKey); + + new Pay(WETH); + + vm.stopBroadcast(); + } +} From a4f0628f33632e0048ba206b1b55a58903fe5b5d Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:27:50 -0500 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=9A=80=20deploy=20pay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/utils/parameters/BaseParameters.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/utils/parameters/BaseParameters.sol b/script/utils/parameters/BaseParameters.sol index b4a5af16..ae5da26f 100644 --- a/script/utils/parameters/BaseParameters.sol +++ b/script/utils/parameters/BaseParameters.sol @@ -33,6 +33,8 @@ contract BaseParameters { address public constant ZAP = 0x84f531d85fAA7Be42f8a248B87e40f760e558F7C; + address payable public constant PAY = payable(0xdFdDC95c4997f8CE09c412d53378E2101b400609); + address public constant USDT = address(0); address public constant CBBTC = 0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf; From e9bcad06e16ea6d71af473ffb1454c09e65927d9 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:28:40 -0500 Subject: [PATCH 07/14] =?UTF-8?q?=E2=9C=85=20remove=20payable=20from=20boo?= =?UTF-8?q?tstrap=20and=20update=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/Upgrade.s.sol | 4 ++++ .../parameters/BaseSepoliaParameters.sol | 2 ++ test/Collateral.t.sol | 7 +++--- test/Deployment.t.sol | 23 +++++++++++++++++++ test/Upgrade.t.sol | 2 ++ test/utils/Bootstrap.sol | 19 ++++++++++----- test/utils/Constants.sol | 10 ++++---- test/utils/exposed/EngineExposed.sol | 2 ++ test/utils/mocks/MockEngineUpgrade.sol | 2 ++ 9 files changed, 55 insertions(+), 16 deletions(-) diff --git a/script/Upgrade.s.sol b/script/Upgrade.s.sol index d1950723..4aec8eac 100644 --- a/script/Upgrade.s.sol +++ b/script/Upgrade.s.sol @@ -22,6 +22,7 @@ contract Setup is Script { address sUSDProxy, address pDAO, address zap, + address payable pay, address usdc, address weth ) public returns (Engine engine) { @@ -31,6 +32,7 @@ contract Setup is Script { _sUSDProxy: sUSDProxy, _pDAO: pDAO, _zap: zap, + _pay: pay, _usdc: usdc, _weth: weth }); @@ -51,6 +53,7 @@ contract DeployBase is Setup, BaseParameters { sUSDProxy: USD_PROXY_ANDROMEDA, pDAO: PDAO, zap: ZAP, + pay: PAY, usdc: USDC, weth: WETH }); @@ -73,6 +76,7 @@ contract DeployBaseSepolia is Setup, BaseSepoliaParameters { sUSDProxy: USD_PROXY_ANDROMEDA, pDAO: PDAO, zap: ZAP, + pay: PAY, usdc: USDC, weth: WETH }); diff --git a/script/utils/parameters/BaseSepoliaParameters.sol b/script/utils/parameters/BaseSepoliaParameters.sol index 4fe1e5c9..1e50e11b 100644 --- a/script/utils/parameters/BaseSepoliaParameters.sol +++ b/script/utils/parameters/BaseSepoliaParameters.sol @@ -32,4 +32,6 @@ contract BaseSepoliaParameters { uint128 public constant SUSDC_SPOT_MARKET_ID = 1; address public constant ZAP = 0xC9aF789Ae606F69cF8Ed073A04eC92f2354b027d; + + address payable public constant PAY = payable(address(0)); } diff --git a/test/Collateral.t.sol b/test/Collateral.t.sol index 08e1520d..2f812962 100644 --- a/test/Collateral.t.sol +++ b/test/Collateral.t.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.27; import {IEngine} from "src/interfaces/IEngine.sol"; import {Bootstrap} from "test/utils/Bootstrap.sol"; +import {Pay} from "src/utils/Pay.sol"; contract CollateralTest is Bootstrap { function setUp() public { @@ -638,9 +639,7 @@ contract WithdrawCollateral is CollateralTest { _tolerance: SMALLER_AMOUNT }); - vm.expectRevert( - abi.encodeWithSelector(IEngine.ETHTransferFailed.selector) - ); + vm.expectRevert(); engine.withdrawCollateralETH({ _accountId: accountId, @@ -654,7 +653,7 @@ contract WithdrawCollateral is CollateralTest { // Helper contract that rejects ETH transfers contract MaliciousReceiver { receive() external payable { - revert("I reject ETH"); + revert(); } function onERC721Received(address, address, uint256, bytes calldata) diff --git a/test/Deployment.t.sol b/test/Deployment.t.sol index e03a2cb3..1a7dd489 100644 --- a/test/Deployment.t.sol +++ b/test/Deployment.t.sol @@ -19,6 +19,7 @@ contract DeploymentTest is Test, Setup { address internal sUSDC = address(0x6); address internal zap = address(0x7); address internal weth = address(0x8); + address payable internal pay = payable(address(0x9)); /// keccak256(abi.encodePacked("Synthetic USD Coin Spot Market")) bytes32 internal constant _HASHED_SUSDC_NAME = @@ -42,6 +43,7 @@ contract DeploymentTest is Test, Setup { sUSDProxy: sUSDProxy, pDAO: pDAO, zap: zap, + pay: pay, usdc: usdc, weth: weth }); @@ -56,6 +58,7 @@ contract DeploymentTest is Test, Setup { sUSDProxy: sUSDProxy, pDAO: pDAO, zap: zap, + pay: pay, usdc: usdc, weth: weth }) {} catch (bytes memory reason) { @@ -70,6 +73,7 @@ contract DeploymentTest is Test, Setup { sUSDProxy: sUSDProxy, pDAO: pDAO, zap: zap, + pay: pay, usdc: usdc, weth: weth }) {} catch (bytes memory reason) { @@ -84,6 +88,7 @@ contract DeploymentTest is Test, Setup { sUSDProxy: address(0), pDAO: pDAO, zap: zap, + pay: pay, usdc: usdc, weth: weth }) {} catch (bytes memory reason) { @@ -98,6 +103,22 @@ contract DeploymentTest is Test, Setup { sUSDProxy: sUSDProxy, pDAO: pDAO, zap: address(0), + pay: pay, + usdc: usdc, + weth: weth + }) {} catch (bytes memory reason) { + assertEq(bytes4(reason), IEngine.ZeroAddress.selector); + } + } + + function test_deploy_pay_zero_address() public { + try setup.deploySystem({ + perpsMarketProxy: perpsMarketProxy, + spotMarketProxy: spotMarketProxy, + sUSDProxy: sUSDProxy, + pDAO: pDAO, + zap: zap, + pay: payable(address(0)), usdc: usdc, weth: weth }) {} catch (bytes memory reason) { @@ -112,6 +133,7 @@ contract DeploymentTest is Test, Setup { sUSDProxy: sUSDProxy, pDAO: pDAO, zap: zap, + pay: pay, usdc: address(0), weth: weth }) {} catch (bytes memory reason) { @@ -126,6 +148,7 @@ contract DeploymentTest is Test, Setup { sUSDProxy: sUSDProxy, pDAO: pDAO, zap: zap, + pay: pay, usdc: usdc, weth: address(0) }) {} catch (bytes memory reason) { diff --git a/test/Upgrade.t.sol b/test/Upgrade.t.sol index d36bf8fd..630c376a 100644 --- a/test/Upgrade.t.sol +++ b/test/Upgrade.t.sol @@ -41,6 +41,7 @@ contract MockUpgrade is UpgradeTest { address(sUSD), address(pDAO), address(zap), + payable(address(pay)), address(USDC), address(WETH) ); @@ -158,6 +159,7 @@ contract RemoveUpgradability is UpgradeTest { address(sUSD), address(0), // set pDAO to zero address to effectively remove upgradability address(zap), + payable(address(pay)), address(USDC), address(WETH) ); diff --git a/test/utils/Bootstrap.sol b/test/utils/Bootstrap.sol index 2377111b..a6f64431 100644 --- a/test/utils/Bootstrap.sol +++ b/test/utils/Bootstrap.sol @@ -63,6 +63,7 @@ contract Bootstrap is IERC20 public cbBTC; IERC20 public USDe; address public zap; + address payable public pay; address public usdc; address public weth; @@ -75,13 +76,14 @@ contract Bootstrap is function initializeBase() public { BootstrapBase bootstrap = new BootstrapBase(); ( - address payable _engineAddress, - address payable _engineExposedAddress, + address _engineAddress, + address _engineExposedAddress, address _perpsMarketProxyAddress, address _spotMarketProxyAddress, address _sUSDAddress, address _pDAOAddress, address _zapAddress, + address payable _payAddress, address _usdcAddress, address _wethAddress, address _usdtAddress, @@ -102,6 +104,7 @@ contract Bootstrap is synthMinter = new SynthMinter(_sUSDAddress, _spotMarketProxyAddress); pDAO = _pDAOAddress; zap = _zapAddress; + pay = _payAddress; usdc = _usdcAddress; weth = _wethAddress; @@ -128,8 +131,6 @@ contract BootstrapBase is Setup, BaseParameters { function init() public returns ( - address payable, - address payable, address, address, address, @@ -137,6 +138,9 @@ contract BootstrapBase is Setup, BaseParameters { address, address, address, + address payable, + address, + address, address, address, address @@ -148,6 +152,7 @@ contract BootstrapBase is Setup, BaseParameters { sUSDProxy: USD_PROXY_ANDROMEDA, pDAO: PDAO, zap: ZAP, + pay: PAY, usdc: USDC, weth: WETH }); @@ -158,18 +163,20 @@ contract BootstrapBase is Setup, BaseParameters { _sUSDProxy: USD_PROXY_ANDROMEDA, _pDAO: PDAO, _zap: ZAP, + _pay: PAY, _usdc: USDC, _weth: WETH }); return ( - payable(address(engine)), - payable(address(engineExposed)), + address(engine), + address(engineExposed), PERPS_MARKET_PROXY_ANDROMEDA, SPOT_MARKET_PROXY_ANDROMEDA, USD_PROXY_ANDROMEDA, PDAO, ZAP, + PAY, USDC, WETH, USDT, diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 4ad57837..61a36496 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -4,10 +4,8 @@ pragma solidity 0.8.27; /// @title Contract for defining constants used in testing /// @author JaredBorders (jaredborders@pm.me) contract Constants { - // /// @dev Dec-10-2024 09:34:19 PM +UTC - // uint256 public constant BASE_BLOCK_NUMBER = 23_538_556; - // - uint256 public constant BASE_BLOCK_NUMBER = 23_579_166; + /// @dev Dec-13-2024 02:32:19 AM +UTC + uint256 public constant BASE_BLOCK_NUMBER = 23_633_896; address internal constant OWNER = address(0x01); @@ -60,8 +58,8 @@ contract Constants { uint128 constant CBBTC_SYNTH_MARKET_ID = 4; - /// @dev this is the ETH price in USD at the block number 23_538_556 - uint256 internal constant ETH_PRICE = 3630; + /// @dev this is the ETH price in USD at the block number 23_633_896 + uint256 internal constant ETH_PRICE = 3880; uint256 internal constant AMOUNT = 10_000 ether; diff --git a/test/utils/exposed/EngineExposed.sol b/test/utils/exposed/EngineExposed.sol index 29c056d9..95974813 100644 --- a/test/utils/exposed/EngineExposed.sol +++ b/test/utils/exposed/EngineExposed.sol @@ -12,6 +12,7 @@ contract EngineExposed is Engine { address _sUSDProxy, address _pDAO, address _zap, + address payable _pay, address _usdc, address _weth ) @@ -21,6 +22,7 @@ contract EngineExposed is Engine { _sUSDProxy, _pDAO, _zap, + _pay, _usdc, _weth ) diff --git a/test/utils/mocks/MockEngineUpgrade.sol b/test/utils/mocks/MockEngineUpgrade.sol index ef6295fb..86efda93 100644 --- a/test/utils/mocks/MockEngineUpgrade.sol +++ b/test/utils/mocks/MockEngineUpgrade.sol @@ -12,6 +12,7 @@ contract MockEngineUpgrade is Engine { address _sUSDProxy, address _pDAO, address _zap, + address payable _pay, address _usdc, address _weth ) @@ -21,6 +22,7 @@ contract MockEngineUpgrade is Engine { _sUSDProxy, _pDAO, _zap, + _pay, _usdc, _weth ) From 9bd965cfaa3eb36adf4afa767c49f34800d63721 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Thu, 12 Dec 2024 23:36:55 -0500 Subject: [PATCH 08/14] =?UTF-8?q?=E2=9C=A8=20fmt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/utils/parameters/BaseParameters.sol | 3 ++- src/Engine.sol | 4 ++-- src/utils/Pay.sol | 8 +++----- test/Pay.t.sol | 10 ++++------ 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/script/utils/parameters/BaseParameters.sol b/script/utils/parameters/BaseParameters.sol index ae5da26f..06802a6a 100644 --- a/script/utils/parameters/BaseParameters.sol +++ b/script/utils/parameters/BaseParameters.sol @@ -33,7 +33,8 @@ contract BaseParameters { address public constant ZAP = 0x84f531d85fAA7Be42f8a248B87e40f760e558F7C; - address payable public constant PAY = payable(0xdFdDC95c4997f8CE09c412d53378E2101b400609); + address payable public constant PAY = + payable(0xdFdDC95c4997f8CE09c412d53378E2101b400609); address public constant USDT = address(0); diff --git a/src/Engine.sol b/src/Engine.sol index 0f5ce6ac..b133dd27 100644 --- a/src/Engine.sol +++ b/src/Engine.sol @@ -143,8 +143,8 @@ contract Engine is ) { if ( _perpsMarketProxy == address(0) || _spotMarketProxy == address(0) - || _sUSDProxy == address(0) || _zap == address(0) || _pay == address(0) - || _usdc == address(0) || _weth == address(0) + || _sUSDProxy == address(0) || _zap == address(0) + || _pay == address(0) || _usdc == address(0) || _weth == address(0) ) revert ZeroAddress(); PERPS_MARKET_PROXY = IPerpsMarketProxy(_perpsMarketProxy); diff --git a/src/utils/Pay.sol b/src/utils/Pay.sol index eddd25eb..2ed11a8c 100644 --- a/src/utils/Pay.sol +++ b/src/utils/Pay.sol @@ -6,7 +6,6 @@ import {IWETH} from "src/interfaces/tokens/IWETH.sol"; /// @notice Pay contract for unwrapping WETH and sending it to a recipient /// @author cmontecoding contract Pay { - /// @notice WETH contract IWETH public WETH; @@ -20,15 +19,14 @@ contract Pay { /// @notice unwrap WETH and send it to a recipient /// @param amount amount of WETH to unwrap /// @param to recipient address - function unwrapAndPay(uint amount, address to) public { + function unwrapAndPay(uint256 amount, address to) public { WETH.transferFrom(msg.sender, address(this), amount); WETH.withdraw(amount); - (bool success, ) = to.call{value: amount}(""); + (bool success,) = to.call{value: amount}(""); if (success != true) { revert ETHTransferFailed(); } } receive() external payable {} - -} \ No newline at end of file +} diff --git a/test/Pay.t.sol b/test/Pay.t.sol index 84005be2..80c6b180 100644 --- a/test/Pay.t.sol +++ b/test/Pay.t.sol @@ -6,7 +6,6 @@ import {Pay} from "src/utils/Pay.sol"; import {IWETH} from "src/interfaces/tokens/IWETH.sol"; contract PayTest is Bootstrap { - Pay payLocal; Pay payFork; IWETH wethWrapped; @@ -21,7 +20,7 @@ contract PayTest is Bootstrap { } function test_unwrapAndPay_local() public { - uint amount = 100; + uint256 amount = 100; address to = address(1); uint256 balanceBefore = to.balance; @@ -50,7 +49,7 @@ contract PayTest is Bootstrap { } function test_unwrapAndPay_withMaliciousReceiver() public { - uint amount = 100; + uint256 amount = 100; MaliciousReceiver maliciousReceiver = new MaliciousReceiver(); address to = address(maliciousReceiver); @@ -65,7 +64,7 @@ contract PayTest is Bootstrap { } function test_unwrapAndPay_fork() public { - uint amount = 100; + uint256 amount = 100; address to = address(1); uint256 balanceBefore = to.balance; @@ -92,7 +91,6 @@ contract PayTest is Bootstrap { payFork.unwrapAndPay(amount, to); assertEq(to.balance, balanceBefore + amount); } - } // Helper contract that rejects ETH transfers @@ -108,4 +106,4 @@ contract MaliciousReceiver { { return 0x150b7a02; } -} \ No newline at end of file +} From d80338d31d95b4f3052fa406c6d098c14e423896 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Fri, 13 Dec 2024 14:17:46 -0500 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=93=9A=20rename=20deployer=20to=20D?= =?UTF-8?q?eployPayBase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/Deploy.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index fe2f810d..d28af414 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -108,7 +108,7 @@ contract DeployMulticallBase is Setup, BaseParameters { /// @dev steps to deploy and verify on Base: /// (1) load the variables in the .env file via `source .env` /// (2) run `forge script script/Deploy.s.sol:DeployPay --rpc-url $BASE_RPC_URL --etherscan-api-key $BASESCAN_API_KEY --broadcast --verify -vvvv` -contract DeployPay is Setup, BaseParameters { +contract DeployPayBase is Setup, BaseParameters { function run() public { uint256 privateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(privateKey); From f6dc00db3cac5cfb02a1556db87979d31eb4b134 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Fri, 13 Dec 2024 14:20:32 -0500 Subject: [PATCH 10/14] =?UTF-8?q?=F0=9F=91=B7=20make=20WETH=20in=20pay.sol?= =?UTF-8?q?=20immutable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/Pay.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Pay.sol b/src/utils/Pay.sol index 2ed11a8c..76425d7d 100644 --- a/src/utils/Pay.sol +++ b/src/utils/Pay.sol @@ -7,7 +7,7 @@ import {IWETH} from "src/interfaces/tokens/IWETH.sol"; /// @author cmontecoding contract Pay { /// @notice WETH contract - IWETH public WETH; + IWETH public immutable WETH; /// @notice thrown when a call to transfer eth fails error ETHTransferFailed(); From 725470fff53a69c72b2636a91a025c36afeb68ca Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Fri, 13 Dec 2024 14:25:24 -0500 Subject: [PATCH 11/14] =?UTF-8?q?=E2=9C=85=20relocate=20MaliciousReceiver?= =?UTF-8?q?=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Collateral.t.sol | 16 +--------------- test/Pay.t.sol | 18 ++---------------- test/utils/MaliciousReceiver.sol | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 31 deletions(-) create mode 100644 test/utils/MaliciousReceiver.sol diff --git a/test/Collateral.t.sol b/test/Collateral.t.sol index 2f812962..70f0042c 100644 --- a/test/Collateral.t.sol +++ b/test/Collateral.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.27; import {IEngine} from "src/interfaces/IEngine.sol"; import {Bootstrap} from "test/utils/Bootstrap.sol"; import {Pay} from "src/utils/Pay.sol"; +import {MaliciousReceiver} from "test/utils/MaliciousReceiver.sol"; contract CollateralTest is Bootstrap { function setUp() public { @@ -649,18 +650,3 @@ contract WithdrawCollateral is CollateralTest { vm.stopPrank(); } } - -// Helper contract that rejects ETH transfers -contract MaliciousReceiver { - receive() external payable { - revert(); - } - - function onERC721Received(address, address, uint256, bytes calldata) - external - pure - returns (bytes4) - { - return 0x150b7a02; - } -} diff --git a/test/Pay.t.sol b/test/Pay.t.sol index 80c6b180..8bf5ec48 100644 --- a/test/Pay.t.sol +++ b/test/Pay.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.27; import {Bootstrap} from "test/utils/Bootstrap.sol"; +import {MaliciousReceiver} from "test/utils/MaliciousReceiver.sol"; import {Pay} from "src/utils/Pay.sol"; import {IWETH} from "src/interfaces/tokens/IWETH.sol"; @@ -91,19 +92,4 @@ contract PayTest is Bootstrap { payFork.unwrapAndPay(amount, to); assertEq(to.balance, balanceBefore + amount); } -} - -// Helper contract that rejects ETH transfers -contract MaliciousReceiver { - receive() external payable { - revert(); - } - - function onERC721Received(address, address, uint256, bytes calldata) - external - pure - returns (bytes4) - { - return 0x150b7a02; - } -} +} \ No newline at end of file diff --git a/test/utils/MaliciousReceiver.sol b/test/utils/MaliciousReceiver.sol new file mode 100644 index 00000000..08b840f5 --- /dev/null +++ b/test/utils/MaliciousReceiver.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.27; + +/// @notice Helper contract that rejects ETH transfers +/// @author cmontecoding +contract MaliciousReceiver { + receive() external payable { + revert(); + } + + function onERC721Received(address, address, uint256, bytes calldata) + external + pure + returns (bytes4) + { + return 0x150b7a02; + } +} From cb904b47014ebe3e7bc53fe6b0ea4d7c48bba63c Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Fri, 13 Dec 2024 14:27:14 -0500 Subject: [PATCH 12/14] =?UTF-8?q?=E2=9C=A8=20fmt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/Pay.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Pay.t.sol b/test/Pay.t.sol index 8bf5ec48..63d3742a 100644 --- a/test/Pay.t.sol +++ b/test/Pay.t.sol @@ -92,4 +92,4 @@ contract PayTest is Bootstrap { payFork.unwrapAndPay(amount, to); assertEq(to.balance, balanceBefore + amount); } -} \ No newline at end of file +} From 2140b2060945b764990ddf2c5cbc3df5ba567f39 Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Fri, 13 Dec 2024 14:35:54 -0500 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=9A=80=20deploy=20pay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/Deploy.s.sol | 2 +- script/utils/parameters/BaseParameters.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index d28af414..4fdce46d 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -107,7 +107,7 @@ contract DeployMulticallBase is Setup, BaseParameters { /// @dev steps to deploy and verify on Base: /// (1) load the variables in the .env file via `source .env` -/// (2) run `forge script script/Deploy.s.sol:DeployPay --rpc-url $BASE_RPC_URL --etherscan-api-key $BASESCAN_API_KEY --broadcast --verify -vvvv` +/// (2) run `forge script script/Deploy.s.sol:DeployPayBase --rpc-url $BASE_RPC_URL --etherscan-api-key $BASESCAN_API_KEY --broadcast --verify -vvvv` contract DeployPayBase is Setup, BaseParameters { function run() public { uint256 privateKey = vm.envUint("PRIVATE_KEY"); diff --git a/script/utils/parameters/BaseParameters.sol b/script/utils/parameters/BaseParameters.sol index 06802a6a..3765615b 100644 --- a/script/utils/parameters/BaseParameters.sol +++ b/script/utils/parameters/BaseParameters.sol @@ -34,7 +34,7 @@ contract BaseParameters { address public constant ZAP = 0x84f531d85fAA7Be42f8a248B87e40f760e558F7C; address payable public constant PAY = - payable(0xdFdDC95c4997f8CE09c412d53378E2101b400609); + payable(0x127Fb7602bF3De092d351f922791cF9a149A4837); address public constant USDT = address(0); From 061476059be8f550274ffbca717d498d635eb4fa Mon Sep 17 00:00:00 2001 From: Andrew Chiaramonte Date: Fri, 13 Dec 2024 14:36:08 -0500 Subject: [PATCH 14/14] =?UTF-8?q?=E2=9C=85=20update=20block=20number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/utils/Constants.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 61a36496..e518fb71 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -4,8 +4,8 @@ pragma solidity 0.8.27; /// @title Contract for defining constants used in testing /// @author JaredBorders (jaredborders@pm.me) contract Constants { - /// @dev Dec-13-2024 02:32:19 AM +UTC - uint256 public constant BASE_BLOCK_NUMBER = 23_633_896; + /// @dev Dec-13-2024 07:33:47 PM +UTC + uint256 public constant BASE_BLOCK_NUMBER = 23_664_540; address internal constant OWNER = address(0x01); @@ -58,8 +58,8 @@ contract Constants { uint128 constant CBBTC_SYNTH_MARKET_ID = 4; - /// @dev this is the ETH price in USD at the block number 23_633_896 - uint256 internal constant ETH_PRICE = 3880; + /// @dev this is the ETH price in USD at the block number 23_664_540 + uint256 internal constant ETH_PRICE = 3918; uint256 internal constant AMOUNT = 10_000 ether;