diff --git a/frameworks/bitcoin-move/doc/bitcoin.md b/frameworks/bitcoin-move/doc/bitcoin.md index 7ab19ea82d..6ad8d52dfd 100644 --- a/frameworks/bitcoin-move/doc/bitcoin.md +++ b/frameworks/bitcoin-move/doc/bitcoin.md @@ -8,7 +8,8 @@ - [Struct `UTXONotExistsEvent`](#0x4_bitcoin_UTXONotExistsEvent) - [Struct `RepeatCoinbaseTxEvent`](#0x4_bitcoin_RepeatCoinbaseTxEvent) - [Resource `BitcoinBlockStore`](#0x4_bitcoin_BitcoinBlockStore) -- [Struct `TransferUTXOEvent`](#0x4_bitcoin_TransferUTXOEvent) +- [Struct `SpendUTXOEvent`](#0x4_bitcoin_SpendUTXOEvent) +- [Struct `ReceiveUTXOEvent`](#0x4_bitcoin_ReceiveUTXOEvent) - [Constants](#@Constants_0) - [Function `genesis_init`](#0x4_bitcoin_genesis_init) - [Function `get_tx`](#0x4_bitcoin_get_tx) @@ -21,7 +22,8 @@ - [Function `get_latest_block`](#0x4_bitcoin_get_latest_block) - [Function `get_bitcoin_time`](#0x4_bitcoin_get_bitcoin_time) - [Function `contains_header`](#0x4_bitcoin_contains_header) -- [Function `unpack_transfer_utxo_event`](#0x4_bitcoin_unpack_transfer_utxo_event) +- [Function `unpack_spend_utxo_event`](#0x4_bitcoin_unpack_spend_utxo_event) +- [Function `unpack_receive_utxo_event`](#0x4_bitcoin_unpack_receive_utxo_event)
use 0x1::option;
@@ -81,13 +83,24 @@
 
 
 
-
+
 
-## Struct `TransferUTXOEvent`
+## Struct `SpendUTXOEvent`
 
 
 
-
struct TransferUTXOEvent has copy, drop, store
+
struct SpendUTXOEvent has copy, drop, store
+
+ + + + + +## Struct `ReceiveUTXOEvent` + + + +
struct ReceiveUTXOEvent has copy, drop, store
 
@@ -280,11 +293,22 @@ Get the bitcoin time in seconds - + + +## Function `unpack_spend_utxo_event` + + + +
public fun unpack_spend_utxo_event(event: bitcoin::SpendUTXOEvent): (address, address, option::Option<address>, u64)
+
+ + + + -## Function `unpack_transfer_utxo_event` +## Function `unpack_receive_utxo_event` -
public fun unpack_transfer_utxo_event(event: bitcoin::TransferUTXOEvent): (address, option::Option<address>, address, u64)
+
public fun unpack_receive_utxo_event(event: bitcoin::ReceiveUTXOEvent): (address, option::Option<address>, address, u64)
 
diff --git a/frameworks/bitcoin-move/sources/bitcoin.move b/frameworks/bitcoin-move/sources/bitcoin.move index 8b8b7e9bda..5dfbcd921b 100644 --- a/frameworks/bitcoin-move/sources/bitcoin.move +++ b/frameworks/bitcoin-move/sources/bitcoin.move @@ -67,7 +67,14 @@ module bitcoin_move::bitcoin{ } - struct TransferUTXOEvent has drop, store, copy { + struct SpendUTXOEvent has drop, store, copy { + txid: address, + sender: address, + receiver: Option
, + value: u64 + } + + struct ReceiveUTXOEvent has drop, store, copy { txid: address, sender: Option
, receiver: address, @@ -237,7 +244,7 @@ module bitcoin_move::bitcoin{ let owner_address = types::txout_object_address(txout); utxo::transfer(utxo_obj, owner_address); if (owner_address != @bitcoin_move){ - event_queue::emit(to_string(&owner_address), TransferUTXOEvent{ + event_queue::emit(to_string(&owner_address), ReceiveUTXOEvent { txid, sender, receiver: owner_address, @@ -246,10 +253,15 @@ module bitcoin_move::bitcoin{ }; if (option::is_some(&sender)){ let sender_address = option::extract(&mut sender); - event_queue::emit(to_string(&sender_address), TransferUTXOEvent{ + let receiver_address = if (owner_address != @bitcoin_move) { + option::some(owner_address) + }else { + option::none
() + }; + event_queue::emit(to_string(&sender_address), SpendUTXOEvent { txid, - sender, - receiver: owner_address, + sender: sender_address, + receiver: receiver_address, value }); }; @@ -420,8 +432,13 @@ module bitcoin_move::bitcoin{ execute_l1_tx(block_hash, types::tx_id(&coinbase_tx)); } - public fun unpack_transfer_utxo_event(event: TransferUTXOEvent): (address, Option
, address, u64) { - let TransferUTXOEvent { txid, sender, receiver, value } = event; + public fun unpack_spend_utxo_event(event: SpendUTXOEvent): (address, address, Option
, u64) { + let SpendUTXOEvent { txid, sender, receiver, value } = event; + (txid, sender, receiver, value) + } + + public fun unpack_receive_utxo_event(event: ReceiveUTXOEvent): (address, Option
, address, u64) { + let ReceiveUTXOEvent { txid, sender, receiver, value } = event; (txid, sender, receiver, value) } diff --git a/frameworks/framework-release/released/8/stdlib b/frameworks/framework-release/released/8/stdlib index cf81b625ba..2ff9c31c77 100644 Binary files a/frameworks/framework-release/released/8/stdlib and b/frameworks/framework-release/released/8/stdlib differ diff --git a/frameworks/moveos-stdlib/doc/README.md b/frameworks/moveos-stdlib/doc/README.md index 2d8ecc937a..d75936a65e 100644 --- a/frameworks/moveos-stdlib/doc/README.md +++ b/frameworks/moveos-stdlib/doc/README.md @@ -25,6 +25,7 @@ This is the reference documentation of the MoveOS standard library. - [`0x2::compare`](compare.md#0x2_compare) - [`0x2::copyable_any`](copyable_any.md#0x2_copyable_any) - [`0x2::core_addresses`](core_addresses.md#0x2_core_addresses) +- [`0x2::decimal_value`](decimal_value.md#0x2_decimal_value) - [`0x2::display`](display.md#0x2_display) - [`0x2::event`](event.md#0x2_event) - [`0x2::event_queue`](event_queue.md#0x2_event_queue) diff --git a/frameworks/moveos-stdlib/doc/address.md b/frameworks/moveos-stdlib/doc/address.md index 98624113c6..5b5296a47b 100644 --- a/frameworks/moveos-stdlib/doc/address.md +++ b/frameworks/moveos-stdlib/doc/address.md @@ -68,7 +68,7 @@ The length of an address, in bytes -
const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
+
const MAX: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
 
@@ -207,7 +207,7 @@ Length of a Rooch address in bytes Largest possible address -
public fun max(): u256
+
public fun max(): u256
 
diff --git a/frameworks/moveos-stdlib/doc/bcs.md b/frameworks/moveos-stdlib/doc/bcs.md index 5a4848381a..12d47b7147 100644 --- a/frameworks/moveos-stdlib/doc/bcs.md +++ b/frameworks/moveos-stdlib/doc/bcs.md @@ -311,10 +311,10 @@ Read u128 value from bcs-serialized bytes. ## Function `peel_u256` -Read u256 value from bcs-serialized bytes. +Read u256 value from bcs-serialized bytes. -
public fun peel_u256(bcs: &mut bcs::BCS): u256
+
public fun peel_u256(bcs: &mut bcs::BCS): u256
 
@@ -435,10 +435,10 @@ Peel a vector of u128 from serialized bytes. ## Function `peel_vec_u256` -Peel a vector of u256 from serialized bytes. +Peel a vector of u256 from serialized bytes. -
public fun peel_vec_u256(bcs: &mut bcs::BCS): vector<u256>
+
public fun peel_vec_u256(bcs: &mut bcs::BCS): vector<u256>
 
@@ -531,10 +531,10 @@ Peel Option<u128> from serialized bytes. ## Function `peel_option_u256` -Peel Option<u256> from serialized bytes. +Peel Option<u256> from serialized bytes. -
public fun peel_option_u256(bcs: &mut bcs::BCS): option::Option<u256>
+
public fun peel_option_u256(bcs: &mut bcs::BCS): option::Option<u256>
 
diff --git a/frameworks/moveos-stdlib/doc/compare.md b/frameworks/moveos-stdlib/doc/compare.md index 79910ea4fd..132065f440 100644 --- a/frameworks/moveos-stdlib/doc/compare.md +++ b/frameworks/moveos-stdlib/doc/compare.md @@ -17,7 +17,9 @@ Utilities for comparing Move values
use 0x1::compare;
 use 0x1::type_name;
+use 0x1::u256;
 use 0x2::bcs;
+use 0x2::decimal_value;
 
diff --git a/frameworks/moveos-stdlib/doc/decimal_value.md b/frameworks/moveos-stdlib/doc/decimal_value.md new file mode 100644 index 0000000000..8056500c29 --- /dev/null +++ b/frameworks/moveos-stdlib/doc/decimal_value.md @@ -0,0 +1,58 @@ + + + +# Module `0x2::decimal_value` + + + +- [Struct `DecimalValue`](#0x2_decimal_value_DecimalValue) +- [Function `new`](#0x2_decimal_value_new) +- [Function `value`](#0x2_decimal_value_value) +- [Function `decimal`](#0x2_decimal_value_decimal) + + +
+ + + + + +## Struct `DecimalValue` + + + +
struct DecimalValue has copy, drop, store
+
+ + + + + +## Function `new` + + + +
public fun new(value: u64, decimal: u8): decimal_value::DecimalValue
+
+ + + + + +## Function `value` + + + +
public fun value(self: &decimal_value::DecimalValue): u64
+
+ + + + + +## Function `decimal` + + + +
public fun decimal(self: &decimal_value::DecimalValue): u8
+
diff --git a/frameworks/moveos-stdlib/doc/move_module.md b/frameworks/moveos-stdlib/doc/move_module.md index fbdebccdc8..0bc811a2c7 100644 --- a/frameworks/moveos-stdlib/doc/move_module.md +++ b/frameworks/moveos-stdlib/doc/move_module.md @@ -263,7 +263,7 @@ Replace given u64 constant to the new ones Replace given u256 constant to the new ones -
public fun replace_constant_u256(modules: vector<move_module::MoveModule>, old_u256s: vector<u256>, new_u256s: vector<u256>): vector<move_module::MoveModule>
+
public fun replace_constant_u256(modules: vector<move_module::MoveModule>, old_u256s: vector<u256>, new_u256s: vector<u256>): vector<move_module::MoveModule>
 
@@ -393,5 +393,5 @@ Native function to replace constant u256 in module binary where the length of old_u256s must equal to that of new_u256s. -
public(friend) fun replace_u256_constant(bytes: vector<vector<u8>>, old_u256s: vector<u256>, new_u256s: vector<u256>): vector<vector<u8>>
+
public(friend) fun replace_u256_constant(bytes: vector<vector<u8>>, old_u256s: vector<u256>, new_u256s: vector<u256>): vector<vector<u8>>
 
diff --git a/frameworks/moveos-stdlib/doc/string_utils.md b/frameworks/moveos-stdlib/doc/string_utils.md index 1af1bd76f0..361d568361 100644 --- a/frameworks/moveos-stdlib/doc/string_utils.md +++ b/frameworks/moveos-stdlib/doc/string_utils.md @@ -116,7 +116,7 @@ -
public fun parse_u256_option(s: &string::String): option::Option<u256>
+
public fun parse_u256_option(s: &string::String): option::Option<u256>
 
@@ -127,7 +127,7 @@ -
public fun parse_u256(s: &string::String): u256
+
public fun parse_u256(s: &string::String): u256
 
@@ -138,7 +138,7 @@ -
public fun parse_decimal_option(s: &string::String, decimal: u64): option::Option<u256>
+
public fun parse_decimal_option(s: &string::String, decimal: u64): option::Option<u256>
 
@@ -149,7 +149,7 @@ -
public fun parse_decimal(s: &string::String, decimal: u64): u256
+
public fun parse_decimal(s: &string::String, decimal: u64): u256
 
@@ -182,7 +182,7 @@ -
public fun to_string_u256(n: u256): string::String
+
public fun to_string_u256(n: u256): string::String
 
diff --git a/frameworks/moveos-stdlib/sources/bcs.move b/frameworks/moveos-stdlib/sources/bcs.move index bf17bf4c6c..a2a6a991aa 100644 --- a/frameworks/moveos-stdlib/sources/bcs.move +++ b/frameworks/moveos-stdlib/sources/bcs.move @@ -10,6 +10,8 @@ module moveos_std::bcs{ use std::option::{Self, Option}; use std::vector; + #[test_only] + use std::vector::{is_empty, pop_back}; friend moveos_std::any; friend moveos_std::copyable_any; @@ -74,12 +76,11 @@ module moveos_std::bcs{ /// Read `address` value from the bcs-serialized bytes. public fun peel_address(bcs: &mut BCS): address { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 32, ErrorInvalidLength); + assert!(vector::length(&bcs.bytes) >= 32, ErrorInvalidLength); let i = 0; let addr_bytes = vector::empty(); while (i < 32) { - let byte = vector::pop_back(&mut bytes); + let byte = vector::pop_back(&mut bcs.bytes); vector::push_back(&mut addr_bytes, byte); i = i + 1; }; @@ -100,20 +101,18 @@ module moveos_std::bcs{ /// Read `u8` value from bcs-serialized bytes. public fun peel_u8(bcs: &mut BCS): u8 { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 1, ErrorOutOfRange); - vector::pop_back(&mut bytes) + assert!(vector::length(&bcs.bytes) >= 1, ErrorOutOfRange); + vector::pop_back(&mut bcs.bytes) } /// Read `u16` value from bcs-serialized bytes. public fun peel_u16(bcs: &mut BCS): u16 { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 2, ErrorOutOfRange); + assert!(vector::length(&bcs.bytes) >= 2, ErrorOutOfRange); let value = 0; let i = 0; let bits = 16u8; while (i < bits) { - let byte = (vector::pop_back(&mut bytes) as u16); + let byte = (vector::pop_back(&mut bcs.bytes) as u16); value = value + (byte << (i as u8)); i = i + 8; }; @@ -123,13 +122,12 @@ module moveos_std::bcs{ /// Read `u32` value from bcs-serialized bytes. public fun peel_u32(bcs: &mut BCS): u32 { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 4, ErrorOutOfRange); + assert!(vector::length(&bcs.bytes) >= 4, ErrorOutOfRange); let value = 0; let i = 0; let bits = 32u8; while (i < bits) { - let byte = (vector::pop_back(&mut bytes) as u32); + let byte = (vector::pop_back(&mut bcs.bytes) as u32); value = value + (byte << (i as u8)); i = i + 8; }; @@ -139,13 +137,12 @@ module moveos_std::bcs{ /// Read `u64` value from bcs-serialized bytes. public fun peel_u64(bcs: &mut BCS): u64 { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 8, ErrorOutOfRange); + assert!(vector::length(&bcs.bytes) >= 8, ErrorOutOfRange); let value = 0; let i = 0; let bits = 64u8; while (i < bits) { - let byte = (vector::pop_back(&mut bytes) as u64); + let byte = (vector::pop_back(&mut bcs.bytes) as u64); value = value + (byte << (i as u8)); i = i + 8; }; @@ -155,13 +152,12 @@ module moveos_std::bcs{ /// Read `u128` value from bcs-serialized bytes. public fun peel_u128(bcs: &mut BCS): u128 { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 16, ErrorOutOfRange); + assert!(vector::length(&bcs.bytes) >= 16, ErrorOutOfRange); let value = 0; let i = 0; let bits = 128u8; while (i < bits) { - let byte = (vector::pop_back(&mut bytes) as u128); + let byte = (vector::pop_back(&mut bcs.bytes) as u128); value = value + (byte << (i as u8)); i = i + 8; }; @@ -171,13 +167,12 @@ module moveos_std::bcs{ /// Read `u256` value from bcs-serialized bytes. public fun peel_u256(bcs: &mut BCS): u256 { - let bytes = bcs.bytes; - assert!(vector::length(&bytes) >= 32, ErrorOutOfRange); + assert!(vector::length(&bcs.bytes) >= 32, ErrorOutOfRange); let value = 0; let i = 0; let bits = 256u16; while (i < bits) { - let byte = (vector::pop_back(&mut bytes) as u256); + let byte = (vector::pop_back(&mut bcs.bytes) as u256); value = value + (byte << (i as u8)); i = i + 8; }; @@ -193,13 +188,12 @@ module moveos_std::bcs{ /// In BCS `vector` length is implemented with ULEB128; /// See more here: https://en.wikipedia.org/wiki/LEB128 public fun peel_vec_length(bcs: &mut BCS): u64 { - let bytes = bcs.bytes; let total = 0u64; let shift = 0; let len = 0; loop { assert!(len <= 4, ErrorLengthOutOfRange); - let byte = (vector::pop_back(&mut bytes) as u64); + let byte = (vector::pop_back(&mut bcs.bytes) as u64); len = len + 1; total = total | ((byte & 0x7f) << shift); if ((byte & 0x80) == 0) { @@ -574,205 +568,78 @@ module moveos_std::bcs{ } #[test] - fun test_peel_vec_address_success() { - let bytes = x"7fe695faf7047ccfbc85f7dccb6c405d4e9b7b44788e71a71c3891a06ce0ca12"; - let bcs = new(bytes); - let vec_address = peel_vec_address(&mut bcs); - let expected_vec_address = vector::empty
(); - let expected_address = @0x7fe695faf7047ccfbc85f7dccb6c405d4e9b7b44788e71a71c3891a06ce0ca12; - let i = 0; - while (i < vector::length(&vec_address)) { - vector::push_back(&mut expected_vec_address, expected_address); - i = i + 1; + fun test_vec() { + let bool_cases = vector[vector[], vector[true], vector[false, true, false]]; + let excepet_bool_cases = bool_cases; + while (!is_empty(&excepet_bool_cases)) { + let case = pop_back(&mut excepet_bool_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_bool(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_address == expected_vec_address, ErrorLengthOutOfRange); - } - #[test] - fun test_peel_vec_bool_success() { - let bytes = x"01"; - let bcs = new(bytes); - let vec_bool = peel_vec_bool(&mut bcs); - let expected_vec_bool = vector::empty(); - let expected_bool = true; - vector::push_back(&mut expected_vec_bool, expected_bool); - assert!(vec_bool == expected_vec_bool, ErrorLengthOutOfRange); - } - - #[test] - fun test_peel_vec_u8_success() { - let bytes = x"11"; - let bcs = new(bytes); - let u8 = peel_vec_u8(&mut bcs); - let expected_vec_u8 = x"1111111111111111111111111111111111"; - assert!(u8 == expected_vec_u8, ErrorLengthOutOfRange); - } - - #[test] - fun test_peel_vec_vec_u8_success() { - let bytes = x"11"; - let bcs = new(bytes); - let vec_vec_u8 = peel_vec_vec_u8(&mut bcs); - let expected_vec_vec_u8 = vector::empty>(); - let expected_vec_u8 = x"1111111111111111111111111111111111"; - let i = 0; - while (i < vector::length(&vec_vec_u8)) { - vector::push_back(&mut expected_vec_vec_u8, expected_vec_u8); - i = i + 1; + let u8_cases = vector[vector[], vector[1], vector[0, 2, 0xFF]]; + let excepet_u8_cases = u8_cases; + while (!is_empty(&excepet_u8_cases)) { + let case = pop_back(&mut excepet_u8_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_u8(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_vec_u8 == expected_vec_vec_u8, ErrorLengthOutOfRange); - } - #[test] - fun test_peel_vec_u16_success() { - let bytes = x"1111"; - let bcs = new(bytes); - let vec_u16 = peel_vec_u16(&mut bcs); - let expected_vec_u16 = vector::empty(); - let expected_u16 = 4369u16; - let i = 0; - while (i < vector::length(&vec_u16)) { - vector::push_back(&mut expected_vec_u16, expected_u16); - i = i + 1; + let u16_cases = vector[vector[], vector[1], vector[0, 2, 0xFFFF]]; + let excepet_u16_cases = u16_cases; + while (!is_empty(&excepet_u16_cases)) { + let case = pop_back(&mut excepet_u16_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_u16(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_u16 == expected_vec_u16, ErrorLengthOutOfRange); - } - #[test] - fun test_peel_vec_u32_success() { - let bytes = x"11111111"; - let bcs = new(bytes); - let vec_u32 = peel_vec_u32(&mut bcs); - let expected_vec_u32 = vector::empty(); - let expected_u32 = 286331153u32; - let i = 0; - while (i < vector::length(&vec_u32)) { - vector::push_back(&mut expected_vec_u32, expected_u32); - i = i + 1; + let u32_cases = vector[vector[], vector[1], vector[0, 2, 0xFFFF_FFFF]]; + let excepet_u32_cases = u32_cases; + while (!is_empty(&excepet_u32_cases)) { + let case = pop_back(&mut excepet_u32_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_u32(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_u32 == expected_vec_u32, ErrorLengthOutOfRange); - } - #[test] - fun test_peel_vec_u64_success() { - let bytes = x"1111111111111111"; - let bcs = new(bytes); - let vec_u64 = peel_vec_u64(&mut bcs); - let expected_vec_u64 = vector::empty(); - let expected_u64 = 1229782938247303441u64; - let i = 0; - while (i < vector::length(&vec_u64)) { - vector::push_back(&mut expected_vec_u64, expected_u64); - i = i + 1; + let u64_cases = vector[vector[], vector[1], vector[0, 2, 0xFFFF_FFFF_FFFF_FFFF]]; + let excepet_u64_cases = u64_cases; + while (!is_empty(&excepet_u64_cases)) { + let case = pop_back(&mut excepet_u64_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_u64(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_u64 == expected_vec_u64, ErrorLengthOutOfRange); - } - #[test] - fun test_peel_vec_u128_success() { - let bytes = x"11111111111111111111111111111111"; - let bcs = new(bytes); - let vec_u128 = peel_vec_u128(&mut bcs); - let expected_vec_u128 = vector::empty(); - let expected_u128 = 22685491128062564230891640495451214097u128; - let i = 0; - while (i < vector::length(&vec_u128)) { - vector::push_back(&mut expected_vec_u128, expected_u128); - i = i + 1; + let u128_cases = vector[vector[], vector[1], vector[0, 2, 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF]]; + let excepet_u128_cases = u128_cases; + while (!is_empty(&excepet_u128_cases)) { + let case = pop_back(&mut excepet_u128_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_u128(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_u128 == expected_vec_u128, ErrorLengthOutOfRange); - } - #[test] - fun test_peel_vec_u256_success() { - let bytes = x"1111111111111111111111111111111111111111111111111111111111111111"; - let bcs = new(bytes); - let vec_u256 = peel_vec_u256(&mut bcs); - let expected_vec_u256 = vector::empty(); - let expected_u256 = 7719472615821079694904732333912527190217998977709370935963838933860875309329u256; - let i = 0; - while (i < vector::length(&vec_u256)) { - vector::push_back(&mut expected_vec_u256, expected_u256); - i = i + 1; + let u256_cases = vector[vector[], vector[1], vector[0, 2, 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF]]; + let excepet_u256_cases = u256_cases; + while (!is_empty(&excepet_u256_cases)) { + let case = pop_back(&mut excepet_u256_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_u256(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); }; - assert!(vec_u256 == expected_vec_u256, ErrorLengthOutOfRange); - } - - #[test] - fun test_peel_option_address_success() { - let bytes = x"017fe695faf7047ccfbc85f7dccb6c405d4e9b7b44788e71a71c3891a06ce0ca12"; - let bcs = new(bytes); - let option_address = peel_option_address(&mut bcs); - let expected_option_addr = option::some(@0x17fe695faf7047ccfbc85f7dccb6c405d4e9b7b44788e71a71c3891a06ce0ca); - assert!(option_address == expected_option_addr, ErrorInvalidLength); - } - - #[test] - fun test_peel_option_bool_success() { - let bytes = x"01"; - let bcs = new(bytes); - let option_bool = peel_option_bool(&mut bcs); - let expected_option_bool = option::some(true); - assert!(option_bool == expected_option_bool, ErrorInvalidBool); - } - - #[test] - fun test_peel_option_u8_success() { - let bytes = x"0101"; - let bcs = new(bytes); - let option_u8 = peel_option_u8(&mut bcs); - std::debug::print(&option_u8); - let expected_option_u8 = option::some(1); - assert!(option_u8 == expected_option_u8, ErrorOutOfRange); - } - #[test] - fun test_peel_option_u16_success() { - let bytes = x"010011"; - let bcs = new(bytes); - let option_u16 = peel_option_u16(&mut bcs); - std::debug::print(&option_u16); - let expected_option_u16 = option::some(1); - assert!(option_u16 == expected_option_u16, ErrorOutOfRange); - } - - #[test] - fun test_peel_option_u32_success() { - let bytes = x"0100001111"; - let bcs = new(bytes); - let option_u32 = peel_option_u32(&mut bcs); - std::debug::print(&option_u32); - let expected_option_u32 = option::some(285212673); - assert!(option_u32 == expected_option_u32, ErrorOutOfRange); - } - - #[test] - fun test_peel_option_u64_success() { - let bytes = x"010000000011111111"; - let bcs = new(bytes); - let option_u64 = peel_option_u64(&mut bcs); - std::debug::print(&option_u64); - let expected_option_u64 = option::some(1229782864946528257); - assert!(option_u64 == expected_option_u64, ErrorOutOfRange); - } - - #[test] - fun test_peel_option_u128_success() { - let bytes = x"0100000000111111110000000011111111"; - let bcs = new(bytes); - let option_u128 = peel_option_u128(&mut bcs); - std::debug::print(&option_u128); - let expected_option_u128 = option::some(22685489775901924302271377683643367425); - assert!(option_u128 == expected_option_u128, ErrorOutOfRange); - } + let address_cases = vector[vector[], vector[@0x0], vector[@0x1, @0x2, @0x3]]; + let excepet_address_cases = address_cases; + while (!is_empty(&excepet_address_cases)) { + let case = pop_back(&mut excepet_address_cases); + let bytes = new(to_bytes(&case)); + assert!(peel_vec_address(&mut bytes) == case, 0); + assert!(is_empty(&into_remainder_bytes(bytes)), 1); + }; - #[test] - fun test_peel_option_u256_success() { - let bytes = x"010000000011111111000000001111111100000000111111110000000011111111"; - let bcs = new(bytes); - let option_u256 = peel_option_u256(&mut bcs); - std::debug::print(&option_u256); - let expected_option_u256 = option::some(7719472155704656682663016097251860136573850893801914284240011010441236971521); - assert!(option_u256 == expected_option_u256, ErrorOutOfRange); } } diff --git a/frameworks/moveos-stdlib/sources/compare.move b/frameworks/moveos-stdlib/sources/compare.move index e651574900..0de19f612e 100644 --- a/frameworks/moveos-stdlib/sources/compare.move +++ b/frameworks/moveos-stdlib/sources/compare.move @@ -2,6 +2,8 @@ module moveos_std::compare { use std::vector; use std::type_name; + use std::u256; + use moveos_std::decimal_value::DecimalValue; use moveos_std::bcs; @@ -95,7 +97,24 @@ module moveos_std::compare { } else { return LESS_THAN } - }else { + } else if (t == type_name::get()) { + let a_value = bcs::peel_u64(&mut a); + let a_decimal = bcs::peel_u8(&mut a); + let b_value = bcs::peel_u64(&mut b); + let b_decimal = bcs::peel_u8(&mut b); + // Normalise the decimal values + let a = (a_value as u256) * u256::pow(10, b_decimal); + let b = (b_value as u256) * u256::pow(10, a_decimal); + + if (a > b) { + return GREATER_THAN + } else if (a == b) { + return EQUAL + } else { + return LESS_THAN + } + } + else { compare_vector_u8(&bcs::into_remainder_bytes(a), &bcs::into_remainder_bytes(b)) } } diff --git a/frameworks/moveos-stdlib/sources/decimal_value.move b/frameworks/moveos-stdlib/sources/decimal_value.move new file mode 100644 index 0000000000..975ef3ad43 --- /dev/null +++ b/frameworks/moveos-stdlib/sources/decimal_value.move @@ -0,0 +1,21 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +module moveos_std::decimal_value { + struct DecimalValue has store, drop, copy { + value: u64, + decimal: u8, + } + + public fun new(value: u64, decimal: u8): DecimalValue { + DecimalValue { value, decimal } + } + + public fun value(self: &DecimalValue): u64 { + self.value + } + + public fun decimal(self: &DecimalValue): u8 { + self.decimal + } +} \ No newline at end of file diff --git a/frameworks/rooch-framework/doc/README.md b/frameworks/rooch-framework/doc/README.md index d5bca85a80..d025e71c48 100644 --- a/frameworks/rooch-framework/doc/README.md +++ b/frameworks/rooch-framework/doc/README.md @@ -34,6 +34,9 @@ This is the reference documentation of the Rooch Framework. - [`0x3::genesis`](genesis.md#0x3_genesis) - [`0x3::multichain_address`](multichain_address.md#0x3_multichain_address) - [`0x3::onchain_config`](onchain_config.md#0x3_onchain_config) +- [`0x3::oracle`](oracle.md#0x3_oracle) +- [`0x3::oracle_data`](oracle_data.md#0x3_oracle_data) +- [`0x3::oracle_meta`](oracle_meta.md#0x3_oracle_meta) - [`0x3::session_key`](session_key.md#0x3_session_key) - [`0x3::session_validator`](session_validator.md#0x3_session_validator) - [`0x3::simple_rng`](simple_rng.md#0x3_simple_rng) diff --git a/frameworks/rooch-framework/doc/account_coin_store.md b/frameworks/rooch-framework/doc/account_coin_store.md index 3b887eeb88..696aa909fd 100644 --- a/frameworks/rooch-framework/doc/account_coin_store.md +++ b/frameworks/rooch-framework/doc/account_coin_store.md @@ -97,7 +97,7 @@ Account hasn't accept CoinType Returns the balance of addr for provided CoinType. -
public fun balance<CoinType: key>(addr: address): u256
+
public fun balance<CoinType: key>(addr: address): u256
 
@@ -173,7 +173,7 @@ Withdraw specified amount of coin CoinType from the si This public entry function requires the CoinType to have key and store abilities. -
public fun withdraw<CoinType: store, key>(account: &signer, amount: u256): coin::Coin<CoinType>
+
public fun withdraw<CoinType: store, key>(account: &signer, amount: u256): coin::Coin<CoinType>
 
@@ -199,7 +199,7 @@ Transfer amount of coins CoinType from fromCoinType must have key and store abilities. -
public fun transfer<CoinType: store, key>(from: &signer, to: address, amount: u256)
+
public fun transfer<CoinType: store, key>(from: &signer, to: address, amount: u256)
 
@@ -235,7 +235,7 @@ This function is only called by the CoinType module, for the develo
#[private_generics(#[CoinType])]
-public fun withdraw_extend<CoinType: key>(addr: address, amount: u256): coin::Coin<CoinType>
+public fun withdraw_extend<CoinType: key>(addr: address, amount: u256): coin::Coin<CoinType>
 
@@ -263,7 +263,7 @@ This function is only called by the CoinType module, for the develo
#[private_generics(#[CoinType])]
-public fun transfer_extend<CoinType: key>(from: address, to: address, amount: u256)
+public fun transfer_extend<CoinType: key>(from: address, to: address, amount: u256)
 
diff --git a/frameworks/rooch-framework/doc/coin.md b/frameworks/rooch-framework/doc/coin.md index 46572f19f3..487c83ff7c 100644 --- a/frameworks/rooch-framework/doc/coin.md +++ b/frameworks/rooch-framework/doc/coin.md @@ -130,7 +130,7 @@ Maximum possible coin supply. -
const MAX_U256: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
+
const MAX_U256: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
 
@@ -337,7 +337,7 @@ be displayed to a user as 5.05 (505 / 10 ** 2). Returns the amount of coin in existence. -
public fun supply<CoinType: key>(coin_info: &coin::CoinInfo<CoinType>): u256
+
public fun supply<CoinType: key>(coin_info: &coin::CoinInfo<CoinType>): u256
 
@@ -386,7 +386,7 @@ so it is impossible to "burn" any non-zero amount of coin, where the original coin is modified in place. -
public fun extract<CoinType: key>(coin: &mut coin::Coin<CoinType>, amount: u256): coin::Coin<CoinType>
+
public fun extract<CoinType: key>(coin: &mut coin::Coin<CoinType>, amount: u256): coin::Coin<CoinType>
 
@@ -423,7 +423,7 @@ to the sum of the two coins (dst_coin and source_coin) Returns the value passed in coin. -
public fun value<CoinType: key>(coin: &coin::Coin<CoinType>): u256
+
public fun value<CoinType: key>(coin: &coin::Coin<CoinType>): u256
 
@@ -487,7 +487,7 @@ This function is protected by private_generics, so it can only be c Public coin can mint by anyone with the mutable Object> -
public fun mint<CoinType: store, key>(coin_info: &mut object::Object<coin::CoinInfo<CoinType>>, amount: u256): coin::Coin<CoinType>
+
public fun mint<CoinType: store, key>(coin_info: &mut object::Object<coin::CoinInfo<CoinType>>, amount: u256): coin::Coin<CoinType>
 
@@ -500,7 +500,7 @@ Mint new Coin, this function is
#[private_generics(#[CoinType])]
-public fun mint_extend<CoinType: key>(coin_info: &mut object::Object<coin::CoinInfo<CoinType>>, amount: u256): coin::Coin<CoinType>
+public fun mint_extend<CoinType: key>(coin_info: &mut object::Object<coin::CoinInfo<CoinType>>, amount: u256): coin::Coin<CoinType>
 
@@ -537,7 +537,7 @@ This function is only called by the CoinType module, for the develo -
public(friend) fun unpack<CoinType: key>(coin: coin::Coin<CoinType>): u256
+
public(friend) fun unpack<CoinType: key>(coin: coin::Coin<CoinType>): u256
 
@@ -548,5 +548,5 @@ This function is only called by the CoinType module, for the develo -
public(friend) fun pack<CoinType: key>(value: u256): coin::Coin<CoinType>
+
public(friend) fun pack<CoinType: key>(value: u256): coin::Coin<CoinType>
 
diff --git a/frameworks/rooch-framework/doc/coin_store.md b/frameworks/rooch-framework/doc/coin_store.md index 568c652cb5..8631b742dc 100644 --- a/frameworks/rooch-framework/doc/coin_store.md +++ b/frameworks/rooch-framework/doc/coin_store.md @@ -225,7 +225,7 @@ Remove the CoinStore Object, return the Coin in balance -
public fun balance<CoinType: key>(coin_store_obj: &object::Object<coin_store::CoinStore<CoinType>>): u256
+
public fun balance<CoinType: key>(coin_store_obj: &object::Object<coin_store::CoinStore<CoinType>>): u256
 
@@ -249,7 +249,7 @@ Withdraw amount Coin from the balance of the passed-in CoinType
must has key and store ability -
public fun withdraw<CoinType: store, key>(coin_store_obj: &mut object::Object<coin_store::CoinStore<CoinType>>, amount: u256): coin::Coin<CoinType>
+
public fun withdraw<CoinType: store, key>(coin_store_obj: &mut object::Object<coin_store::CoinStore<CoinType>>, amount: u256): coin::Coin<CoinType>
 
@@ -263,7 +263,7 @@ This function is for the CoinType module to extend
#[private_generics(#[CoinType])]
-public fun withdraw_extend<CoinType: key>(coin_store_obj: &mut object::Object<coin_store::CoinStore<CoinType>>, amount: u256): coin::Coin<CoinType>
+public fun withdraw_extend<CoinType: key>(coin_store_obj: &mut object::Object<coin_store::CoinStore<CoinType>>, amount: u256): coin::Coin<CoinType>
 
@@ -374,7 +374,7 @@ Only the CoinType module can freeze or unfreeze a CoinStore by the -
public(friend) fun withdraw_internal<CoinType: key>(coin_store_obj: &mut object::Object<coin_store::CoinStore<CoinType>>, amount: u256): coin::Coin<CoinType>
+
public(friend) fun withdraw_internal<CoinType: key>(coin_store_obj: &mut object::Object<coin_store::CoinStore<CoinType>>, amount: u256): coin::Coin<CoinType>
 
diff --git a/frameworks/rooch-framework/doc/gas_coin.md b/frameworks/rooch-framework/doc/gas_coin.md index df2642ea89..7abdcafcaf 100644 --- a/frameworks/rooch-framework/doc/gas_coin.md +++ b/frameworks/rooch-framework/doc/gas_coin.md @@ -70,7 +70,7 @@ This module defines Rooch Gas Coin. -
public fun balance(addr: address): u256
+
public fun balance(addr: address): u256
 
@@ -93,7 +93,7 @@ This module defines Rooch Gas Coin. deduct gas coin from the given account. -
public(friend) fun deduct_gas(addr: address, amount: u256): coin::Coin<gas_coin::GasCoin>
+
public(friend) fun deduct_gas(addr: address, amount: u256): coin::Coin<gas_coin::GasCoin>
 
@@ -105,7 +105,7 @@ deduct gas coin from the given account. Mint gas coin to the given account. -
public(friend) fun faucet(addr: address, amount: u256)
+
public(friend) fun faucet(addr: address, amount: u256)
 
@@ -117,7 +117,7 @@ Mint gas coin to the given account. Entry point for the faucet, anyone can get Gas via this function on local/dev net, otherwise only sequencer account can call this function. -
public entry fun faucet_entry(account: &signer, amount: u256)
+
public entry fun faucet_entry(account: &signer, amount: u256)
 
diff --git a/frameworks/rooch-framework/doc/oracle.md b/frameworks/rooch-framework/doc/oracle.md new file mode 100644 index 0000000000..8520b6debb --- /dev/null +++ b/frameworks/rooch-framework/doc/oracle.md @@ -0,0 +1,138 @@ + + + +# Module `0x3::oracle` + + + +- [Resource `TablePlaceholder`](#0x3_oracle_TablePlaceholder) +- [Resource `SimpleOracle`](#0x3_oracle_SimpleOracle) +- [Struct `StoredData`](#0x3_oracle_StoredData) +- [Constants](#@Constants_0) +- [Function `get_historical_data`](#0x3_oracle_get_historical_data) +- [Function `get_latest_data`](#0x3_oracle_get_latest_data) +- [Function `create`](#0x3_oracle_create) +- [Function `submit_data`](#0x3_oracle_submit_data) +- [Function `archive_data`](#0x3_oracle_archive_data) + + +
use 0x1::option;
+use 0x1::string;
+use 0x2::object;
+use 0x2::table;
+use 0x2::timestamp;
+use 0x2::tx_context;
+use 0x3::oracle_data;
+
+ + + + + +## Resource `TablePlaceholder` + + + +
struct TablePlaceholder has key
+
+ + + + + +## Resource `SimpleOracle` + + + +
struct SimpleOracle has store, key
+
+ + + + + +## Struct `StoredData` + + + +
struct StoredData<T: store> has copy, drop, store
+
+ + + + + +## Constants + + + + + + +
const ErrorSenderNotOracle: u64 = 0;
+
+ + + + + + + +
const ErrorTickerNotExists: u64 = 1;
+
+ + + + + +## Function `get_historical_data` + + + +
public fun get_historical_data<K: copy, drop, store, V: copy, store>(oracle_obj: &object::Object<oracle::SimpleOracle>, ticker: string::String, archival_key: K): option::Option<oracle_data::Data<V>>
+
+ + + + + +## Function `get_latest_data` + + + +
public fun get_latest_data<T: copy, store>(oracle_obj: &object::Object<oracle::SimpleOracle>, ticker: string::String): option::Option<oracle_data::Data<T>>
+
+ + + + + +## Function `create` + +Create a new shared SimpleOracle object for publishing data. + + +
public entry fun create(name: string::String, url: string::String, description: string::String)
+
+ + + + + +## Function `submit_data` + + + +
public fun submit_data<T: copy, drop, store>(oracle_obj: &mut object::Object<oracle::SimpleOracle>, ticker: string::String, value: T, identifier: string::String)
+
+ + + + + +## Function `archive_data` + + + +
public fun archive_data<K: copy, drop, store, V: copy, drop, store>(oracle_obj: &mut object::Object<oracle::SimpleOracle>, ticker: string::String, archival_key: K)
+
diff --git a/frameworks/rooch-framework/doc/oracle_data.md b/frameworks/rooch-framework/doc/oracle_data.md new file mode 100644 index 0000000000..9b0a9d93e7 --- /dev/null +++ b/frameworks/rooch-framework/doc/oracle_data.md @@ -0,0 +1,83 @@ + + + +# Module `0x3::oracle_data` + + + +- [Struct `Data`](#0x3_oracle_data_Data) +- [Struct `Metadata`](#0x3_oracle_data_Metadata) +- [Function `new`](#0x3_oracle_data_new) +- [Function `value`](#0x3_oracle_data_value) +- [Function `oracle_address`](#0x3_oracle_data_oracle_address) +- [Function `timestamp`](#0x3_oracle_data_timestamp) + + +
use 0x1::string;
+
+ + + + + +## Struct `Data` + + + +
struct Data<T> has copy, drop
+
+ + + + + +## Struct `Metadata` + + + +
struct Metadata has copy, drop
+
+ + + + + +## Function `new` + + + +
public fun new<T>(value: T, ticker: string::String, sequence_number: u64, timestamp: u64, oracle: address, identifier: string::String): oracle_data::Data<T>
+
+ + + + + +## Function `value` + + + +
public fun value<T>(data: &oracle_data::Data<T>): &T
+
+ + + + + +## Function `oracle_address` + + + +
public fun oracle_address<T>(data: &oracle_data::Data<T>): &address
+
+ + + + + +## Function `timestamp` + + + +
public fun timestamp<T>(data: &oracle_data::Data<T>): u64
+
diff --git a/frameworks/rooch-framework/doc/oracle_meta.md b/frameworks/rooch-framework/doc/oracle_meta.md new file mode 100644 index 0000000000..827ea987cc --- /dev/null +++ b/frameworks/rooch-framework/doc/oracle_meta.md @@ -0,0 +1,186 @@ + + + +# Module `0x3::oracle_meta` + + + +- [Struct `MetaOracle`](#0x3_oracle_meta_MetaOracle) +- [Struct `TrustedData`](#0x3_oracle_meta_TrustedData) +- [Constants](#@Constants_0) +- [Function `new`](#0x3_oracle_meta_new) +- [Function `add_simple_oracle`](#0x3_oracle_meta_add_simple_oracle) +- [Function `median`](#0x3_oracle_meta_median) +- [Function `data`](#0x3_oracle_meta_data) +- [Function `threshold`](#0x3_oracle_meta_threshold) +- [Function `time_window_ms`](#0x3_oracle_meta_time_window_ms) +- [Function `ticker`](#0x3_oracle_meta_ticker) +- [Function `max_timestamp`](#0x3_oracle_meta_max_timestamp) +- [Function `value`](#0x3_oracle_meta_value) +- [Function `oracles`](#0x3_oracle_meta_oracles) + + +
use 0x1::option;
+use 0x1::string;
+use 0x1::vector;
+use 0x2::object;
+use 0x2::sort;
+use 0x3::oracle;
+use 0x3::oracle_data;
+
+ + + + + +## Struct `MetaOracle` + + + +
struct MetaOracle<T>
+
+ + + + + +## Struct `TrustedData` + + + +
struct TrustedData<T> has copy, drop
+
+ + + + + +## Constants + + + + + + +
const ErrorUnsupportedDataType: u64 = 1;
+
+ + + + + + + +
const ErrorValidDataSizeLessThanThreshold: u64 = 0;
+
+ + + + + +## Function `new` + + + +
public fun new<T: copy, drop>(threshold: u64, time_window_ms: u64, ticker: string::String): oracle_meta::MetaOracle<T>
+
+ + + + + +## Function `add_simple_oracle` + + + +
public fun add_simple_oracle<T: copy, drop, store>(meta_oracle: &mut oracle_meta::MetaOracle<T>, oracle: &object::Object<oracle::SimpleOracle>)
+
+ + + + + +## Function `median` + +take the median value + + +
public fun median<T: copy, drop>(meta_oracle: oracle_meta::MetaOracle<T>): oracle_meta::TrustedData<T>
+
+ + + + + +## Function `data` + + + +
public fun data<T>(meta: &oracle_meta::MetaOracle<T>): &vector<option::Option<oracle_data::Data<T>>>
+
+ + + + + +## Function `threshold` + + + +
public fun threshold<T>(meta: &oracle_meta::MetaOracle<T>): u64
+
+ + + + + +## Function `time_window_ms` + + + +
public fun time_window_ms<T>(meta: &oracle_meta::MetaOracle<T>): u64
+
+ + + + + +## Function `ticker` + + + +
public fun ticker<T>(meta: &oracle_meta::MetaOracle<T>): string::String
+
+ + + + + +## Function `max_timestamp` + + + +
public fun max_timestamp<T>(meta: &oracle_meta::MetaOracle<T>): u64
+
+ + + + + +## Function `value` + + + +
public fun value<T>(data: &oracle_meta::TrustedData<T>): &T
+
+ + + + + +## Function `oracles` + + + +
public fun oracles<T>(data: &oracle_meta::TrustedData<T>): vector<address>
+
diff --git a/frameworks/rooch-framework/doc/transaction_fee.md b/frameworks/rooch-framework/doc/transaction_fee.md index da401fbabd..69602342b8 100644 --- a/frameworks/rooch-framework/doc/transaction_fee.md +++ b/frameworks/rooch-framework/doc/transaction_fee.md @@ -61,7 +61,7 @@ Returns the gas factor of gas. -
public fun calculate_gas(gas_amount: u64): u256
+
public fun calculate_gas(gas_amount: u64): u256
 
@@ -72,7 +72,7 @@ Returns the gas factor of gas. -
public(friend) fun withdraw_fee(amount: u256): coin::Coin<gas_coin::GasCoin>
+
public(friend) fun withdraw_fee(amount: u256): coin::Coin<gas_coin::GasCoin>
 
diff --git a/frameworks/rooch-framework/doc/transfer.md b/frameworks/rooch-framework/doc/transfer.md index 3e053e2dad..cc402ec366 100644 --- a/frameworks/rooch-framework/doc/transfer.md +++ b/frameworks/rooch-framework/doc/transfer.md @@ -46,7 +46,7 @@ Transfer amount of coins CoinType from fromCoinType to have key and store abilities. -
public entry fun transfer_coin<CoinType: store, key>(from: &signer, to: address, amount: u256)
+
public entry fun transfer_coin<CoinType: store, key>(from: &signer, to: address, amount: u256)
 
@@ -58,7 +58,7 @@ This public entry function requires the CoinType to have key< Transfer amount of coins CoinType from from to a Bitcoin Address. -
public entry fun transfer_coin_to_bitcoin_address<CoinType: store, key>(from: &signer, to: string::String, amount: u256)
+
public entry fun transfer_coin_to_bitcoin_address<CoinType: store, key>(from: &signer, to: string::String, amount: u256)
 
@@ -72,7 +72,7 @@ The MultiChainAddress is represented by multichain_id and raw This public entry function requires the CoinType to have key and store abilities. -
public entry fun transfer_coin_to_multichain_address<CoinType: store, key>(from: &signer, multichain_id: u64, raw_address: vector<u8>, amount: u256)
+
public entry fun transfer_coin_to_multichain_address<CoinType: store, key>(from: &signer, multichain_id: u64, raw_address: vector<u8>, amount: u256)
 
diff --git a/frameworks/rooch-framework/sources/oracle/oracle.move b/frameworks/rooch-framework/sources/oracle/oracle.move new file mode 100644 index 0000000000..a69fe56d37 --- /dev/null +++ b/frameworks/rooch-framework/sources/oracle/oracle.move @@ -0,0 +1,124 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +module rooch_framework::oracle { + use std::option; + use std::option::Option; + use std::string; + use std::string::String; + use moveos_std::timestamp::now_milliseconds; + use moveos_std::tx_context::sender; + use moveos_std::object; + use moveos_std::object::Object; + use moveos_std::table::Table; + use moveos_std::table; + + use rooch_framework::oracle_data::{Self, Data}; + + const ErrorSenderNotOracle: u64 = 0; + const ErrorTickerNotExists: u64 = 1; + + struct TablePlaceholder has key { + _placeholder: bool, + } + + struct SimpleOracle has store, key { + id: Object, + /// The address of the oracle. + address: address, + /// The name of the oracle. + name: String, + /// The description of the oracle. + description: String, + /// The URL of the oracle. + url: String, + } + + struct StoredData has copy, store, drop { + value: T, + sequence_number: u64, + timestamp: u64, + /// An identifier for the reading (for example real time of observation, or sequence number of observation on other chain). + identifier: String, + } + + public fun get_historical_data( + oracle_obj: &Object, + ticker: String, + archival_key: K + ): Option> { + let oracle = object::borrow(oracle_obj); + string::append(&mut string::utf8(b"[historical] "), ticker); + let historical_data: &Table> = object::borrow_field(&oracle.id, ticker); + let StoredData { value, sequence_number, timestamp, identifier } = *table::borrow( + historical_data, + archival_key + ); + option::some(oracle_data::new(value, ticker, sequence_number, timestamp, oracle.address, identifier)) + } + + public fun get_latest_data(oracle_obj: &Object, ticker: String): Option> { + let oracle = object::borrow(oracle_obj); + if (!object::contains_field(&oracle.id, ticker)) { + return option::none() + }; + let data: &StoredData = object::borrow_field(&oracle.id, ticker); + let StoredData { value, sequence_number, timestamp, identifier } = *data; + option::some(oracle_data::new(value, ticker, sequence_number, timestamp, oracle.address, identifier)) + } + + /// Create a new shared SimpleOracle object for publishing data. + public entry fun create(name: String, url: String, description: String) { + let oracle = object::new(SimpleOracle { id: object::new(TablePlaceholder{_placeholder: false}), address: sender(), name, description, url }); + object::to_shared(oracle) + } + + public fun submit_data( + oracle_obj: &mut Object, + ticker: String, + value: T, + identifier: String, + ) { + let oracle = object::borrow_mut(oracle_obj); + assert!(oracle.address == sender(), ErrorSenderNotOracle); + + let sequence_number = if (object::contains_field(&oracle.id, ticker)) { + let old_data: StoredData = object::remove_field(&mut oracle.id, ticker); + old_data.sequence_number + 1 + }else { + 0 + }; + + let new_data = StoredData { + value, + sequence_number, + timestamp: now_milliseconds(), + identifier, + }; + object::add_field(&mut oracle.id, ticker, new_data); + } + + public fun archive_data( + oracle_obj: &mut Object, + ticker: String, + archival_key: K, + ) { + let oracle = object::borrow_mut(oracle_obj); + assert!(oracle.address == sender(), ErrorSenderNotOracle); + assert!(object::contains_field(&oracle.id, ticker), ErrorTickerNotExists); + + let latest_data: StoredData = *object::borrow_mut_field(&mut oracle.id, ticker); + + string::append(&mut string::utf8(b"[historical] "), ticker); + if (!object::contains_field(&oracle.id, ticker)) { + let data_source = table::new>(); + object::add_field(&mut oracle.id, ticker, data_source); + }; + let historical_data: &mut Table> = object::borrow_mut_field(&mut oracle.id, ticker); + // Replace the old data in historical data if any. + if (table::contains(historical_data, archival_key)) { + table::remove(historical_data, archival_key); + }; + table::add(historical_data, archival_key, latest_data); + } +} \ No newline at end of file diff --git a/frameworks/rooch-framework/sources/oracle/oracle_data.move b/frameworks/rooch-framework/sources/oracle/oracle_data.move new file mode 100644 index 0000000000..82f034118c --- /dev/null +++ b/frameworks/rooch-framework/sources/oracle/oracle_data.move @@ -0,0 +1,52 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +module rooch_framework::oracle_data { + use std::string::String; + + struct Data has drop, copy { + value: T, + metadata: Metadata, + } + + struct Metadata has drop, copy { + ticker: String, + sequence_number: u64, + timestamp: u64, + oracle: address, + /// An identifier for the reading (for example real time of observation, or sequence number of observation on other chain). + identifier: String, + } + + public fun new( + value: T, + ticker: String, + sequence_number: u64, + timestamp: u64, + oracle: address, + identifier: String + ): Data { + Data { + value, + metadata: Metadata { + ticker, + sequence_number, + timestamp, + oracle, + identifier, + }, + } + } + + public fun value(data: &Data): &T { + &data.value + } + + public fun oracle_address(data: &Data): &address { + &data.metadata.oracle + } + + public fun timestamp(data: &Data): u64 { + data.metadata.timestamp + } +} \ No newline at end of file diff --git a/frameworks/rooch-framework/sources/oracle/oracle_meta.move b/frameworks/rooch-framework/sources/oracle/oracle_meta.move new file mode 100644 index 0000000000..2f42d5bf18 --- /dev/null +++ b/frameworks/rooch-framework/sources/oracle/oracle_meta.move @@ -0,0 +1,179 @@ +// Copyright (c) RoochNetwork +// SPDX-License-Identifier: Apache-2.0 + +module rooch_framework::oracle_meta { + use std::option; + use std::option::Option; + use std::string::String; + use std::vector; + use moveos_std::sort::quick_sort; + use rooch_framework::oracle; + use moveos_std::object::Object; + + use rooch_framework::oracle_data::{Self, Data}; + use rooch_framework::oracle::SimpleOracle; + #[test_only] + use moveos_std::decimal_value; + #[test_only] + use moveos_std::decimal_value::DecimalValue; + + + const ErrorValidDataSizeLessThanThreshold: u64 = 0; + const ErrorUnsupportedDataType: u64 = 1; + + struct MetaOracle { + oracle_data: vector>>, + threshold: u64, + time_window_ms: u64, + ticker: String, + max_timestamp: u64, + } + + public fun new(threshold: u64, time_window_ms: u64, ticker: String): MetaOracle { + MetaOracle { + oracle_data: vector::empty(), + threshold, + time_window_ms, + ticker, + max_timestamp: 0, + } + } + + public fun add_simple_oracle( + meta_oracle: &mut MetaOracle, + oracle: &Object + ) { + let oracle_data = oracle::get_latest_data(oracle, meta_oracle.ticker); + if (option::is_some(&oracle_data)) { + meta_oracle.max_timestamp = oracle_data::timestamp(option::borrow(&oracle_data)); + }; + vector::push_back(&mut meta_oracle.oracle_data, oracle_data); + } + + struct TrustedData has copy, drop { + value: T, + oracles: vector
, + } + + fun combine(meta_oracle: MetaOracle, ): (vector, vector
) { + let MetaOracle { oracle_data, threshold, time_window_ms, ticker: _, max_timestamp } = meta_oracle; + let min_timestamp = max_timestamp - time_window_ms; + let values = vector[]; + let oracles = vector
[]; + while (vector::length(&oracle_data) > 0) { + let oracle_data = vector::remove(&mut oracle_data, 0); + if (option::is_some(&oracle_data)) { + let oracle_data = option::destroy_some(oracle_data); + if (oracle_data::timestamp(&oracle_data) > min_timestamp) { + vector::push_back(&mut values, *oracle_data::value(&oracle_data)); + vector::push_back(&mut oracles, *oracle_data::oracle_address(&oracle_data)); + }; + }; + }; + assert!(vector::length(&values) >= threshold, ErrorValidDataSizeLessThanThreshold); + (values, oracles) + } + + /// take the median value + public fun median(meta_oracle: MetaOracle): TrustedData { + let (values, oracles) = combine(meta_oracle); + quick_sort(&mut values); + let i = vector::length(&values) / 2; + let value = vector::remove(&mut values, i); + TrustedData { value, oracles } + } + + + + public fun data(meta: &MetaOracle): &vector>> { + &meta.oracle_data + } + + public fun threshold(meta: &MetaOracle): u64 { + meta.threshold + } + + public fun time_window_ms(meta: &MetaOracle): u64 { + meta.time_window_ms + } + + public fun ticker(meta: &MetaOracle): String { + meta.ticker + } + + public fun max_timestamp(meta: &MetaOracle): u64 { + meta.max_timestamp + } + + public fun value(data: &TrustedData): &T { + &data.value + } + + public fun oracles(data: &TrustedData): vector
{ + data.oracles + } + + #[test] + fun test_quick_sort() { + let data = vector[1, 3, 2, 5, 4]; + quick_sort(&mut data); + assert!(vector::length(&data) == 5, 0); + assert!(*vector::borrow(&data, 0) == 1, 0); + assert!(*vector::borrow(&data, 1) == 2, 0); + assert!(*vector::borrow(&data, 2) == 3, 0); + assert!(*vector::borrow(&data, 3) == 4, 0); + assert!(*vector::borrow(&data, 4) == 5, 0); + } + + #[test] + fun test_quick_sort_u128() { + let data = vector[1, 3, 2, 5, 4]; + quick_sort(&mut data); + assert!(vector::length(&data) == 5, 0); + assert!(*vector::borrow(&data, 0) == 1, 0); + assert!(*vector::borrow(&data, 1) == 2, 0); + assert!(*vector::borrow(&data, 2) == 3, 0); + assert!(*vector::borrow(&data, 3) == 4, 0); + assert!(*vector::borrow(&data, 4) == 5, 0); + } + + #[test] + fun test_quick_sort_decimal_value() { + let data = vector[ + decimal_value::new(1000000, 6), + decimal_value::new(3000000, 6), + decimal_value::new(2000000, 6), + decimal_value::new(5000000, 6), + decimal_value::new(4000000, 6)]; + quick_sort(&mut data); + assert!(vector::length(&data) == 5, 0); + assert!(decimal_value::value(vector::borrow(&data, 0)) == 1000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 1)) == 2000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 2)) == 3000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 3)) == 4000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 4)) == 5000000, 0); + } + + #[test] + fun test_quick_sort_decimal_value_different_decimal() { + let data = vector[ + decimal_value::new(60000, 2), + decimal_value::new(70000, 2), + decimal_value::new(1000000, 6), + decimal_value::new(3000000, 6), + decimal_value::new(2000000, 6), + decimal_value::new(5000000, 6), + decimal_value::new(4000000, 6)]; + + quick_sort(&mut data); + + assert!(vector::length(&data) == 7, 0); + assert!(decimal_value::value(vector::borrow(&data, 0)) == 1000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 1)) == 2000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 2)) == 3000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 3)) == 4000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 4)) == 5000000, 0); + assert!(decimal_value::value(vector::borrow(&data, 5)) == 60000, 0); + assert!(decimal_value::value(vector::borrow(&data, 6)) == 70000, 0); + } +} \ No newline at end of file diff --git a/frameworks/rooch-nursery/doc/brc20.md b/frameworks/rooch-nursery/doc/brc20.md index 3e720ecaaa..1dbb39418c 100644 --- a/frameworks/rooch-nursery/doc/brc20.md +++ b/frameworks/rooch-nursery/doc/brc20.md @@ -237,5 +237,5 @@ https://domo-2.gitbook.io/brc-20-experiment/ -
public fun get_balance(brc20_store_obj: &object::Object<brc20::BRC20Store>, tick: &string::String, address: address): u256
+
public fun get_balance(brc20_store_obj: &object::Object<brc20::BRC20Store>, tick: &string::String, address: address): u256