// SPDX-License-Identifier: MIT pragma solidity 0.8.19; contract TokenExchange { // Mapping of user addresses to their token balances mapping(address => uint256) private balances; // Reference to the TokenLibrary contract address public tokenLibrary; string public price; string public buy; string public sell; // Event emitted when tokens are bought event TokensBought(address indexed buyer, uint256 amount, uint256 cost); // Event emitted when tokens are sold event TokensSold(address indexed seller, uint256 amount, uint256 revenue); // Event emitted when the library is updated event LibraryUpdate(address indexed auth, address newLibAddress); // Constructor - Pass the address of the TokenLibrary contract during deployment constructor(address _tokenLibrary, string memory p, string memory b, string memory s) { tokenLibrary = _tokenLibrary; price = p; buy = b; sell = s; } // Function to buy tokens function buyTokens() external payable { // Call library to see how many tokens you cound buy (bool ok, bytes memory data) = tokenLibrary.call(abi.encodeWithSignature(price)); require(ok, "Call failed"); uint256 _price = uint256(bytes32(data)); uint256 _amount = msg.value / _price; require(_amount > 0, "Insufficient funds to buy token"); // Call library to buy tokens (ok, ) = tokenLibrary.call{value: _price*_amount}(abi.encodeWithSignature(buy, _amount)); require(ok, "Call failed"); // Update number of tokens that the user owns balances[msg.sender] += _amount; // Emit the TokensBought event emit TokensBought(msg.sender, _amount, _price); // Give back exchanges uint256 leftOver = msg.value - _price*_amount; if (leftOver > 0) { payable(msg.sender).transfer(leftOver); } } // Function to sell tokens function sellTokens(uint256 _amount) external { require(_amount <= balances[msg.sender], "Insufficient amount"); // Contract balance before selling tokens uint256 temp = address(this).balance; // Call library to sell tokens (bool ok, ) = tokenLibrary.call(abi.encodeWithSignature(sell, _amount)); require(ok, "Call failed"); // Update number of tokens that the user owns balances[msg.sender] -= _amount; // Calculate revenue and transfer to seller uint256 revenue = address(this).balance - temp; payable(msg.sender).transfer(revenue); // Emit the TokensSold event emit TokensSold(msg.sender, _amount, revenue); } // Function to see token price function priceToken() external returns(uint256){ (bool ok, bytes memory data) = tokenLibrary.call(abi.encodeWithSignature(price)); require(ok, "Call failed"); return (uint256(bytes32(data))); } // Function to get the user's token balance function getBalance() external view returns (uint256) { require(balances[msg.sender] > 0, "You don't have any tokens"); return balances[msg.sender]; } //Functions to update library settings function updateLibrary(address newLib) public returns(bool){ tokenLibrary = newLib; emit LibraryUpdate(msg.sender, newLib); return true; } function updatePrice(string calldata newPrice) public returns(bool){ price = newPrice; return true; } function updateBuy(string calldata newBuy) public returns(bool){ buy = newBuy; return true; } function updatesell(string calldata newSell) public returns(bool){ sell = newSell; return true; } } contract invOracle{ uint256 public bought; uint256 public sold; receive() external payable { } function getPrice() public pure returns(uint256){ return 1 ether; } function buy(uint256 _amt) public payable returns(bool){ bought += _amt; return true; } function sell(uint256 _sll) public returns(bool){ sold += _sll; return true; } } contract invOracleMalicious{ invOracle InvOracle; constructor(address addr) { InvOracle = invOracle(payable(addr)); } receive() external payable { } function getPrice() public pure returns(uint256){ return 100 wei; } function buy(uint256 _amt) public payable returns(bool){ InvOracle.buy(_amt); return true; } function sell(uint256 _sll) public returns(bool){ InvOracle.sell(_sll); return true; } }