Temporal Oracle

Exploring Temporal Predictions in Solidity

Overview

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.

1. Making Temporal Predictions

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;

Advantages

  • Future Prediction: Users can make predictions with a specified future timestamp, offering insights into future states.
  • Recursive Predictions: If a prediction is successful, it can trigger another prediction, creating a recursive system of future outcomes.

Disadvantages

  • Time Dependency: Predictions can only be verified after the specified future time, which limits their immediate usefulness.
  • Complexity: Recursive and time loop predictions can increase complexity and potentially higher gas costs.

2. Verifying Predictions

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
        );
    }
}

Advantages

  • Outcome Verification: Users can verify the accuracy of their predictions and trigger additional predictions based on the results.
  • Time-Based Loops: The system allows for time loops, where predictions continuously create future predictions, extending the temporal oracle's insights.

Disadvantages

  • Delayed Verification: Predictions cannot be verified until the future timestamp, meaning users must wait for the results.
  • Gas Costs: Verifying predictions and creating recursive outcomes could lead to increased gas usage over time.

Full Contract Code


// 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);
    }
}