| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253 |
- use snforge_std::{
- declare, ContractClassTrait, start_prank, stop_prank, CheatTarget, spy_events, SpyOn, EventSpy,
- EventFetcher, event_name_hash, Event, start_warp, stop_warp, ContractClass,
- };
- use pyth::pyth::{
- IPythDispatcher, IPythDispatcherTrait, DataSource, Event as PythEvent, PriceFeedUpdated,
- WormholeAddressSet, GovernanceDataSourceSet, ContractUpgraded, DataSourcesSet, FeeSet,
- PriceFeedPublishTime, GetPriceNoOlderThanError, Price, PriceFeed, GetPriceUnsafeError,
- };
- use pyth::byte_buffer::{ByteBuffer, ByteBufferImpl};
- use pyth::util::{array_try_into, UnwrapWithFelt252};
- use pyth::wormhole::{IWormholeDispatcher, IWormholeDispatcherTrait};
- use core::starknet::ContractAddress;
- use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
- use super::wormhole::corrupted_vm;
- use super::data;
- #[generate_trait]
- impl DecodeEventHelpers of DecodeEventHelpersTrait {
- fn pop<T, +TryInto<felt252, T>>(ref self: Array<felt252>) -> T {
- self.pop_front().unwrap().try_into().unwrap()
- }
- fn pop_u256(ref self: Array<felt252>) -> u256 {
- u256 { low: self.pop(), high: self.pop(), }
- }
- fn pop_data_source(ref self: Array<felt252>) -> DataSource {
- DataSource { emitter_chain_id: self.pop(), emitter_address: self.pop_u256(), }
- }
- fn pop_data_sources(ref self: Array<felt252>) -> Array<DataSource> {
- let count: usize = self.pop();
- let mut i = 0;
- let mut output = array![];
- while i < count {
- output.append(self.pop_data_source());
- i += 1;
- };
- output
- }
- }
- fn decode_event(mut event: Event) -> PythEvent {
- let key0: felt252 = event.keys.pop();
- let output = if key0 == event_name_hash('PriceFeedUpdated') {
- let event = PriceFeedUpdated {
- price_id: event.keys.pop_u256(),
- price: event.data.pop(),
- conf: event.data.pop(),
- publish_time: event.data.pop(),
- };
- PythEvent::PriceFeedUpdated(event)
- } else if key0 == event_name_hash('FeeSet') {
- let event = FeeSet {
- old_fee: event.data.pop_u256(), new_fee: event.data.pop_u256(), token: event.data.pop(),
- };
- PythEvent::FeeSet(event)
- } else if key0 == event_name_hash('DataSourcesSet') {
- let event = DataSourcesSet {
- old_data_sources: event.data.pop_data_sources(),
- new_data_sources: event.data.pop_data_sources(),
- };
- PythEvent::DataSourcesSet(event)
- } else if key0 == event_name_hash('WormholeAddressSet') {
- let event = WormholeAddressSet {
- old_address: event.data.pop(), new_address: event.data.pop(),
- };
- PythEvent::WormholeAddressSet(event)
- } else if key0 == event_name_hash('GovernanceDataSourceSet') {
- let event = GovernanceDataSourceSet {
- old_data_source: event.data.pop_data_source(),
- new_data_source: event.data.pop_data_source(),
- last_executed_governance_sequence: event.data.pop(),
- };
- PythEvent::GovernanceDataSourceSet(event)
- } else if key0 == event_name_hash('ContractUpgraded') {
- let event = ContractUpgraded { new_class_hash: event.data.pop() };
- PythEvent::ContractUpgraded(event)
- } else {
- panic!("unrecognized event")
- };
- assert!(event.keys.len() == 0);
- assert!(event.data.len() == 0);
- output
- }
- #[test]
- fn test_getters_work() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- assert!(pyth.wormhole_address() == ctx.wormhole.contract_address);
- assert!(
- pyth
- .fee_token_addresses() == array![
- ctx.fee_contract.contract_address, ctx.fee_contract2.contract_address,
- ]
- );
- assert!(pyth.get_single_update_fee(ctx.fee_contract.contract_address) == 1000);
- assert!(pyth.get_single_update_fee(ctx.fee_contract2.contract_address) == 2000);
- assert!(
- pyth
- .valid_data_sources() == array![
- DataSource {
- emitter_chain_id: 26,
- emitter_address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71,
- }
- ]
- );
- assert!(
- pyth
- .is_valid_data_source(
- DataSource {
- emitter_chain_id: 26,
- emitter_address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71,
- }
- )
- );
- assert!(
- !pyth.is_valid_data_source(DataSource { emitter_chain_id: 26, emitter_address: 0xbad, })
- );
- assert!(
- !pyth
- .is_valid_data_source(
- DataSource {
- emitter_chain_id: 27,
- emitter_address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71,
- }
- )
- );
- assert!(
- pyth.governance_data_source() == DataSource { emitter_chain_id: 1, emitter_address: 41, }
- );
- assert!(
- pyth
- .is_valid_governance_data_source(
- DataSource { emitter_chain_id: 1, emitter_address: 41, }
- )
- );
- assert!(
- !pyth
- .is_valid_governance_data_source(
- DataSource { emitter_chain_id: 1, emitter_address: 42, }
- )
- );
- assert!(pyth.last_executed_governance_sequence() == 0);
- assert!(pyth.governance_data_source_index() == 0);
- assert!(pyth.chain_id() == 60051);
- }
- #[test]
- fn update_price_feeds_works() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- assert!(
- !pyth.price_feed_exists(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- );
- assert!(
- pyth
- .latest_price_info_publish_time(
- 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
- ) == 0
- );
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- ctx.approve_fee(fee);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = PriceFeedUpdated {
- price_id: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43,
- publish_time: 1712589206,
- price: 7192002930010,
- conf: 3596501465,
- };
- assert!(event == PythEvent::PriceFeedUpdated(expected));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 7192002930010);
- assert!(last_price.conf == 3596501465);
- assert!(last_price.expo == -8);
- assert!(last_price.publish_time == 1712589206);
- let last_ema_price = pyth
- .get_ema_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_ema_price.price == 7181868900000);
- assert!(last_ema_price.conf == 4096812700);
- assert!(last_ema_price.expo == -8);
- assert!(last_ema_price.publish_time == 1712589206);
- let feed = pyth
- .query_price_feed_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(feed.id == 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43);
- assert!(feed.price.price == 7192002930010);
- assert!(feed.price.conf == 3596501465);
- assert!(feed.price.expo == -8);
- assert!(feed.price.publish_time == 1712589206);
- assert!(feed.ema_price.price == 7181868900000);
- assert!(feed.ema_price.conf == 4096812700);
- assert!(feed.ema_price.expo == -8);
- assert!(feed.ema_price.publish_time == 1712589206);
- assert!(
- pyth.price_feed_exists(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- );
- assert!(
- pyth
- .latest_price_info_publish_time(
- 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
- ) == 1712589206
- );
- }
- #[test]
- fn update_price_feeds_works2() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let fee = pyth.get_update_fee(data::good_update2(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- ctx.approve_fee(fee);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update2());
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- fn test_accepts_secondary_fee() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- assert!(
- !pyth.price_feed_exists(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- );
- assert!(
- pyth
- .latest_price_info_publish_time(
- 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
- ) == 0
- );
- let fee2 = pyth.get_update_fee(data::good_update1(), ctx.fee_contract2.contract_address);
- assert!(fee2 == 2000);
- ctx.approve_fee2(fee2);
- let balance1 = ctx.fee_contract.balanceOf(ctx.user);
- let balance2 = ctx.fee_contract2.balanceOf(ctx.user);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- assert!(balance1 - ctx.fee_contract.balanceOf(ctx.user) == 0);
- assert!(balance2 - ctx.fee_contract2.balanceOf(ctx.user) == 2000);
- }
- #[test]
- fn test_accepts_secondary_fee_if_first_allowance_insufficient() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- assert!(
- !pyth.price_feed_exists(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- );
- assert!(
- pyth
- .latest_price_info_publish_time(
- 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
- ) == 0
- );
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- let fee2 = pyth.get_update_fee(data::good_update1(), ctx.fee_contract2.contract_address);
- assert!(fee2 == 2000);
- ctx.approve_fee(500);
- ctx.approve_fee2(fee2);
- let balance1 = ctx.fee_contract.balanceOf(ctx.user);
- let balance2 = ctx.fee_contract2.balanceOf(ctx.user);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- assert!(balance1 - ctx.fee_contract.balanceOf(ctx.user) == 0);
- assert!(balance2 - ctx.fee_contract2.balanceOf(ctx.user) == 2000);
- }
- #[test]
- fn test_accepts_secondary_fee_if_first_balance_insufficient() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let user2 = 'user2'.try_into().unwrap();
- start_prank(CheatTarget::One(ctx.fee_contract.contract_address), ctx.user);
- ctx.fee_contract.transfer(user2, 500);
- stop_prank(CheatTarget::One(ctx.fee_contract.contract_address));
- start_prank(CheatTarget::One(ctx.fee_contract2.contract_address), ctx.user);
- ctx.fee_contract2.transfer(user2, 2000);
- stop_prank(CheatTarget::One(ctx.fee_contract2.contract_address));
- assert!(
- !pyth.price_feed_exists(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- );
- assert!(
- pyth
- .latest_price_info_publish_time(
- 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
- ) == 0
- );
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- let fee2 = pyth.get_update_fee(data::good_update1(), ctx.fee_contract2.contract_address);
- assert!(fee2 == 2000);
- start_prank(CheatTarget::One(ctx.fee_contract.contract_address), user2);
- ctx.fee_contract.approve(ctx.pyth.contract_address, fee);
- stop_prank(CheatTarget::One(ctx.fee_contract.contract_address));
- start_prank(CheatTarget::One(ctx.fee_contract2.contract_address), user2);
- ctx.fee_contract2.approve(ctx.pyth.contract_address, fee2);
- stop_prank(CheatTarget::One(ctx.fee_contract2.contract_address));
- let balance1 = ctx.fee_contract.balanceOf(user2);
- let balance2 = ctx.fee_contract2.balanceOf(user2);
- start_prank(CheatTarget::One(pyth.contract_address), user2.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- assert!(balance1 - ctx.fee_contract.balanceOf(user2) == 0);
- assert!(balance2 - ctx.fee_contract2.balanceOf(user2) == 2000);
- }
- #[test]
- #[should_panic(expected: ('insufficient fee allowance',))]
- fn test_rejects_if_both_fees_insufficient() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- assert!(
- !pyth.price_feed_exists(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- );
- assert!(
- pyth
- .latest_price_info_publish_time(
- 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
- ) == 0
- );
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- let fee2 = pyth.get_update_fee(data::good_update1(), ctx.fee_contract2.contract_address);
- assert!(fee2 == 2000);
- ctx.approve_fee(500);
- ctx.approve_fee2(1500);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- #[should_panic(expected: ('unsupported token',))]
- fn test_get_update_fee_rejects_unsupported_token() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- pyth.get_update_fee(data::good_update1(), ctx.pyth.contract_address);
- }
- #[test]
- #[should_panic(expected: ('unsupported token',))]
- fn test_get_single_update_fee_rejects_unsupported_token() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- pyth.get_single_update_fee(ctx.pyth.contract_address);
- }
- #[test]
- fn test_update_if_necessary_works() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- ctx.approve_fee(10000);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- let price_id = 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43;
- assert!(pyth.get_price_unsafe(price_id).is_err());
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- let times = array![PriceFeedPublishTime { price_id, publish_time: 1715769470 }];
- pyth.update_price_feeds_if_necessary(data::test_price_update1(), times);
- let last_price = pyth.get_price_unsafe(price_id).unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- assert!(last_price.publish_time == 1715769470);
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let times = array![PriceFeedPublishTime { price_id, publish_time: 1715769475 }];
- pyth.update_price_feeds_if_necessary(data::test_price_update2(), times);
- let last_price = pyth.get_price_unsafe(price_id).unwrap_with_felt252();
- assert!(last_price.price == 6281522520745);
- assert!(last_price.publish_time == 1715769475);
- spy.fetch_events();
- assert!(spy.events.len() == 2);
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- fn test_parse_price_feed_updates_works() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- ctx.approve_fee(1000);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- let output = pyth
- .parse_price_feed_updates(
- data::good_update1(),
- array![0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43],
- 0,
- 1712589208
- );
- stop_prank(CheatTarget::One(pyth.contract_address));
- assert!(output.len() == 1);
- let output = output.at(0).clone();
- let expected = PriceFeed {
- id: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43,
- price: Price {
- price: 7192002930010, conf: 3596501465, expo: -8, publish_time: 1712589206,
- },
- ema_price: Price {
- price: 7181868900000, conf: 4096812700, expo: -8, publish_time: 1712589206,
- },
- };
- assert!(output == expected);
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = PriceFeedUpdated {
- price_id: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43,
- publish_time: 1712589206,
- price: 7192002930010,
- conf: 3596501465,
- };
- assert!(event == PythEvent::PriceFeedUpdated(expected));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 7192002930010);
- assert!(last_price.conf == 3596501465);
- assert!(last_price.expo == -8);
- assert!(last_price.publish_time == 1712589206);
- let last_ema_price = pyth
- .get_ema_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_ema_price.price == 7181868900000);
- assert!(last_ema_price.conf == 4096812700);
- assert!(last_ema_price.expo == -8);
- assert!(last_ema_price.publish_time == 1712589206);
- }
- #[test]
- #[should_panic(expected: ('price feed not found',))]
- fn test_parse_price_feed_updates_rejects_bad_price_id() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- ctx.approve_fee(fee);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.parse_price_feed_updates(data::good_update1(), array![0x14], 0, 1712589208);
- }
- #[test]
- #[should_panic(expected: ('price feed not found',))]
- fn test_parse_price_feed_updates_rejects_out_of_range() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let fee = pyth.get_update_fee(data::good_update1(), ctx.fee_contract.contract_address);
- assert!(fee == 1000);
- ctx.approve_fee(fee);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth
- .parse_price_feed_updates(
- data::good_update1(),
- array![0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43],
- 0,
- 1712589000
- );
- }
- #[test]
- fn test_parse_price_feed_updates_unique_works() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let fee1 = pyth.get_update_fee(data::test_price_update2(), ctx.fee_contract.contract_address);
- assert!(fee1 == 1000);
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- let output = pyth
- .parse_unique_price_feed_updates(
- data::unique_update1(),
- array![0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43],
- 1716904943,
- 2,
- );
- stop_prank(CheatTarget::One(pyth.contract_address));
- assert!(output.len() == 1);
- let output = output.at(0).clone();
- let expected = PriceFeed {
- id: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43,
- price: Price {
- price: 6751021151231, conf: 7471389383, expo: -8, publish_time: 1716904943,
- },
- ema_price: Price {
- price: 6815630100000, conf: 6236878200, expo: -8, publish_time: 1716904943,
- },
- };
- assert!(output == expected);
- }
- #[test]
- #[should_panic(expected: ('price feed not found',))]
- fn test_parse_price_feed_updates_unique_rejects_non_unique() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let fee1 = pyth.get_update_fee(data::test_price_update2(), ctx.fee_contract.contract_address);
- assert!(fee1 == 1000);
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth
- .parse_unique_price_feed_updates(
- data::good_update1(),
- array![0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43],
- 1712589206,
- 2,
- );
- }
- #[test]
- #[should_panic(expected: ('no fresh update',))]
- fn test_update_if_necessary_rejects_empty() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds_if_necessary(data::test_price_update1(), array![]);
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- #[should_panic(expected: ('no fresh update',))]
- fn test_update_if_necessary_rejects_no_fresh() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- ctx.approve_fee(10000);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds_if_necessary(data::test_price_update1(), array![]);
- let price_id = 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43;
- assert!(pyth.get_price_unsafe(price_id).is_err());
- spy.fetch_events();
- assert!(spy.events.len() == 0);
- let times = array![PriceFeedPublishTime { price_id, publish_time: 1715769470 }];
- pyth.update_price_feeds_if_necessary(data::test_price_update1(), times);
- let last_price = pyth.get_price_unsafe(price_id).unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- assert!(last_price.publish_time == 1715769470);
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let times = array![PriceFeedPublishTime { price_id, publish_time: 1715769470 }];
- pyth.update_price_feeds_if_necessary(data::test_price_update2(), times);
- }
- #[test]
- fn test_get_no_older_works() {
- let ctx = deploy_mainnet();
- let pyth = ctx.pyth;
- let price_id = 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43;
- let err = pyth.get_price_unsafe(price_id).unwrap_err();
- assert!(err == GetPriceUnsafeError::PriceFeedNotFound);
- let err = pyth.get_ema_price_unsafe(price_id).unwrap_err();
- assert!(err == GetPriceUnsafeError::PriceFeedNotFound);
- let err = pyth.query_price_feed_unsafe(price_id).unwrap_err();
- assert!(err == GetPriceUnsafeError::PriceFeedNotFound);
- let err = pyth.get_price_no_older_than(price_id, 100).unwrap_err();
- assert!(err == GetPriceNoOlderThanError::PriceFeedNotFound);
- let err = pyth.get_ema_price_no_older_than(price_id, 100).unwrap_err();
- assert!(err == GetPriceNoOlderThanError::PriceFeedNotFound);
- let err = pyth.query_price_feed_no_older_than(price_id, 100).unwrap_err();
- assert!(err == GetPriceNoOlderThanError::PriceFeedNotFound);
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- start_warp(CheatTarget::One(pyth.contract_address), 1712589210);
- let err = pyth.get_price_no_older_than(price_id, 3).unwrap_err();
- assert!(err == GetPriceNoOlderThanError::StalePrice);
- let err = pyth.get_ema_price_no_older_than(price_id, 3).unwrap_err();
- assert!(err == GetPriceNoOlderThanError::StalePrice);
- let err = pyth.query_price_feed_no_older_than(price_id, 3).unwrap_err();
- assert!(err == GetPriceNoOlderThanError::StalePrice);
- start_warp(CheatTarget::One(pyth.contract_address), 1712589208);
- let val = pyth.get_price_no_older_than(price_id, 3).unwrap_with_felt252();
- assert!(val.publish_time == 1712589206);
- assert!(val.price == 7192002930010);
- let val = pyth.get_ema_price_no_older_than(price_id, 3).unwrap_with_felt252();
- assert!(val.publish_time == 1712589206);
- assert!(val.price == 7181868900000);
- let val = pyth.query_price_feed_no_older_than(price_id, 3).unwrap_with_felt252();
- assert!(val.price.publish_time == 1712589206);
- assert!(val.price.price == 7192002930010);
- start_warp(CheatTarget::One(pyth.contract_address), 1712589204);
- let val = pyth.get_price_no_older_than(price_id, 3).unwrap_with_felt252();
- assert!(val.publish_time == 1712589206);
- assert!(val.price == 7192002930010);
- let val = pyth.get_ema_price_no_older_than(price_id, 3).unwrap_with_felt252();
- assert!(val.publish_time == 1712589206);
- assert!(val.price == 7181868900000);
- let val = pyth.query_price_feed_no_older_than(price_id, 3).unwrap_with_felt252();
- assert!(val.price.publish_time == 1712589206);
- assert!(val.price.price == 7192002930010);
- stop_warp(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- fn test_governance_set_fee_works() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- let fee_contract = ctx.fee_contract;
- let user = ctx.user;
- let fee1 = pyth.get_update_fee(data::test_price_update1(), ctx.fee_contract.contract_address);
- assert!(fee1 == 1000);
- ctx.approve_fee(10000);
- let mut balance = fee_contract.balanceOf(user);
- start_prank(CheatTarget::One(pyth.contract_address), user);
- pyth.update_price_feeds(data::test_price_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let new_balance = fee_contract.balanceOf(user);
- assert!(balance - new_balance == 1000);
- balance = new_balance;
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- pyth.execute_governance_instruction(data::pyth_set_fee());
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = FeeSet {
- old_fee: 1000, new_fee: 4200, token: ctx.fee_contract.contract_address
- };
- assert!(event == PythEvent::FeeSet(expected));
- let fee2 = pyth.get_update_fee(data::test_price_update2(), ctx.fee_contract.contract_address);
- assert!(fee2 == 4200);
- let fee2_alt = pyth
- .get_update_fee(data::test_price_update2(), ctx.fee_contract2.contract_address);
- assert!(fee2_alt == 2000);
- start_prank(CheatTarget::One(pyth.contract_address), user);
- pyth.update_price_feeds(data::test_price_update2());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let new_balance = fee_contract.balanceOf(user);
- assert!(balance - new_balance == 4200);
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281522520745);
- }
- #[test]
- fn test_governance_set_fee_in_token_works() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- let fee_contract = ctx.fee_contract;
- let user = ctx.user;
- let fee1 = pyth.get_update_fee(data::test_price_update1(), ctx.fee_contract.contract_address);
- assert!(fee1 == 1000);
- ctx.approve_fee(1000);
- let mut balance = fee_contract.balanceOf(user);
- start_prank(CheatTarget::One(pyth.contract_address), user);
- pyth.update_price_feeds(data::test_price_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let new_balance = fee_contract.balanceOf(user);
- assert!(balance - new_balance == 1000);
- balance = new_balance;
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- pyth.execute_governance_instruction(data::pyth_set_fee_in_token());
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = FeeSet {
- old_fee: 2000, new_fee: 4200, token: ctx.fee_contract2.contract_address
- };
- assert!(event == PythEvent::FeeSet(expected));
- let fee2 = pyth.get_update_fee(data::test_price_update2(), ctx.fee_contract.contract_address);
- assert!(fee2 == 1000);
- let fee2_alt = pyth
- .get_update_fee(data::test_price_update2(), ctx.fee_contract2.contract_address);
- assert!(fee2_alt == 4200);
- ctx.approve_fee2(4200);
- let balance2 = ctx.fee_contract2.balanceOf(user);
- start_prank(CheatTarget::One(pyth.contract_address), user);
- pyth.update_price_feeds(data::test_price_update2());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let new_balance2 = ctx.fee_contract2.balanceOf(user);
- assert!(balance2 - new_balance2 == 4200);
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281522520745);
- }
- #[test]
- #[fuzzer(runs: 100, seed: 0)]
- #[should_panic]
- fn test_rejects_corrupted_governance_instruction(pos: usize, random1: usize, random2: usize) {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- let input = corrupted_vm(data::pyth_set_fee(), pos, random1, random2);
- pyth.execute_governance_instruction(input);
- }
- #[test]
- fn test_governance_set_data_sources_works() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds(data::test_price_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- pyth.execute_governance_instruction(data::pyth_set_data_sources());
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = DataSourcesSet {
- old_data_sources: array![
- DataSource {
- emitter_chain_id: 26,
- emitter_address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71,
- }
- ],
- new_data_sources: array![
- DataSource {
- emitter_chain_id: 1,
- emitter_address: 0x6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25,
- },
- DataSource { emitter_chain_id: 3, emitter_address: 0x12d, },
- ],
- };
- assert!(event == PythEvent::DataSourcesSet(expected));
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds(data::test_update2_alt_emitter());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281522520745);
- }
- #[test]
- #[should_panic(expected: ('invalid update data source',))]
- fn test_rejects_update_after_data_source_changed() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds(data::test_price_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- pyth.execute_governance_instruction(data::pyth_set_data_sources());
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds(data::test_price_update2());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281522520745);
- }
- #[test]
- fn test_governance_set_wormhole_works() {
- let wormhole_class = declare("wormhole");
- // Arbitrary
- let wormhole_address = 0x42.try_into().unwrap();
- let wormhole = super::wormhole::deploy_declared_with_test_guardian_at(
- @wormhole_class, wormhole_address
- );
- let user = 'user'.try_into().unwrap();
- let fee_class = declare("ERC20");
- let fee_contract = deploy_fee_contract(fee_class, fee_address1(), user);
- let fee_contract2 = deploy_fee_contract(fee_class, fee_address2(), user);
- let pyth = deploy_pyth_default(
- wormhole.contract_address, fee_contract.contract_address, fee_contract2.contract_address
- );
- start_prank(CheatTarget::One(fee_contract.contract_address), user);
- fee_contract.approve(pyth.contract_address, 10000);
- stop_prank(CheatTarget::One(fee_contract.contract_address));
- start_prank(CheatTarget::One(pyth.contract_address), user);
- pyth.update_price_feeds(data::test_price_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- // Address used in the governance instruction
- let wormhole2_address = 0x05033f06d5c47bcce7960ea703b04a0bf64bf33f6f2eb5613496da747522d9c2
- .try_into()
- .unwrap();
- let wormhole2 = super::wormhole::deploy_declared_with_test_guardian_at(
- @wormhole_class, wormhole2_address
- );
- wormhole2.submit_new_guardian_set(data::upgrade_to_test2());
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- pyth.execute_governance_instruction(data::pyth_set_wormhole());
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = WormholeAddressSet {
- old_address: wormhole_address, new_address: wormhole2_address,
- };
- assert!(event == PythEvent::WormholeAddressSet(expected));
- start_prank(CheatTarget::One(pyth.contract_address), user);
- pyth.update_price_feeds(data::test_update2_set2());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281522520745);
- }
- #[test]
- #[should_panic(expected: ('invalid guardian set index',))]
- fn test_rejects_price_update_without_setting_wormhole() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- ctx.approve_fee(10000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds(data::test_price_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- let last_price = pyth
- .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
- .unwrap_with_felt252();
- assert!(last_price.price == 6281060000000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user);
- pyth.update_price_feeds(data::test_update2_set2());
- }
- // This test doesn't pass because of an snforge bug.
- // See https://github.com/foundry-rs/starknet-foundry/issues/2096
- // TODO: update snforge and unignore when the next release is available
- #[test]
- #[should_panic]
- #[ignore]
- fn test_rejects_set_wormhole_without_deploying() {
- let wormhole_class = declare("wormhole");
- // Arbitrary
- let wormhole_address = 0x42.try_into().unwrap();
- let wormhole = super::wormhole::deploy_declared_with_test_guardian_at(
- @wormhole_class, wormhole_address
- );
- let user = 'user'.try_into().unwrap();
- let fee_class = declare("ERC20");
- let fee_contract = deploy_fee_contract(fee_class, fee_address1(), user);
- let fee_contract2 = deploy_fee_contract(fee_class, fee_address2(), user);
- let pyth = deploy_pyth_default(
- wormhole.contract_address, fee_contract.contract_address, fee_contract2.contract_address
- );
- pyth.execute_governance_instruction(data::pyth_set_wormhole());
- }
- #[test]
- #[should_panic(expected: ('Invalid signature',))]
- fn test_rejects_set_wormhole_with_incompatible_guardians() {
- let wormhole_class = declare("wormhole");
- // Arbitrary
- let wormhole_address = 0x42.try_into().unwrap();
- let wormhole = super::wormhole::deploy_declared_with_test_guardian_at(
- @wormhole_class, wormhole_address
- );
- let user = 'user'.try_into().unwrap();
- let fee_class = declare("ERC20");
- let fee_contract = deploy_fee_contract(fee_class, fee_address1(), user);
- let fee_contract2 = deploy_fee_contract(fee_class, fee_address2(), user);
- let pyth = deploy_pyth_default(
- wormhole.contract_address, fee_contract.contract_address, fee_contract2.contract_address
- );
- // Address used in the governance instruction
- let wormhole2_address = 0x05033f06d5c47bcce7960ea703b04a0bf64bf33f6f2eb5613496da747522d9c2
- .try_into()
- .unwrap();
- super::wormhole::deploy_declared_at(
- @wormhole_class,
- 0,
- array_try_into(array![0x301]),
- super::wormhole::CHAIN_ID,
- super::wormhole::GOVERNANCE_CHAIN_ID,
- super::wormhole::GOVERNANCE_CONTRACT,
- Option::Some(wormhole2_address),
- );
- pyth.execute_governance_instruction(data::pyth_set_wormhole());
- }
- #[test]
- fn test_governance_transfer_works() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- pyth.execute_governance_instruction(data::pyth_auth_transfer());
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = GovernanceDataSourceSet {
- old_data_source: DataSource { emitter_chain_id: 1, emitter_address: 41, },
- new_data_source: DataSource { emitter_chain_id: 2, emitter_address: 43, },
- last_executed_governance_sequence: 1,
- };
- assert!(event == PythEvent::GovernanceDataSourceSet(expected));
- pyth.execute_governance_instruction(data::pyth_set_fee_alt_emitter());
- }
- #[test]
- #[should_panic(expected: ('invalid governance data source',))]
- fn test_set_fee_rejects_wrong_emitter() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- pyth.execute_governance_instruction(data::pyth_set_fee_alt_emitter());
- }
- #[test]
- #[should_panic(expected: ('invalid governance data source',))]
- fn test_rejects_old_emitter_after_transfer() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- pyth.execute_governance_instruction(data::pyth_auth_transfer());
- pyth.execute_governance_instruction(data::pyth_set_fee());
- }
- #[test]
- fn test_upgrade_works() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- let class = declare("pyth_fake_upgrade1");
- let mut spy = spy_events(SpyOn::One(pyth.contract_address));
- pyth.execute_governance_instruction(data::pyth_upgrade_fake1());
- spy.fetch_events();
- assert!(spy.events.len() == 1);
- let (from, event) = spy.events.pop_front().unwrap();
- assert!(from == pyth.contract_address);
- let event = decode_event(event);
- let expected = ContractUpgraded { new_class_hash: class.class_hash };
- assert!(event == PythEvent::ContractUpgraded(expected));
- let last_price = pyth.get_price_unsafe(1234).unwrap_with_felt252();
- assert!(last_price.price == 42);
- }
- #[test]
- #[should_panic]
- #[ignore] // TODO: unignore when snforge is updated
- fn test_upgrade_rejects_invalid_hash() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- pyth.execute_governance_instruction(data::pyth_upgrade_invalid_hash());
- }
- #[test]
- #[should_panic]
- #[ignore] // TODO: unignore when snforge is updated
- fn test_upgrade_rejects_not_pyth() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- declare("pyth_fake_upgrade_not_pyth");
- pyth.execute_governance_instruction(data::pyth_upgrade_not_pyth());
- }
- #[test]
- #[should_panic(expected: ('invalid governance message',))]
- fn test_upgrade_rejects_wrong_magic() {
- let ctx = deploy_test();
- let pyth = ctx.pyth;
- declare("pyth_fake_upgrade_wrong_magic");
- pyth.execute_governance_instruction(data::pyth_upgrade_wrong_magic());
- }
- #[test]
- #[should_panic(expected: ('invalid guardian set index',))]
- fn update_price_feeds_with_set3_rejects_on_guardian_set4() {
- let wormhole = super::wormhole::deploy_with_mainnet_guardian_set4();
- let ctx = deploy_with_wormhole(wormhole);
- let pyth = ctx.pyth;
- ctx.approve_fee(1000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- fn update_price_feeds_works_with_guardian_set4() {
- let wormhole = super::wormhole::deploy_with_mainnet_guardian_set4();
- let ctx = deploy_with_wormhole(wormhole);
- let pyth = ctx.pyth;
- ctx.approve_fee(1000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::unique_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[test]
- fn update_price_feeds_works_with_guardian_sets_3_4() {
- let wormhole = super::wormhole::deploy_with_mainnet_guardian_sets_3_4();
- let ctx = deploy_with_wormhole(wormhole);
- let pyth = ctx.pyth;
- ctx.approve_fee(2000);
- start_prank(CheatTarget::One(pyth.contract_address), ctx.user.try_into().unwrap());
- pyth.update_price_feeds(data::good_update1());
- pyth.update_price_feeds(data::unique_update1());
- stop_prank(CheatTarget::One(pyth.contract_address));
- }
- #[derive(Drop, Copy)]
- struct Context {
- user: ContractAddress,
- wormhole: IWormholeDispatcher,
- fee_contract: IERC20CamelDispatcher,
- fee_contract2: IERC20CamelDispatcher,
- pyth: IPythDispatcher,
- }
- #[generate_trait]
- impl ContextImpl of ContextTrait {
- fn approve_fee(self: Context, amount: u256) {
- start_prank(CheatTarget::One(self.fee_contract.contract_address), self.user);
- self.fee_contract.approve(self.pyth.contract_address, amount);
- stop_prank(CheatTarget::One(self.fee_contract.contract_address));
- }
- fn approve_fee2(self: Context, amount: u256) {
- start_prank(CheatTarget::One(self.fee_contract2.contract_address), self.user);
- self.fee_contract2.approve(self.pyth.contract_address, amount);
- stop_prank(CheatTarget::One(self.fee_contract2.contract_address));
- }
- }
- fn deploy_test() -> Context {
- deploy_with_wormhole(super::wormhole::deploy_with_test_guardian())
- }
- fn deploy_mainnet() -> Context {
- deploy_with_wormhole(super::wormhole::deploy_with_mainnet_guardians())
- }
- fn deploy_with_wormhole(wormhole: IWormholeDispatcher) -> Context {
- let user = 'user'.try_into().unwrap();
- let fee_class = declare("ERC20");
- let fee_contract = deploy_fee_contract(fee_class, fee_address1(), user);
- let fee_contract2 = deploy_fee_contract(fee_class, fee_address2(), user);
- let pyth = deploy_pyth_default(
- wormhole.contract_address, fee_contract.contract_address, fee_contract2.contract_address
- );
- Context { user, wormhole, fee_contract, fee_contract2, pyth }
- }
- fn deploy_pyth_default(
- wormhole_address: ContractAddress,
- fee_token_address1: ContractAddress,
- fee_token_address2: ContractAddress
- ) -> IPythDispatcher {
- deploy_pyth(
- wormhole_address,
- fee_token_address1,
- 1000,
- fee_token_address2,
- 2000,
- array![
- DataSource {
- emitter_chain_id: 26,
- emitter_address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71,
- }
- ],
- 1,
- 41,
- 0,
- )
- }
- fn deploy_pyth(
- wormhole_address: ContractAddress,
- fee_token_address1: ContractAddress,
- single_update_fee1: u256,
- fee_token_address2: ContractAddress,
- single_update_fee2: u256,
- data_sources: Array<DataSource>,
- governance_emitter_chain_id: u16,
- governance_emitter_address: u256,
- governance_initial_sequence: u64,
- ) -> IPythDispatcher {
- let mut args = array![];
- (wormhole_address, fee_token_address1, single_update_fee1).serialize(ref args);
- (fee_token_address2, single_update_fee2).serialize(ref args);
- (data_sources, governance_emitter_chain_id).serialize(ref args);
- (governance_emitter_address, governance_initial_sequence).serialize(ref args);
- let contract = declare("pyth");
- let contract_address = match contract.deploy(@args) {
- Result::Ok(v) => { v },
- Result::Err(err) => { panic(err.panic_data) },
- };
- IPythDispatcher { contract_address }
- }
- fn fee_address1() -> ContractAddress {
- 0x1010.try_into().unwrap()
- }
- fn fee_address2() -> ContractAddress {
- 0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7.try_into().unwrap()
- }
- fn deploy_fee_contract(
- class: ContractClass, at: ContractAddress, recipient: ContractAddress
- ) -> IERC20CamelDispatcher {
- let mut args = array![];
- let name: ByteArray = "eth";
- let symbol: ByteArray = "eth";
- (name, symbol, 100000_u256, recipient).serialize(ref args);
- let contract_address = match class.deploy_at(@args, at) {
- Result::Ok(v) => { v },
- Result::Err(err) => { panic(err.panic_data) },
- };
- IERC20CamelDispatcher { contract_address }
- }
|