Search code examples
ethereumsolidityremixuniswap

TypeError: "msg.value" and "callvalue()" can only be used in payable public functions


In my contract I'm trying to swap Eth for Dai using Uniswap's swapExactETHForTokens() function:

pragma solidity ^0.6.6;

interface IUniswap {
  function swapExactETHForTokens(
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline)
  external
  payable
  returns (uint[] memory amounts);
  function WETH() external pure returns (address);
}

contract MyContract {
  IUniswap uniswap;

  constructor(address _uniswap) public {
    uniswap = IUniswap(_uniswap);
  }

  function swapExactETHForTokens(uint amountOutMin, address token) external {
    address[] memory path = new address[](2);
    path[0] = uniswap.WETH();
    path[1] = token;
    uniswap.swapExactETHForTokens{value: msg.value}(
      amountOutMin, 
      path,
      msg.sender, 
      now
    );
  }
}

However on this line in swapExactETHForTokens():

uniswap.swapExactETHForTokens{value: msg.value}(

Remix IDE is showing the follow error:

contracts/MyContract.sol:26:42: TypeError: "msg.value" and "callvalue()" can only be used in payable public functions. Make the function "payable" or use an internal function to avoid this error.
    uniswap.swapExactETHForTokens{value: msg.value}(
                                         ^-------^

I'm confused, because at the top I've already declared swapExactETHForTokens() to be payable in the IUniswap interface.

Search results for this error turned up blank so I thought it would be good to ask here. How can I fix this?


Solution

  • I realized my mistake: I needed to add the payable keyword to my own implementation of swapExactETHForTokens(), like so:

      function swapExactETHForTokens(uint amountOutMin, address token) external payable { // payable keyword here
        address[] memory path = new address[](2);
        path[0] = uniswap.WETH();
        path[1] = token;
        uniswap.swapExactETHForTokens{value: msg.value}(
          amountOutMin, 
          path,
          msg.sender, 
          now
        );
      }