state.move 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. module pyth::state {
  2. use std::vector;
  3. use sui::object::{Self, UID, ID};
  4. use sui::tx_context::{Self, TxContext};
  5. use sui::package::{UpgradeCap, UpgradeTicket, UpgradeReceipt};
  6. use pyth::data_source::{Self, DataSource};
  7. use pyth::price_info::{Self};
  8. use pyth::price_identifier::{Self, PriceIdentifier};
  9. use pyth::version_control::{Self};
  10. use wormhole::consumed_vaas::{Self, ConsumedVAAs};
  11. use wormhole::bytes32::{Self, Bytes32};
  12. use wormhole::package_utils::{Self};
  13. use wormhole::external_address::{ExternalAddress};
  14. friend pyth::pyth;
  15. #[test_only]
  16. friend pyth::pyth_tests;
  17. friend pyth::governance_action;
  18. friend pyth::set_update_fee;
  19. friend pyth::set_stale_price_threshold;
  20. friend pyth::set_data_sources;
  21. friend pyth::governance;
  22. friend pyth::set_governance_data_source;
  23. friend pyth::migrate;
  24. friend pyth::contract_upgrade;
  25. friend pyth::set_fee_recipient;
  26. friend pyth::setup;
  27. /// Build digest does not agree with current implementation.
  28. const E_INVALID_BUILD_DIGEST: u64 = 0;
  29. /// Specified version does not match this build's version.
  30. const E_VERSION_MISMATCH: u64 = 1;
  31. /// Sui's chain ID is hard-coded to one value.
  32. const CHAIN_ID: u16 = 21;
  33. /// Capability reflecting that the current build version is used to invoke
  34. /// state methods.
  35. struct LatestOnly has drop {}
  36. struct State has key, store {
  37. id: UID,
  38. governance_data_source: DataSource,
  39. stale_price_threshold: u64,
  40. base_update_fee: u64,
  41. fee_recipient_address: address,
  42. last_executed_governance_sequence: u64,
  43. consumed_vaas: ConsumedVAAs,
  44. // Upgrade capability.
  45. upgrade_cap: UpgradeCap
  46. }
  47. public(friend) fun new(
  48. upgrade_cap: UpgradeCap,
  49. sources: vector<DataSource>,
  50. governance_data_source: DataSource,
  51. stale_price_threshold: u64,
  52. base_update_fee: u64,
  53. ctx: &mut TxContext
  54. ): State {
  55. let uid = object::new(ctx);
  56. // Create a set that contains all registered data sources and
  57. // attach it to uid as a dynamic field to minimize the
  58. // size of State.
  59. data_source::new_data_source_registry(&mut uid, ctx);
  60. // Create a table that tracks the object IDs of price feeds and
  61. // attach it to the uid as a dynamic object field to minimize the
  62. // size of State.
  63. price_info::new_price_info_registry(&mut uid, ctx);
  64. while (!vector::is_empty(&sources)) {
  65. data_source::add(&mut uid, vector::pop_back(&mut sources));
  66. };
  67. let consumed_vaas = consumed_vaas::new(ctx);
  68. // Initialize package info. This will be used for emitting information
  69. // of successful migrations.
  70. package_utils::init_package_info(
  71. &mut uid,
  72. version_control::current_version(),
  73. &upgrade_cap
  74. );
  75. State {
  76. id: uid,
  77. upgrade_cap,
  78. governance_data_source,
  79. stale_price_threshold,
  80. fee_recipient_address: tx_context::sender(ctx),
  81. base_update_fee,
  82. consumed_vaas,
  83. last_executed_governance_sequence: 0
  84. }
  85. }
  86. ////////////////////////////////////////////////////////////////////////////
  87. //
  88. // Simple Getters
  89. //
  90. // These methods do not require `LatestOnly` for access. Anyone is free to
  91. // access these values.
  92. //
  93. ////////////////////////////////////////////////////////////////////////////
  94. public fun get_stale_price_threshold_secs(s: &State): u64 {
  95. s.stale_price_threshold
  96. }
  97. public fun get_base_update_fee(s: &State): u64 {
  98. s.base_update_fee
  99. }
  100. public fun get_fee_recipient(s: &State): address {
  101. s.fee_recipient_address
  102. }
  103. public fun is_valid_data_source(s: &State, data_source: DataSource): bool {
  104. data_source::contains(&s.id, data_source)
  105. }
  106. public fun is_valid_governance_data_source(s: &State, source: DataSource): bool {
  107. s.governance_data_source == source
  108. }
  109. public fun price_feed_object_exists(s: &State, p: PriceIdentifier): bool {
  110. price_info::contains(&s.id, p)
  111. }
  112. /// Retrieve governance chain ID, which is governance's emitter chain ID.
  113. public fun governance_data_source(self: &State): DataSource {
  114. self.governance_data_source
  115. }
  116. public fun get_last_executed_governance_sequence(self: &State): u64{
  117. return self.last_executed_governance_sequence
  118. }
  119. /// Retrieve governance module name.
  120. public fun governance_module(): Bytes32 {
  121. bytes32::new(
  122. x"0000000000000000000000000000000000000000000000000000000000000001"
  123. )
  124. }
  125. /// Retrieve governance chain ID, which is governance's emitter chain ID.
  126. public fun governance_chain(self: &State): u16 {
  127. let governance_data_source = governance_data_source(self);
  128. (data_source::emitter_chain(&governance_data_source) as u16)
  129. }
  130. /// Retrieve governance emitter address.
  131. public fun governance_contract(self: &State): ExternalAddress {
  132. let governance_data_source = governance_data_source(self);
  133. data_source::emitter_address(&governance_data_source)
  134. }
  135. public fun get_price_info_object_id(self: &State, price_identifier_bytes: vector<u8>): ID {
  136. let price_identifier = price_identifier::from_byte_vec(price_identifier_bytes);
  137. price_info::get_id(&self.id, price_identifier)
  138. }
  139. ////////////////////////////////////////////////////////////////////////////
  140. //
  141. // Privileged `State` Access
  142. //
  143. // This section of methods require a `LatestOnly`, which can only be created
  144. // within the Wormhole package. This capability allows special access to
  145. // the `State` object.
  146. //
  147. // NOTE: A lot of these methods are still marked as `(friend)` as a safety
  148. // precaution. When a package is upgraded, friend modifiers can be
  149. // removed.
  150. //
  151. ////////////////////////////////////////////////////////////////////////////
  152. /// Obtain a capability to interact with `State` methods. This method checks
  153. /// that we are running the current build.
  154. ///
  155. /// NOTE: This method allows caching the current version check so we avoid
  156. /// multiple checks to dynamic fields.
  157. public(friend) fun assert_latest_only(self: &State): LatestOnly {
  158. package_utils::assert_version(
  159. &self.id,
  160. version_control::current_version()
  161. );
  162. LatestOnly {}
  163. }
  164. public(friend) fun set_fee_recipient(
  165. _: &LatestOnly,
  166. self: &mut State,
  167. addr: address
  168. ) {
  169. self.fee_recipient_address = addr;
  170. }
  171. /// Store `VAA` hash as a way to claim a VAA. This method prevents a VAA
  172. /// from being replayed. For Wormhole, the only VAAs that it cares about
  173. /// being replayed are its governance actions.
  174. public(friend) fun borrow_mut_consumed_vaas(
  175. _: &LatestOnly,
  176. self: &mut State
  177. ): &mut ConsumedVAAs {
  178. borrow_mut_consumed_vaas_unchecked(self)
  179. }
  180. /// Store `VAA` hash as a way to claim a VAA. This method prevents a VAA
  181. /// from being replayed. For Wormhole, the only VAAs that it cares about
  182. /// being replayed are its governance actions.
  183. ///
  184. /// NOTE: This method does not require `LatestOnly`. Only methods in the
  185. /// `upgrade_contract` module requires this to be unprotected to prevent
  186. /// a corrupted upgraded contract from bricking upgradability.
  187. public(friend) fun borrow_mut_consumed_vaas_unchecked(
  188. self: &mut State
  189. ): &mut ConsumedVAAs {
  190. &mut self.consumed_vaas
  191. }
  192. public(friend) fun current_package(_: &LatestOnly, self: &State): ID {
  193. package_utils::current_package(&self.id)
  194. }
  195. public(friend) fun set_data_sources(_: &LatestOnly, s: &mut State, new_sources: vector<DataSource>) {
  196. // Empty the existing table of data sources registered in state.
  197. data_source::empty(&mut s.id);
  198. // Add the new data sources to the dynamic field registry.
  199. while (!vector::is_empty(&new_sources)) {
  200. data_source::add(&mut s.id, vector::pop_back(&mut new_sources));
  201. };
  202. }
  203. public(friend) fun register_price_info_object(_: &LatestOnly, s: &mut State, price_identifier: PriceIdentifier, id: ID) {
  204. price_info::add(&mut s.id, price_identifier, id);
  205. }
  206. public(friend) fun set_governance_data_source(_: &LatestOnly, s: &mut State, source: DataSource) {
  207. s.governance_data_source = source;
  208. }
  209. public(friend) fun set_last_executed_governance_sequence(_: &LatestOnly, s: &mut State, sequence: u64) {
  210. s.last_executed_governance_sequence = sequence;
  211. }
  212. public(friend) fun set_base_update_fee(_: &LatestOnly, s: &mut State, fee: u64) {
  213. s.base_update_fee = fee;
  214. }
  215. public(friend) fun set_stale_price_threshold_secs(_: &LatestOnly, s: &mut State, threshold_secs: u64) {
  216. s.stale_price_threshold = threshold_secs;
  217. }
  218. ////////////////////////////////////////////////////////////////////////////
  219. //
  220. // Upgradability
  221. //
  222. // A special space that controls upgrade logic. These methods are invoked
  223. // via the `upgrade_contract` module.
  224. //
  225. // Also in this section is managing contract migrations, which uses the
  226. // `migrate` module to officially roll state access to the latest build.
  227. // Only those methods that require `LatestOnly` will be affected by an
  228. // upgrade.
  229. //
  230. ////////////////////////////////////////////////////////////////////////////
  231. /// Issue an `UpgradeTicket` for the upgrade.
  232. ///
  233. /// NOTE: The Sui VM performs a check that this method is executed from the
  234. /// latest published package. If someone were to try to execute this using
  235. /// a stale build, the transaction will revert with `PackageUpgradeError`,
  236. /// specifically `PackageIDDoesNotMatch`.
  237. public(friend) fun authorize_upgrade(
  238. self: &mut State,
  239. package_digest: Bytes32
  240. ): UpgradeTicket {
  241. let cap = &mut self.upgrade_cap;
  242. package_utils::authorize_upgrade(&mut self.id, cap, package_digest)
  243. }
  244. /// Finalize the upgrade that ran to produce the given `receipt`.
  245. ///
  246. /// NOTE: The Sui VM performs a check that this method is executed from the
  247. /// latest published package. If someone were to try to execute this using
  248. /// a stale build, the transaction will revert with `PackageUpgradeError`,
  249. /// specifically `PackageIDDoesNotMatch`.
  250. public(friend) fun commit_upgrade(
  251. self: &mut State,
  252. receipt: UpgradeReceipt
  253. ): (ID, ID) {
  254. let cap = &mut self.upgrade_cap;
  255. package_utils::commit_upgrade(&mut self.id, cap, receipt)
  256. }
  257. /// Method executed by the `migrate` module to roll access from one package
  258. /// to another. This method will be called from the upgraded package.
  259. public(friend) fun migrate_version(self: &mut State) {
  260. package_utils::migrate_version(
  261. &mut self.id,
  262. version_control::previous_version(),
  263. version_control::current_version()
  264. );
  265. }
  266. /// As a part of the migration, we verify that the upgrade contract VAA's
  267. /// encoded package digest used in `migrate` equals the one used to conduct
  268. /// the upgrade.
  269. public(friend) fun assert_authorized_digest(
  270. _: &LatestOnly,
  271. self: &State,
  272. digest: Bytes32
  273. ) {
  274. let authorized = package_utils::authorized_digest(&self.id);
  275. assert!(digest == authorized, E_INVALID_BUILD_DIGEST);
  276. }
  277. ////////////////////////////////////////////////////////////////////////////
  278. //
  279. // Special State Interaction via Migrate
  280. //
  281. // A VERY special space that manipulates `State` via calling `migrate`.
  282. //
  283. // PLEASE KEEP ANY METHODS HERE AS FRIENDS. We want the ability to remove
  284. // these for future builds.
  285. //
  286. ////////////////////////////////////////////////////////////////////////////
  287. public(friend) fun migrate__v__0_1_1(self: &mut State) {
  288. // We need to add dynamic fields via the new package utils method. These
  289. // fields do not exist in the previous build (0.1.0).
  290. // See `state::new` above.
  291. // Initialize package info. This will be used for emitting information
  292. // of successful migrations.
  293. let upgrade_cap = &self.upgrade_cap;
  294. package_utils::init_package_info(
  295. &mut self.id,
  296. version_control::current_version(),
  297. upgrade_cap,
  298. );
  299. }
  300. #[test_only]
  301. /// Bloody hack.
  302. public fun reverse_migrate__v__0_1_0(self: &mut State) {
  303. package_utils::remove_package_info(&mut self.id);
  304. // Add back in old dynamic field(s)...
  305. // Add dummy hash since this is the first time the package is published.
  306. sui::dynamic_field::add(&mut self.id, CurrentDigest {}, bytes32::from_bytes(b"new build"));
  307. }
  308. ////////////////////////////////////////////////////////////////////////////
  309. //
  310. // Deprecated
  311. //
  312. // Dumping grounds for old structs and methods. These things should not
  313. // be used in future builds.
  314. //
  315. ////////////////////////////////////////////////////////////////////////////
  316. struct CurrentDigest has store, drop, copy {}
  317. }