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

[Feature] Spender permit feature #110

Open
wants to merge 60 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
d1d0156
feat: spender contract and foundry test
oneleo Oct 19, 2022
93833a5
Merge branch 'master' into LABS-960/rfq-with-spender-permit
oneleo Oct 19, 2022
ecbe62e
bug: change to new signature format
oneleo Oct 24, 2022
b05f0ec
feat: replace rfq spendfromuser func with spendfromusertowithpermit
oneleo Oct 24, 2022
a05cfcd
refac: leverage struct spendwithpermit in params
oneleo Oct 26, 2022
eae8717
chg: modify variable names for readability
oneleo Oct 26, 2022
d89c922
refac: move require condition from rfq to spender contract
oneleo Oct 26, 2022
89c376a
refac: modify variables and function in rfq foundry test
oneleo Oct 26, 2022
8af0b60
chg: modify variable names for readability
oneleo Oct 26, 2022
b5b3793
spec: Add requester verification foundry test
oneleo Oct 26, 2022
b2f296b
refac: leverage struct spendwithpermit in params
oneleo Oct 26, 2022
9dca7b1
bug: assign replay protection check before sig valid check
oneleo Oct 26, 2022
c376229
bug: use safeTransfer() in SafeERC20 instead
oneleo Oct 26, 2022
2d21eaa
feat: remove taker/maker spendWithPermit but create they from _order
oneleo Oct 26, 2022
d493f7c
refac: convert the BPS_MAX variable appropriately
oneleo Oct 26, 2022
31ad782
refac: move taker/maker spendWithPermit from fill() to _settle()
oneleo Oct 27, 2022
ac38d3e
feat: modify error message returned when replay protection checks
oneleo Oct 27, 2022
123e7df
refac: use only libconstant.bps_max variable
oneleo Oct 27, 2022
c310fa1
chg: run prettier to format spender.sol to resolve code style issues
oneleo Oct 27, 2022
556ddc7
Merge pull request #99 from consenlabs/LABS-940/spender-adds-backward…
oneleo Oct 27, 2022
65d0d60
Merge branch 'master' into modify-salt-usage-of-spendwithpermit
oneleo Oct 27, 2022
9f242b9
feat: spendWithPermit should contain transaction or order hash
oneleo Oct 28, 2022
45e146f
Merge branch 'master' into spender_permit_feature
oneleo Oct 28, 2022
049cda6
Merge branch 'spender_permit_feature' into modify-salt-usage-of-spend…
oneleo Oct 28, 2022
8acfb68
Merge pull request #105 from consenlabs/modify-salt-usage-of-spendwit…
oneleo Oct 31, 2022
c8b8f2d
Merge branch 'master' into spender_permit_feature
oneleo Nov 4, 2022
2a5da3d
feat: spendWithPermit should contain transaction or order hash
oneleo Nov 4, 2022
36d2730
Merge pull request #111 from consenlabs/modify-txhash-name-of-spendwi…
charlesjhongc Nov 7, 2022
db4726e
refac: rfq, spender contracts changed to non named parameter type
oneleo Nov 7, 2022
db1564a
Merge branch 'master' into spender_permit_feature
oneleo Nov 7, 2022
03d5b72
Merge pull request #112 from consenlabs/rfq_spender_to_no_named_param…
oneleo Nov 8, 2022
77fb55a
refac: move the signSpendWithPermit function in foundry test
oneleo Nov 9, 2022
5627a14
perf: use eip712 domain separator instead of spender contract
oneleo Nov 9, 2022
b9f4bac
bug: revert when sigType is invalid
oneleo Nov 9, 2022
9a1d452
modify spendFromUser --> spendFromUserToWithPermit
Nov 10, 2022
a130849
add helper function regarding spenderPermit on l2Deposit action
Nov 10, 2022
f17e7ab
modify test case using spenderPermit
Nov 10, 2022
0714df3
replace comment for _createSpenderPermitFromL2Deposit
Nov 10, 2022
c3377c7
remove accidentally added files
Nov 10, 2022
f02e23a
remove redundant comments
Nov 10, 2022
4dd27c9
fix nit
Nov 11, 2022
7b4392e
modify solidity objects using named parameters
Nov 11, 2022
be48682
modify DEFAULT_DEPOSIT to _deposit in _createSpenderPermitFromL2Deposit
Nov 11, 2022
b66e418
Merge pull request #114 from consenlabs/move_signspendwithpermit_func
oneleo Nov 11, 2022
6bdf206
feat: replace amm spendfromuser func with spendfromusertowithpermit
oneleo Nov 11, 2022
a52be1c
chg: modify variable name to match internal variable format
oneleo Nov 11, 2022
7150101
Merge branch 'spender_permit_feature' into modify-l2deposit-using-spe…
Nov 14, 2022
a0e582e
remove signSpendWithPermit() from Setup.t.sol
Nov 14, 2022
4130802
use signSpendWithPermit() from contracts-test/utils/Permit.sol
Nov 14, 2022
58d1b78
refec: modify comments and function names
oneleo Nov 14, 2022
4aa11d0
Merge pull request #115 from consenlabs/modify-l2deposit-using-spende…
108356037 Nov 14, 2022
eb9ca88
refec: modify comments and remove unused imported package
oneleo Nov 14, 2022
66b606f
doc: adject _transferTakerAssetToAMM func comment to be clearer
oneleo Nov 15, 2022
2619aca
doc: use named parameters to make code clearer
oneleo Nov 15, 2022
6c542db
doc: apply named parameters to transferTakerAssetToAMM in ammwrapper
oneleo Nov 15, 2022
424feec
Merge pull request #116 from consenlabs/amm-with-spender-permit
oneleo Nov 15, 2022
a67eba2
refac: handle the conflict between RFQ.t.sol and the master branch
oneleo Nov 16, 2022
e8b9284
Merge branch 'master' into spender_permit_feature
oneleo Nov 16, 2022
8dcef47
feat: remove spendFromUser() func in Spender.sol
oneleo Nov 16, 2022
d1e7f20
Merge pull request #119 from consenlabs/remove_spendfromuser_function
charlesjhongc Feb 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 36 additions & 40 deletions contracts/AMMWrapper.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
Expand Down Expand Up @@ -114,30 +115,12 @@ contract AMMWrapper is IAMMWrapper, StrategyBase, ReentrancyGuard, BaseLibEIP712
* External functions *
*************************************************************/
function trade(
address _makerAddr,
address _takerAssetAddr,
address _makerAssetAddr,
uint256 _takerAssetAmount,
uint256 _makerAssetAmount,
AMMLibEIP712.Order calldata _order,
uint256 _feeFactor,
address _userAddr,
address payable _receiverAddr,
uint256 _salt,
uint256 _deadline,
bytes calldata _sig
bytes calldata _sig,
bytes calldata _takerAssetPermitSig
) external payable override nonReentrant onlyUserProxy returns (uint256) {
AMMLibEIP712.Order memory order = AMMLibEIP712.Order(
_makerAddr,
_takerAssetAddr,
_makerAssetAddr,
_takerAssetAmount,
_makerAssetAmount,
_userAddr,
_receiverAddr,
_salt,
_deadline
);
require(order.deadline >= block.timestamp, "AMMWrapper: expired order");
require(_order.deadline >= block.timestamp, "AMMWrapper: expired order");

// These variables are copied straight from function parameters and
// used to bypass stack too deep error.
Expand All @@ -151,36 +134,36 @@ contract AMMWrapper is IAMMWrapper, StrategyBase, ReentrancyGuard, BaseLibEIP712
}

