pyth.cairo 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. use snforge_std::{
  2. declare, ContractClassTrait, start_prank, stop_prank, CheatTarget, spy_events, SpyOn, EventSpy,
  3. EventFetcher, event_name_hash, Event
  4. };
  5. use pyth::pyth::{
  6. IPythDispatcher, IPythDispatcherTrait, DataSource, Event as PythEvent, PriceFeedUpdateEvent,
  7. WormholeAddressSet, GovernanceDataSourceSet, ContractUpgraded,
  8. };
  9. use pyth::byte_array::{ByteArray, ByteArrayImpl};
  10. use pyth::util::{array_try_into, UnwrapWithFelt252};
  11. use pyth::wormhole::IWormholeDispatcherTrait;
  12. use core::starknet::ContractAddress;
  13. use openzeppelin::token::erc20::interface::{IERC20CamelDispatcher, IERC20CamelDispatcherTrait};
  14. use super::wormhole::corrupted_vm;
  15. use super::data;
  16. #[generate_trait]
  17. impl DecodeEventHelpers of DecodeEventHelpersTrait {
  18. fn pop<T, +TryInto<felt252, T>>(ref self: Array<felt252>) -> T {
  19. self.pop_front().unwrap().try_into().unwrap()
  20. }
  21. fn pop_u256(ref self: Array<felt252>) -> u256 {
  22. u256 { low: self.pop(), high: self.pop(), }
  23. }
  24. fn pop_data_source(ref self: Array<felt252>) -> DataSource {
  25. DataSource { emitter_chain_id: self.pop(), emitter_address: self.pop_u256(), }
  26. }
  27. }
  28. fn decode_event(mut event: Event) -> PythEvent {
  29. let key0: felt252 = event.keys.pop();
  30. let output = if key0 == event_name_hash('PriceFeedUpdate') {
  31. let event = PriceFeedUpdateEvent {
  32. price_id: event.keys.pop_u256(),
  33. publish_time: event.data.pop(),
  34. price: event.data.pop(),
  35. conf: event.data.pop(),
  36. };
  37. PythEvent::PriceFeedUpdate(event)
  38. } else if key0 == event_name_hash('WormholeAddressSet') {
  39. let event = WormholeAddressSet {
  40. old_address: event.data.pop(), new_address: event.data.pop(),
  41. };
  42. PythEvent::WormholeAddressSet(event)
  43. } else if key0 == event_name_hash('GovernanceDataSourceSet') {
  44. let event = GovernanceDataSourceSet {
  45. old_data_source: event.data.pop_data_source(),
  46. new_data_source: event.data.pop_data_source(),
  47. last_executed_governance_sequence: event.data.pop(),
  48. };
  49. PythEvent::GovernanceDataSourceSet(event)
  50. } else if key0 == event_name_hash('ContractUpgraded') {
  51. let event = ContractUpgraded { new_class_hash: event.data.pop() };
  52. PythEvent::ContractUpgraded(event)
  53. } else {
  54. panic!("unrecognized event")
  55. };
  56. assert!(event.keys.len() == 0);
  57. assert!(event.data.len() == 0);
  58. output
  59. }
  60. #[test]
  61. fn update_price_feeds_works() {
  62. let owner = 'owner'.try_into().unwrap();
  63. let user = 'user'.try_into().unwrap();
  64. let wormhole = super::wormhole::deploy_with_mainnet_guardians();
  65. let fee_contract = deploy_fee_contract(user);
  66. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  67. start_prank(CheatTarget::One(fee_contract.contract_address), user.try_into().unwrap());
  68. fee_contract.approve(pyth.contract_address, 10000);
  69. stop_prank(CheatTarget::One(fee_contract.contract_address));
  70. let mut spy = spy_events(SpyOn::One(pyth.contract_address));
  71. start_prank(CheatTarget::One(pyth.contract_address), user.try_into().unwrap());
  72. pyth.update_price_feeds(data::good_update1());
  73. stop_prank(CheatTarget::One(pyth.contract_address));
  74. spy.fetch_events();
  75. assert!(spy.events.len() == 1);
  76. let (from, event) = spy.events.pop_front().unwrap();
  77. assert!(from == pyth.contract_address);
  78. let event = decode_event(event);
  79. let expected = PriceFeedUpdateEvent {
  80. price_id: 0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43,
  81. publish_time: 1712589206,
  82. price: 7192002930010,
  83. conf: 3596501465,
  84. };
  85. assert!(event == PythEvent::PriceFeedUpdate(expected));
  86. let last_price = pyth
  87. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  88. .unwrap_with_felt252();
  89. assert!(last_price.price == 7192002930010);
  90. assert!(last_price.conf == 3596501465);
  91. assert!(last_price.expo == -8);
  92. assert!(last_price.publish_time == 1712589206);
  93. let last_ema_price = pyth
  94. .get_ema_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  95. .unwrap_with_felt252();
  96. assert!(last_ema_price.price == 7181868900000);
  97. assert!(last_ema_price.conf == 4096812700);
  98. assert!(last_ema_price.expo == -8);
  99. assert!(last_ema_price.publish_time == 1712589206);
  100. }
  101. #[test]
  102. fn test_governance_set_fee_works() {
  103. let owner = 'owner'.try_into().unwrap();
  104. let user = 'user'.try_into().unwrap();
  105. let wormhole = super::wormhole::deploy_with_test_guardian();
  106. let fee_contract = deploy_fee_contract(user);
  107. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  108. start_prank(CheatTarget::One(fee_contract.contract_address), user);
  109. fee_contract.approve(pyth.contract_address, 10000);
  110. stop_prank(CheatTarget::One(fee_contract.contract_address));
  111. let mut balance = fee_contract.balanceOf(user);
  112. start_prank(CheatTarget::One(pyth.contract_address), user);
  113. pyth.update_price_feeds(data::test_price_update1());
  114. stop_prank(CheatTarget::One(pyth.contract_address));
  115. let new_balance = fee_contract.balanceOf(user);
  116. assert!(balance - new_balance == 1000);
  117. balance = new_balance;
  118. let last_price = pyth
  119. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  120. .unwrap_with_felt252();
  121. assert!(last_price.price == 6281060000000);
  122. pyth.execute_governance_instruction(data::pyth_set_fee());
  123. start_prank(CheatTarget::One(pyth.contract_address), user);
  124. pyth.update_price_feeds(data::test_price_update2());
  125. stop_prank(CheatTarget::One(pyth.contract_address));
  126. let new_balance = fee_contract.balanceOf(user);
  127. assert!(balance - new_balance == 4200);
  128. let last_price = pyth
  129. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  130. .unwrap_with_felt252();
  131. assert!(last_price.price == 6281522520745);
  132. }
  133. #[test]
  134. #[fuzzer(runs: 100, seed: 0)]
  135. #[should_panic]
  136. fn test_rejects_corrupted_governance_instruction(pos: usize, random1: usize, random2: usize) {
  137. let owner = 'owner'.try_into().unwrap();
  138. let user = 'user'.try_into().unwrap();
  139. let wormhole = super::wormhole::deploy_with_test_guardian();
  140. let fee_contract = deploy_fee_contract(user);
  141. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  142. let input = corrupted_vm(data::pyth_set_fee(), pos, random1, random2);
  143. pyth.execute_governance_instruction(input);
  144. }
  145. #[test]
  146. fn test_governance_set_data_sources_works() {
  147. let owner = 'owner'.try_into().unwrap();
  148. let user = 'user'.try_into().unwrap();
  149. let wormhole = super::wormhole::deploy_with_test_guardian();
  150. let fee_contract = deploy_fee_contract(user);
  151. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  152. start_prank(CheatTarget::One(fee_contract.contract_address), user);
  153. fee_contract.approve(pyth.contract_address, 10000);
  154. stop_prank(CheatTarget::One(fee_contract.contract_address));
  155. start_prank(CheatTarget::One(pyth.contract_address), user);
  156. pyth.update_price_feeds(data::test_price_update1());
  157. stop_prank(CheatTarget::One(pyth.contract_address));
  158. let last_price = pyth
  159. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  160. .unwrap_with_felt252();
  161. assert!(last_price.price == 6281060000000);
  162. pyth.execute_governance_instruction(data::pyth_set_data_sources());
  163. start_prank(CheatTarget::One(pyth.contract_address), user);
  164. pyth.update_price_feeds(data::test_update2_alt_emitter());
  165. stop_prank(CheatTarget::One(pyth.contract_address));
  166. let last_price = pyth
  167. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  168. .unwrap_with_felt252();
  169. assert!(last_price.price == 6281522520745);
  170. }
  171. #[test]
  172. #[should_panic(expected: ('invalid update data source',))]
  173. fn test_rejects_update_after_data_source_changed() {
  174. let owner = 'owner'.try_into().unwrap();
  175. let user = 'user'.try_into().unwrap();
  176. let wormhole = super::wormhole::deploy_with_test_guardian();
  177. let fee_contract = deploy_fee_contract(user);
  178. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  179. start_prank(CheatTarget::One(fee_contract.contract_address), user);
  180. fee_contract.approve(pyth.contract_address, 10000);
  181. stop_prank(CheatTarget::One(fee_contract.contract_address));
  182. start_prank(CheatTarget::One(pyth.contract_address), user);
  183. pyth.update_price_feeds(data::test_price_update1());
  184. stop_prank(CheatTarget::One(pyth.contract_address));
  185. let last_price = pyth
  186. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  187. .unwrap_with_felt252();
  188. assert!(last_price.price == 6281060000000);
  189. pyth.execute_governance_instruction(data::pyth_set_data_sources());
  190. start_prank(CheatTarget::One(pyth.contract_address), user);
  191. pyth.update_price_feeds(data::test_price_update2());
  192. stop_prank(CheatTarget::One(pyth.contract_address));
  193. let last_price = pyth
  194. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  195. .unwrap_with_felt252();
  196. assert!(last_price.price == 6281522520745);
  197. }
  198. #[test]
  199. fn test_governance_set_wormhole_works() {
  200. let wormhole_class = declare("wormhole");
  201. // Arbitrary
  202. let wormhole_address = 0x42.try_into().unwrap();
  203. let wormhole = super::wormhole::deploy_declared_with_test_guardian_at(
  204. @wormhole_class, wormhole_address
  205. );
  206. let owner = 'owner'.try_into().unwrap();
  207. let user = 'user'.try_into().unwrap();
  208. let fee_contract = deploy_fee_contract(user);
  209. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  210. start_prank(CheatTarget::One(fee_contract.contract_address), user);
  211. fee_contract.approve(pyth.contract_address, 10000);
  212. stop_prank(CheatTarget::One(fee_contract.contract_address));
  213. start_prank(CheatTarget::One(pyth.contract_address), user);
  214. pyth.update_price_feeds(data::test_price_update1());
  215. stop_prank(CheatTarget::One(pyth.contract_address));
  216. let last_price = pyth
  217. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  218. .unwrap_with_felt252();
  219. assert!(last_price.price == 6281060000000);
  220. // Address used in the governance instruction
  221. let wormhole2_address = 0x05033f06d5c47bcce7960ea703b04a0bf64bf33f6f2eb5613496da747522d9c2
  222. .try_into()
  223. .unwrap();
  224. let wormhole2 = super::wormhole::deploy_declared_with_test_guardian_at(
  225. @wormhole_class, wormhole2_address
  226. );
  227. wormhole2.submit_new_guardian_set(data::upgrade_to_test2());
  228. let mut spy = spy_events(SpyOn::One(pyth.contract_address));
  229. pyth.execute_governance_instruction(data::pyth_set_wormhole());
  230. spy.fetch_events();
  231. assert!(spy.events.len() == 1);
  232. let (from, event) = spy.events.pop_front().unwrap();
  233. assert!(from == pyth.contract_address);
  234. let event = decode_event(event);
  235. let expected = WormholeAddressSet {
  236. old_address: wormhole_address, new_address: wormhole2_address,
  237. };
  238. assert!(event == PythEvent::WormholeAddressSet(expected));
  239. start_prank(CheatTarget::One(pyth.contract_address), user);
  240. pyth.update_price_feeds(data::test_update2_set2());
  241. stop_prank(CheatTarget::One(pyth.contract_address));
  242. let last_price = pyth
  243. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  244. .unwrap_with_felt252();
  245. assert!(last_price.price == 6281522520745);
  246. }
  247. #[test]
  248. #[should_panic(expected: ('invalid guardian set index',))]
  249. fn test_rejects_price_update_without_setting_wormhole() {
  250. let wormhole = super::wormhole::deploy_with_test_guardian();
  251. let owner = 'owner'.try_into().unwrap();
  252. let user = 'user'.try_into().unwrap();
  253. let fee_contract = deploy_fee_contract(user);
  254. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  255. start_prank(CheatTarget::One(fee_contract.contract_address), user);
  256. fee_contract.approve(pyth.contract_address, 10000);
  257. stop_prank(CheatTarget::One(fee_contract.contract_address));
  258. start_prank(CheatTarget::One(pyth.contract_address), user);
  259. pyth.update_price_feeds(data::test_price_update1());
  260. stop_prank(CheatTarget::One(pyth.contract_address));
  261. let last_price = pyth
  262. .get_price_unsafe(0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43)
  263. .unwrap_with_felt252();
  264. assert!(last_price.price == 6281060000000);
  265. start_prank(CheatTarget::One(pyth.contract_address), user);
  266. pyth.update_price_feeds(data::test_update2_set2());
  267. }
  268. // This test doesn't pass because of an snforge bug.
  269. // See https://github.com/foundry-rs/starknet-foundry/issues/2096
  270. // TODO: update snforge and unignore when the next release is available
  271. #[test]
  272. #[should_panic]
  273. #[ignore]
  274. fn test_rejects_set_wormhole_without_deploying() {
  275. let wormhole_class = declare("wormhole");
  276. // Arbitrary
  277. let wormhole_address = 0x42.try_into().unwrap();
  278. let wormhole = super::wormhole::deploy_declared_with_test_guardian_at(
  279. @wormhole_class, wormhole_address
  280. );
  281. let owner = 'owner'.try_into().unwrap();
  282. let user = 'user'.try_into().unwrap();
  283. let fee_contract = deploy_fee_contract(user);
  284. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  285. pyth.execute_governance_instruction(data::pyth_set_wormhole());
  286. }
  287. #[test]
  288. #[should_panic(expected: ('Invalid signature',))]
  289. fn test_rejects_set_wormhole_with_incompatible_guardians() {
  290. let wormhole_class = declare("wormhole");
  291. // Arbitrary
  292. let wormhole_address = 0x42.try_into().unwrap();
  293. let wormhole = super::wormhole::deploy_declared_with_test_guardian_at(
  294. @wormhole_class, wormhole_address
  295. );
  296. let owner = 'owner'.try_into().unwrap();
  297. let user = 'user'.try_into().unwrap();
  298. let fee_contract = deploy_fee_contract(user);
  299. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  300. // Address used in the governance instruction
  301. let wormhole2_address = 0x05033f06d5c47bcce7960ea703b04a0bf64bf33f6f2eb5613496da747522d9c2
  302. .try_into()
  303. .unwrap();
  304. super::wormhole::deploy_declared_at(
  305. @wormhole_class,
  306. array_try_into(array![0x301]),
  307. super::wormhole::CHAIN_ID,
  308. super::wormhole::GOVERNANCE_CHAIN_ID,
  309. super::wormhole::GOVERNANCE_CONTRACT,
  310. Option::Some(wormhole2_address),
  311. );
  312. pyth.execute_governance_instruction(data::pyth_set_wormhole());
  313. }
  314. #[test]
  315. fn test_governance_transfer_works() {
  316. let owner = 'owner'.try_into().unwrap();
  317. let user = 'user'.try_into().unwrap();
  318. let wormhole = super::wormhole::deploy_with_test_guardian();
  319. let fee_contract = deploy_fee_contract(user);
  320. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  321. let mut spy = spy_events(SpyOn::One(pyth.contract_address));
  322. pyth.execute_governance_instruction(data::pyth_auth_transfer());
  323. spy.fetch_events();
  324. assert!(spy.events.len() == 1);
  325. let (from, event) = spy.events.pop_front().unwrap();
  326. assert!(from == pyth.contract_address);
  327. let event = decode_event(event);
  328. let expected = GovernanceDataSourceSet {
  329. old_data_source: DataSource { emitter_chain_id: 1, emitter_address: 41, },
  330. new_data_source: DataSource { emitter_chain_id: 2, emitter_address: 43, },
  331. last_executed_governance_sequence: 1,
  332. };
  333. assert!(event == PythEvent::GovernanceDataSourceSet(expected));
  334. pyth.execute_governance_instruction(data::pyth_set_fee_alt_emitter());
  335. }
  336. #[test]
  337. #[should_panic(expected: ('invalid governance data source',))]
  338. fn test_set_fee_rejects_wrong_emitter() {
  339. let owner = 'owner'.try_into().unwrap();
  340. let user = 'user'.try_into().unwrap();
  341. let wormhole = super::wormhole::deploy_with_test_guardian();
  342. let fee_contract = deploy_fee_contract(user);
  343. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  344. pyth.execute_governance_instruction(data::pyth_set_fee_alt_emitter());
  345. }
  346. #[test]
  347. #[should_panic(expected: ('invalid governance data source',))]
  348. fn test_rejects_old_emitter_after_transfer() {
  349. let owner = 'owner'.try_into().unwrap();
  350. let user = 'user'.try_into().unwrap();
  351. let wormhole = super::wormhole::deploy_with_test_guardian();
  352. let fee_contract = deploy_fee_contract(user);
  353. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  354. pyth.execute_governance_instruction(data::pyth_auth_transfer());
  355. pyth.execute_governance_instruction(data::pyth_set_fee());
  356. }
  357. #[test]
  358. fn test_upgrade_works() {
  359. let owner = 'owner'.try_into().unwrap();
  360. let user = 'user'.try_into().unwrap();
  361. let wormhole = super::wormhole::deploy_with_test_guardian();
  362. let fee_contract = deploy_fee_contract(user);
  363. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  364. let class = declare("pyth_fake_upgrade1");
  365. let mut spy = spy_events(SpyOn::One(pyth.contract_address));
  366. pyth.execute_governance_instruction(data::pyth_upgrade_fake1());
  367. spy.fetch_events();
  368. assert!(spy.events.len() == 1);
  369. let (from, event) = spy.events.pop_front().unwrap();
  370. assert!(from == pyth.contract_address);
  371. let event = decode_event(event);
  372. let expected = ContractUpgraded { new_class_hash: class.class_hash };
  373. assert!(event == PythEvent::ContractUpgraded(expected));
  374. let last_price = pyth.get_price_unsafe(1234).unwrap_with_felt252();
  375. assert!(last_price.price == 42);
  376. }
  377. #[test]
  378. #[should_panic]
  379. #[ignore] // TODO: unignore when snforge is updated
  380. fn test_upgrade_rejects_invalid_hash() {
  381. let owner = 'owner'.try_into().unwrap();
  382. let user = 'user'.try_into().unwrap();
  383. let wormhole = super::wormhole::deploy_with_test_guardian();
  384. let fee_contract = deploy_fee_contract(user);
  385. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  386. pyth.execute_governance_instruction(data::pyth_upgrade_invalid_hash());
  387. }
  388. #[test]
  389. #[should_panic]
  390. #[ignore] // TODO: unignore when snforge is updated
  391. fn test_upgrade_rejects_not_pyth() {
  392. let owner = 'owner'.try_into().unwrap();
  393. let user = 'user'.try_into().unwrap();
  394. let wormhole = super::wormhole::deploy_with_test_guardian();
  395. let fee_contract = deploy_fee_contract(user);
  396. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  397. declare("pyth_fake_upgrade_not_pyth");
  398. pyth.execute_governance_instruction(data::pyth_upgrade_not_pyth());
  399. }
  400. #[test]
  401. #[should_panic(expected: ('invalid governance message',))]
  402. fn test_upgrade_rejects_wrong_magic() {
  403. let owner = 'owner'.try_into().unwrap();
  404. let user = 'user'.try_into().unwrap();
  405. let wormhole = super::wormhole::deploy_with_test_guardian();
  406. let fee_contract = deploy_fee_contract(user);
  407. let pyth = deploy_default(owner, wormhole.contract_address, fee_contract.contract_address);
  408. declare("pyth_fake_upgrade_wrong_magic");
  409. pyth.execute_governance_instruction(data::pyth_upgrade_wrong_magic());
  410. }
  411. fn deploy_default(
  412. owner: ContractAddress, wormhole_address: ContractAddress, fee_contract_address: ContractAddress
  413. ) -> IPythDispatcher {
  414. deploy(
  415. owner,
  416. wormhole_address,
  417. fee_contract_address,
  418. 1000,
  419. array![
  420. DataSource {
  421. emitter_chain_id: 26,
  422. emitter_address: 0xe101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71,
  423. }
  424. ],
  425. 1,
  426. 41,
  427. 0,
  428. )
  429. }
  430. fn deploy(
  431. owner: ContractAddress,
  432. wormhole_address: ContractAddress,
  433. fee_contract_address: ContractAddress,
  434. single_update_fee: u256,
  435. data_sources: Array<DataSource>,
  436. governance_emitter_chain_id: u16,
  437. governance_emitter_address: u256,
  438. governance_initial_sequence: u64,
  439. ) -> IPythDispatcher {
  440. let mut args = array![];
  441. (owner, wormhole_address, fee_contract_address, single_update_fee).serialize(ref args);
  442. (data_sources, governance_emitter_chain_id).serialize(ref args);
  443. (governance_emitter_address, governance_initial_sequence).serialize(ref args);
  444. let contract = declare("pyth");
  445. let contract_address = match contract.deploy(@args) {
  446. Result::Ok(v) => { v },
  447. Result::Err(err) => {
  448. panic(err.panic_data);
  449. 0.try_into().unwrap()
  450. },
  451. };
  452. IPythDispatcher { contract_address }
  453. }
  454. fn deploy_fee_contract(recipient: ContractAddress) -> IERC20CamelDispatcher {
  455. let mut args = array![];
  456. let name: core::byte_array::ByteArray = "eth";
  457. let symbol: core::byte_array::ByteArray = "eth";
  458. (name, symbol, 100000_u256, recipient).serialize(ref args);
  459. let contract = declare("ERC20");
  460. let contract_address = match contract.deploy(@args) {
  461. Result::Ok(v) => { v },
  462. Result::Err(err) => {
  463. panic(err.panic_data);
  464. 0.try_into().unwrap()
  465. },
  466. };
  467. IERC20CamelDispatcher { contract_address }
  468. }