Exploring Temporal Predictions in Solidity
The TemporalOracle contract enables users to make temporal predictions and verify them after a future timestamp. It also allows recursive predictions and predictions based on time loops. Below, we explore the contract's features, advantages, and disadvantages.
The contract allows users to make predictions with a future timestamp, which can be verified later:
struct Prediction {
uint256 predictionId;
address predictor;
bytes32 predictedOutcome;
uint256 creationTime;
uint256 predictionTime;
}
mapping(uint256 => Prediction) public predictions;
uint256 public nextPredictionId;
Users can verify predictions once the future time arrives, with outcomes either succeeding or failing:
function verifyPrediction(uint256 predictionId, bytes32 actualOutcome)
public
{
Prediction storage prediction = predictions[predictionId];
require(
block.timestamp >= prediction.predictionTime,
"Too early to verify"
);
require(prediction.predictor == msg.sender, "Not the predictor");
bool success = (actualOutcome == prediction.predictedOutcome);
emit PredictionVerified(predictionId, actualOutcome, success);
if (success) {
recursivePrediction(
actualOutcome,
prediction.predictionTime + 1 weeks
);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
contract TemporalOracle {
struct Prediction {
uint256 predictionId;
address predictor;
bytes32 predictedOutcome;
uint256 creationTime;
uint256 predictionTime;
}
mapping(uint256 => Prediction) public predictions;
uint256 public nextPredictionId;
event PredictionMade(
uint256 predictionId,
address predictor,
uint256 creationTime,
uint256 predictionTime
);
event PredictionVerified(
uint256 predictionId,
bytes32 actualOutcome,
bool success
);
function makePrediction(bytes32 predictedOutcome, uint256 futureTime)
public
{
require(
futureTime > block.timestamp,
"Future time must be in the future"
);
uint256 predictionId = nextPredictionId++;
predictions[predictionId] = Prediction({
predictionId: predictionId,
predictor: msg.sender,
predictedOutcome: predictedOutcome,
creationTime: block.timestamp,
predictionTime: futureTime
});
emit PredictionMade(
predictionId,
msg.sender,
block.timestamp,
futureTime
);
}
function verifyPrediction(uint256 predictionId, bytes32 actualOutcome)
public
{
Prediction storage prediction = predictions[predictionId];
require(
block.timestamp >= prediction.predictionTime,
"Too early to verify"
);
require(prediction.predictor == msg.sender, "Not the predictor");
bool success = (actualOutcome == prediction.predictedOutcome);
emit PredictionVerified(predictionId, actualOutcome, success);
if (success) {
recursivePrediction(
actualOutcome,
prediction.predictionTime + 1 weeks
);
}
}
function recursivePrediction(bytes32 outcome, uint256 futureTime) internal {
uint256 newPredictionId = nextPredictionId++;
predictions[newPredictionId] = Prediction({
predictionId: newPredictionId,
predictor: msg.sender,
predictedOutcome: keccak256(
abi.encodePacked(outcome, block.timestamp)
),
creationTime: block.timestamp,
predictionTime: futureTime
});
emit PredictionMade(
newPredictionId,
msg.sender,
block.timestamp,
futureTime
);
}
function queryPastPrediction(uint256 predictionId)
public
view
returns (bytes32, uint256)
{
Prediction storage prediction = predictions[predictionId];
return (prediction.predictedOutcome, prediction.creationTime);
}
function generateTemporalKey(uint256 predictionId)
public
view
returns (bytes32)
{
Prediction storage prediction = predictions[predictionId];
return
keccak256(
abi.encodePacked(
prediction.predictedOutcome,
prediction.creationTime,
prediction.predictionTime
)
);
}
function timeLoopPrediction(bytes32 initialOutcome, uint8 iterations)
public
{
bytes32 currentOutcome = initialOutcome;
uint256 futureTime = block.timestamp + 1 weeks;
for (uint8 i = 0; i < iterations; i++) {
makePrediction(currentOutcome, futureTime);
futureTime += 1 weeks;
currentOutcome = keccak256(
abi.encodePacked(currentOutcome, futureTime)
);
}
}
function observeDecay(uint256 predictionId) public view returns (uint256) {
Prediction storage prediction = predictions[predictionId];
uint256 timeElapsed = block.timestamp - prediction.creationTime;
uint256 decayFactor = timeElapsed / 1 days;
return prediction.predictionTime / (1 + decayFactor);
}
}