// Assign trade vairables
internalTxData.fromEth = (order.takerAssetAddr == LibConstant.ZERO_ADDRESS || order.takerAssetAddr == LibConstant.ETH_ADDRESS);
internalTxData.toEth = (order.makerAssetAddr == LibConstant.ZERO_ADDRESS || order.makerAssetAddr == LibConstant.ETH_ADDRESS);
if (_isCurve(order.makerAddr)) {
internalTxData.fromEth = (_order.takerAssetAddr == LibConstant.ZERO_ADDRESS || _order.takerAssetAddr == LibConstant.ETH_ADDRESS);
internalTxData.toEth = (_order.makerAssetAddr == LibConstant.ZERO_ADDRESS || _order.makerAssetAddr == LibConstant.ETH_ADDRESS);
if (_isCurve(_order.makerAddr)) {
// PermanetStorage can recognize `ETH_ADDRESS` but not `ZERO_ADDRESS`.
// Convert it to `ETH_ADDRESS` as passed in `order.takerAssetAddr` or `order.makerAssetAddr` might be `ZERO_ADDRESS`.
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? LibConstant.ETH_ADDRESS : order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? LibConstant.ETH_ADDRESS : order.makerAssetAddr;
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? LibConstant.ETH_ADDRESS : _order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? LibConstant.ETH_ADDRESS : _order.makerAssetAddr;
} else {
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? address(weth) : order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? address(weth) : order.makerAssetAddr;
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? address(weth) : _order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? address(weth) : _order.makerAssetAddr;
}

txMetaData.transactionHash = _verify(order, _sig);
txMetaData.transactionHash = _verify(_order, _sig);

_prepare(order, internalTxData);
_transferTakerAssetToAMM(_order, internalTxData, _takerAssetPermitSig);

{
// Set min amount for swap = _order.makerAssetAmount * (10000 / (10000 - feeFactor))
uint256 swapMinOutAmount = order.makerAssetAmount.mul(LibConstant.BPS_MAX).div(LibConstant.BPS_MAX.sub(txMetaData.feeFactor));
(txMetaData.source, txMetaData.receivedAmount) = _swap(order, internalTxData, swapMinOutAmount);
uint256 swapMinOutAmount = _order.makerAssetAmount.mul(LibConstant.BPS_MAX).div(LibConstant.BPS_MAX.sub(txMetaData.feeFactor));
(txMetaData.source, txMetaData.receivedAmount) = _swap(_order, internalTxData, swapMinOutAmount);

// Settle
// Calculate fee using actually received from swap
uint256 actualFee = txMetaData.receivedAmount.mul(txMetaData.feeFactor).div(LibConstant.BPS_MAX);
txMetaData.settleAmount = txMetaData.receivedAmount.sub(actualFee);
require(txMetaData.settleAmount >= order.makerAssetAmount, "AMMWrapper: insufficient maker output");
_settle(order, internalTxData, txMetaData.settleAmount, actualFee);
require(txMetaData.settleAmount >= _order.makerAssetAmount, "AMMWrapper: insufficient maker output");
_settle(_order, internalTxData, txMetaData.settleAmount, actualFee);
}

emitSwappedEvent(order, txMetaData);
emitSwappedEvent(_order, txMetaData);
return txMetaData.settleAmount;
}

