Skip to content

Commit

Permalink
Merge pull request #293 from consenlabs/rfq-maker-weth-option
Browse files Browse the repository at this point in the history
add WETH option design for maker
  • Loading branch information
108356037 authored Sep 5, 2023
2 parents 1f46ec1 + e74eee6 commit d1dfdff
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 4 deletions.
34 changes: 30 additions & 4 deletions contracts/RFQ.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ contract RFQ is IRFQ, Ownable, TokenCollector, EIP712 {

uint256 private constant FLG_ALLOW_CONTRACT_SENDER = 1 << 255;
uint256 private constant FLG_ALLOW_PARTIAL_FILL = 1 << 254;
uint256 private constant FLG_MAKER_RECEIVES_WETH = 1 << 253;

IWETH public immutable weth;
address payable public feeCollector;
Expand Down Expand Up @@ -117,12 +118,16 @@ contract RFQ is IRFQ, Ownable, TokenCollector, EIP712 {
// transfer takerToken to maker
if (_rfqOffer.takerToken.isETH()) {
if (msg.value != _rfqTx.takerRequestAmount) revert InvalidMsgValue();
Address.sendValue(_rfqOffer.maker, _rfqTx.takerRequestAmount);
_collecETHAndSend(_rfqOffer.maker, _rfqTx.takerRequestAmount, ((_rfqOffer.flags & FLG_MAKER_RECEIVES_WETH) != 0));
} else if (_rfqOffer.takerToken == address(weth)) {
if (msg.value != 0) revert InvalidMsgValue();
_collect(_rfqOffer.takerToken, _rfqOffer.taker, address(this), _rfqTx.takerRequestAmount, _takerTokenPermit);
weth.withdraw(_rfqTx.takerRequestAmount);
Address.sendValue(_rfqOffer.maker, _rfqTx.takerRequestAmount);
_collecWETHAndSend(
_rfqOffer.taker,
_rfqOffer.maker,
_rfqTx.takerRequestAmount,
_takerTokenPermit,
((_rfqOffer.flags & FLG_MAKER_RECEIVES_WETH) != 0)
);
} else {
if (msg.value != 0) revert InvalidMsgValue();
_collect(_rfqOffer.takerToken, _rfqOffer.taker, _rfqOffer.maker, _rfqTx.takerRequestAmount, _takerTokenPermit);
Expand Down Expand Up @@ -174,4 +179,25 @@ contract RFQ is IRFQ, Ownable, TokenCollector, EIP712 {
fee
);
}

// Only used when taker token is ETH
function _collecETHAndSend(address payable to, uint256 amount, bool makerReceivesWETH) internal {
if (makerReceivesWETH) {
weth.deposit{ value: amount }();
weth.transfer(to, amount);
} else {
Address.sendValue(to, amount);
}
}

// Only used when taker token is WETH
function _collecWETHAndSend(address from, address payable to, uint256 amount, bytes calldata data, bool makerReceivesWETH) internal {
if (makerReceivesWETH) {
_collect(address(weth), from, to, amount, data);
} else {
_collect(address(weth), from, address(this), amount, data);
weth.withdraw(amount);
Address.sendValue(to, amount);
}
}
}
78 changes: 78 additions & 0 deletions test/forkMainnet/RFQ.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ contract RFQTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper {

uint256 private constant FLG_ALLOW_CONTRACT_SENDER = 1 << 255;
uint256 private constant FLG_ALLOW_PARTIAL_FILL = 1 << 254;
uint256 private constant FLG_MAKER_RECEIVES_WETH = 1 << 253;

event FilledRFQ(
bytes32 indexed rfqOfferHash,
Expand Down Expand Up @@ -242,6 +243,44 @@ contract RFQTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper {
fcMakerToken.assertChange(int256(fee));
}

function testFillRFQWithRawETHAndRecieveWETH() public {
// case : taker token is ETH
RFQOffer memory rfqOffer = defaultRFQOffer;
rfqOffer.takerToken = Constant.ZERO_ADDRESS;
rfqOffer.takerTokenAmount = 1 ether;
rfqOffer.flags |= FLG_MAKER_RECEIVES_WETH;

bytes memory makerSig = signRFQOffer(makerSignerPrivateKey, rfqOffer, address(rfq));

Snapshot memory takerTakerToken = BalanceSnapshot.take({ owner: rfqOffer.taker, token: rfqOffer.takerToken });
Snapshot memory takerMakerToken = BalanceSnapshot.take({ owner: rfqOffer.taker, token: rfqOffer.makerToken });
// maker should receive WETH
Snapshot memory makerWETHToken = BalanceSnapshot.take({ owner: rfqOffer.maker, token: address(weth) });
Snapshot memory makerMakerToken = BalanceSnapshot.take({ owner: rfqOffer.maker, token: rfqOffer.makerToken });
Snapshot memory recTakerToken = BalanceSnapshot.take({ owner: recipient, token: rfqOffer.takerToken });
Snapshot memory recMakerToken = BalanceSnapshot.take({ owner: recipient, token: rfqOffer.makerToken });
Snapshot memory fcMakerToken = BalanceSnapshot.take({ owner: feeCollector, token: rfqOffer.makerToken });

uint256 fee = (rfqOffer.makerTokenAmount * defaultFeeFactor) / Constant.BPS_MAX;
uint256 amountAfterFee = rfqOffer.makerTokenAmount - fee;

RFQTx memory rfqTx = defaultRFQTx;
rfqTx.rfqOffer = rfqOffer;
rfqTx.takerRequestAmount = rfqOffer.takerTokenAmount;

vm.prank(rfqOffer.taker, rfqOffer.taker);
rfq.fillRFQ{ value: rfqOffer.takerTokenAmount }(rfqTx, makerSig, defaultMakerPermit, defaultTakerPermit);

takerTakerToken.assertChange(-int256(rfqOffer.takerTokenAmount));
takerMakerToken.assertChange(int256(0));
makerWETHToken.assertChange(int256(rfqOffer.takerTokenAmount));
makerMakerToken.assertChange(-int256(rfqOffer.makerTokenAmount));
recTakerToken.assertChange(int256(0));
// recipient gets less than original makerTokenAmount because of the fee
recMakerToken.assertChange(int256(amountAfterFee));
fcMakerToken.assertChange(int256(fee));
}

function testFillRFQTakerGetRawETH() public {
// case : maker token is WETH
RFQOffer memory rfqOffer = defaultRFQOffer;
Expand Down Expand Up @@ -316,6 +355,45 @@ contract RFQTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper {
fcMakerToken.assertChange(int256(fee));
}

function testFillRFQWithWETHAndRecieveWETH() public {
// case : taker token is WETH
RFQOffer memory rfqOffer = defaultRFQOffer;
rfqOffer.takerToken = WETH_ADDRESS;
rfqOffer.takerTokenAmount = 1 ether;
rfqOffer.flags |= FLG_MAKER_RECEIVES_WETH;

bytes memory makerSig = signRFQOffer(makerSignerPrivateKey, rfqOffer, address(rfq));

Snapshot memory takerTakerToken = BalanceSnapshot.take({ owner: rfqOffer.taker, token: rfqOffer.takerToken });
Snapshot memory takerMakerToken = BalanceSnapshot.take({ owner: rfqOffer.taker, token: rfqOffer.makerToken });
// maker should receive WETH
Snapshot memory makerWETHToken = BalanceSnapshot.take({ owner: rfqOffer.maker, token: address(weth) });
Snapshot memory makerMakerToken = BalanceSnapshot.take({ owner: rfqOffer.maker, token: rfqOffer.makerToken });
Snapshot memory recTakerToken = BalanceSnapshot.take({ owner: recipient, token: rfqOffer.takerToken });
Snapshot memory recMakerToken = BalanceSnapshot.take({ owner: recipient, token: rfqOffer.makerToken });
Snapshot memory fcMakerToken = BalanceSnapshot.take({ owner: feeCollector, token: rfqOffer.makerToken });

uint256 fee = (rfqOffer.makerTokenAmount * defaultFeeFactor) / Constant.BPS_MAX;
uint256 amountAfterFee = rfqOffer.makerTokenAmount - fee;

RFQTx memory rfqTx = defaultRFQTx;
rfqTx.rfqOffer = rfqOffer;
rfqTx.takerRequestAmount = rfqOffer.takerTokenAmount;

bytes memory takerPermit = getTokenlonPermit2Data(taker, takerPrivateKey, rfqOffer.takerToken, address(rfq));

vm.prank(rfqOffer.taker, rfqOffer.taker);
rfq.fillRFQ(rfqTx, makerSig, defaultMakerPermit, takerPermit);

takerTakerToken.assertChange(-int256(rfqOffer.takerTokenAmount));
takerMakerToken.assertChange(int256(0));
makerWETHToken.assertChange(int256(rfqOffer.takerTokenAmount));
makerMakerToken.assertChange(-int256(rfqOffer.makerTokenAmount));
recTakerToken.assertChange(int256(0));
recMakerToken.assertChange(int256(amountAfterFee));
fcMakerToken.assertChange(int256(fee));
}

function testFillWithContract() public {
RFQOffer memory rfqOffer = defaultRFQOffer;
rfqOffer.flags |= FLG_ALLOW_CONTRACT_SENDER;
Expand Down

0 comments on commit d1dfdff

Please sign in to comment.