Skip to content

Commit adf8207

Browse files
committed
fix(lazer/sui): add funding_rate_interval, address review comments
1 parent cdf0457 commit adf8207

File tree

7 files changed

+56
-30
lines changed

7 files changed

+56
-30
lines changed

lazer/contracts/sui/sources/channel.move

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ public fun get_update_interval_ms(channel: &Channel): u64 {
6666
Channel::FixedRate200ms => 200,
6767
_ => 0,
6868
}
69-
}
69+
}

lazer/contracts/sui/sources/feed.move

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use pyth_lazer::i16::I16;
44
use pyth_lazer::i64::I64;
55

66
/// The feed struct is based on the Lazer rust protocol definition defined here:
7-
/// https://github.com/pyth-network/pyth-crosschain/blob/main/lazer/sdk/rust/protocol/src/types.rs#L10
7+
/// https://github.com/pyth-network/pyth-crosschain/blob/main/lazer/sdk/rust/protocol/src/payload.rs
88
///
99
/// Some fields in Lazer are optional, as in Lazer might return None for them due to some conditions (for example,
1010
/// not having enough publishers to calculate the price) and that is why they are represented as Option<Option<T>>.
@@ -29,6 +29,8 @@ public struct Feed has copy, drop {
2929
funding_rate: Option<Option<I64>>,
3030
/// Timestamp when the funding rate was last updated
3131
funding_timestamp: Option<Option<u64>>,
32+
/// How often the funding rate and funding payments are calculated, in microseconds
33+
funding_rate_interval: Option<Option<u64>>,
3234
}
3335