Expand Down Expand Up @@ -229,9 +212,13 @@ contract AMMWrapper is IAMMWrapper, StrategyBase, ReentrancyGuard, BaseLibEIP712

/**
* @dev internal function of `trade`.
* It executes the swap on chosen AMM.
* It transfers assets from the taker to this contract with taker's permission.
*/
function _prepare(AMMLibEIP712.Order memory _order, InternalTxData memory _internalTxData) internal {
function _transferTakerAssetToAMM(
AMMLibEIP712.Order memory _order,
InternalTxData memory _internalTxData,
bytes memory _takerAssetPermitSig
) internal {
// Transfer asset from user and deposit to weth if needed
if (_internalTxData.fromEth) {
require(msg.value > 0, "AMMWrapper: msg.value is zero");
Expand All @@ -241,8 +228,17 @@ contract AMMWrapper is IAMMWrapper, StrategyBase, ReentrancyGuard, BaseLibEIP712
weth.deposit{ value: msg.value }();
}
} else {
// other ERC20 tokens
spender.spendFromUser(_order.userAddr, _order.takerAssetAddr, _order.takerAssetAmount);
// Transfer other ERC20 tokens to this contract
SpenderLibEIP712.SpendWithPermit memory takerAssetPermit = SpenderLibEIP712.SpendWithPermit({
tokenAddr: _order.takerAssetAddr,
requester: address(this),
user: _order.userAddr,
recipient: address(this),
amount: _order.takerAssetAmount,
actionHash: AMMLibEIP712._getOrderHash(_order),
expiry: uint64(_order.deadline)
});
spender.spendFromUserToWithPermit(takerAssetPermit, _takerAssetPermitSig);
}
}

