@gnosis.pm/conditional-tokens-market-makers
Version:
Collection of Market Makers for Gnosis Conditional Tokens
1 lines • 22.9 kB
JSON
{"contractName":"FixedProductMarketMakerData","abi":[{"anonymous":false,"inputs":[{"indexed":true,"name":"funder","type":"address"},{"indexed":false,"name":"amountsAdded","type":"uint256[]"},{"indexed":false,"name":"sharesMinted","type":"uint256"}],"name":"FPMMFundingAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"funder","type":"address"},{"indexed":false,"name":"amountsRemoved","type":"uint256[]"},{"indexed":false,"name":"collateralRemovedFromFeePool","type":"uint256"},{"indexed":false,"name":"sharesBurnt","type":"uint256"}],"name":"FPMMFundingRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"buyer","type":"address"},{"indexed":false,"name":"investmentAmount","type":"uint256"},{"indexed":false,"name":"feeAmount","type":"uint256"},{"indexed":true,"name":"outcomeIndex","type":"uint256"},{"indexed":false,"name":"outcomeTokensBought","type":"uint256"}],"name":"FPMMBuy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"returnAmount","type":"uint256"},{"indexed":false,"name":"feeAmount","type":"uint256"},{"indexed":true,"name":"outcomeIndex","type":"uint256"},{"indexed":false,"name":"outcomeTokensSold","type":"uint256"}],"name":"FPMMSell","type":"event"}],"metadata":"{\"compiler\":{\"version\":\"0.5.10+commit.5a6ea5b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"funder\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amountsAdded\",\"type\":\"uint256[]\"},{\"indexed\":false,\"name\":\"sharesMinted\",\"type\":\"uint256\"}],\"name\":\"FPMMFundingAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"funder\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amountsRemoved\",\"type\":\"uint256[]\"},{\"indexed\":false,\"name\":\"collateralRemovedFromFeePool\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"sharesBurnt\",\"type\":\"uint256\"}],\"name\":\"FPMMFundingRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"buyer\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"investmentAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"outcomeIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"outcomeTokensBought\",\"type\":\"uint256\"}],\"name\":\"FPMMBuy\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"seller\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"returnAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"feeAmount\",\"type\":\"uint256\"},{\"indexed\":true,\"name\":\"outcomeIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"outcomeTokensSold\",\"type\":\"uint256\"}],\"name\":\"FPMMSell\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"/home/alan/src/github.com/gnosis/conditional-tokens-market-makers/contracts/FixedProductMarketMaker.sol\":\"FixedProductMarketMakerData\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/alan/src/github.com/gnosis/conditional-tokens-market-makers/contracts/ERC20.sol\":{\"keccak256\":\"0x40a58d43f7c61c93c3e31fa2e398cbbd2768635703066fc37fc98ec19c1da70f\",\"urls\":[\"bzzr://535a311aa4c5d1d4c082822608b7d41eecdc45e4be9df6dc190f158546c809d9\",\"dweb:/ipfs/QmUacDZ7YZ7spzy2XsQuaZeMnKNTQuJUs7cXgQAjbGNScW\"]},\"/home/alan/src/github.com/gnosis/conditional-tokens-market-makers/contracts/FixedProductMarketMaker.sol\":{\"keccak256\":\"0x68003703f48a2b244f5f0fe19473bb1602791d1277882ab3a159af3b1a31daec\",\"urls\":[\"bzzr://4d0cb66cc5c935d8631414bd811452c0eb2901bf6ef794350ebc393085b075fe\",\"dweb:/ipfs/QmdZskHkHDANmxM4XVcXLLeUjRJTuUKpWYYRFbR1FseVwv\"]},\"@gnosis.pm/conditional-tokens-contracts/contracts/CTHelpers.sol\":{\"keccak256\":\"0x921eadb1d6cd0e742448334fb84c39b358a18cdeb7c6badbb89cae847d44a201\",\"urls\":[\"bzzr://54ea8cd3a2ef100710306ce15475573542ad5235ced471d59fa1744cfaea51c8\",\"dweb:/ipfs/Qme871evGa1PBSBnV9PisLhYnFnnahLmBuy5KakLSUKRPF\"]},\"@gnosis.pm/conditional-tokens-contracts/contracts/ConditionalTokens.sol\":{\"keccak256\":\"0x11a610a3fa07ac8a59a09a76fdb944f058fdb06d3414fe49995595e68cd17d41\",\"urls\":[\"bzzr://aec70f70bf6166a9ae46146c7d293156967b345273a250667732f6f8a4355342\",\"dweb:/ipfs/QmWUFR7eKVsMS61UCK1yY2bQQhcqEQHAAmJ2FJ3GozWV8k\"]},\"@gnosis.pm/conditional-tokens-contracts/contracts/ERC1155/ERC1155.sol\":{\"keccak256\":\"0xd8e6583f45a98380ff10a5656a7ae7ba6a275e0d051043e5842f0d541abd7caa\",\"urls\":[\"bzzr://978cc82d056d10d8cc14b02f35801b10c0c2f87b0adbf6c41bbd622e20ab8cee\",\"dweb:/ipfs/QmYWqCK6moph6oeBEUc1nDaGz4GRdGXmykwKD5rykVbhcU\"]},\"@gnosis.pm/conditional-tokens-contracts/contracts/ERC1155/ERC1155TokenReceiver.sol\":{\"keccak256\":\"0x5d1e709c759b9bd72865c8608582d66fc338fde3a77f41abb04ae943915a5695\",\"urls\":[\"bzzr://55e5a597486430ad437bb8c8f0c93cf573b833fa84ccf64a25afaa01c761b839\",\"dweb:/ipfs/QmQ727N1676jG9F5iwakSG2RNeV82TVBGJHgHPmHxib8ah\"]},\"@gnosis.pm/conditional-tokens-contracts/contracts/ERC1155/IERC1155.sol\":{\"keccak256\":\"0x4971631d7de74464fed3e0abac04553e917be5e8cd10b3f825e2e7c39ccc2734\",\"urls\":[\"bzzr://e1e88dfe7440ceab59d4cd604d12e5dc93409a3c5058e497763703027ea7b9e6\",\"dweb:/ipfs/QmRzsL1o6iVEFmqBYCo3XpM4kpvbK7iSJWssXHQ3gHb5uq\"]},\"@gnosis.pm/conditional-tokens-contracts/contracts/ERC1155/IERC1155TokenReceiver.sol\":{\"keccak256\":\"0xca815b5ca57df8f1056b962c2728d6a1e56fc7d9a7869ccee8f5a1ac6075b75d\",\"urls\":[\"bzzr://61df3e61bf24c80714e326ffdc274aaefc342241de3e72374131f613cddbd042\",\"dweb:/ipfs/QmPnF3rGuY2H3Gifvha4dW7fJPptP7wJerHzjz4dpzfTJW\"]},\"openzeppelin-solidity/contracts/introspection/ERC165.sol\":{\"keccak256\":\"0xac2eacd7e7762e275442f28f21d821544df5aae2ed7698af13be8c41b7005e2e\",\"urls\":[\"bzzr://43e901f6f210568ebc1d3591da3ce6a9d10796b854767a9c6e3da10305a8a332\",\"dweb:/ipfs/QmQhfx2Ufr8a2gFXm3KogL66xGgAuAWMwcamkWFKGG6Vya\"]},\"openzeppelin-solidity/contracts/introspection/IERC165.sol\":{\"keccak256\":\"0x661553e43d7c4fbb2de504e5999fd5c104d367488350ed5bf023031bd1ba5ac5\",\"urls\":[\"bzzr://fc2ba15143ce3a00268ecd15fc98eb2469b18bfe27a64bbab0ac6446f161c739\",\"dweb:/ipfs/QmV7wjtRf11ibUHh4g8JjuhMpy68pPhV95L2y46UBoRfsZ\"]},\"openzeppelin-solidity/contracts/math/SafeMath.sol\":{\"keccak256\":\"0x4ccf2d7b51873db1ccfd54ca2adae5eac3b184f9699911ed4490438419f1c690\",\"urls\":[\"bzzr://1604f5b6d6e916c154efd8c6720cda069e5ba32dfa0a9dedf2b42e5b02d07f89\",\"dweb:/ipfs/QmV3yVktya1s617QmuzQR2CfuJgUi3dR2xEZY9ecmqZ2G1\"]},\"openzeppelin-solidity/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0x90e8c2521653bbb1768b05889c5760031e688d9cd361f167489b89215e201b95\",\"urls\":[\"bzzr://aa8b45b57edafc3d67bc5d916327ea16807fae33f753ca163ae0c4061b789766\",\"dweb:/ipfs/QmP5NaEwZthQeM2ESz4WTT3osrP7jhbvu7ocbttBi2JAw6\"]},\"openzeppelin-solidity/contracts/utils/Address.sol\":{\"keccak256\":\"0xf3358e5819ca73357abd6c90bdfffd0474af54364897f6b3e3234c4b71fbe9a1\",\"urls\":[\"bzzr://f7f6da60a184233fd666ac44e6fb2bd51ca6ebdc4867a310d368049aa4e62786\",\"dweb:/ipfs/Qmb3kNCoBUZdah1AgBBD4zMk898j5Qw8ahT1w5cCMYp5Y3\"]}},\"version\":1}","bytecode":"0x6080604052348015600f57600080fd5b50603e80601d6000396000f3fe6080604052600080fdfea265627a7a7230582011f7242dbdc179c23a781f4c12a141c341f59ce4375744202f1f38243128b73964736f6c634300050a0032","deployedBytecode":"0x6080604052600080fdfea265627a7a7230582011f7242dbdc179c23a781f4c12a141c341f59ce4375744202f1f38243128b73964736f6c634300050a0032","sourceMap":"13102:1365:3:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;13102:1365:3;;;;;;;","deployedSourceMap":"13102:1365:3:-;;;;;","source":"pragma solidity ^0.5.1;\n\nimport { SafeMath } from \"openzeppelin-solidity/contracts/math/SafeMath.sol\";\nimport { IERC20 } from \"openzeppelin-solidity/contracts/token/ERC20/IERC20.sol\";\nimport { ConditionalTokens } from \"@gnosis.pm/conditional-tokens-contracts/contracts/ConditionalTokens.sol\";\nimport { CTHelpers } from \"@gnosis.pm/conditional-tokens-contracts/contracts/CTHelpers.sol\";\nimport { ERC1155TokenReceiver } from \"@gnosis.pm/conditional-tokens-contracts/contracts/ERC1155/ERC1155TokenReceiver.sol\";\nimport { ERC20 } from \"./ERC20.sol\";\n\n\nlibrary CeilDiv {\n // calculates ceil(x/y)\n function ceildiv(uint x, uint y) internal pure returns (uint) {\n if(x > 0) return ((x - 1) / y) + 1;\n return x / y;\n }\n}\n\n\ncontract FixedProductMarketMaker is ERC20, ERC1155TokenReceiver {\n event FPMMFundingAdded(\n address indexed funder,\n uint[] amountsAdded,\n uint sharesMinted\n );\n event FPMMFundingRemoved(\n address indexed funder,\n uint[] amountsRemoved,\n uint collateralRemovedFromFeePool,\n uint sharesBurnt\n );\n event FPMMBuy(\n address indexed buyer,\n uint investmentAmount,\n uint feeAmount,\n uint indexed outcomeIndex,\n uint outcomeTokensBought\n );\n event FPMMSell(\n address indexed seller,\n uint returnAmount,\n uint feeAmount,\n uint indexed outcomeIndex,\n uint outcomeTokensSold\n );\n\n using SafeMath for uint;\n using CeilDiv for uint;\n\n uint constant ONE = 10**18;\n\n ConditionalTokens public conditionalTokens;\n IERC20 public collateralToken;\n bytes32[] public conditionIds;\n uint public fee;\n uint internal feePoolWeight;\n\n uint[] outcomeSlotCounts;\n bytes32[][] collectionIds;\n uint[] positionIds;\n mapping (address => uint256) withdrawnFees;\n uint internal totalWithdrawnFees;\n\n function getPoolBalances() private view returns (uint[] memory) {\n address[] memory thises = new address[](positionIds.length);\n for(uint i = 0; i < positionIds.length; i++) {\n thises[i] = address(this);\n }\n return conditionalTokens.balanceOfBatch(thises, positionIds);\n }\n\n function generateBasicPartition(uint outcomeSlotCount)\n private\n pure\n returns (uint[] memory partition)\n {\n partition = new uint[](outcomeSlotCount);\n for(uint i = 0; i < outcomeSlotCount; i++) {\n partition[i] = 1 << i;\n }\n }\n\n function splitPositionThroughAllConditions(uint amount)\n private\n {\n for(uint i = conditionIds.length - 1; int(i) >= 0; i--) {\n uint[] memory partition = generateBasicPartition(outcomeSlotCounts[i]);\n for(uint j = 0; j < collectionIds[i].length; j++) {\n conditionalTokens.splitPosition(collateralToken, collectionIds[i][j], conditionIds[i], partition, amount);\n }\n }\n }\n\n function mergePositionsThroughAllConditions(uint amount)\n private\n {\n for(uint i = 0; i < conditionIds.length; i++) {\n uint[] memory partition = generateBasicPartition(outcomeSlotCounts[i]);\n for(uint j = 0; j < collectionIds[i].length; j++) {\n conditionalTokens.mergePositions(collateralToken, collectionIds[i][j], conditionIds[i], partition, amount);\n }\n }\n }\n\n function collectedFees() external view returns (uint) {\n return feePoolWeight.sub(totalWithdrawnFees);\n }\n\n function feesWithdrawableBy(address account) public view returns (uint) {\n uint rawAmount = feePoolWeight.mul(balanceOf(account)) / totalSupply();\n return rawAmount.sub(withdrawnFees[account]);\n }\n\n function withdrawFees(address account) public {\n uint rawAmount = feePoolWeight.mul(balanceOf(account)) / totalSupply();\n uint withdrawableAmount = rawAmount.sub(withdrawnFees[account]);\n if(withdrawableAmount > 0){\n withdrawnFees[account] = rawAmount;\n totalWithdrawnFees = totalWithdrawnFees.add(withdrawableAmount);\n require(collateralToken.transfer(account, withdrawableAmount), \"withdrawal transfer failed\");\n }\n }\n\n function _beforeTokenTransfer(address from, address to, uint256 amount) internal {\n if (from != address(0)) {\n withdrawFees(from);\n }\n\n uint totalSupply = totalSupply();\n uint withdrawnFeesTransfer = totalSupply == 0 ?\n amount :\n feePoolWeight.mul(amount) / totalSupply;\n\n if (from != address(0)) {\n withdrawnFees[from] = withdrawnFees[from].sub(withdrawnFeesTransfer);\n totalWithdrawnFees = totalWithdrawnFees.sub(withdrawnFeesTransfer);\n } else {\n feePoolWeight = feePoolWeight.add(withdrawnFeesTransfer);\n }\n if (to != address(0)) {\n withdrawnFees[to] = withdrawnFees[to].add(withdrawnFeesTransfer);\n totalWithdrawnFees = totalWithdrawnFees.add(withdrawnFeesTransfer);\n } else {\n feePoolWeight = feePoolWeight.sub(withdrawnFeesTransfer);\n }\n }\n\n function addFunding(uint addedFunds, uint[] calldata distributionHint)\n external\n {\n require(addedFunds > 0, \"funding must be non-zero\");\n\n uint[] memory sendBackAmounts = new uint[](positionIds.length);\n uint poolShareSupply = totalSupply();\n uint mintAmount;\n if(poolShareSupply > 0) {\n require(distributionHint.length == 0, \"cannot use distribution hint after initial funding\");\n uint[] memory poolBalances = getPoolBalances();\n uint poolWeight = 0;\n for(uint i = 0; i < poolBalances.length; i++) {\n uint balance = poolBalances[i];\n if(poolWeight < balance)\n poolWeight = balance;\n }\n\n for(uint i = 0; i < poolBalances.length; i++) {\n uint remaining = addedFunds.mul(poolBalances[i]) / poolWeight;\n sendBackAmounts[i] = addedFunds.sub(remaining);\n }\n\n mintAmount = addedFunds.mul(poolShareSupply) / poolWeight;\n } else {\n if(distributionHint.length > 0) {\n require(distributionHint.length == positionIds.length, \"hint length off\");\n uint maxHint = 0;\n for(uint i = 0; i < distributionHint.length; i++) {\n uint hint = distributionHint[i];\n if(maxHint < hint)\n maxHint = hint;\n }\n\n for(uint i = 0; i < distributionHint.length; i++) {\n uint remaining = addedFunds.mul(distributionHint[i]) / maxHint;\n require(remaining > 0, \"must hint a valid distribution\");\n sendBackAmounts[i] = addedFunds.sub(remaining);\n }\n }\n\n mintAmount = addedFunds;\n }\n\n require(collateralToken.transferFrom(msg.sender, address(this), addedFunds), \"funding transfer failed\");\n require(collateralToken.approve(address(conditionalTokens), addedFunds), \"approval for splits failed\");\n splitPositionThroughAllConditions(addedFunds);\n\n _mint(msg.sender, mintAmount);\n\n conditionalTokens.safeBatchTransferFrom(address(this), msg.sender, positionIds, sendBackAmounts, \"\");\n\n // transform sendBackAmounts to array of amounts added\n for (uint i = 0; i < sendBackAmounts.length; i++) {\n sendBackAmounts[i] = addedFunds.sub(sendBackAmounts[i]);\n }\n\n emit FPMMFundingAdded(msg.sender, sendBackAmounts, mintAmount);\n }\n\n function removeFunding(uint sharesToBurn)\n external\n {\n uint[] memory poolBalances = getPoolBalances();\n\n uint[] memory sendAmounts = new uint[](poolBalances.length);\n\n uint poolShareSupply = totalSupply();\n for(uint i = 0; i < poolBalances.length; i++) {\n sendAmounts[i] = poolBalances[i].mul(sharesToBurn) / poolShareSupply;\n }\n\n uint collateralRemovedFromFeePool = collateralToken.balanceOf(address(this));\n\n _burn(msg.sender, sharesToBurn);\n collateralRemovedFromFeePool = collateralRemovedFromFeePool.sub(\n collateralToken.balanceOf(address(this))\n );\n\n conditionalTokens.safeBatchTransferFrom(address(this), msg.sender, positionIds, sendAmounts, \"\");\n\n emit FPMMFundingRemoved(msg.sender, sendAmounts, collateralRemovedFromFeePool, sharesToBurn);\n }\n\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 value,\n bytes calldata data\n )\n external\n returns (bytes4)\n {\n if (operator == address(this)) {\n return this.onERC1155Received.selector;\n }\n return 0x0;\n }\n\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n )\n external\n returns (bytes4)\n {\n if (operator == address(this) && from == address(0)) {\n return this.onERC1155BatchReceived.selector;\n }\n return 0x0;\n }\n\n function calcBuyAmount(uint investmentAmount, uint outcomeIndex) public view returns (uint) {\n require(outcomeIndex < positionIds.length, \"invalid outcome index\");\n\n uint[] memory poolBalances = getPoolBalances();\n uint investmentAmountMinusFees = investmentAmount.sub(investmentAmount.mul(fee) / ONE);\n uint buyTokenPoolBalance = poolBalances[outcomeIndex];\n uint endingOutcomeBalance = buyTokenPoolBalance.mul(ONE);\n for(uint i = 0; i < poolBalances.length; i++) {\n if(i != outcomeIndex) {\n uint poolBalance = poolBalances[i];\n endingOutcomeBalance = endingOutcomeBalance.mul(poolBalance).ceildiv(\n poolBalance.add(investmentAmountMinusFees)\n );\n }\n }\n require(endingOutcomeBalance > 0, \"must have non-zero balances\");\n\n return buyTokenPoolBalance.add(investmentAmountMinusFees).sub(endingOutcomeBalance.ceildiv(ONE));\n }\n\n function calcSellAmount(uint returnAmount, uint outcomeIndex) public view returns (uint outcomeTokenSellAmount) {\n require(outcomeIndex < positionIds.length, \"invalid outcome index\");\n\n uint[] memory poolBalances = getPoolBalances();\n uint returnAmountPlusFees = returnAmount.mul(ONE) / ONE.sub(fee);\n uint sellTokenPoolBalance = poolBalances[outcomeIndex];\n uint endingOutcomeBalance = sellTokenPoolBalance.mul(ONE);\n for(uint i = 0; i < poolBalances.length; i++) {\n if(i != outcomeIndex) {\n uint poolBalance = poolBalances[i];\n endingOutcomeBalance = endingOutcomeBalance.mul(poolBalance).ceildiv(\n poolBalance.sub(returnAmountPlusFees)\n );\n }\n }\n require(endingOutcomeBalance > 0, \"must have non-zero balances\");\n\n return returnAmountPlusFees.add(endingOutcomeBalance.ceildiv(ONE)).sub(sellTokenPoolBalance);\n }\n\n function buy(uint investmentAmount, uint outcomeIndex, uint minOutcomeTokensToBuy) external {\n uint outcomeTokensToBuy = calcBuyAmount(investmentAmount, outcomeIndex);\n require(outcomeTokensToBuy >= minOutcomeTokensToBuy, \"minimum buy amount not reached\");\n\n require(collateralToken.transferFrom(msg.sender, address(this), investmentAmount), \"cost transfer failed\");\n\n uint feeAmount = investmentAmount.mul(fee) / ONE;\n feePoolWeight = feePoolWeight.add(feeAmount);\n uint investmentAmountMinusFees = investmentAmount.sub(feeAmount);\n require(collateralToken.approve(address(conditionalTokens), investmentAmountMinusFees), \"approval for splits failed\");\n splitPositionThroughAllConditions(investmentAmountMinusFees);\n\n conditionalTokens.safeTransferFrom(address(this), msg.sender, positionIds[outcomeIndex], outcomeTokensToBuy, \"\");\n\n emit FPMMBuy(msg.sender, investmentAmount, feeAmount, outcomeIndex, outcomeTokensToBuy);\n }\n\n function sell(uint returnAmount, uint outcomeIndex, uint maxOutcomeTokensToSell) external {\n uint outcomeTokensToSell = calcSellAmount(returnAmount, outcomeIndex);\n require(outcomeTokensToSell <= maxOutcomeTokensToSell, \"maximum sell amount exceeded\");\n\n conditionalTokens.safeTransferFrom(msg.sender, address(this), positionIds[outcomeIndex], outcomeTokensToSell, \"\");\n\n uint feeAmount = returnAmount.mul(fee) / (ONE.sub(fee));\n feePoolWeight = feePoolWeight.add(feeAmount);\n uint returnAmountPlusFees = returnAmount.add(feeAmount);\n mergePositionsThroughAllConditions(returnAmountPlusFees);\n\n require(collateralToken.transfer(msg.sender, returnAmount), \"return transfer failed\");\n\n emit FPMMSell(msg.sender, returnAmount, feeAmount, outcomeIndex, outcomeTokensToSell);\n }\n}\n\n\n// for proxying purposes\ncontract FixedProductMarketMakerData {\n mapping (address => uint256) internal _balances;\n mapping (address => mapping (address => uint256)) internal _allowances;\n uint256 internal _totalSupply;\n\n\n bytes4 internal constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;\n mapping(bytes4 => bool) internal _supportedInterfaces;\n\n\n event FPMMFundingAdded(\n address indexed funder,\n uint[] amountsAdded,\n uint sharesMinted\n );\n event FPMMFundingRemoved(\n address indexed funder,\n uint[] amountsRemoved,\n uint collateralRemovedFromFeePool,\n uint sharesBurnt\n );\n event FPMMBuy(\n address indexed buyer,\n uint investmentAmount,\n uint feeAmount,\n uint indexed outcomeIndex,\n uint outcomeTokensBought\n );\n event FPMMSell(\n address indexed seller,\n uint returnAmount,\n uint feeAmount,\n uint indexed outcomeIndex,\n uint outcomeTokensSold\n );\n ConditionalTokens internal conditionalTokens;\n IERC20 internal collateralToken;\n bytes32[] internal conditionIds;\n uint internal fee;\n uint internal feePoolWeight;\n\n uint[] internal outcomeSlotCounts;\n bytes32[][] internal collectionIds;\n uint[] internal positionIds;\n mapping (address => uint256) internal withdrawnFees;\n uint internal totalWithdrawnFees;\n}\n","compiler":{"name":"solc","version":"0.5.10+commit.5a6ea5b1.Emscripten.clang"},"networks":{},"schemaVersion":"3.0.16","updatedAt":"2020-03-16T19:03:53.071Z","devdoc":{"methods":{}},"userdoc":{"methods":{}}}