# Round based datafeed oracles on Algorand

## Abstract

The following document introduces conventions for building round based datafeed oracles on Algorand using the ABI defined in [ARC-4](https://dev.algorand.co/arc-standards/arc-0004).

## Specification

The key words “ **MUST**”, “ **MUST NOT**”, “ **REQUIRED**”, “ **SHALL**”, “ **SHALL NOT**”, “ **SHOULD**”, “ **SHOULD NOT**”, “ **RECOMMENDED**”, “ **MAY**”, and “ **OPTIONAL**” in this document are to be interpreted as described in [RFC-2119](https://www.ietf.org/rfc/rfc2119.txt).

> Comments like this are non-normative.

An [ARC-21](https://dev.algorand.co/arc-standards/arc-0021) oracle **MUST** have an associated smart-contract implementaing the ABI interface described below.

### ABI Interface

Round based datafeed oracles allow smart-contracts to get data with relevancy to a specific block number, for example the ALGO price at a specific round.

The associated smart contract **MUST** implement the following ABI interface:

```
{

"name": "ARC_0021",

"desc": "Interface for a round based datafeed oracle",

"methods": [

{

"name": "get",

"desc": "Get data from the oracle for a specific round",

"args": [

{ "type": "uint64", "name": "round", "desc": "The desired round" },

{ "type": "byte[]", "name": "user_data", "desc": "Optional: Extra data provided by the user. Pass an empty slice if not used." }

],

"returns": { "type": "byte[]", "desc": "The oracle's response. If the data doesn't exist, the response is an empty slice." }

},

{

"name": "must_get",

"desc": "Get data from the oracle for a specific round. Panics if the data doesn't exist.",

"args": [

{ "type": "uint64", "name": "round", "desc": "The desired round" },

{ "type": "byte[]", "name": "user_data", "desc": "Optional: Extra data provided by the user. Pass an empty slice if not used." }

],

"returns": { "type": "byte[]", "desc": "The oracle's response" }

},

/** Optional */

{

"name": "get_closest",

"desc": "Get data from the oracle closest to a specified round by searching over past rounds.",

"args": [

{ "type": "uint64", "name": "round", "desc": "The desired round" },

{ "type": "uint64", "name": "search_span", "desc": "Threshold for number of rounds in the past to search on." },

{ "type": "byte[]", "name": "user_data", "desc": "Optional: Extra data provided by the user. Pass an empty slice if not used." }

],

"returns": { "type": "(uint64,byte[])", "desc": "The closest round and the oracle's response for that round. If the data doesn't exist, the round is set to 0 and the response is an empty slice." }

},

/** Optional */

{

"name": "must_get_closest",

"desc": "Get data from the oracle closest to a specified round by searching over past rounds. Panics if no data is found within the specified range.",

"args": [

{ "type": "uint64", "name": "round", "desc": "The desired round" },

{ "type": "uint64", "name": "search_span", "desc": "Threshold for number of rounds in the past to search on." },

{ "type": "byte[]", "name": "user_data", "desc": "Optional: Extra data provided by the user. Pass an empty slice if not used." }

],

"returns": { "type": "(uint64,byte[])", "desc": "The closest round and the oracle's response for that round." }

}

]

}
```

### Method boundaries

- All of `get`, `must_get`, `get_closest` and `must_get_closest` functions **MUST NOT** use local state.
- Optional arguments of type `byte[]` that are not used are expected to be passed as an empty byte slice.

## Rationale

The goal of these conventions is to make it easier for smart-contracts to interact with off-chain data sources.

## Security Considerations

None.

## Copyright

Copyright and related rights waived via [CCO](https://creativecommons.org/publicdomain/zero/1.0/).
