Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weth unwrapper #57

Merged
merged 14 commits into from
Dec 13, 2024
19 changes: 19 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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) {
Expand All @@ -30,6 +32,7 @@ contract Setup is Script {
_sUSDProxy: sUSDProxy,
_pDAO: pDAO,
_zap: zap,
_pay: pay,
_usdc: usdc,
_weth: weth
});
Expand All @@ -56,6 +59,7 @@ contract DeployBase is Setup, BaseParameters {
sUSDProxy: USD_PROXY_ANDROMEDA,
pDAO: PDAO,
zap: ZAP,
pay: PAY,
usdc: USDC,
weth: WETH
});
Expand All @@ -78,6 +82,7 @@ contract DeployBaseSepolia is Setup, BaseSepoliaParameters {
sUSDProxy: USD_PROXY_ANDROMEDA,
pDAO: PDAO,
zap: ZAP,
pay: PAY,
usdc: USDC,
weth: WETH
});
Expand All @@ -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: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");
vm.startBroadcast(privateKey);

new Pay(WETH);

vm.stopBroadcast();
}
}
4 changes: 4 additions & 0 deletions script/Upgrade.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -31,6 +32,7 @@ contract Setup is Script {
_sUSDProxy: sUSDProxy,
_pDAO: pDAO,
_zap: zap,
_pay: pay,
_usdc: usdc,
_weth: weth
});
Expand All @@ -51,6 +53,7 @@ contract DeployBase is Setup, BaseParameters {
sUSDProxy: USD_PROXY_ANDROMEDA,
pDAO: PDAO,
zap: ZAP,
pay: PAY,
usdc: USDC,
weth: WETH
});
Expand All @@ -73,6 +76,7 @@ contract DeployBaseSepolia is Setup, BaseSepoliaParameters {
sUSDProxy: USD_PROXY_ANDROMEDA,
pDAO: PDAO,
zap: ZAP,
pay: PAY,
usdc: USDC,
weth: WETH
});
Expand Down
3 changes: 3 additions & 0 deletions script/utils/parameters/BaseParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contract BaseParameters {

address public constant ZAP = 0x84f531d85fAA7Be42f8a248B87e40f760e558F7C;

address payable public constant PAY =
payable(0x127Fb7602bF3De092d351f922791cF9a149A4837);

address public constant USDT = address(0);

address public constant CBBTC = 0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf;
Expand Down
2 changes: 2 additions & 0 deletions script/utils/parameters/BaseSepoliaParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
17 changes: 9 additions & 8 deletions src/Engine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -133,20 +137,22 @@ 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)
|| _usdc == address(0) || _weth == address(0)
|| _pay == address(0) || _usdc == address(0) || _weth == address(0)
) revert ZeroAddress();

PERPS_MARKET_PROXY = IPerpsMarketProxy(_perpsMarketProxy);
SPOT_MARKET_PROXY = ISpotMarketProxy(_spotMarketProxy);

SUSD = IERC20(_sUSDProxy);
zap = Zap(_zap);
pay = Pay(_pay);
cmontecoding marked this conversation as resolved.
Show resolved Hide resolved
USDC = IERC20(_usdc);
WETH = IWETH(_weth);

Expand All @@ -155,9 +161,6 @@ contract Engine is
pDAO = _pDAO;
}

/// @notice Allows the contract to receive ETH when unwrapping WETH
receive() external payable {}

/*//////////////////////////////////////////////////////////////
UPGRADE MANAGEMENT
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -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(
Expand Down
3 changes: 0 additions & 3 deletions src/interfaces/IEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
//////////////////////////////////////////////////////////////*/
Expand Down
32 changes: 32 additions & 0 deletions src/utils/Pay.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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 immutable 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(uint256 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 {}
}
21 changes: 3 additions & 18 deletions test/Collateral.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ 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 {
Expand Down Expand Up @@ -638,9 +640,7 @@ contract WithdrawCollateral is CollateralTest {
_tolerance: SMALLER_AMOUNT
});

vm.expectRevert(
abi.encodeWithSelector(IEngine.ETHTransferFailed.selector)
);
vm.expectRevert();

engine.withdrawCollateralETH({
_accountId: accountId,
Expand All @@ -650,18 +650,3 @@ contract WithdrawCollateral is CollateralTest {
vm.stopPrank();
}
}

// Helper contract that rejects ETH transfers
contract MaliciousReceiver {
receive() external payable {
revert("I reject ETH");
}

function onERC721Received(address, address, uint256, bytes calldata)
external
pure
returns (bytes4)
{
return 0x150b7a02;
}
}
23 changes: 23 additions & 0 deletions test/Deployment.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -42,6 +43,7 @@ contract DeploymentTest is Test, Setup {
sUSDProxy: sUSDProxy,
pDAO: pDAO,
zap: zap,
pay: pay,
usdc: usdc,
weth: weth
});
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
6 changes: 4 additions & 2 deletions test/EIP7412.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading
Loading