3436
/// Create a new Feed with the specified parameters
@@ -42,6 +44,7 @@ public fun new(
4244
confidence: Option<Option<I64>>,
4345
funding_rate: Option<Option<I64>>,
4446
funding_timestamp: Option<Option<u64>>,
47+
funding_rate_interval: Option<Option<u64>>,
4548
): Feed {
4649
Feed {
4750
feed_id,
@@ -53,6 +56,7 @@ public fun new(
5356
confidence,
5457
funding_rate,
5558
funding_timestamp,
59+
funding_rate_interval
5660
}
5761
}
5862

@@ -101,6 +105,11 @@ public fun funding_timestamp(feed: &Feed): Option<Option<u64>> {
101105
feed.funding_timestamp
102106
}
103107

108+
/// Get the funding rate interval
109+
public fun funding_rate_interval(feed: &Feed): Option<Option<u64>> {
110+
feed.funding_rate_interval
111+
}
112+
104113
/// Set the feed ID
105114
public(package) fun set_feed_id(feed: &mut Feed, feed_id: u32) {
106115
feed.feed_id = feed_id;
@@ -145,3 +154,8 @@ public(package) fun set_funding_rate(feed: &mut Feed, funding_rate: Option<Optio
145154
public(package) fun set_funding_timestamp(feed: &mut Feed, funding_timestamp: Option<Option<u64>>) {
146155
feed.funding_timestamp = funding_timestamp;
147156
}
157+
158+
/// Set the funding rate interval
159+
public(package) fun set_funding_rate_interval(feed: &mut Feed, funding_rate_interval: Option<Option<u64>>) {
160+
feed.funding_rate_interval = funding_rate_interval;
161+
}

lazer/contracts/sui/sources/i16.move

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// Adopted from pyth::i64, adapted for i16
1+
/// Adapted from pyth::i64, modified for i16
22

33
module pyth_lazer::i16;
44

@@ -147,4 +147,4 @@ fun test_boundary_values() {
147147

148148
// Test -1
149149
assert!(from_u16(0xFFFF) == new(1, true), 1);
150-
}
150+
}

lazer/contracts/sui/sources/i64.move

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// Adopted from pyth::i64
1+
/// Adapted from pyth::i64
22

33
module pyth_lazer::i64;
44

@@ -134,4 +134,4 @@ fun test_single_zero_representation() {
134134
assert!(&new(0, true) == &new(0, false), 1);
135135
assert!(&new(0, true) == &from_u64(0), 1);
136136
assert!(&new(0, false) == &from_u64(0), 1);
137-
}
137+
}

lazer/contracts/sui/sources/pyth_lazer.move

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public fun parse_and_verify_le_ecdsa_update(update: vector<u8>): Update {
8585
option::none(),
8686
option::none(),
8787
option::none(),
88+
option::none(),
8889
option::none()
8990
);
9091

@@ -145,6 +146,15 @@ public fun parse_and_verify_le_ecdsa_update(update: vector<u8>): Update {
145146
} else {
146147
feed.set_funding_timestamp(option::some(option::none()));
147148
}
149+
} else if (property_id == 8) {
150+
let exists = cursor.peel_u8();
151+
152+
if (exists == 1) {
153+
let funding_rate_interval = cursor.peel_u64();
154+
feed.set_funding_rate_interval(option::some(option::some(funding_rate_interval)));
155+
} else {
156+
feed.set_funding_rate_interval(option::some(option::none()));
157+
}
148158
} else {
149159
// When we have an unknown property, we do not know its length, and therefore
150160
// we cannot ignore it and parse the next properties.

lazer/contracts/sui/sources/update.move

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ public fun channel(update: &Update): Channel {
3535
/// Get a reference to the feeds vector of the update
3636
public fun feeds(update: &Update): vector<Feed> {
3737
update.feeds
38-
}
38+
}

lazer/contracts/sui/tests/pyth_lazer_tests.move

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,60 +10,61 @@ public fun test_parse_and_verify_le_ecdsa_update() {
1010
/*
1111
The test data is from the Lazer subscription:
1212
> Request
13-
{"subscriptionId": 1, "type": "subscribe", "priceFeedIds": [1, 2, 112], "properties": ["price", "bestBidPrice", "bestAskPrice", "exponent", "fundingRate", "fundingTimestamp"], "chains": ["leEcdsa"], "channel": "fixed_rate@200ms", "jsonBinaryEncoding": "hex"}
13+
{"subscriptionId": 1, "type": "subscribe", "priceFeedIds": [1, 2, 112], "properties": ["price", "bestBidPrice", "bestAskPrice", "exponent", "fundingRate", "fundingTimestamp", "fundingRateInterval"], "chains": ["leEcdsa"], "channel": "fixed_rate@200ms", "jsonBinaryEncoding": "hex"}
1414
< Response
1515
{
1616
"type": "streamUpdated",
1717
"subscriptionId": 1,
1818
"parsed": {
19-
"timestampUs": "1753787555800000",
19+
"timestampUs": "1755625313400000",
2020
"priceFeeds": [
2121
{
2222
"priceFeedId": 1,
23-
"price": "11838353875029",
24-
"bestBidPrice": "11838047151903",
25-
"bestAskPrice": "11839270720540",
23+
"price": "11350721594969",
24+
"bestBidPrice": "11350696257890",
25+
"bestAskPrice": "11350868428965",
2626
"exponent": -8
2727
},
2828
{
2929
"priceFeedId": 2,
30-
"price": "382538699314",
31-
"bestBidPrice": "382520831095",
32-
"bestAskPrice": "382561500067",
30+
"price": "417775510136",
31+
"bestBidPrice": "417771266475",
32+
"bestAskPrice": "417782074042",
3333
"exponent": -8
3434
},
3535
{
3636
"priceFeedId": 112,
37-
"price": "118856300000000000",
37+
"price": "113747064619385816",
3838
"exponent": -12,
39-
"fundingRate": 100000000,
40-
"fundingTimestamp": 1753776000000000
39+
"fundingRate": 31670000,
40+
"fundingTimestamp": 1755619200000000,
41+
"fundingRateInterval": 28800000000
4142
}
4243
]
4344
},
4445
"leEcdsa": {
4546
"encoding": "hex",
46-
"data": "e4bd474daafa101a7cdc2f4af22f5735aa3278f7161ae15efa9eac3851ca437e322fde467c9475497e1297499344826fe1209f6de234dce35bdfab8bf6b073be12a07cb201930075d3c793c063467c0f3b0600030301000000060055a0e054c40a0000011f679842c40a0000021c94868bc40a000004f8ff0600070002000000060032521511590000000177ac04105900000002a33b71125900000004f8ff060007007000000006000038d1d42c43a60101000000000000000002000000000000000004f4ff060100e1f50500000000070100e07ecb0c3b0600"
47+
"data": "e4bd474d42e3c9c3477b30f2c5527ebe2fb2c8adadadacaddfa7d95243b80fb8f0d813b453e587f140cf40a1120d75f1ffee8ad4337267e4fcbd23eabb2a555804f85ec101a10075d3c793c0f4295fbb3c060003030100000007005986bacb520a00000162e937ca520a000002a5087bd4520a000004f8ff06000700080002000000070078625c456100000001aba11b456100000002ba8ac0456100000004f8ff060007000800700000000700d8c3e1445a1c940101000000000000000002000000000000000004f4ff0601f03ee30100000000070100e0c6f2b93c0600080100209db406000000"
4748
}
4849
}
4950
*/
5051

5152
let hex_message =
52-
x"e4bd474daafa101a7cdc2f4af22f5735aa3278f7161ae15efa9eac3851ca437e322fde467c9475497e1297499344826fe1209f6de234dce35bdfab8bf6b073be12a07cb201930075d3c793c063467c0f3b0600030301000000060055a0e054c40a0000011f679842c40a0000021c94868bc40a000004f8ff0600070002000000060032521511590000000177ac04105900000002a33b71125900000004f8ff060007007000000006000038d1d42c43a60101000000000000000002000000000000000004f4ff060100e1f50500000000070100e07ecb0c3b0600";
53+
x"e4bd474d42e3c9c3477b30f2c5527ebe2fb2c8adadadacaddfa7d95243b80fb8f0d813b453e587f140cf40a1120d75f1ffee8ad4337267e4fcbd23eabb2a555804f85ec101a10075d3c793c0f4295fbb3c060003030100000007005986bacb520a00000162e937ca520a000002a5087bd4520a000004f8ff06000700080002000000070078625c456100000001aba11b456100000002ba8ac0456100000004f8ff060007000800700000000700d8c3e1445a1c940101000000000000000002000000000000000004f4ff0601f03ee30100000000070100e0c6f2b93c0600080100209db406000000";
5354

5455
let update = parse_and_verify_le_ecdsa_update(hex_message);
5556

5657
// If we reach this point, the function worked correctly
5758
// (no assertion failures in parse_and_validate_update)
58-
assert!(update.timestamp() == 1753787555800000, 0);
59+
assert!(update.timestamp() == 1755625313400000, 0);
5960
assert!(update.channel() == new_fixed_rate_200ms(), 0);
6061
assert!(vector::length(&update.feeds()) == 3, 0);
6162

6263
let feed_1 = vector::borrow(&update.feeds(), 0);
6364
assert!(feed_1.feed_id() == 1, 0);
64-
assert!(feed_1.price() == option::some(option::some(i64::from_u64(11838353875029))), 0);
65-
assert!(feed_1.best_bid_price() == option::some(option::some(i64::from_u64(11838047151903))), 0);
66-
assert!(feed_1.best_ask_price() == option::some(option::some(i64::from_u64(11839270720540))), 0);
65+
assert!(feed_1.price() == option::some(option::some(i64::from_u64(11350721594969))), 0);
66+
assert!(feed_1.best_bid_price() == option::some(option::some(i64::from_u64(11350696257890))), 0);
67+
assert!(feed_1.best_ask_price() == option::some(option::some(i64::from_u64(11350868428965))), 0);
6768
assert!(feed_1.exponent() == option::some(i16::new(8, true)), 0);
6869
assert!(feed_1.publisher_count() == option::none(), 0);
6970
assert!(feed_1.confidence() == option::none(), 0);
@@ -72,9 +73,9 @@ public fun test_parse_and_verify_le_ecdsa_update() {
7273

7374
let feed_2 = vector::borrow(&update.feeds(), 1);
7475
assert!(feed_2.feed_id() == 2, 0);
75-
assert!(feed_2.price() == option::some(option::some(i64::from_u64(382538699314))), 0);
76-
assert!(feed_2.best_bid_price() == option::some(option::some(i64::from_u64(382520831095))), 0);
77-
assert!(feed_2.best_ask_price() == option::some(option::some(i64::from_u64(382561500067))), 0);
76+
assert!(feed_2.price() == option::some(option::some(i64::from_u64(417775510136))), 0);
77+
assert!(feed_2.best_bid_price() == option::some(option::some(i64::from_u64(417771266475))), 0);
78+
assert!(feed_2.best_ask_price() == option::some(option::some(i64::from_u64(417782074042))), 0);
7879
assert!(feed_2.exponent() == option::some(i16::new(8, true)), 0);
7980
assert!(feed_2.publisher_count() == option::none(), 0);
8081
assert!(feed_2.confidence() == option::none(), 0);
@@ -83,12 +84,13 @@ public fun test_parse_and_verify_le_ecdsa_update() {
8384

8485
let feed_3 = vector::borrow(&update.feeds(), 2);
8586
assert!(feed_3.feed_id() == 112, 0);
86-
assert!(feed_3.price() == option::some(option::some(i64::from_u64(118856300000000000))), 0);
87+
assert!(feed_3.price() == option::some(option::some(i64::from_u64(113747064619385816))), 0);
8788
assert!(feed_3.best_bid_price() == option::some(option::none()), 0);
8889
assert!(feed_3.best_ask_price() == option::some(option::none()), 0);
8990
assert!(feed_3.exponent() == option::some(i16::new(12, true)), 0);
9091
assert!(feed_3.publisher_count() == option::none(), 0);
9192
assert!(feed_3.confidence() == option::none(), 0);
92-
assert!(feed_3.funding_rate() == option::some(option::some(i64::from_u64(100000000))), 0);
93-
assert!(feed_3.funding_timestamp() == option::some(option::some(1753776000000000)), 0);
93+
assert!(feed_3.funding_rate() == option::some(option::some(i64::from_u64(31670000))), 0);
94+
assert!(feed_3.funding_timestamp() == option::some(option::some(1755619200000000)), 0);
95+
assert!(feed_3.funding_rate_interval() == option::some(option::some(28800000000)), 0);
9496
}

0 commit comments

Comments
 (0)