I am trying to write a Prediction Markets smart contract in Solidity. Whenever I call the following function closeMarket
in Remix, the function is reverted, even though all the parameters and require statements are all fulfilled. I also compiled the contract and no errors appeared.
The called function should be payable if you send value and the value you send should be less than your current balance.
function closeMarket(string memory _eventName, bool result) payable public {
Event storage currentEvent = events[_eventName];
require(currentEvent.eventCreator == msg.sender, "Only the event creator can close this market");
if (result) {
// Calculate total profit for the "yes" outcome
uint totalSharesYes = currentEvent.sharesYes;
uint totalPayoutYes = totalSharesYes.mul(currentEvent.sharePriceYes);
uint profitYes = totalPayoutYes.sub(totalSharesYes.mul(currentEvent.sharePriceYes.div(2)));
balance -= profitYes;
// Pay out profits to shareholders of the "yes" outcome
uint profitPerShareYes = currentEvent.sharePriceYes.div(2);
for (uint i = 0; i < totalSharesYes; i++) {
address shareholder = currentEvent.shareholdersYes[i];
payable(shareholder).transfer(profitPerShareYes);
}
} else {
// Calculate total profit for the "no" outcome
uint totalSharesNo = currentEvent.sharesNo;
uint totalPayoutNo = totalSharesNo.mul(currentEvent.sharePriceNo);
uint profitNo = totalPayoutNo.sub(totalSharesNo.mul(currentEvent.sharePriceNo.div(2)));
balance -= profitNo;
// Pay out profits to shareholders of the "no" outcome
uint profitPerShareNo = currentEvent.sharePriceNo.div(2);
for (uint i = 0; i < totalSharesNo; i++) {
address shareholder = currentEvent.shareholdersNo[i];
payable(shareholder).transfer(profitPerShareNo);
}
}
}
I think there might be some kind of unhandled exception going on when the function is called, such as dividing by zero or something wrong with the arthemetic operations that I am running, but couldn't find the cause.
Here is the rest of my contract :
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract PredictionMarket {
using SafeMath for uint;
// The address of the contract owner
address public owner;
// A mapping of event names to event data
mapping(string => Event) public events;
mapping(uint => string) public eventIdToName;
// The event data for a specific event
struct Event {
address eventCreator;
string name;
uint eventId;
uint totalShares;
uint sharePriceYes;
uint sharePriceNo;
uint sharesYes;
uint sharesNo;
address[] shareholdersYes;
address[] shareholdersNo;
}
uint public eventId = 0;
// The balance of the contract
uint public balance;
// Events for logging
event Purchase(address buyer, string eventName, uint shares, uint totalCost);
event Refund(address buyer, string eventName, uint shares, uint refundAmount);
event NewEvent(address eventCreator, string eventName, uint totalShares, uint sharePriceYes, uint sharePriceNo);
// Constructor function
constructor() {
owner = msg.sender;
}
// Function to create a new event
function createEvent(string memory _eventName, uint _totalShares, uint _sharePriceYes, uint _sharePriceNo) public {
require(_sharePriceYes > 0, "Share price must be greater than zero");
require(_sharePriceNo > 0, "Share price must be greater than zero");
eventIdToName[eventId] = _eventName;
eventId++;
events[_eventName] = Event(msg.sender, _eventName, eventId, _totalShares, _sharePriceYes, _sharePriceNo, 0, 0, new address[](0), new address[](0));
emit NewEvent(msg.sender, _eventName, _totalShares, _sharePriceYes, _sharePriceNo);
}
function getEventNameById(uint _eventId) public view returns (string memory) {
return eventIdToName[_eventId];
}
// Function to buy shares in the "yes" outcome of a specific event
function buySharesYes(string memory _eventName, uint _payment) payable public {
Event storage currentEvent = events[_eventName];
require(_payment >= currentEvent.sharePriceYes, "Insufficient payment");
uint shares = _payment / currentEvent.sharePriceYes;
require(shares <= currentEvent.totalShares - currentEvent.sharesYes, "No more shares available");
currentEvent.sharesYes += shares;
balance += _payment;
currentEvent.shareholdersYes.push(msg.sender);
events[_eventName] = currentEvent;
emit Purchase(msg.sender, _eventName, shares, _payment);
}
// Function to buy shares in the "no" outcome of a specific event
function buySharesNo(string memory _eventName, uint _payment) payable public {
Event storage currentEvent = events[_eventName];
require(_payment >= currentEvent.sharePriceNo, "Insufficient payment");
uint shares = _payment / currentEvent.sharePriceNo;
require(shares <= currentEvent.totalShares - currentEvent.sharesNo, "No more shares available");
currentEvent.sharesNo += shares;
balance += _payment;
currentEvent.shareholdersNo.push(msg.sender);
events[_eventName] = currentEvent;
emit Purchase(msg.sender, _eventName, shares, _payment);
}
function closeMarket(string memory _eventName, bool result) payable public {
Event storage currentEvent = events[_eventName];
require(currentEvent.eventCreator == msg.sender, "Only the event creator can close this market");
if (result) {
// Calculate total profit for the "yes" outcome
uint totalSharesYes = currentEvent.sharesYes;
uint totalPayoutYes = totalSharesYes.mul(currentEvent.sharePriceYes);
uint profitYes = totalPayoutYes.sub(totalSharesYes.mul(currentEvent.sharePriceYes.div(2)));
balance -= profitYes;
// Pay out profits to shareholders of the "yes" outcome
uint profitPerShareYes = currentEvent.sharePriceYes.div(2);
for (uint i = 0; i < totalSharesYes; i++) {
address shareholder = currentEvent.shareholdersYes[i];
payable(shareholder).transfer(profitPerShareYes);
}
} else {
// Calculate total profit for the "no" outcome
uint totalSharesNo = currentEvent.sharesNo;
uint totalPayoutNo = totalSharesNo.mul(currentEvent.sharePriceNo);
uint profitNo = totalPayoutNo.sub(totalSharesNo.mul(currentEvent.sharePriceNo.div(2)));
balance -= profitNo;
// Pay out profits to shareholders of the "no" outcome
uint profitPerShareNo = currentEvent.sharePriceNo.div(2);
for (uint i = 0; i < totalSharesNo; i++) {
address shareholder = currentEvent.shareholdersNo[i];
payable(shareholder).transfer(profitPerShareNo);
}
}
}
}
Any help would be appreciated. Thanks
createEvent
, set event name to = "Event1",_totalShares
= 1,000,000 ,_sharePriceYes
= 80,_sharePriceNo
= 20 -> 2. Then I calledbuySharesYes
, entered the same event name, and setpayment
= 160 (bought 2 yes shares) ->. 3. Then I calledbuySharesNo
, entered the same event name, and setpayment
= 40 (bought 2 no shares) ->. 4. CalledcloseMarket
, the problematic function, set result = true. I got the error from here. I am wondering, what values did you put for the mentioned parameters that got it to work? Thanks!