state.move 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // SPDX-License-Identifier: Apache 2
  2. /// This module implements the global state variables for Token Bridge as a
  3. /// shared object. The `State` object is used to perform anything that requires
  4. /// access to data that defines the Token Bridge contract. Examples of which are
  5. /// accessing registered assets and verifying `VAA` intended for Token Bridge by
  6. /// checking the emitter against its own registered emitters.
  7. module token_bridge::state {
  8. use sui::object::{Self, ID, UID};
  9. use sui::package::{UpgradeCap, UpgradeReceipt, UpgradeTicket};
  10. use sui::table::{Self, Table};
  11. use sui::tx_context::{TxContext};
  12. use wormhole::bytes32::{Self, Bytes32};
  13. use wormhole::consumed_vaas::{Self, ConsumedVAAs};
  14. use wormhole::emitter::{EmitterCap};
  15. use wormhole::external_address::{ExternalAddress};
  16. use wormhole::package_utils::{Self};
  17. use wormhole::publish_message::{MessageTicket};
  18. use token_bridge::token_registry::{Self, TokenRegistry, VerifiedAsset};
  19. use token_bridge::version_control::{Self};
  20. /// Build digest does not agree with current implementation.
  21. const E_INVALID_BUILD_DIGEST: u64 = 0;
  22. /// Specified version does not match this build's version.
  23. const E_VERSION_MISMATCH: u64 = 1;
  24. /// Emitter has already been used to emit Wormhole messages.
  25. const E_USED_EMITTER: u64 = 2;
  26. friend token_bridge::attest_token;
  27. friend token_bridge::complete_transfer;
  28. friend token_bridge::complete_transfer_with_payload;
  29. friend token_bridge::create_wrapped;
  30. friend token_bridge::migrate;
  31. friend token_bridge::register_chain;
  32. friend token_bridge::setup;
  33. friend token_bridge::transfer_tokens;
  34. friend token_bridge::transfer_tokens_with_payload;
  35. friend token_bridge::upgrade_contract;
  36. friend token_bridge::vaa;
  37. /// Capability reflecting that the current build version is used to invoke
  38. /// state methods.
  39. struct LatestOnly has drop {}
  40. /// Container for all state variables for Token Bridge.
  41. struct State has key, store {
  42. id: UID,
  43. /// Governance chain ID.
  44. governance_chain: u16,
  45. /// Governance contract address.
  46. governance_contract: ExternalAddress,
  47. /// Set of consumed VAA hashes.
  48. consumed_vaas: ConsumedVAAs,
  49. /// Emitter capability required to publish Wormhole messages.
  50. emitter_cap: EmitterCap,
  51. /// Registry for foreign Token Bridge contracts.
  52. emitter_registry: Table<u16, ExternalAddress>,
  53. /// Registry for native and wrapped assets.
  54. token_registry: TokenRegistry,
  55. /// Upgrade capability.
  56. upgrade_cap: UpgradeCap
  57. }
  58. /// Create new `State`. This is only executed using the `setup` module.
  59. public(friend) fun new(
  60. emitter_cap: EmitterCap,
  61. upgrade_cap: UpgradeCap,
  62. governance_chain: u16,
  63. governance_contract: ExternalAddress,
  64. ctx: &mut TxContext
  65. ): State {
  66. assert!(wormhole::emitter::sequence(&emitter_cap) == 0, E_USED_EMITTER);
  67. let state = State {
  68. id: object::new(ctx),
  69. governance_chain,
  70. governance_contract,
  71. consumed_vaas: consumed_vaas::new(ctx),
  72. emitter_cap,
  73. emitter_registry: table::new(ctx),
  74. token_registry: token_registry::new(ctx),
  75. upgrade_cap
  76. };
  77. // Set first version and initialize package info. This will be used for
  78. // emitting information of successful migrations.
  79. let upgrade_cap = &state.upgrade_cap;
  80. package_utils::init_package_info(
  81. &mut state.id,
  82. version_control::current_version(),
  83. upgrade_cap
  84. );
  85. state
  86. }
  87. ////////////////////////////////////////////////////////////////////////////
  88. //
  89. // Simple Getters
  90. //
  91. // These methods do not require `LatestOnly` for access. Anyone is free to
  92. // access these values.
  93. //
  94. ////////////////////////////////////////////////////////////////////////////
  95. /// Retrieve governance module name.
  96. public fun governance_module(): Bytes32 {
  97. // A.K.A. "TokenBridge".
  98. bytes32::new(
  99. x"000000000000000000000000000000000000000000546f6b656e427269646765"
  100. )
  101. }
  102. /// Retrieve governance chain ID, which is governance's emitter chain ID.
  103. public fun governance_chain(self: &State): u16 {
  104. self.governance_chain
  105. }
  106. /// Retrieve governance emitter address.
  107. public fun governance_contract(self: &State): ExternalAddress {
  108. self.governance_contract
  109. }
  110. /// Retrieve immutable reference to `TokenRegistry`.
  111. public fun borrow_token_registry(
  112. self: &State
  113. ): &TokenRegistry {
  114. &self.token_registry
  115. }
  116. public fun borrow_emitter_registry(
  117. self: &State
  118. ): &Table<u16, ExternalAddress> {
  119. &self.emitter_registry
  120. }
  121. public fun verified_asset<CoinType>(
  122. self: &State
  123. ): VerifiedAsset<CoinType> {
  124. token_registry::assert_has<CoinType>(&self.token_registry);
  125. token_registry::verified_asset(&self.token_registry)
  126. }
  127. #[test_only]
  128. public fun borrow_mut_token_registry_test_only(
  129. self: &mut State
  130. ): &mut TokenRegistry {
  131. borrow_mut_token_registry(&assert_latest_only(self), self)
  132. }
  133. #[test_only]
  134. public fun migrate_version_test_only<Old: store + drop, New: store + drop>(
  135. self: &mut State,
  136. old_version: Old,
  137. new_version: New
  138. ) {
  139. wormhole::package_utils::update_version_type_test_only(
  140. &mut self.id,
  141. old_version,
  142. new_version
  143. );
  144. }
  145. #[test_only]
  146. public fun test_upgrade(self: &mut State) {
  147. let test_digest = bytes32::from_bytes(b"new build");
  148. let ticket = authorize_upgrade(self, test_digest);
  149. let receipt = sui::package::test_upgrade(ticket);
  150. commit_upgrade(self, receipt);
  151. }
  152. #[test_only]
  153. public fun reverse_migrate_version(self: &mut State) {
  154. package_utils::update_version_type_test_only(
  155. &mut self.id,
  156. version_control::current_version(),
  157. version_control::previous_version()
  158. );
  159. }
  160. ////////////////////////////////////////////////////////////////////////////
  161. //
  162. // Privileged `State` Access
  163. //
  164. // This section of methods require a `LatestOnly`, which can only be
  165. // created within the Token Bridge package. This capability allows special
  166. // access to the `State` object where we require that the latest build is
  167. // used for these interactions.
  168. //
  169. // NOTE: A lot of these methods are still marked as `(friend)` as a safety
  170. // precaution. When a package is upgraded, friend modifiers can be
  171. // removed.
  172. //
  173. ////////////////////////////////////////////////////////////////////////////
  174. /// Obtain a capability to interact with `State` methods. This method checks
  175. /// that we are running the current build.
  176. ///
  177. /// NOTE: This method allows caching the current version check so we avoid
  178. /// multiple checks to dynamic fields.
  179. public(friend) fun assert_latest_only(self: &State): LatestOnly {
  180. package_utils::assert_version(
  181. &self.id,
  182. version_control::current_version()
  183. );
  184. LatestOnly {}
  185. }
  186. /// Obtain a capability to interact with `State` methods. This method checks
  187. /// that we are running the current build and that the specified `Version`
  188. /// equals the current version. This method is useful when external modules
  189. /// invoke Token Bridge and we need to check that the external module's
  190. /// version is up-to-date (e.g. `create_wrapped::prepare_registration`).
  191. ///
  192. /// NOTE: This method allows caching the current version check so we avoid
  193. /// multiple checks to dynamic fields.
  194. public(friend) fun assert_latest_only_specified<Version>(
  195. self: &State
  196. ): LatestOnly {
  197. use std::type_name::{get};
  198. // Explicitly check the type names.
  199. let current_type =
  200. package_utils::type_of_version(version_control::current_version());
  201. assert!(current_type == get<Version>(), E_VERSION_MISMATCH);
  202. assert_latest_only(self)
  203. }
  204. /// Store `VAA` hash as a way to claim a VAA. This method prevents a VAA
  205. /// from being replayed.
  206. public(friend) fun borrow_mut_consumed_vaas(
  207. _: &LatestOnly,
  208. self: &mut State
  209. ): &mut ConsumedVAAs {
  210. borrow_mut_consumed_vaas_unchecked(self)
  211. }
  212. /// Store `VAA` hash as a way to claim a VAA. This method prevents a VAA
  213. /// from being replayed.
  214. ///
  215. /// NOTE: This method does not require `LatestOnly`. Only methods in the
  216. /// `upgrade_contract` module requires this to be unprotected to prevent
  217. /// a corrupted upgraded contract from bricking upgradability.
  218. public(friend) fun borrow_mut_consumed_vaas_unchecked(
  219. self: &mut State
  220. ): &mut ConsumedVAAs {
  221. &mut self.consumed_vaas
  222. }
  223. /// Publish Wormhole message using Token Bridge's `EmitterCap`.
  224. public(friend) fun prepare_wormhole_message(
  225. _: &LatestOnly,
  226. self: &mut State,
  227. nonce: u32,
  228. payload: vector<u8>
  229. ): MessageTicket {
  230. wormhole::publish_message::prepare_message(
  231. &mut self.emitter_cap,
  232. nonce,
  233. payload,
  234. )
  235. }
  236. /// Retrieve mutable reference to `TokenRegistry`.
  237. public(friend) fun borrow_mut_token_registry(
  238. _: &LatestOnly,
  239. self: &mut State
  240. ): &mut TokenRegistry {
  241. &mut self.token_registry
  242. }
  243. public(friend) fun borrow_mut_emitter_registry(
  244. _: &LatestOnly,
  245. self: &mut State
  246. ): &mut Table<u16, ExternalAddress> {
  247. &mut self.emitter_registry
  248. }
  249. public(friend) fun current_package(_: &LatestOnly, self: &State): ID {
  250. package_utils::current_package(&self.id)
  251. }
  252. ////////////////////////////////////////////////////////////////////////////
  253. //
  254. // Upgradability
  255. //
  256. // A special space that controls upgrade logic. These methods are invoked
  257. // via the `upgrade_contract` module.
  258. //
  259. // Also in this section is managing contract migrations, which uses the
  260. // `migrate` module to officially roll state access to the latest build.
  261. // Only those methods that require `LatestOnly` will be affected by an
  262. // upgrade.
  263. //
  264. ////////////////////////////////////////////////////////////////////////////
  265. /// Issue an `UpgradeTicket` for the upgrade.
  266. ///
  267. /// NOTE: The Sui VM performs a check that this method is executed from the
  268. /// latest published package. If someone were to try to execute this using
  269. /// a stale build, the transaction will revert with `PackageUpgradeError`,
  270. /// specifically `PackageIDDoesNotMatch`.
  271. public(friend) fun authorize_upgrade(
  272. self: &mut State,
  273. package_digest: Bytes32
  274. ): UpgradeTicket {
  275. let cap = &mut self.upgrade_cap;
  276. package_utils::authorize_upgrade(&mut self.id, cap, package_digest)
  277. }
  278. /// Finalize the upgrade that ran to produce the given `receipt`.
  279. ///
  280. /// NOTE: The Sui VM performs a check that this method is executed from the
  281. /// latest published package. If someone were to try to execute this using
  282. /// a stale build, the transaction will revert with `PackageUpgradeError`,
  283. /// specifically `PackageIDDoesNotMatch`.
  284. public(friend) fun commit_upgrade(
  285. self: &mut State,
  286. receipt: UpgradeReceipt
  287. ): (ID, ID) {
  288. let cap = &mut self.upgrade_cap;
  289. package_utils::commit_upgrade(&mut self.id, cap, receipt)
  290. }
  291. /// Method executed by the `migrate` module to roll access from one package
  292. /// to another. This method will be called from the upgraded package.
  293. public(friend) fun migrate_version(self: &mut State) {
  294. package_utils::migrate_version(
  295. &mut self.id,
  296. version_control::previous_version(),
  297. version_control::current_version()
  298. );
  299. }
  300. /// As a part of the migration, we verify that the upgrade contract VAA's
  301. /// encoded package digest used in `migrate` equals the one used to conduct
  302. /// the upgrade.
  303. public(friend) fun assert_authorized_digest(
  304. _: &LatestOnly,
  305. self: &State,
  306. digest: Bytes32
  307. ) {
  308. let authorized = package_utils::authorized_digest(&self.id);
  309. assert!(digest == authorized, E_INVALID_BUILD_DIGEST);
  310. }
  311. ////////////////////////////////////////////////////////////////////////////
  312. //
  313. // Special State Interaction via Migrate
  314. //
  315. // A VERY special space that manipulates `State` via calling `migrate`.
  316. //
  317. // PLEASE KEEP ANY METHODS HERE AS FRIENDS. We want the ability to remove
  318. // these for future builds.
  319. //
  320. ////////////////////////////////////////////////////////////////////////////
  321. /// This method is used to make modifications to `State` when `migrate` is
  322. /// called. This method name should change reflecting which version this
  323. /// contract is migrating to.
  324. ///
  325. /// NOTE: Please keep this method as public(friend) because we never want
  326. /// to expose this method as a public method.
  327. public(friend) fun migrate__v__0_2_0(_self: &mut State) {
  328. // Intentionally do nothing.
  329. }
  330. #[test_only]
  331. /// Bloody hack.
  332. ///
  333. /// This method is used to set up tests where we migrate to a new version,
  334. /// which is meant to test that modules protected by version control will
  335. /// break.
  336. public fun reverse_migrate__v__dummy(_self: &mut State) {
  337. // Intentionally do nothing.
  338. }
  339. ////////////////////////////////////////////////////////////////////////////
  340. //
  341. // Deprecated
  342. //
  343. // Dumping grounds for old structs and methods. These things should not
  344. // be used in future builds.
  345. //
  346. ////////////////////////////////////////////////////////////////////////////
  347. }