All funds can be stolen from FixedStrikeOptionTeller using a token with malicious decimals
`FixedStrikeOptionTeller` is a single contract which deploys multiple option tokens. Hence this single contract holds significant payout/quote tokens as collateral. Also the `deploy`, `create` & `exercise` functions of this contract can be called by anyone.\\nThis mechanism can be exploited to drain `FixedStrikeOptionTeller` of all tokens.\\nThis is how the create functions looks like:\\n```\\n    function create(\\n        FixedStrikeOptionToken optionToken_,\\n        uint256 amount_\\n    ) external override nonReentrant {\\n        // rest of code\\n        if (call) {\\n            // rest of code\\n        } else {\\n            uint256 quoteAmount = amount_.mulDiv(strikePrice, 10 ** payoutToken.decimals());\\n            // rest of code\\n            quoteToken.safeTransferFrom(msg.sender, address(this), quoteAmount);\\n            // rest of code\\n        }\\n\\n        optionToken.mint(msg.sender, amount_);\\n    }\\n```\\n\\nexercise function:\\n```\\n    function exercise(\\n        FixedStrikeOptionToken optionToken_,\\n        uint256 amount_\\n    ) external override nonReentrant {\\n        // rest of code\\n        uint256 quoteAmount = amount_.mulDiv(strikePrice, 10 ** payoutToken.decimals());\\n\\n        if (msg.sender != receiver) {\\n            // rest of code\\n        }\\n\\n        optionToken.burn(msg.sender, amount_);\\n\\n        if (call) {\\n            // rest of code\\n        } else {\\n            quoteToken.safeTransfer(msg.sender, quoteAmount);\\n        }\\n    }\\n```\\n\\nConsider this attack scenario:\\nLet's suppose the `FixedStrikeOptionTeller` holds some DAI tokens.\\nAn attacker can create a malicious payout token of which he can control the `decimals`.\\nThe attacker calls `deploy` to create an option token with malicious payout token and DAI as quote token and `put` option type\\nMake `payoutToken.decimals` return a large number and call `FixedStrikeOptionTeller.create` with input X. Here `quoteAmount` will be calculated as `0`.\\n```\\n// Calculate amount of quote tokens required to mint\\nuint256 quoteAmount = amount_.mulDiv(strikePrice, 10 ** payoutToken.decimals());\\n\\n// Transfer quote tokens from user\\n// Check that amount received is not less than amount expected\\n// Handles edge cases like fee-on-transfer tokens (which are not supported)\\nuint256 startBalance = quoteToken.balanceOf(address(this));\\nquoteToken.safeTransferFrom(msg.sender, address(this), quoteAmount);\\n```\\n\\nSo 0 DAI will be pulled from the attacker's account but he will receive X option token.\\nMake `payoutToken.decimals` return a small value and call `FixedStrikeOptionTeller.exercise` with X input. Here `quoteAmount` will be calculated as a very high number (which represents number of DAI tokens). So he will receive huge amount of DAI against his X option tokens when exercise the option or when reclaim the token\\n```\\n// Transfer remaining collateral to receiver\\nuint256 amount = optionToken.totalSupply();\\nif (call) {\\n payoutToken.safeTransfer(receiver, amount);\\n} else {\\n // Calculate amount of quote tokens equivalent to amount at strike price\\n uint256 quoteAmount = amount.mulDiv(strikePrice, 10 ** payoutToken.decimals());\\n quoteToken.safeTransfer(receiver, quoteAmount);\\n}\\n```\\n\\nHence, the attacker was able to drain all DAI tokens from the `FixedStrikeOptionTeller` contract. The same mechanism can be repeated to drain all other ERC20 tokens from the `FixedStrikeOptionTeller` contract by changing the return value of the decimal external call
Consider storing the `payoutToken.decimals` value locally instead of fetching it real-time on all `exercise` or `reclaim` calls.\\nor support payout token and quote token whitelist, if the payout token and quote token are permissionless created, there will always be high risk
Anyone can drain `FixedStrikeOptionTeller` contract of all ERC20 tokens. The cost of attack is negligible (only gas cost).\\nHigh impact, high likelyhood.
```\\n    function create(\\n        FixedStrikeOptionToken optionToken_,\\n        uint256 amount_\\n    ) external override nonReentrant {\\n        // rest of code\\n        if (call) {\\n            // rest of code\\n        } else {\\n            uint256 quoteAmount = amount_.mulDiv(strikePrice, 10 ** payoutToken.decimals());\\n            // rest of code\\n            quoteToken.safeTransferFrom(msg.sender, address(this), quoteAmount);\\n            // rest of code\\n        }\\n\\n        optionToken.mint(msg.sender, amount_);\\n    }\\n```\\n