# Need help personal project - user predicts up or down -> get oracle price to calc results -> output address list of winners

Hi all,

Working on a personal project and ran into a bit of a wall… hope someone here can give some insight or pointers on how to move onto the next step.

There’s still a lot of broken parts, and not expecting anyone to write a complete magic solution, but hoping some of you experts can give any insight at all into how i can improve the code or the logic, or what mistakes there are (e.g. using the wrong structures to store the data) and generally any small or big things I can do to improve.

I’m very very very new to programming and completed the solidity 101 course less than a week ago so any help at all would be appreciated!! Thank you in advance!!! <3 <3 <3

### OVERVIEW

#### What does the contract do?

Users will be able to make a binary outcome prediction, i.e. will price of ETH be higher or lower when a ‘round’ ends vs when it started.

#### How does it work?

Please see comments at the beginning of code block for a detailed explanation of how I’m thinking about the solution, and the code plan listing some inputs, functions, calculations required.

### Problem

``````/* UP OR DOWN
*
* Users can make predictions on whether the price of ETH will be higher or lower when a Round closes vs when it opened.
*
* A round is started by owner calling `createRoundAndStart`, and also sets the timeNoMoreBets and timeEnd.
* During the round duration before timeNoMoreBets, any user can call `submitPrediction` to submit their answer.
* After timeNoMoreBets, no more predictions can be submitted.
* After timeEnd, call `computeResult` to get the `priceEnd`.
* Then compute if the round was up or down, and compute and return the list of Winners of that round.
*/

// CODE PLAN

// types of data points:
// 1. list of ADDRESS => PREDICTIONS
// 2. list of ROUNDS => INDEX, STARTTIME, ENDTIME, NOMOREBETS, STARTPRICE, ENDPRICE, RESULT
// 3. for ROUND[index] ==> list of predictors addresses => PREDICTION, WIN/LOSE

// functions to:
//create (and start) a round
//let user submit a prediction
//after round end, get endPrice
//w endPrice we know if startPrice higher or lower, and hence know if user's prediction is Win or Lose

// what outputs do i want?
//For ROUND[n], i want to know the data: startPrice, endPrice, boolean for Up or Down
//For ROUND[n], i also want to know the list of all addresses that submited prediction + what was their prediction,
//              from this list compare UpOrDown result to know if their PredictionWinOrLose is true or false.
//          i.e. ADDRESS => UPorDOWN.boolean => ... compare with results ... => PredictionWinOrLose.boolean
// Then LIST all WINNERS ; and list all LOSERS

pragma solidity 0.8.15;

contract UpOrDown {

// 3 lines to make onlyOwner work in function headers:

modifier onlyOwner {
require(msg.sender == owner);
_;
}

constructor() {
owner = msg.sender;
}

// Handling owner create round

struct Round{
uint roundId;
uint timeStart;
uint timeEnd; // input for createRound
uint noMoreBets; // input for createRound
uint priceStart;
uint priceEnd; // THIS IS NOT KNOWN WHEN CREATEROUND. CAN PUSH NULL VALUE TO THE ARRAY?
bool roundResult; // THIS IS NOT KNOWN WHEN CREATEROUND. CAN PUSH NULL VALUE TO THE ARRAY?
}

Round[] roundLog;

function createRoundAndStart(uint _timeEnd, uint _noMoreBets) public onlyOwner {
// require timeStart > timeCurrent
_priceStart = getLatestPrice(); // priceStart
_timeStart = getLatestPriceTimestamp(); // timeStart // or should it be the time/block the function was executed

roundLog.push( Round( roundLog.length, _timeStart, _timeEnd, _noMoreBets, _priceStart ) );
}

// timeEnd and noMoreBets can then become input with SECONDS from now instead of unix timestamp. i.e. roundDuration, and noMoreBetsCutoff (e.g. 60 mins before roundEnd)

// Handling user submit prediction

struct Users{
uint userId;
bool prediction; // true for up, false for down
}

Users[] userLog;

function submitPrediction(bool _prediction) public {
userLog.push( Users( userLog.length, msg.sender, _prediction ) );
}

// // get priceStart and priceEnd for timeStart and timeEnd // no need timeStart anymore; priceStart generated with createRoundAndStart
// ==> get priceEnd for timeEnd

// HOW DO I GET THE priceEnd ?
// AT timeEnd, HOW DO I AUTOMATICALLY CALL A FUNCTION?
//      OR AT ANY TIME AFTER timeEnd, I must manually CALL FUNCTION,
//      which will check back to the price at timestamp that's closest to the timeEnd of round.

function fetchPriceEndAndComputeResults() public {
// if timeCurrent > timeEnd, fetch priceEnd
_priceEnd = getLatestPrice(); // function need to look back at price timestamps to determine closest one to endTime.
/* e.g.
* get latest roundID, latest timeStamp from priceFeed. also get endTime of this contract.
* count roundID down from current with i--, until we find a timeStamp that is < than endTime.
* take the 2nd last one (the last one which timeStamp > endTime), and get PRICE for that timestamp, equal to = priceEnd !!
*/

// if priceEnd >= priceStart , then true
// if priceEnd < priceStart , then false
if (_priceEnd >= priceStart) {
_roundResult = true;
} else {
_roundResult = false;
}

roundLog.push( Round( x, x, x, x, x, _priceEnd, _roundResult  ) );

}

function getWinners() public {
// `roundResult` and `prediction` both true or both false means USER==WIN i.e. bool.userPrediction == bool.roundResult
// Get USERS[address] list , by filtering all users in the round where USERS[prediction] == ROUND[roundResult]
for roundLog[roundResult]
}

}

// // HOW TO HANDLE USERS IN MULTIPLE ROUNDS? make no clashes in predictions/results etc., how to structure rounds/users/...?

// array[Round, Users]
// array[Round, Users, Results]

``````