Collecting fees before sending transaction

Hi

I want to collect fees before each transaction is sent. In the first example, I am sending ETH and the fees are added to the contract. If I sent ERC20 tokens and check the contract value it is always 0. Any idea what I am doing wrong here?

works

    function sendETH(
        address _token,
        address payable _to,
        address _orderBookUID,
        uint256 _orderID,
        bytes32[2] memory _title,
        uint256 _deadline
    ) external payable override lock ensure(_deadline) {
        require(msg.sender != _to, "BPR::Now allowed send yourself");
        require(
            msg.value > 0,
            "BPR::sendETH amount not > 0"
        );
        uint256 _amountInMinusFee = PayLibrary.getAmountOut(msg.value);
        _to.transfer(_amountInMinusFee);
        emit Transfer(msg.sender, _to, msg.value);
    }

not works

    function sendToken(
        address _token,
        address _to,
        address _orderBookUID,
        uint256 _orderID,
        uint256 _amount,
        bytes32[2] memory _title,
        uint256 _deadline
    ) external override lock ensure(_deadline) returns (bool) {
        IERC20 token = IERC20(_token);
        require(msg.sender != _to, "BPR::Now allowed send yourself");
        require(_amount > 0, "BPR::sendToken amount not > 0");
        uint256 _amountInMinusFee = PayLibrary.getAmountOut(_amount);
        token.transferFrom(msg.sender, _to, _amountInMinusFee);
        emit Transfer(msg.sender, _to, _amount);
        return true;
    }

Collecting Fees PayLibrary.sol

    function getAmountOut(uint256 _amountIn)
        internal
        pure
        returns (uint256 amountOut)
    {
        require(_amountIn > 0, "AmountOut: INSUFFICIENT_AMOUNT");
        uint256 amountInWithFee = _amountIn * (990);
        return amountInWithFee / 1000;
    }

the problem is that the tokens are not sent to the contract in the first place. Assume UserA has 100 units of TokenA and calls sendToken() to transfer everything, then 99 tokens will be sent to "_to" and 1 token stays with UserA. At no point are the tokens transfered to the contract

1 Like

Rightly explained by @minh_trng

Add a line to transfer fee to smart contract address (or any other address) and also logic to retrieve or else funds will be lost !
token.transferFrom(msg.sender, address(this), FEE);

1 Like

Ok, then sending ETH works but sending tokens does not.

I have created two internal functions and collect the fees by transfer. Calling the function within sendToken function:

   function _depositTokens(address _token, uint256 _amount) internal {
        IERC20 token = IERC20(_token);
        token.safeTransferFrom(msg.sender, address(this), _amount);
    }

   //The amount is amount - fees
    function _transfer(
        address _token,
        address to,
        uint256 amount
    ) internal {
        IERC20 token = IERC20(_token);
        token.safeTransfer(to, amount-fees);
    }

Make sure to add function to "use" the token later ? It can be swapping to eth, or transferring the tokens to owner etc.
Or else, the tokens are locked forever in the contract.

Yes, for tokens I have following function:

    function withdrawToken(address _token, uint256 _amount) external {
        address feeTo = IPayFactory(factory).feeTo();
        require(msg.sender == feeTo, "BPR: Only feeTo allowed");
        IERC20 tokenContract = IERC20(_token);
        tokenContract.safeTransfer(msg.sender, _amount);
    }
1 Like