price_info.move 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. module pyth::price_info {
  2. use sui::object::{Self, UID, ID};
  3. use sui::tx_context::{TxContext};
  4. use sui::dynamic_object_field::{Self};
  5. use sui::table::{Self};
  6. use sui::coin::{Self, Coin};
  7. use sui::sui::SUI;
  8. use pyth::price_feed::{Self, PriceFeed};
  9. use pyth::price_identifier::{PriceIdentifier};
  10. const KEY: vector<u8> = b"price_info";
  11. const FEE_STORAGE_KEY: vector<u8> = b"fee_storage";
  12. const E_PRICE_INFO_REGISTRY_ALREADY_EXISTS: u64 = 0;
  13. const E_PRICE_IDENTIFIER_ALREADY_REGISTERED: u64 = 1;
  14. const E_PRICE_IDENTIFIER_NOT_REGISTERED: u64 = 2;
  15. friend pyth::pyth;
  16. friend pyth::state;
  17. /// Sui object version of PriceInfo.
  18. /// Has a key ability, is unique for each price identifier, and lives in global store.
  19. struct PriceInfoObject has key, store {
  20. id: UID,
  21. price_info: PriceInfo
  22. }
  23. /// Copyable and droppable.
  24. struct PriceInfo has copy, drop, store {
  25. attestation_time: u64,
  26. arrival_time: u64,
  27. price_feed: PriceFeed,
  28. }
  29. /// Creates a table which maps a PriceIdentifier to the
  30. /// UID (in bytes) of the corresponding Sui PriceInfoObject.
  31. public(friend) fun new_price_info_registry(parent_id: &mut UID, ctx: &mut TxContext) {
  32. assert!(
  33. !dynamic_object_field::exists_(parent_id, KEY),
  34. E_PRICE_INFO_REGISTRY_ALREADY_EXISTS
  35. );
  36. dynamic_object_field::add(
  37. parent_id,
  38. KEY,
  39. table::new<PriceIdentifier, ID>(ctx)
  40. )
  41. }
  42. public(friend) fun add(parent_id: &mut UID, price_identifier: PriceIdentifier, id: ID) {
  43. assert!(
  44. !contains(parent_id, price_identifier),
  45. E_PRICE_IDENTIFIER_ALREADY_REGISTERED
  46. );
  47. table::add(
  48. dynamic_object_field::borrow_mut(parent_id, KEY),
  49. price_identifier,
  50. id
  51. )
  52. }
  53. /// Returns ID of price info object corresponding to price_identifier as a byte vector.
  54. public fun get_id_bytes(parent_id: &UID, price_identifier: PriceIdentifier): vector<u8> {
  55. assert!(
  56. contains(parent_id, price_identifier),
  57. E_PRICE_IDENTIFIER_NOT_REGISTERED
  58. );
  59. object::id_to_bytes(
  60. table::borrow<PriceIdentifier, ID>(
  61. dynamic_object_field::borrow(parent_id, KEY),
  62. price_identifier
  63. )
  64. )
  65. }
  66. /// Returns ID of price info object corresponding to price_identifier as an ID.
  67. public fun get_id(parent_id: &UID, price_identifier: PriceIdentifier): ID {
  68. assert!(
  69. contains(parent_id, price_identifier),
  70. E_PRICE_IDENTIFIER_NOT_REGISTERED
  71. );
  72. object::id_from_bytes(
  73. object::id_to_bytes(
  74. table::borrow<PriceIdentifier, ID>(
  75. dynamic_object_field::borrow(parent_id, KEY),
  76. price_identifier
  77. )
  78. )
  79. )
  80. }
  81. public fun contains(parent_id: &UID, price_identifier: PriceIdentifier): bool {
  82. let ref = dynamic_object_field::borrow(parent_id, KEY);
  83. table::contains<PriceIdentifier, ID>(ref, price_identifier)
  84. }
  85. public fun get_balance(price_info_object: &PriceInfoObject): u64 {
  86. if (!dynamic_object_field::exists_with_type<vector<u8>, Coin<SUI>>(&price_info_object.id, FEE_STORAGE_KEY)) {
  87. return 0
  88. };
  89. let fee = dynamic_object_field::borrow<vector<u8>, Coin<SUI>>(&price_info_object.id, FEE_STORAGE_KEY);
  90. coin::value(fee)
  91. }
  92. public fun deposit_fee_coins(price_info_object: &mut PriceInfoObject, fee_coins: Coin<SUI>) {
  93. if (!dynamic_object_field::exists_with_type<vector<u8>, Coin<SUI>>(&price_info_object.id, FEE_STORAGE_KEY)) {
  94. dynamic_object_field::add(&mut price_info_object.id, FEE_STORAGE_KEY, fee_coins);
  95. }
  96. else {
  97. let current_fee = dynamic_object_field::borrow_mut<vector<u8>, Coin<SUI>>(
  98. &mut price_info_object.id,
  99. FEE_STORAGE_KEY
  100. );
  101. coin::join(current_fee, fee_coins);
  102. };
  103. }
  104. public(friend) fun new_price_info_object(
  105. price_info: PriceInfo,
  106. ctx: &mut TxContext
  107. ): PriceInfoObject {
  108. PriceInfoObject {
  109. id: object::new(ctx),
  110. price_info
  111. }
  112. }
  113. public fun new_price_info(
  114. attestation_time: u64,
  115. arrival_time: u64,
  116. price_feed: PriceFeed,
  117. ): PriceInfo {
  118. PriceInfo {
  119. attestation_time,
  120. arrival_time,
  121. price_feed,
  122. }
  123. }
  124. #[test]
  125. public fun test_get_price_info_object_id_from_price_identifier(){
  126. use sui::object::{Self};
  127. use sui::test_scenario::{Self, ctx};
  128. use pyth::price_identifier::{Self};
  129. let scenario = test_scenario::begin(@pyth);
  130. let uid = object::new(ctx(&mut scenario));
  131. // Create a new price info object registry.
  132. new_price_info_registry(&mut uid, ctx(&mut scenario));
  133. // Register a price info object in the registry.
  134. let price_identifier = price_identifier::from_byte_vec(x"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace");
  135. // Create a new ID.
  136. let id = object::id_from_bytes(x"19f253b07e88634bfd5a3a749f60bfdb83c9748910646803f06b60b76319e7ba");
  137. add(&mut uid, price_identifier, id);
  138. let result = get_id_bytes(&uid, price_identifier);
  139. // Assert that ID matches original.
  140. assert!(result==x"19f253b07e88634bfd5a3a749f60bfdb83c9748910646803f06b60b76319e7ba", 0);
  141. // Clean up.
  142. object::delete(uid);
  143. test_scenario::end(scenario);
  144. }
  145. #[test_only]
  146. public fun destroy(price_info: PriceInfoObject) {
  147. let PriceInfoObject {
  148. id,
  149. price_info: _,
  150. } = price_info;
  151. object::delete(id);
  152. }
  153. public fun uid_to_inner(price_info: &PriceInfoObject): ID {
  154. object::uid_to_inner(&price_info.id)
  155. }
  156. public fun get_price_info_from_price_info_object(price_info: &PriceInfoObject): PriceInfo {
  157. price_info.price_info
  158. }
  159. public fun get_price_identifier(price_info: &PriceInfo): PriceIdentifier {
  160. price_feed::get_price_identifier(&price_info.price_feed)
  161. }
  162. public fun get_price_feed(price_info: &PriceInfo): &PriceFeed {
  163. &price_info.price_feed
  164. }
  165. public fun get_attestation_time(price_info: &PriceInfo): u64 {
  166. price_info.attestation_time
  167. }
  168. public fun get_arrival_time(price_info: &PriceInfo): u64 {
  169. price_info.arrival_time
  170. }
  171. public(friend) fun update_price_info_object(
  172. price_info_object: &mut PriceInfoObject,
  173. price_info: &PriceInfo
  174. ) {
  175. price_info_object.price_info = new_price_info(
  176. price_info.attestation_time,
  177. price_info.arrival_time,
  178. price_info.price_feed
  179. );
  180. }
  181. }