🗳️

Voting Oracle (Stateful)

Learn how stateful oracles maintain state across invocations

Step 1 of 5

1

Create Voting Oracle

Submit CreateScriptOracle message to create a stateful voting oracle

🔮 STATEFUL ORACLE CREATION: This oracle maintains state across invocations. Unlike the calculator oracle, this one has initialState that will be updated with each method call. The oracle supports create, vote, and close methods.

📨 Message Type: CreateScriptOracle

{
  "cid": "voting-oracle-uuid",
  "scriptProgram": {
    "if": [
      {
        "==": [
          {
            "var": "method"
          },
          "create"
        ]
      },
      {
        "if": [
          {
            "and": [
              {
                "exists": [
                  {
                    "var": "title"
                  },
                  {
                    "var": "options"
                  },
                  {
                    "var": "endTime"
                  }
                ]
              },
              {
                ">": [
                  {
                    "var": "endTime"
                  },
                  {
                    "var": "currentTime"
                  }
                ]
              }
            ]
          },
          {
            "title": {
              "var": "title"
            },
            "options": {
              "var": "options"
            },
            "voteCount": 0,
            "endTime": {
              "var": "endTime"
            },
            "active": true
          },
          "Failed create checks"
        ]
      },
      {
        "==": [
          {
            "var": "method"
          },
          "vote"
        ]
      },
      {
        "if": [
          {
            "and": [
              {
                "==": [
                  {
                    "var": "state.active"
                  },
                  true
                ]
              },
              {
                "<": [
                  {
                    "var": "currentTime"
                  },
                  {
                    "var": "state.endTime"
                  }
                ]
              },
              {
                "in": [
                  {
                    "var": "option"
                  },
                  {
                    "var": "state.options"
                  }
                ]
              },
              {
                "in": [
                  {
                    "var": "voter"
                  },
                  {
                    "var": "participants"
                  }
                ]
              }
            ]
          },
          {
            "title": {
              "var": "state.title"
            },
            "options": {
              "var": "state.options"
            },
            "voteCount": {
              "+": [
                {
                  "var": "state.voteCount"
                },
                1
              ]
            },
            "lastVoter": {
              "var": "voter"
            },
            "lastOption": {
              "var": "option"
            },
            "endTime": {
              "var": "state.endTime"
            },
            "active": {
              "var": "state.active"
            }
          },
          "Failed vote checks"
        ]
      },
      {
        "==": [
          {
            "var": "method"
          },
          "close"
        ]
      },
      {
        "if": [
          {
            "and": [
              {
                "==": [
                  {
                    "var": "state.active"
                  },
                  true
                ]
              },
              {
                ">=": [
                  {
                    "var": "currentTime"
                  },
                  {
                    "var": "state.endTime"
                  }
                ]
              }
            ]
          },
          {
            "title": {
              "var": "state.title"
            },
            "options": {
              "var": "state.options"
            },
            "voteCount": {
              "var": "state.voteCount"
            },
            "endTime": {
              "var": "state.endTime"
            },
            "active": false
          },
          "Failed close checks"
        ]
      },
      "Unknown method"
    ]
  },
  "initialState": null,
  "accessControl": {
    "Public": {}
  }
}

State Before

null

State After

null

Oracle Script Program

The voting oracle uses nested if statements to handle create, vote, and close methods. Notice how it references {var: "state.field"} to access the oracle's persistent state:

{
  "if": [
    {
      "==": [
        {
          "var": "method"
        },
        "create"
      ]
    },
    {
      "if": [
        {
          "and": [
            {
              "exists": [
                {
                  "var": "title"
                },
                {
                  "var": "options"
                },
                {
                  "var": "endTime"
                }
              ]
            },
            {
              ">": [
                {
                  "var": "endTime"
                },
                {
                  "var": "currentTime"
                }
              ]
            }
          ]
        },
        {
          "title": {
            "var": "title"
          },
          "options": {
            "var": "options"
          },
          "voteCount": 0,
          "endTime": {
            "var": "endTime"
          },
          "active": true
        },
        "Failed create checks"
      ]
    },
    {
      "==": [
        {
          "var": "method"
        },
        "vote"
      ]
    },
    {
      "if": [
        {
          "and": [
            {
              "==": [
                {
                  "var": "state.active"
                },
                true
              ]
            },
            {
              "<": [
                {
                  "var": "currentTime"
                },
                {
                  "var": "state.endTime"
                }
              ]
            },
            {
              "in": [
                {
                  "var": "option"
                },
                {
                  "var": "state.options"
                }
              ]
            },
            {
              "in": [
                {
                  "var": "voter"
                },
                {
                  "var": "participants"
                }
              ]
            }
          ]
        },
        {
          "title": {
            "var": "state.title"
          },
          "options": {
            "var": "state.options"
          },
          "voteCount": {
            "+": [
              {
                "var": "state.voteCount"
              },
              1
            ]
          },
          "lastVoter": {
            "var": "voter"
          },
          "lastOption": {
            "var": "option"
          },
          "endTime": {
            "var": "state.endTime"
          },
          "active": {
            "var": "state.active"
          }
        },
        "Failed vote checks"
      ]
    },
    {
      "==": [
        {
          "var": "method"
        },
        "close"
      ]
    },
    {
      "if": [
        {
          "and": [
            {
              "==": [
                {
                  "var": "state.active"
                },
                true
              ]
            },
            {
              ">=": [
                {
                  "var": "currentTime"
                },
                {
                  "var": "state.endTime"
                }
              ]
            }
          ]
        },
        {
          "title": {
            "var": "state.title"
          },
          "options": {
            "var": "state.options"
          },
          "voteCount": {
            "var": "state.voteCount"
          },
          "endTime": {
            "var": "state.endTime"
          },
          "active": false
        },
        "Failed close checks"
      ]
    },
    "Unknown method"
  ]
}

Key Concepts Demonstrated

💾

Stateful Oracles

Oracles can maintain state across invocations, enabling complex workflows like voting, escrow, and marketplace contracts

🔄

State Transitions

Each invocation reads the current state, validates guards, and returns new state that persists for the next call

🛡️

Business Rule Enforcement

Guards validate conditions like active status, deadlines, and participant authorization before allowing state changes

📊

Accumulating Data

State like voteCount increments across invocations, demonstrating how oracles can aggregate information over time