diff --git a/lazer/contracts/sui/sources/i16.move b/lazer/contracts/sui/sources/i16.move index c4588e25be..0fbe5850a4 100644 --- a/lazer/contracts/sui/sources/i16.move +++ b/lazer/contracts/sui/sources/i16.move @@ -49,7 +49,7 @@ public fun get_magnitude_if_negative(in: &I16): u64 { public fun from_u16(from: u16): I16 { // Use the MSB to determine whether the number is negative or not. - let from_u64 = (from as u64); + let from_u64 = from as u64; let negative = (from_u64 >> 15) == 1; let magnitude = parse_magnitude(from_u64, negative); @@ -71,7 +71,7 @@ fun parse_magnitude(from: u64, negative: bool): u64 { #[test] fun test_max_positive_magnitude() { new(0x7FFF, false); // 32767 - assert!(&new((1<<15) - 1, false) == &from_u16(((1<<15) - 1) as u16), 1); + assert!(&new((1 << 15) - 1, false) == &from_u16((1 << 15) - 1), 1); } #[test] @@ -83,7 +83,7 @@ fun test_magnitude_too_large_positive() { #[test] fun test_max_negative_magnitude() { new(0x8000, true); // 32768 - assert!(&new(1<<15, true) == &from_u16((1<<15) as u16), 1); + assert!(&new(1 << 15, true) == &from_u16(1 << 15), 1); } #[test] diff --git a/lazer/contracts/sui/sources/i64.move b/lazer/contracts/sui/sources/i64.move index ec20b4d931..863527c2ce 100644 --- a/lazer/contracts/sui/sources/i64.move +++ b/lazer/contracts/sui/sources/i64.move @@ -70,7 +70,7 @@ fun parse_magnitude(from: u64, negative: bool): u64 { #[test] fun test_max_positive_magnitude() { new(0x7FFFFFFFFFFFFFFF, false); - assert!(&new(1<<63 - 1, false) == &from_u64(1<<63 - 1), 1); + assert!(&new((1 << 63) - 1, false) == &from_u64((1 << 63) - 1), 1); } #[test] @@ -82,7 +82,7 @@ fun test_magnitude_too_large_positive() { #[test] fun test_max_negative_magnitude() { new(0x8000000000000000, true); - assert!(&new(1<<63, true) == &from_u64(1<<63), 1); + assert!(&new(1 << 63, true) == &from_u64(1 << 63), 1); } #[test] diff --git a/lazer/contracts/sui/sources/pyth_lazer.move b/lazer/contracts/sui/sources/pyth_lazer.move index a70102644f..4d23b8341c 100644 --- a/lazer/contracts/sui/sources/pyth_lazer.move +++ b/lazer/contracts/sui/sources/pyth_lazer.move @@ -54,14 +54,14 @@ public(package) fun verify_le_ecdsa_message( let pubkey = secp256k1_ecrecover(signature, payload, 0); // Check if the recovered pubkey is in the trusted signers list - let trusted_signers = state::get_trusted_signers(s); + let trusted_signers = s.get_trusted_signers(); let mut maybe_idx = state::find_signer_index(trusted_signers, &pubkey); if (option::is_some(&maybe_idx)) { let idx = option::extract(&mut maybe_idx); let found_signer = &trusted_signers[idx]; - let expires_at = state::expires_at(found_signer); - assert!(clock.timestamp_ms() < expires_at, ESignerExpired); + let expires_at_ms = found_signer.expires_at_ms(); + assert!(clock.timestamp_ms() < expires_at_ms, ESignerExpired); } else { abort ESignerNotTrusted } @@ -100,8 +100,8 @@ public fun parse_and_verify_le_ecdsa_update(s: &State, clock: &Clock, update: ve let payload_len = cursor.peel_u16(); let payload = cursor.into_remainder_bytes(); - // Validate expectedpayload length - assert!((payload_len as u64) == payload.length(), EInvalidPayloadLength); + // Validate expected payload length + assert!(payload_len as u64 == payload.length(), EInvalidPayloadLength); // Parse payload let mut payload_cursor = bcs::new(payload); diff --git a/lazer/contracts/sui/sources/state.move b/lazer/contracts/sui/sources/state.move index 23f86b1e3d..bfa08967ea 100644 --- a/lazer/contracts/sui/sources/state.move +++ b/lazer/contracts/sui/sources/state.move @@ -1,6 +1,8 @@ module pyth_lazer::state; -use pyth_lazer::admin::{Self, AdminCap}; +#[test_only] +use pyth_lazer::admin; +use pyth_lazer::admin::AdminCap; const SECP256K1_COMPRESSED_PUBKEY_LEN: u64 = 33; const EInvalidPubkeyLen: u64 = 1; @@ -35,9 +37,9 @@ public fun public_key(info: &TrustedSignerInfo): &vector { &info.public_key } -/// Get the trusted signer's expiry timestamp (seconds since Unix epoch) -public fun expires_at(info: &TrustedSignerInfo): u64 { - info.expires_at +/// Get the trusted signer's expiry timestamp, converted to milliseconds +public fun expires_at_ms(info: &TrustedSignerInfo): u64 { + info.expires_at * 1000 } /// Get the list of trusted signers @@ -50,31 +52,30 @@ public fun get_trusted_signers(s: &State): &vector { /// - If the expired_at is set to zero, the trusted signer will be removed. /// - If the pubkey isn't found, it is added as a new trusted signer with the given expires_at. public fun update_trusted_signer(_: &AdminCap, s: &mut State, pubkey: vector, expires_at: u64) { - assert!(vector::length(&pubkey) as u64 == SECP256K1_COMPRESSED_PUBKEY_LEN, EInvalidPubkeyLen); + assert!(pubkey.length() == SECP256K1_COMPRESSED_PUBKEY_LEN, EInvalidPubkeyLen); let mut maybe_idx = find_signer_index(&s.trusted_signers, &pubkey); if (expires_at == 0) { - if (option::is_some(&maybe_idx)) { - let idx = option::extract(&mut maybe_idx); + if (maybe_idx.is_some()) { + let idx = maybe_idx.extract(); // Remove by swapping with last (order not preserved), discard removed value - let _ = vector::swap_remove(&mut s.trusted_signers, idx); + let _ = s.trusted_signers.swap_remove(idx); } else { - option::destroy_none(maybe_idx); + maybe_idx.destroy_none(); abort ESignerNotFound }; return }; - if (option::is_some(&maybe_idx)) { - let idx = option::extract(&mut maybe_idx); - let info_ref = vector::borrow_mut(&mut s.trusted_signers, idx); + if (maybe_idx.is_some()) { + let idx = maybe_idx.extract(); + let info_ref = &mut s.trusted_signers[idx]; info_ref.expires_at = expires_at } else { - option::destroy_none(maybe_idx); - vector::push_back( - &mut s.trusted_signers, - TrustedSignerInfo { public_key: pubkey, expires_at }, - ) + maybe_idx.destroy_none(); + s.trusted_signers.push_back( + TrustedSignerInfo { public_key: pubkey, expires_at } + ); } } @@ -82,11 +83,11 @@ public fun find_signer_index( signers: &vector, public_key: &vector, ): Option { - let len = vector::length(signers); + let len = signers.length(); let mut i: u64 = 0; - while (i < (len as u64)) { - let info_ref = vector::borrow(signers, i); - if (*public_key(info_ref) == *public_key) { + while (i < len) { + let signer = &signers[i]; + if (signer.public_key() == public_key) { return option::some(i) }; i = i + 1 @@ -106,7 +107,7 @@ public fun new_for_test(ctx: &mut TxContext): State { public fun destroy_for_test(s: State) { let State { id, trusted_signers } = s; let _ = trusted_signers; - object::delete(id); + id.delete(); } #[test] @@ -120,16 +121,15 @@ public fun test_add_new_signer() { update_trusted_signer(&admin_cap, &mut s, pk, expiry); - let signers_ref = get_trusted_signers(&s); - assert!(vector::length(signers_ref) == 1, 100); - let info = vector::borrow(signers_ref, 0); - assert!(expires_at(info) == 123, 101); - let got_pk = public_key(info); - assert!(vector::length(got_pk) == (SECP256K1_COMPRESSED_PUBKEY_LEN as u64), 102); - let State { id, trusted_signers } = s; - let _ = trusted_signers; - object::delete(id); - admin::destroy_for_test(admin_cap); + let signers_ref = s.get_trusted_signers(); + assert!(signers_ref.length() == 1, 100); + let info = &signers_ref[0]; + assert!(info.expires_at == 123, 101); + let got_pk = info.public_key(); + assert!(got_pk.length() == SECP256K1_COMPRESSED_PUBKEY_LEN, 102); + + s.destroy_for_test(); + admin_cap.destroy_for_test(); } #[test] @@ -151,14 +151,13 @@ public fun test_update_existing_signer_expiry() { 2000, ); - let signers_ref = get_trusted_signers(&s); - assert!(vector::length(signers_ref) == 1, 110); - let info = vector::borrow(signers_ref, 0); - assert!(expires_at(info) == 2000, 111); - let State { id, trusted_signers } = s; - let _ = trusted_signers; - object::delete(id); - admin::destroy_for_test(admin_cap); + let signers_ref = s.get_trusted_signers(); + assert!(signers_ref.length() == 1, 110); + let info = &signers_ref[0]; + assert!(info.expires_at == 2000, 111); + + s.destroy_for_test(); + admin_cap.destroy_for_test(); } #[test] @@ -180,12 +179,11 @@ public fun test_remove_signer_by_zero_expiry() { 0, ); - let signers_ref = get_trusted_signers(&s); - assert!(vector::length(signers_ref) == 0, 120); - let State { id, trusted_signers } = s; - let _ = trusted_signers; - object::delete(id); - admin::destroy_for_test(admin_cap); + let signers_ref = s.get_trusted_signers(); + assert!(signers_ref.length() == 0, 120); + + s.destroy_for_test(); + admin_cap.destroy_for_test(); } #[test, expected_failure(abort_code = EInvalidPubkeyLen)] @@ -196,10 +194,9 @@ public fun test_invalid_pubkey_length_rejected() { let short_pk = x"010203"; update_trusted_signer(&admin_cap, &mut s, short_pk, 1); - let State { id, trusted_signers } = s; - let _ = trusted_signers; - object::delete(id); - admin::destroy_for_test(admin_cap); + + s.destroy_for_test(); + admin_cap.destroy_for_test(); } #[test, expected_failure(abort_code = ESignerNotFound)] @@ -215,8 +212,7 @@ public fun test_remove_nonexistent_signer_fails() { x"03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, ); - let State { id, trusted_signers } = s; - let _ = trusted_signers; - object::delete(id); - admin::destroy_for_test(admin_cap); + + s.destroy_for_test(); + admin_cap.destroy_for_test(); } diff --git a/lazer/contracts/sui/sources/update.move b/lazer/contracts/sui/sources/update.move index f7845d5967..f46ddd0a9a 100644 --- a/lazer/contracts/sui/sources/update.move +++ b/lazer/contracts/sui/sources/update.move @@ -27,35 +27,40 @@ public fun channel(update: &Update): Channel { update.channel } -/// Get a reference to the feeds vector of the update +/// Get a copy of the feeds vector of the update public fun feeds(update: &Update): vector { update.feeds } +/// Get a reference to the feeds vector of the update +public fun feeds_ref(update: &Update): &vector { + &update.feeds +} + /// Parse the update from a BCS cursor containing the payload data /// This assumes the payload magic has already been validated and consumed public(package) fun parse_from_cursor(mut cursor: bcs::BCS): Update { // Parse timestamp let timestamp = cursor.peel_u64(); - + // Parse channel let channel_value = cursor.peel_u8(); let channel = channel::from_u8(channel_value); - + // Parse feeds let feed_count = cursor.peel_u8(); let mut feeds = vector::empty(); let mut feed_i = 0; - + while (feed_i < feed_count) { let feed = feed::parse_from_cursor(&mut cursor); vector::push_back(&mut feeds, feed); feed_i = feed_i + 1; }; - + // Verify no remaining bytes let remaining_bytes = cursor.into_remainder_bytes(); assert!(remaining_bytes.length() == 0, EInvalidPayload); - + Update { timestamp, channel, feeds } } diff --git a/lazer/contracts/sui/tests/pyth_lazer_tests.move b/lazer/contracts/sui/tests/pyth_lazer_tests.move index ded4fc42a9..74dd8e2773 100644 --- a/lazer/contracts/sui/tests/pyth_lazer_tests.move +++ b/lazer/contracts/sui/tests/pyth_lazer_tests.move @@ -66,7 +66,7 @@ public fun test_parse_and_verify_le_ecdsa_update() { // Add the trusted signer that matches the test data let trusted_pubkey = TEST_TRUSTED_SIGNER_PUBKEY; - let expiry_time = 2000000000000000; // Far in the future + let expiry_time = 2_000_000_000_000; // Far in the future state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey, expiry_time); let update = parse_and_verify_le_ecdsa_update(&s, &clock, TEST_LAZER_UPDATE); @@ -75,9 +75,9 @@ public fun test_parse_and_verify_le_ecdsa_update() { // Validate that the fields have correct values assert!(update.timestamp() == 1755625313400000, 0); assert!(update.channel() == new_fixed_rate_200ms(), 0); - assert!(vector::length(&update.feeds()) == 3, 0); + assert!(update.feeds_ref().length() == 3, 0); - let feed_1 = vector::borrow(&update.feeds(), 0); + let feed_1 = &update.feeds_ref()[0]; assert!(feed_1.feed_id() == 1, 0); assert!(feed_1.price() == option::some(option::some(i64::from_u64(11350721594969))), 0); assert!( @@ -95,7 +95,7 @@ public fun test_parse_and_verify_le_ecdsa_update() { assert!(feed_1.funding_timestamp() == option::some(option::none()), 0); assert!(feed_1.funding_rate_interval() == option::some(option::none()), 0); - let feed_2 = vector::borrow(&update.feeds(), 1); + let feed_2 = &update.feeds_ref()[1]; assert!(feed_2.feed_id() == 2, 0); assert!(feed_2.price() == option::some(option::some(i64::from_u64(417775510136))), 0); assert!(feed_2.best_bid_price() == option::some(option::some(i64::from_u64(417771266475))), 0); @@ -107,7 +107,7 @@ public fun test_parse_and_verify_le_ecdsa_update() { assert!(feed_2.funding_timestamp() == option::some(option::none()), 0); assert!(feed_2.funding_rate_interval() == option::some(option::none()), 0); - let feed_3 = vector::borrow(&update.feeds(), 2); + let feed_3 = &update.feeds_ref()[2]; assert!(feed_3.feed_id() == 112, 0); assert!(feed_3.price() == option::some(option::some(i64::from_u64(113747064619385816))), 0); assert!(feed_3.best_bid_price() == option::some(option::none()), 0); @@ -120,9 +120,9 @@ public fun test_parse_and_verify_le_ecdsa_update() { assert!(feed_3.funding_rate_interval() == option::some(option::some(28800000000)), 0); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } #[test] @@ -133,16 +133,30 @@ public fun test_verify_le_ecdsa_message_success() { let clock = clock::create_for_testing(&mut ctx); // Add the trusted signer - let expiry_time = 20000000000000000; // Far in the future + let expiry_time = 20_000_000_000_000; // Far in the future state::update_trusted_signer(&admin_cap, &mut s, TEST_TRUSTED_SIGNER_PUBKEY, expiry_time); // This should succeed verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); +} + +#[test, expected_failure(abort_code = ESignerNotTrusted)] +public fun test_verify_le_ecdsa_message_no_signers() { + let mut ctx = tx_context::dummy(); + let s = state::new_for_test(&mut ctx); + let clock = clock::create_for_testing(&mut ctx); + + // Don't add any trusted signers - this should fail with ESignerNotTrusted + verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); + + // Clean up + s.destroy_for_test(); + clock.destroy_for_testing(); } #[test, expected_failure(abort_code = ESignerNotTrusted)] @@ -152,22 +166,41 @@ public fun test_verify_le_ecdsa_message_untrusted_signer() { let admin_cap = admin::mint_for_test(&mut ctx); let clock = clock::create_for_testing(&mut ctx); - // Don't add any trusted signers - this should fail with ESignerNotTrusted - verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); - // Add signers that don't match the signature - let trusted_pubkey1 = x"03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let trusted_pubkey2 = x"03bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; - state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey1, 1000000000000000); - state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey2, 1000000000000000); + let trusted_pubkey1 = x"03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let trusted_pubkey2 = x"03bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; + state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey1, 1_000_000_000_000); + state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey2, 1_000_000_000_000); // This should still fail with ESignerNotTrusted since the signature doesn't match any of the signers verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); - + // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); +} + +#[test] +public fun test_verify_le_ecdsa_message_nearly_expired_signer() { + let mut ctx = tx_context::dummy(); + let mut s = state::new_for_test(&mut ctx); + let admin_cap = admin::mint_for_test(&mut ctx); + let mut clock = clock::create_for_testing(&mut ctx); + + let expiry_time = 1_000_000_000_000; + clock.set_for_testing(expiry_time * 1000 - 1); // Advance clock right before signer expiry + + // Add an signer + state::update_trusted_signer(&admin_cap, &mut s, TEST_TRUSTED_SIGNER_PUBKEY, expiry_time); + + // This should succeed + verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); + + // Clean up + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } #[test, expected_failure(abort_code = ESignerExpired)] @@ -177,25 +210,41 @@ public fun test_verify_le_ecdsa_message_expired_signer() { let admin_cap = admin::mint_for_test(&mut ctx); let mut clock = clock::create_for_testing(&mut ctx); - let signature = - x"42e3c9c3477b30f2c5527ebe2fb2c8adadadacaddfa7d95243b80fb8f0d813b453e587f140cf40a1120d75f1ffee8ad4337267e4fcbd23eabb2a555804f85ec101"; - let payload = - x"75d3c793c0f4295fbb3c060003030100000007005986bacb520a00000162e937ca520a000002a5087bd4520a000004f8ff06000700080002000000070078625c456100000001aba11b456100000002ba8ac0456100000004f8ff060007000800700000000700d8c3e1445a1c940101000000000000000002000000000000000004f4ff0601f03ee30100000000070100e0c6f2b93c0600080100209db406000000"; + let expiry_time = 1_000_000_000_000; + clock.set_for_testing(expiry_time * 1000); // Advance clock to signer expiry - // Add an expired signer - let trusted_pubkey = x"03a4380f01136eb2640f90c17e1e319e02bbafbeef2e6e67dc48af53f9827e155b"; - let expiry_time = 1000000000000000; - clock.set_for_testing(expiry_time); // Advance clock to signer expiry + // Add an expired signer + state::update_trusted_signer(&admin_cap, &mut s, TEST_TRUSTED_SIGNER_PUBKEY, expiry_time); - state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey, expiry_time); + // This should fail with ESignerExpired + verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); + + // Clean up + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); +} + +#[test, expected_failure(abort_code = ESignerExpired)] +public fun test_verify_le_ecdsa_message_recently_expired_signer() { + let mut ctx = tx_context::dummy(); + let mut s = state::new_for_test(&mut ctx); + let admin_cap = admin::mint_for_test(&mut ctx); + let mut clock = clock::create_for_testing(&mut ctx); + + let expiry_time = 1_000_000_000_000; + clock.set_for_testing(expiry_time * 1000 + 1); // Advance clock right past signer expiry + + // Add an expired signer + state::update_trusted_signer(&admin_cap, &mut s, TEST_TRUSTED_SIGNER_PUBKEY, expiry_time); // This should fail with ESignerExpired - verify_le_ecdsa_message(&s, &clock, &signature, &payload); + verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } #[test] @@ -205,27 +254,21 @@ public fun test_verify_le_ecdsa_message_multiple_signers() { let admin_cap = admin::mint_for_test(&mut ctx); let clock = clock::create_for_testing(&mut ctx); - // Extract signature and payload from the test data - let signature = - x"42e3c9c3477b30f2c5527ebe2fb2c8adadadacaddfa7d95243b80fb8f0d813b453e587f140cf40a1120d75f1ffee8ad4337267e4fcbd23eabb2a555804f85ec101"; - let payload = - x"75d3c793c0f4295fbb3c060003030100000007005986bacb520a00000162e937ca520a000002a5087bd4520a000004f8ff06000700080002000000070078625c456100000001aba11b456100000002ba8ac0456100000004f8ff060007000800700000000700d8c3e1445a1c940101000000000000000002000000000000000004f4ff0601f03ee30100000000070100e0c6f2b93c0600080100209db406000000"; - // Add multiple trusted signers let trusted_pubkey1 = x"03bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; // This doesn't match our signature - let trusted_pubkey2 = x"03a4380f01136eb2640f90c17e1e319e02bbafbeef2e6e67dc48af53f9827e155b"; // This does - let expiry_time = 1000000000000000; + let trusted_pubkey2 = TEST_TRUSTED_SIGNER_PUBKEY; // This does + let expiry_time = 1_000_000_000_000; state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey1, expiry_time); state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey2, expiry_time); // This should succeed because trusted_pubkey2 matches the signature - verify_le_ecdsa_message(&s, &clock, &signature, &payload); + verify_le_ecdsa_message(&s, &clock, &TEST_SIGNATURE, &TEST_PAYLOAD); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } // === NEGATIVE PARSING TESTS === @@ -239,7 +282,7 @@ public fun test_parse_invalid_update_magic() { // Add the trusted signer let trusted_pubkey = TEST_TRUSTED_SIGNER_PUBKEY; - let expiry_time = 2000000000000000; // Far in the future + let expiry_time = 2_000_000_000_000; // Far in the future state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey, expiry_time); // Create update with invalid magic (first 4 bytes corrupted) @@ -250,9 +293,9 @@ public fun test_parse_invalid_update_magic() { parse_and_verify_le_ecdsa_update(&s, &clock, invalid_update); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } #[test, expected_failure(abort_code = EInvalidMagic)] @@ -264,21 +307,21 @@ public fun test_parse_invalid_payload_magic() { // Add the trusted signer let trusted_pubkey = TEST_TRUSTED_SIGNER_PUBKEY; - let expiry_time = 2000000000000000; // Far in the future + let expiry_time = 2_000_000_000_000; // Far in the future state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey, expiry_time); // Create update with invalid payload magic // The payload magic starts at byte 69 (4 bytes magic + 65 bytes signature + 2 payload length) let mut invalid_update = TEST_LAZER_UPDATE; - *vector::borrow_mut(&mut invalid_update, 71) = 0xFF; // Corrupt the payload magic + *invalid_update.borrow_mut(71) = 0xFF; // Corrupt the payload magic // This corrupts the payload magic, so expect EInvalidMagic parse_and_verify_le_ecdsa_update(&s, &clock, invalid_update); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } #[test, expected_failure(abort_code = EInvalidPayloadLength)] @@ -290,22 +333,22 @@ public fun test_parse_invalid_payload_length() { // Add the trusted signer let trusted_pubkey = TEST_TRUSTED_SIGNER_PUBKEY; - let expiry_time = 2000000000000000; // Far in the future + let expiry_time = 2_000_000_000_000; // Far in the future state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey, expiry_time); - // Create update with wrong payload length + // Create update with wrong payload length // Layout: magic(4) + signature(65) + payload_len(2) + payload... // So payload length is at bytes 69-70 let mut invalid_update = TEST_LAZER_UPDATE; - *vector::borrow_mut(&mut invalid_update, 69) = 0xFF; // Set payload length too high + *invalid_update.borrow_mut(69) = 0xFF; // Set payload length too high // This should fail with EInvalidPayloadLength because payload length validation happens before signature verification parse_and_verify_le_ecdsa_update(&s, &clock, invalid_update); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); } #[test, expected_failure(abort_code = 0, location = sui::bcs)] @@ -317,22 +360,17 @@ public fun test_parse_truncated_data() { // Add the trusted signer let trusted_pubkey = TEST_TRUSTED_SIGNER_PUBKEY; - let expiry_time = 2000000000000000; // Far in the future + let expiry_time = 2_000_000_000_000; // Far in the future state::update_trusted_signer(&admin_cap, &mut s, trusted_pubkey, expiry_time); // Create truncated update (only first 50 bytes) - let mut truncated_update = vector::empty(); - let mut i = 0; - while (i < 50) { - vector::push_back(&mut truncated_update, *vector::borrow(&TEST_LAZER_UPDATE, i)); - i = i + 1; - }; + let truncated_update = TEST_LAZER_UPDATE.take(50); // This should fail with BCS EOutOfRange error when trying to read beyond available data parse_and_verify_le_ecdsa_update(&s, &clock, truncated_update); // Clean up - state::destroy_for_test(s); - admin::destroy_for_test(admin_cap); - clock::destroy_for_testing(clock); + s.destroy_for_test(); + admin_cap.destroy_for_test(); + clock.destroy_for_testing(); }