Skip to content

Commit cbcc294

Browse files
authored
sui: integration start, set up dependencies, copy over modules from Pyth-Aptos (#706)
* start * move over initial contracts from aptos * newline Move.toml
1 parent 3f56b30 commit cbcc294

File tree

10 files changed

+505
-0
lines changed

10 files changed

+505
-0
lines changed

target_chains/sui/contracts/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
TARGETS := test
2+
3+
.PHONY: test
4+
test:
5+
sui move test

target_chains/sui/contracts/Move.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "Pyth"
3+
version = "0.0.1"
4+
5+
[dependencies.Sui]
6+
git = "https://github.com/MystenLabs/sui.git"
7+
subdir = "crates/sui-framework"
8+
rev = "157ac72030d014f17d76cefe81f3915b4afab2c9"
9+
10+
[dependencies.Wormhole]
11+
git = "https://github.com/wormhole-foundation/wormhole.git"
12+
subdir = "sui/wormhole"
13+
rev = "sui/wormhole-cleanup"
14+
15+
[addresses]
16+
pyth = "0x250"
17+
wormhole = "0x200"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module pyth::data_source {
2+
use wormhole::external_address::ExternalAddress;
3+
4+
struct DataSource has copy, drop, store {
5+
emitter_chain: u64,
6+
emitter_address: ExternalAddress,
7+
}
8+
9+
public fun new(emitter_chain: u64, emitter_address: ExternalAddress): DataSource {
10+
DataSource {
11+
emitter_chain: emitter_chain,
12+
emitter_address: emitter_address,
13+
}
14+
}
15+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
module pyth::deserialize {
2+
use wormhole::bytes::{Self};
3+
use wormhole::cursor::{take_rest, Cursor};
4+
use pyth::i64::{Self, I64};
5+
6+
#[test_only]
7+
use wormhole::cursor::{Self};
8+
9+
public fun deserialize_vector(cur: &mut Cursor<u8>, n: u64): vector<u8> {
10+
bytes::take_bytes(cur, n)
11+
}
12+
13+
public fun deserialize_u8(cur: &mut Cursor<u8>): u8 {
14+
bytes::take_u8(cur)
15+
}
16+
17+
public fun deserialize_u16(cur: &mut Cursor<u8>): u16 {
18+
bytes::take_u16_be(cur)
19+
}
20+
21+
public fun deserialize_u32(cur: &mut Cursor<u8>): u32 {
22+
bytes::take_u32_be(cur)
23+
}
24+
25+
public fun deserialize_i32(cur: &mut Cursor<u8>): I64 {
26+
let deserialized = deserialize_u32(cur);
27+
// If negative, pad the value
28+
let negative = (deserialized >> 31) == 1;
29+
if (negative) {
30+
let padded = (0xFFFFFFFF << 32) + (deserialized as u64);
31+
i64::from_u64((padded as u64))
32+
} else {
33+
i64::from_u64((deserialized as u64))
34+
}
35+
}
36+
37+
public fun deserialize_u64(cur: &mut Cursor<u8>): u64 {
38+
bytes::take_u64_be(cur)
39+
}
40+
41+
public fun deserialize_i64(cur: &mut Cursor<u8>): I64 {
42+
i64::from_u64(deserialize_u64(cur))
43+
}
44+
45+
#[test]
46+
fun test_deserialize_u8() {
47+
let input = x"48258963";
48+
let cursor = cursor::new(input);
49+
50+
let result = deserialize_u8(&mut cursor);
51+
assert!(result == 0x48, 1);
52+
53+
let rest = take_rest(cursor);
54+
assert!(rest == x"258963", 1);
55+
}
56+
57+
#[test]
58+
fun test_deserialize_u16() {
59+
let input = x"48258963";
60+
let cursor = cursor::new(input);
61+
62+
let result = deserialize_u16(&mut cursor);
63+
assert!(result == 0x4825, 1);
64+
65+
let rest = take_rest(cursor);
66+
assert!(rest == x"8963", 1);
67+
}
68+
69+
#[test]
70+
fun test_deserialize_u32() {
71+
let input = x"4825896349741695";
72+
let cursor = cursor::new(input);
73+
74+
let result = deserialize_u32(&mut cursor);
75+
assert!(result == 0x48258963, 1);
76+
77+
let rest = take_rest(cursor);
78+
assert!(rest == x"49741695", 1);
79+
}
80+
81+
#[test]
82+
fun test_deserialize_i32_positive() {
83+
let input = x"4825896349741695";
84+
let cursor = cursor::new(input);
85+
86+
let result = deserialize_i32(&mut cursor);
87+
assert!(result == i64::from_u64(0x48258963), 1);
88+
89+
let rest = take_rest(cursor);
90+
assert!(rest == x"49741695", 1);
91+
}
92+
93+
#[test]
94+
fun test_deserialize_i32_negative() {
95+
let input = x"FFFFFDC349741695";
96+
97+
let cursor = cursor::new(input);
98+
99+
let result = deserialize_i32(&mut cursor);
100+
assert!(result == i64::from_u64(0xFFFFFFFFFFFFFDC3), 1);
101+
102+
let rest = take_rest(cursor);
103+
assert!(rest == x"49741695", 1);
104+
}
105+
106+
#[test]
107+
fun test_deserialize_u64() {
108+
let input = x"48258963497416957497253486";
109+
let cursor = cursor::new(input);
110+
111+
let result = deserialize_u64(&mut cursor);
112+
assert!(result == 0x4825896349741695, 1);
113+
114+
let rest = take_rest(cursor);
115+
assert!(rest == x"7497253486", 1);
116+
}
117+
118+
#[test]
119+
fun test_deserialize_i64_positive() {
120+
let input = x"48258963497416957497253486";
121+
let cursor = cursor::new(input);
122+
123+
let result = deserialize_i64(&mut cursor);
124+
assert!(result == i64::from_u64(0x4825896349741695), 1);
125+
126+
let rest = take_rest(cursor);
127+
assert!(rest == x"7497253486", 1);
128+
}
129+
130+
#[test]
131+
fun test_deserialize_i64_negative() {
132+
let input = x"FFFFFFFFFFFFFDC37497253486";
133+
let cursor = cursor::new(input);
134+
135+
let result = deserialize_i64(&mut cursor);
136+
assert!(result == i64::from_u64(0xFFFFFFFFFFFFFDC3), 1);
137+
138+
let rest = take_rest(cursor);
139+
assert!(rest == x"7497253486", 1);
140+
}
141+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
module pyth::i64 {
2+
//use pyth::error;
3+
4+
const MAX_POSITIVE_MAGNITUDE: u64 = (1 << 63) - 1;
5+
const MAX_NEGATIVE_MAGNITUDE: u64 = (1 << 63);
6+
7+
/// As Move does not support negative numbers natively, we use our own internal
8+
/// representation.
9+
///
10+
/// To consume these values, first call `get_is_negative()` to determine if the I64
11+
/// represents a negative or positive value. Then call `get_magnitude_if_positive()` or
12+
/// `get_magnitude_if_negative()` to get the magnitude of the number in unsigned u64 format.
13+
/// This API forces consumers to handle positive and negative numbers safely.
14+
struct I64 has copy, drop, store {
15+
negative: bool,
16+
magnitude: u64,
17+
}
18+
19+
public fun new(magnitude: u64, negative: bool): I64 {
20+
let max_magnitude = MAX_POSITIVE_MAGNITUDE;
21+
if (negative) {
22+
max_magnitude = MAX_NEGATIVE_MAGNITUDE;
23+
};
24+
assert!(magnitude <= max_magnitude, 0); //error::magnitude_too_large()
25+
26+
27+
// Ensure we have a single zero representation: (0, false).
28+
// (0, true) is invalid.
29+
if (magnitude == 0) {
30+
negative = false;
31+
};
32+
33+
I64 {
34+
magnitude: magnitude,
35+
negative: negative,
36+
}
37+
}
38+
39+
public fun get_is_negative(i: &I64): bool {
40+
i.negative
41+
}
42+
43+
public fun get_magnitude_if_positive(in: &I64): u64 {
44+
assert!(!in.negative, 0); // error::negative_value()
45+
in.magnitude
46+
}
47+
48+
public fun get_magnitude_if_negative(in: &I64): u64 {
49+
assert!(in.negative, 0); //error::positive_value()
50+
in.magnitude
51+
}
52+
53+
public fun from_u64(from: u64): I64 {
54+
// Use the MSB to determine whether the number is negative or not.
55+
let negative = (from >> 63) == 1;
56+
let magnitude = parse_magnitude(from, negative);
57+
58+
new(magnitude, negative)
59+
}
60+
61+
fun parse_magnitude(from: u64, negative: bool): u64 {
62+
// If positive, then return the input verbatamin
63+
if (!negative) {
64+
return from
65+
};
66+
67+
// Otherwise convert from two's complement by inverting and adding 1
68+
let inverted = from ^ 0xFFFFFFFFFFFFFFFF;
69+
inverted + 1
70+
}
71+
72+
#[test]
73+
fun test_max_positive_magnitude() {
74+
new(0x7FFFFFFFFFFFFFFF, false);
75+
assert!(&new(1<<63 - 1, false) == &from_u64(1<<63 - 1), 1);
76+
}
77+
78+
#[test]
79+
#[expected_failure]
80+
fun test_magnitude_too_large_positive() {
81+
new(0x8000000000000000, false);
82+
}
83+
84+
#[test]
85+
fun test_max_negative_magnitude() {
86+
new(0x8000000000000000, true);
87+
assert!(&new(1<<63, true) == &from_u64(1<<63), 1);
88+
}
89+
90+
#[test]
91+
#[expected_failure]
92+
fun test_magnitude_too_large_negative() {
93+
new(0x8000000000000001, true);
94+
}
95+
96+
#[test]
97+
fun test_from_u64_positive() {
98+
assert!(from_u64(0x64673) == new(0x64673, false), 1);
99+
}
100+
101+
#[test]
102+
fun test_from_u64_negative() {
103+
assert!(from_u64(0xFFFFFFFFFFFEDC73) == new(0x1238D, true), 1);
104+
}
105+
106+
#[test]
107+
fun test_get_is_negative() {
108+
assert!(get_is_negative(&new(234, true)) == true, 1);
109+
assert!(get_is_negative(&new(767, false)) == false, 1);
110+
}
111+
112+
#[test]
113+
fun test_get_magnitude_if_positive_positive() {
114+
assert!(get_magnitude_if_positive(&new(7686, false)) == 7686, 1);
115+
}
116+
117+
#[test]
118+
#[expected_failure]
119+
fun test_get_magnitude_if_positive_negative() {
120+
assert!(get_magnitude_if_positive(&new(7686, true)) == 7686, 1);
121+
}
122+
123+
#[test]
124+
fun test_get_magnitude_if_negative_negative() {
125+
assert!(get_magnitude_if_negative(&new(7686, true)) == 7686, 1);
126+
}
127+
128+
#[test]
129+
#[expected_failure]
130+
fun test_get_magnitude_if_negative_positive() {
131+
assert!(get_magnitude_if_negative(&new(7686, false)) == 7686, 1);
132+
}
133+
134+
#[test]
135+
fun test_single_zero_representation() {
136+
assert!(&new(0, true) == &new(0, false), 1);
137+
assert!(&new(0, true) == &from_u64(0), 1);
138+
assert!(&new(0, false) == &from_u64(0), 1);
139+
}
140+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module pyth::price {
2+
use pyth::i64::I64;
3+
4+
/// A price with a degree of uncertainty, represented as a price +- a confidence interval.
5+
///
6+
/// The confidence interval roughly corresponds to the standard error of a normal distribution.
7+
/// Both the price and confidence are stored in a fixed-point numeric representation,
8+
/// `x * (10^expo)`, where `expo` is the exponent.
9+
//
10+
/// Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how
11+
/// to how this price safely.
12+
struct Price has copy, drop, store {
13+
price: I64,
14+
/// Confidence interval around the price
15+
conf: u64,
16+
/// The exponent
17+
expo: I64,
18+
/// Unix timestamp of when this price was computed
19+
timestamp: u64,
20+
}
21+
22+
public fun new(price: I64, conf: u64, expo: I64, timestamp: u64): Price {
23+
Price {
24+
price: price,
25+
conf: conf,
26+
expo: expo,
27+
timestamp: timestamp,
28+
}
29+
}
30+
31+
public fun get_price(price: &Price): I64 {
32+
price.price
33+
}
34+
35+
public fun get_conf(price: &Price): u64 {
36+
price.conf
37+
}
38+
39+
public fun get_timestamp(price: &Price): u64 {
40+
price.timestamp
41+
}
42+
43+
public fun get_expo(price: &Price): I64 {
44+
price.expo
45+
}
46+
}

0 commit comments

Comments
 (0)