ORACLE_ACCOUNT_MASM

Constant ORACLE_ACCOUNT_MASM 

Source
pub const ORACLE_ACCOUNT_MASM: &str = "use.std::sys\nuse.std::math::u64\nuse.miden::account\nuse.miden::tx\nuse.miden::contracts::auth::basic->auth_tx\n\n# CONSTANTS\n# =================================================================================================\n\n\nconst.MAX_U32=0x0000000100000000\n\n\n#\u{a0}Holds the next storage slot index available. Will be used when we register a publisher,\n# so we can assign it a slot.\nconst.NEXT_PUBLISHER_INDEX_SLOT=0\n\n#\u{a0}Holds the next storage slot index available. Will be used when we register a publisher,\n# so we can assign it a slot.\nconst.PUBLISHER_REGISTRY_MAP_SLOT=1\n\n# The beginning of the storage slots for the publishers.\nconst.PUBLISHERS_STORAGE_SLOT=2\n\n# INTERNAL PROCEDURES (utilities)\n# =================================================================================================\n\n#! Check if the top element of the stack is greater or equal than the second\n#! element on the stack.\n#!\n#! Inputs: [A, B]\n#! Output: [BOOL] 1 if A < B, else 0\nproc.felt_is_lower\n    dup \n    # => [1, 1, 2]\n    movup.2 dup\n    # => [2, 2, 1, 1]\n    swap.3\n    # => [1, 2, 1, 2]\n    gt\n    # => [1, 2]\nend\n\n#! Calls the PUBLISHER_ID get_entry procedure of the provided account.\n#!\n#! Inputs: [PUBLISHER_ID, PAIR]\n#! Output: [ENTRY]\nproc.call_publisher_get_entry\n    push.0x2d1ea4fa1203adfd3c7d00f0961a8d29f459a59768bbe3cf12dcc80b488e1b89\n    # => [GET_ENTRY_HASH, PUBLISHER_ID, PAIR]\n    swapw swap.2 drop swap.2 drop\n    # => [publisher_id,publisher_id,  GET_ENTRY_HASH, PAIR]\n    \n    exec.tx::execute_foreign_procedure\n    # => [ENTRY]\nend\n\n#! Swaps two elements stored in the ram at index (i, j).\n#! Input is taken from the stack, example:\n#!\n#! Inputs: [i, j]\n#! Output: []\nproc.ram_swap\n  dup\n  # => [i, i, j]\n  push.0.0.0.0 movup.4 mul.4 mem_loadw\n  # => [mem_i, i, j]\n  movup.5 dup push.0.0.0.0 movup.4 mul.4 mem_loadw\n  # => [mem_j, j, mem_i, i]\n  movup.9\n  # => [i, mem_j, j, mem_i]\n  mul.4 mem_storew dropw mul.4 mem_storew dropw\nend\n\n\n#! Updates the top word on the stack that is an entry to its price\n#! by selecting its 2nd element.\n#! Example:\n#! => [A, 42, B, C]\n#! returns:\n#! => [42]\nproc.entry_to_price\n  drop drop swap drop\nend\n\n#! Returns 1 if the element at index i is lower than element at index j.\n#! Example:\n#! => [i, j] for RAM[i] = 42, RAM[i] = 69\n#! returns\n#! => [0, i, j]\nproc.ram_is_lower\n  dup push.0.0.0.0 movup.5 mul.4 mem_loadw exec.entry_to_price\n  # => [mem_i, i, j]\n  movup.2 dup push.0.0.0.0 movup.4 mul.4 mem_loadw exec.entry_to_price\n  # => [mem_j, j, mem_i, i]\n  movup.2 swap.1 lt\n  # => [BOOL, j, i]\n  swap.2 movup.2\n  # => [BOOL, i, j]\nend\n\n#! Computes the avarage of two elements\n#! Inputs:  [a, b]\n#! Output : [avg]\nproc.compute_average\n    u32split\n    # => [a_high, a_low, b]\n    movup.2\n    # => [b, a_high, a_low]\n    u32split\n    # => [b_high, b_low, a_high, a_low]\n    exec.u64::wrapping_add\n    # => [c_high, c_low]\n    push.2.0\n     # => [0,2,c_high, c_low]\n    exec.u64::div\n    # => [avg_high, avg_low]\n    push.MAX_U32\n    # => [MAX_U32,avg_high, avg_low]\n    mul add\n    # => [avg]\nend\n#! Sort the N entries in the RAM using a Bubble Sort.\n#! All the elements must already be stored on the RAM and the top of\n#! the stack must include the length of the entries.\n#!\n#! Inputs:  [nb_of_entries]\n#! Output:  []\nproc.ram_bubble_sort\n    # This is the outer counter\n    dup\n\n    # => [N, N]\n    sub.1 dup\n    # => [N-1(i), N-1(i), N]\n    push.1\n    # => [1, N-1(i), N-1(i), N]\n    gt\n    while.true\n        # => [N-1(i), N]\n        dup\n        # => [N-1(i), N-1(i), N]\n        # => Inner index\n        push.0\n        # => [0(j), N-1(i), N-1(i), N]\n        dup \n        # => [0(j), 0(j), N-1(i), N-1(i), N]\n        swap.2\n        # => [N-1(i), 0(j), 0(j), N-1(i), N]\n        # We exit this loop if j > i-1\n        lte\n        # => [bool, N-1(i), 0(j), N]\n        while.true\n            # => [0(j), N-1(i), N]\n            dup\n            # => [0(j), 0(j), N-1(i), N]\n            add.1\n            # => [0(j)+1, 0(j), N-1(i), N]\n            swap\n            # => [0(j), 0(j)+1, N-1(i), N]\n            exec.ram_is_lower\n            # => [bool,  0(j), 0(j)+1, N-1(i), N]\n            if.true\n            else\n                dup \n                # => [0(j), 0(j), 0(j)+1, N-1(i), N]\n                dup.2\n                # => [0(j)+1, 0(j), 0(j), 0(j)+1, N-1(i), N]\n                swap\n                # => [0(j), 0(j)+1, 0(j), 0(j)+1, N-1(i), N]\n                exec.ram_swap\n                # => [0(j), 0(j)+1, N-1(i), N]\n            end\n            drop\n            # => [0(j)+1, N-1(i), N]\n            dup\n            # => [0(j)+1, 0(j)+1, N-1(i), N]\n            dup.2\n            # => [N-1(i), 0(j)+1, 0(j)+1, N-1(i), N]\n            lt\n            # => [bool, 0(j)+1, N-1(i), N]\n        end \n        # => [0(j)+1, N-1(i), N]\n        drop\n        # => [N-1(i), N]\n        sub.1\n        # => [N-2(i-1), N]\n        dup\n        # => [N-2(i-1), N-2(i-1), N]\n        push.1\n        # => [1, N-2(i-1), N-2(i-1), N]\n        gte\n        # => [bool, N-2(i-1), N]\n    end\n    drop\nend\n\n\n#! Reads from the sorted entries on the RAM and get the median.\n#! \u{26a0} The RAM must be sorted before!\n#! The input will be the number of elements on top of the stack.\n#! \n#! Inputs:  [nb_of_entries]\n#! Output:  [median_price]\nproc.ram_get_median\n    dup is_odd\n    # => [nb_of_entries]\n    if.true\n        push.0.2.0\n        exec.u64::div drop\n        # => [index_to_read]\n        # = nb_of_entries / 2\n\n        push.0.0.0.0 movup.4 mul.4 mem_loadw\n        # => [MEDIAN_ENTRY]\n\n        exec.entry_to_price\n        # => [price_median]\n    else\n        push.0.2.0\n        exec.u64::div drop\n        # => [index_to_read]\n        \n        dup sub.1\n        # => [index_to_read - 1, index_to_read]\n\n        push.0.0.0.0 movup.4 mul.4 mem_loadw\n        # => [ENTRY_N_MINUS_1, index_to_read]\n\n        push.0.0.0.0 movup.8 mul.4 mem_loadw\n\n        exec.entry_to_price\n        # => [price_n, ENTRY_N_MINUS_1]\n\n        movdn.4 exec.entry_to_price\n        # => [price_n_minus_1, price_n]\n\n       exec.compute_average\n    end\nend\n\n# EXTERNAL PROCEDURES\n# =================================================================================================\n\n#! Gets entry from the oracle\'s data slots.\n#!\n#! Inputs:  [PUBLISHER_ID, PAIR]\n#! Outputs: [ENTRY]\nexport.get_entry\n    # Verifies if the publisher is registered, panics if not\n    # dupw push.PUBLISHER_REGISTRY_MAP_SLOT exec.account::get_map_item dropw\n    # => [PUBLISHER_ID, PAIR]\n\n    # Push the get_entry hash function for the publisher account\n    exec.call_publisher_get_entry\n\n    # Truncate if necessary\n    exec.sys::truncate_stack\nend\n\n#! Gets the median price of a given asset.\n#!\n#! Inputs:  [PAIR]\n#! Outputs: [median_price]\nexport.get_median\n    # Iterate from 3 to NEXT_PUBLISHER_INDEX_SLOT value.\n    push.0.0.NEXT_PUBLISHER_INDEX_SLOT exec.account::get_item drop drop drop\n    # => [next_publisher_slot, 0, 0, PAIR]\n\n    push.PUBLISHERS_STORAGE_SLOT exec.felt_is_lower\n    # => [PUBLISHERS_STORAGE_SLOT, next_publisher_slot, 0, 0, PAIR]\n\n    while.true\n        # Get the publisher id at slot [top of the stack]\n        dup exec.account::get_item\n        # => [PUBLISHER_ID, PUBLISHERS_STORAGE_SLOT, next_publisher_slot, 0, 0, PAIR]\n\n        dupw.2 swapw.1\n        # => [PUBLISHER_ID, PAIR, PUBLISHERS_STORAGE_SLOT, next_publisher_slot, 0, 0, PAIR]\n\n        # Call get_entry\n        exec.call_publisher_get_entry\n        # => [ENTRY, PUBLISHERS_STORAGE_SLOT, next_publisher_slot, PAIR]\n          \n        # Store the entry in the RAM from index 0 to index N\n        dup.4 push.PUBLISHERS_STORAGE_SLOT sub mul.4  # we multiplied the result by 4 because se can store with % 4!=0 addresses\n        mem_storew dropw\n        # => [PUBLISHERS_STORAGE_SLOT, next_publisher_slot, PAIR]\n        # Increment the next index and check if there\'s still publishers to process\n        add.1 exec.felt_is_lower\n        # => [PUBLISHERS_STORAGE_SLOT +1 , next_publisher_slot, PAIR]\n    end\n    # Drop the utilities used to get all the entries - only keep the length on the ram.\n\n    swap drop movdn.4 dropw\n    # => [4]\n    \n    push.PUBLISHERS_STORAGE_SLOT\n    #\u{a0}=>  [PUBLISHER_STORAGE_SLOT, 4]\n\n    sub \n    # => [Number of entries]\n    # Sort the entries stored on the RAM\n    exec.ram_bubble_sort\n    # => [4]\n    \n    # Retrieves the median from the sorted RAM entries\n    exec.ram_get_median\n    # => [median_price]\n\n\n\n    exec.sys::truncate_stack\nend\n\n#! Registers a new publishers into the Oracle.\n#! Can only be called by the Owner of the Oracle account.\n#! Will reserve a storage slot for the publisher if it\'s not already registered,\n#! which mean this publisher will be able to publish data.\n#!\n#! Inputs:  [PUBLISHER_ID]\n#! Outputs: []\nexport.register_publisher\n    # Check if it is not already present in the registry, if yes raise err (get_map_item)\n    # TODO: How?\n\n    # Duplicate the publisher id\n    dupw\n    # => [PUBLISHER_ID, PUBLISHER_ID]\n\n    # Retrieve the next_publisher_slot available from the slot\n    push.NEXT_PUBLISHER_INDEX_SLOT exec.account::get_item\n\n    # => [NEXT_PUBLISHER_SLOT, PUBLISHER_ID, PUBLISHER_ID]\n\n    # Prepare the stack for the set_item and set_map_item calls\n    dupw movdnw.2 drop drop drop\n    # => [next_publisher_slot, PUBLISHER_ID, NEXT_PUBLISHER_SLOT, PUBLISHER_ID]\n\n    # Store the publisher into its assigned slot\n    exec.account::set_item dropw dropw swapw\n    # => [PUBLISHER_ID, NEXT_PUBLISHER_SLOT]\n\n    # Register the publisher into its mapping\n    push.PUBLISHER_REGISTRY_MAP_SLOT exec.account::set_map_item\n    # => []\n\n    # Increment NEXT_PUBLISHER_INDEX_SLOT\n    push.NEXT_PUBLISHER_INDEX_SLOT exec.account::get_item\n    # => [PUBLISHER_INDEX_SLOT]\n\n    # Update the storage value\n    swap.3 add.1 swap.3\n    # => [PUBLISHER_INDEX_SLOT+1]\n\n    push.NEXT_PUBLISHER_INDEX_SLOT exec.account::set_item\n    # => []\n\n    # Only the oracle owner should be able to call this\n   call.auth_tx::auth_tx_rpo_falcon512\n    drop\n\n    exec.sys::truncate_stack\nend\n";