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:
address owner;
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 ) );
}
// add chainlink oracle feed to get latestPrice=startPrice.
// 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)
// add priceStart to struct
// Handling user submit prediction
struct Users{
uint userId;
address predictor;
bool prediction; // true for up, false for down
}
Users[] userLog;
function submitPrediction(bool _prediction) public {
userLog.push( Users( userLog.length, msg.sender, _prediction ) );
}
// REMAINING TASKS
// // 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]