Home

Awesome

starknet-onchain-oracle

Cairo implementation of a POC on-chain oracle for Starknet, along with a sample Client contract and tests

It works by storing received requests in a storage variable, which is then fed to the off-chain Oracle.

Implementation

Request Structure

A request is defined by the following structure:

struct RequestData:
    member caller_address: felt
    member game: felt
    member team: felt
    member date: felt 
end

Storage variables

There are 3 storage_variables being used:

@storage_var
func _requests(index : felt) -> ( request_data : RequestData ):
end
@storage_var
func _index() -> ( res : felt ):
end
@storage_var
func _queue_size() -> ( res : felt ):
end

Client contract Interface

Every client contract should implement a function "receive_callback", that the on-chain Oracle contract calls when a request has been fulfilled by the off-chain Oracle, with the following signature:

@contract_interface
namespace IClientContract:

    # Receives the callback
    func receive_callback( response_data_len : felt, response_data : felt* ):
    end

end

External functions

@view
func get_queue_size{
        syscall_ptr : felt*,
        pedersen_ptr : HashBuiltin*,
        range_check_ptr}() -> (res : felt)

Called by the off-chain Oracle to check if there are any pending requests in the queue

@external
func receive_request{
        syscall_ptr : felt*,
        pedersen_ptr : HashBuiltin*,
        range_check_ptr}( request_data_len : felt, request_data : felt* )

Similarly to the "receive_callback" function, this interface should be referenced in every Client contract, as it is the function that they will call when interacting with the Oracle contract.

@external
func consume_next_request{
        syscall_ptr : felt*,
        pedersen_ptr : HashBuiltin*,
        range_check_ptr}() -> (res : RequestData)

Called by the off-chain Oracle to retrieve the next pending request in the queue.

@external
func callback_client{
        syscall_ptr : felt*,
        pedersen_ptr : HashBuiltin*,
        range_check_ptr}(client_address : felt, response_data_len : felt, response_data : felt*)

Called by the off-chain Oracle to retrieve the next pending request in the queue.

@external
func callback_client{
        syscall_ptr : felt*,
        pedersen_ptr : HashBuiltin*,
        range_check_ptr}(client_address : felt, response_data_len : felt, response_data : felt*)

Called by the off-chain Oracle in order for it to call back the Client contract with the response.

Calldata structure

Client Contract → Oracle Contract

The Client contract calls the function receive_request( request_data_len : felt, request_data : felt* ) in the Oracle contract.

request_data[0] = the game type, which for Basketball is 0
request_data[1] = the name of one of the teams, which should have previously been converted to int
request_data[2] = the date of the match, which should be passed in the format YYYYMMDD

Off-chain Oracle → Oracle Contract

The off-chain Oracle first calls the get_queue_sizefunction in the on-chain Oracle, which returns an int, to assert if there are any new requests to be consumed. When there is at least 1, it then calls consume_next_request() -> (res : RequestData) to get the next request in the queue, returned in the RequestData structure.

Oracle Contract → Client Contract

The Oracle contract calls the function receive_callback( response_data_len : felt, response_data : felt* ) in the Client contract in order to feed it the response that was given by the off-chain Oracle.