Expand Down
44 changes: 19 additions & 25 deletions contracts/AMMWrapperWithPath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,59 +51,53 @@ contract AMMWrapperWithPath is IAMMWrapperWithPath, AMMWrapper {
* External functions *
*************************************************************/

function trade(
AMMLibEIP712.Order calldata _order,
uint256 _feeFactor,
bytes calldata _sig,
bytes calldata _makerSpecificData,
address[] calldata _path
) external payable override nonReentrant onlyUserProxy returns (uint256) {
require(_order.deadline >= block.timestamp, "AMMWrapper: expired order");
function trade(IAMMWrapperWithPath.TradeWithPathParams calldata _params) external payable override nonReentrant onlyUserProxy returns (uint256) {
require(_params.order.deadline >= block.timestamp, "AMMWrapper: expired order");

// These variables are copied straight from function parameters and
// used to bypass stack too deep error.
TxMetaData memory txMetaData;
InternalTxData memory internalTxData;
txMetaData.feeFactor = uint16(_feeFactor);
txMetaData.feeFactor = uint16(_params.feeFactor);
txMetaData.relayed = permStorage.isRelayerValid(tx.origin);
internalTxData.makerSpecificData = _makerSpecificData;
internalTxData.path = _path;
internalTxData.makerSpecificData = _params.makerSpecificData;
internalTxData.path = _params.path;
if (!txMetaData.relayed) {
// overwrite feeFactor with defaultFeeFactor if not from valid relayer
txMetaData.feeFactor = defaultFeeFactor;
}

// Assign trade vairables
internalTxData.fromEth = (_order.takerAssetAddr == LibConstant.ZERO_ADDRESS || _order.takerAssetAddr == LibConstant.ETH_ADDRESS);
internalTxData.toEth = (_order.makerAssetAddr == LibConstant.ZERO_ADDRESS || _order.makerAssetAddr == LibConstant.ETH_ADDRESS);
if (_isCurve(_order.makerAddr)) {
internalTxData.fromEth = (_params.order.takerAssetAddr == LibConstant.ZERO_ADDRESS || _params.order.takerAssetAddr == LibConstant.ETH_ADDRESS);
internalTxData.toEth = (_params.order.makerAssetAddr == LibConstant.ZERO_ADDRESS || _params.order.makerAssetAddr == LibConstant.ETH_ADDRESS);
if (_isCurve(_params.order.makerAddr)) {
// PermanetStorage can recognize `ETH_ADDRESS` but not `ZERO_ADDRESS`.
// Convert it to `ETH_ADDRESS` as passed in `_order.takerAssetAddr` or `_order.makerAssetAddr` might be `ZERO_ADDRESS`.
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? LibConstant.ETH_ADDRESS : _order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? LibConstant.ETH_ADDRESS : _order.makerAssetAddr;
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? LibConstant.ETH_ADDRESS : _params.order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? LibConstant.ETH_ADDRESS : _params.order.makerAssetAddr;
} else {
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? address(weth) : _order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? address(weth) : _order.makerAssetAddr;
internalTxData.takerAssetInternalAddr = internalTxData.fromEth ? address(weth) : _params.order.takerAssetAddr;
internalTxData.makerAssetInternalAddr = internalTxData.toEth ? address(weth) : _params.order.makerAssetAddr;
}

txMetaData.transactionHash = _verify(_order, _sig);
txMetaData.transactionHash = _verify(_params.order, _params.sig);

_prepare(_order, internalTxData);
_transferTakerAssetToAMM(_params.order, internalTxData, _params.takerAssetPermitSig);

{
// Set min amount for swap = _order.makerAssetAmount * (10000 / (10000 - feeFactor))
uint256 swapMinOutAmount = _order.makerAssetAmount.mul(LibConstant.BPS_MAX).div(LibConstant.BPS_MAX.sub(txMetaData.feeFactor));
(txMetaData.source, txMetaData.receivedAmount) = _swapWithPath(_order, internalTxData, swapMinOutAmount);
uint256 swapMinOutAmount = _params.order.makerAssetAmount.mul(LibConstant.BPS_MAX).div(LibConstant.BPS_MAX.sub(txMetaData.feeFactor));
(txMetaData.source, txMetaData.receivedAmount) = _swapWithPath(_params.order, internalTxData, swapMinOutAmount);

// Settle
// Calculate fee using actually received from swap
uint256 actualFee = txMetaData.receivedAmount.mul(txMetaData.feeFactor).div(LibConstant.BPS_MAX);
txMetaData.settleAmount = txMetaData.receivedAmount.sub(actualFee);
require(txMetaData.settleAmount >= _order.makerAssetAmount, "AMMWrapper: insufficient maker output");
_settle(_order, internalTxData, txMetaData.settleAmount, actualFee);
require(txMetaData.settleAmount >= _params.order.makerAssetAmount, "AMMWrapper: insufficient maker output");
_settle(_params.order, internalTxData, txMetaData.settleAmount, actualFee);
}

emitSwappedEvent(_order, txMetaData);
emitSwappedEvent(_params.order, txMetaData);
return txMetaData.settleAmount;
}

Expand Down
16 changes: 14 additions & 2 deletions contracts/L2Deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "./interfaces/IL2Deposit.sol";
import "./interfaces/IOptimismL1StandardBridge.sol";
import "./interfaces/IPermanentStorage.sol";
import "./interfaces/ISpender.sol";
import "./utils/SpenderLibEIP712.sol";
import "./utils/StrategyBase.sol";
import "./utils/BaseLibEIP712.sol";
import "./utils/Ownable.sol";
Expand Down Expand Up @@ -49,8 +50,19 @@ contract L2Deposit is IL2Deposit, StrategyBase, ReentrancyGuard, BaseLibEIP712,
// PermanentStorage will revert when L2 deposit hash is already seen
permStorage.setL2DepositSeen(depositHash);

// Transfer token from sender to this contract
spender.spendFromUser(_params.deposit.sender, _params.deposit.l1TokenAddr, _params.deposit.amount);
// Create spendWithPermit for spender contract to verify
SpenderLibEIP712.SpendWithPermit memory l1TokenPermit = SpenderLibEIP712.SpendWithPermit({
tokenAddr: _params.deposit.l1TokenAddr,
requester: address(this),
user: _params.deposit.sender,
recipient: address(this),
amount: _params.deposit.amount,
actionHash: depositHash,
expiry: uint64(_params.deposit.expiry)
});

// Verfiy signature then transfer token from sender to this contract
spender.spendFromUserToWithPermit(l1TokenPermit, _params.l1TokenPermitSig);

// Bypass stack too deep
DepositInfo memory depositInfo = DepositInfo(
Expand Down
58 changes: 48 additions & 10 deletions contracts/RFQ.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pragma solidity 0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
Expand All @@ -10,6 +12,7 @@ import "./interfaces/IRFQ.sol";
import "./utils/StrategyBase.sol";
import "./utils/RFQLibEIP712.sol";
import "./utils/BaseLibEIP712.sol";
import "./utils/SpenderLibEIP712.sol";
import "./utils/SignatureValidator.sol";
import "./utils/LibConstant.sol";

Expand All @@ -18,6 +21,7 @@ import "./utils/LibConstant.sol";
contract RFQ is IRFQ, StrategyBase, ReentrancyGuard, SignatureValidator, BaseLibEIP712 {
using SafeMath for uint256;
using Address for address;
using SafeERC20 for IERC20;

// Constants do not have storage slot.
string public constant SOURCE = "RFQ v1";
Expand Down Expand Up @@ -98,7 +102,9 @@ contract RFQ is IRFQ, StrategyBase, ReentrancyGuard, SignatureValidator, BaseLib
function fill(
RFQLibEIP712.Order calldata _order,
bytes calldata _mmSignature,
bytes calldata _userSignature
bytes calldata _userSignature,
bytes calldata _makerAssetPermitSig,
bytes calldata _takerAssetPermitSig
) external payable override nonReentrant onlyUserProxy returns (uint256) {
// check the order deadline and fee factor
require(_order.deadline >= block.timestamp, "RFQ: expired order");
Expand All @@ -115,7 +121,7 @@ contract RFQ is IRFQ, StrategyBase, ReentrancyGuard, SignatureValidator, BaseLib
// Set transaction as seen, PermanentStorage would throw error if transaction already seen.
permStorage.setRFQTransactionSeen(vars.transactionHash);

return _settle(_order, vars);
return _settle(_order, vars, _makerAssetPermitSig, _takerAssetPermitSig);
}

function _emitFillOrder(
Expand All @@ -140,15 +146,45 @@ contract RFQ is IRFQ, StrategyBase, ReentrancyGuard, SignatureValidator, BaseLib
}

// settle
function _settle(RFQLibEIP712.Order memory _order, GroupedVars memory _vars) internal returns (uint256) {
function _settle(
RFQLibEIP712.Order memory _order,
GroupedVars memory _vars,
bytes memory _makerAssetPermitSig,
bytes memory _takerAssetPermitSig
) internal returns (uint256) {
// Declare the 'maker sends makerAsset to this contract' SpendWithPermit struct from _order parameter
SpenderLibEIP712.SpendWithPermit memory makerAssetPermit = SpenderLibEIP712.SpendWithPermit(
_order.makerAssetAddr,
address(this),
_order.makerAddr,
address(this),
_order.makerAssetAmount,
_vars.orderHash,
uint64(_order.deadline)
);

// Declare the 'taker sends takerAsset to this contract' SpendWithPermit struct from _order parameter
SpenderLibEIP712.SpendWithPermit memory takerAssetPermit = SpenderLibEIP712.SpendWithPermit(
_order.takerAssetAddr,
address(this),
_order.takerAddr,
address(this),
_order.takerAssetAmount,
_vars.transactionHash,
uint64(_order.deadline)
);

// Transfer taker asset to maker
if (address(weth) == _order.takerAssetAddr) {
// Deposit to WETH if taker asset is ETH
require(msg.value == _order.takerAssetAmount, "RFQ: insufficient ETH");
weth.deposit{ value: msg.value }();
weth.transfer(_order.makerAddr, _order.takerAssetAmount);
} else {
spender.spendFromUserTo(_order.takerAddr, _order.takerAssetAddr, _order.makerAddr, _order.takerAssetAmount);
// Transfer taker asset to this contract first,
spender.spendFromUserToWithPermit(takerAssetPermit, _takerAssetPermitSig);
// then transfer from this to maker.
IERC20(_order.takerAssetAddr).safeTransfer(_order.makerAddr, _order.takerAssetAmount);
}

// Transfer maker asset to taker, sub fee
Expand All @@ -158,18 +194,20 @@ contract RFQ is IRFQ, StrategyBase, ReentrancyGuard, SignatureValidator, BaseLib
settleAmount = settleAmount.sub(fee);
}

// Transfer token/Eth to receiver
// Transfer maker asset to this contract first
spender.spendFromUserToWithPermit(makerAssetPermit, _makerAssetPermitSig);

// Transfer maker asset less fee from this contract to receiver
if (_order.makerAssetAddr == address(weth)) {
// Transfer from maker
spender.spendFromUser(_order.makerAddr, _order.makerAssetAddr, settleAmount);
weth.withdraw(settleAmount);
payable(_order.receiverAddr).transfer(settleAmount);
} else {
spender.spendFromUserTo(_order.makerAddr, _order.makerAssetAddr, _order.receiverAddr, settleAmount);
IERC20(_order.makerAssetAddr).safeTransfer(_order.receiverAddr, settleAmount);
}
// Collect fee

// Transfer fee from this contract to feeCollector
if (fee > 0) {
spender.spendFromUserTo(_order.makerAddr, _order.makerAssetAddr, feeCollector, fee);
IERC20(_order.makerAssetAddr).safeTransfer(feeCollector, fee);
}

_emitFillOrder(_order, _vars, settleAmount);
Expand Down
Loading