"SafeERC20: low-level call failed" when tryin to use Swap in OneSplitProtocol contract. Possible related to OpenZeppelin SafeERC20?

I am trying to use OneSplitProtocol (0xC586BeF4a0992C495Cf22e1aeEE4E446CECDee0E) to swap some ETH for ChainLink token at a better price. I set up HardHat enviroment with mainnet fork for testing purposes.

When I try to execute swap() function on OneSplit contract I get "SafeERC20: low-level call failed" error. I tracked down the error to SafeERC20 contract provided by OpenZeppelin but I am pretty sure my implementation is wrong, but the error is rather confusing and I have no idea where the problem lies.

At first I thought the problem lies with approval of tokens owned by contract but by testing all the possibilities of approvals I figured out this is probably not the problem.

What does the provided error actually mean? I am trying to understand what went wrong.

:1234: Code to reproduce

I am calling my contract from web3, the contract should call OneSplitProtocol contract and all the logic behind it. I am calling OneSplitProtocol contract in my contract code like this:

interface IOneSplit { // interface for 1inch exchange.
    function swap(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 amount,
        uint256 minReturn,
        uint256[] memory distribution,
        uint256 disableFlags
    ) external payable;

contract MyContract {

	address ONE_SPLIT_ADDRESS = 0xC586BeF4a0992C495Cf22e1aeEE4E446CECDee0E;
	uint256 PARTS = 10;
	uint256 FLAGS = 0;

   function _trade(address _fromTokenAddress, address _toTokenAddress, uint256 _amount, uint256 toTokenMinAmount, uint256[] memory distribution_1) internal {
		// account in 1% slippage
		uint returnAmount_calc = toTokenAmount / 100 * 99;
        // Swap on 1Split
        _oneSplitSwap(_fromTokenAddress, _toTokenAddress, _amount, toTokenMinAmount, distribution_1);
	function _oneSplitSwap(address _from, address _to, uint256 _amount, uint256 _minReturn, uint256[] memory _distribution) internal {
        // Setup contracts
        IERC20 _fromIERC20 = IERC20(_from);
        IERC20 _toIERC20 = IERC20(_to);
        IOneSplit _oneSplitContract = IOneSplit(ONE_SPLIT_ADDRESS);

        // Approve tokens
        _fromIERC20.approve(ONE_SPLIT_ADDRESS, uint(-1));
        console.log("Token Approved");

        // Swap tokens: give _from, get _to
        _oneSplitContract.swap(_fromIERC20, _toIERC20, _amount, _minReturn, _distribution, FLAGS);
		_fromIERC20.approve(address(ONE_SPLIT_ADDRESS), 0);

I was thinking whether my implementation of interface IOneSplit is not wrong and that causes the issue. Pretty much not sure where to look at.

Code stops at "Token Approved" and fails exactly at _oneSplitContract.swap() function with "SafeERC20: low-level call failed" error.

How can I debug further or know what is failing? I am sending ETH as WETH and second argument is Chainlink token address.

:computer: Environment

Hardhat fork mainnet

This error just means that a token transfer failed. The SafeERC20 version this contract is using does not provide more information than that. There may not be enough approve allowance, or balance, etc.

Thank you, I have finally found out the problem. It was in my script, I was pushing the wrong values into the swap function. Took me a solid while to figure it out but now it works. Thank you for explanation.