```\nfunction swap(\n  address inputToken,\n  address outputToken,\n  uint256 inputAmount,\n  uint256 minOutputAmount\n)\n  external\n  payable\n  onlyListedToken(inputToken)\n  onlyListedToken(outputToken)\n  override\n  returns (uint256 outputAmount)\n{\n  // Check that the exchange is unlocked and thus open for business\n  Config memory _config = DFPconfig;\n  require(_config.unlocked, "DFP: Locked");\n\n  // Pull in input token and check the exchange balance for that token\n  uint256 initialInputBalance;\n  if (inputToken == address(0)) {\n    require(msg.value == inputAmount, "DFP: bad ETH amount");\n    initialInputBalance = address(this).balance - inputAmount;\n  } else {\n    initialInputBalance = IERC20(inputToken).balanceOf(address(this));\n    IERC20(inputToken).safeTransferFrom(msg.sender, address(this), inputAmount);\n  }\n\n  // Check dex balance of the output token\n  uint256 initialOutputBalance;\n  if (outputToken == address(0)) {\n    initialOutputBalance = address(this).balance;\n  } else {\n    initialOutputBalance = IERC20(outputToken).balanceOf(address(this));\n  }\n\n  // Calculate the output amount through the x*y=k invariant\n  // Can skip overflow/underflow checks on this calculation as they will always work against an attacker anyway.\n  uint256 netInputAmount = inputAmount * _config.oneMinusTradingFee;\n  outputAmount = netInputAmount * initialOutputBalance / ((initialInputBalance << 64) + netInputAmount);\n  require(outputAmount > minOutputAmount, "DFP: No deal");\n\n  // Send output tokens to whoever invoked the swap function\n  if (outputToken == address(0)) {\n    address payable sender = payable(msg.sender);\n    sender.transfer(outputAmount);\n  } else {\n    IERC20(outputToken).safeTransfer(msg.sender, outputAmount);\n  }\n\n  // Emit swap event to enable better governance decision making\n  emit Swapped(msg.sender, inputToken, outputToken, inputAmount, outputAmount);\n}\n```\n