ARCs:specs:arc-0021.md•4.27 kB
---
arc: 21
title: Round based datafeed oracles on Algorand
description: Conventions for building round based datafeed oracles on Algorand
author: ori-shem-tov (@ori-shem-tov)
discussions-to: https://github.com/algorandfoundation/ARCs/issues/124
status: Final
type: Standards Track
category: Interface
sub-category: Application
created: 2022-03-09
requires: 4
---
# 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](./arc-0004.md)
## 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 <a href="https://www.ietf.org/rfc/rfc2119.txt">RFC-2119</a>.
> Comments like this are non-normative.
An [ARC-21](./arc-0021.md) 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:
```json
{
"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 <a href="https://creativecommons.org/publicdomain/zero/1.0/">CCO</a>.