Skip to content

Commit

Permalink
Merge pull request #57 from Kwenta/weth-unwrapper
Browse files Browse the repository at this point in the history
Weth unwrapper
  • Loading branch information
cmontecoding authored Dec 13, 2024
2 parents 23c3de9 + 0614760 commit dbc049f
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 43 deletions.
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);
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

0 comments on commit dbc049f

Please sign in to comment.