PythTest.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import {
  2. Address,
  3. beginCell,
  4. Cell,
  5. Contract,
  6. contractAddress,
  7. ContractProvider,
  8. Dictionary,
  9. Sender,
  10. SendMode,
  11. } from "@ton/core";
  12. import { HexString, Price } from "@pythnetwork/price-service-sdk";
  13. import { createCellChain } from "../tests/utils";
  14. export type PythTestConfig = {
  15. priceFeedId: HexString;
  16. timePeriod: number;
  17. price: Price;
  18. emaPrice: Price;
  19. singleUpdateFee: number;
  20. };
  21. export class PythTest implements Contract {
  22. constructor(
  23. readonly address: Address,
  24. readonly init?: { code: Cell; data: Cell }
  25. ) {}
  26. static createFromAddress(address: Address) {
  27. return new PythTest(address);
  28. }
  29. static createFromConfig(config: PythTestConfig, code: Cell, workchain = 0) {
  30. const data = PythTest.getPythInitData(
  31. config.priceFeedId,
  32. config.timePeriod,
  33. config.price,
  34. config.emaPrice,
  35. config.singleUpdateFee
  36. );
  37. const init = { code, data };
  38. return new PythTest(contractAddress(workchain, init), init);
  39. }
  40. static getPythInitData(
  41. priceFeedId: HexString,
  42. timePeriod: number,
  43. price: Price,
  44. emaPrice: Price,
  45. singleUpdateFee: number
  46. ): Cell {
  47. const priceDict = Dictionary.empty(
  48. Dictionary.Keys.BigUint(256),
  49. Dictionary.Values.Cell()
  50. );
  51. const priceCell = beginCell()
  52. .storeInt(price.getPriceAsNumberUnchecked() * 10 ** -price.expo, 256)
  53. .storeUint(price.getConfAsNumberUnchecked() * 10 ** -price.expo, 64)
  54. .storeInt(price.expo, 32)
  55. .storeUint(price.publishTime, 64)
  56. .endCell();
  57. const emaPriceCell = beginCell()
  58. .storeInt(
  59. emaPrice.getPriceAsNumberUnchecked() * 10 ** -emaPrice.expo,
  60. 256
  61. )
  62. .storeUint(emaPrice.getConfAsNumberUnchecked() * 10 ** -emaPrice.expo, 64)
  63. .storeInt(emaPrice.expo, 32)
  64. .storeUint(emaPrice.publishTime, 64)
  65. .endCell();
  66. const priceFeedCell = beginCell()
  67. .storeRef(priceCell)
  68. .storeRef(emaPriceCell)
  69. .storeUint(timePeriod, 32)
  70. .endCell();
  71. priceDict.set(BigInt(priceFeedId), priceFeedCell);
  72. return beginCell()
  73. .storeDict(priceDict) // latest_price_feeds
  74. .storeUint(singleUpdateFee, 256) // single_update_fee
  75. .storeUint(0, 32)
  76. .storeDict(Dictionary.empty())
  77. .storeUint(0, 16)
  78. .storeUint(0, 16)
  79. .storeBuffer(
  80. Buffer.from(
  81. "0000000000000000000000000000000000000000000000000000000000000000",
  82. "hex"
  83. )
  84. )
  85. .storeDict(Dictionary.empty()) // consumed_governance_actions,
  86. .endCell();
  87. }
  88. async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
  89. await provider.internal(via, {
  90. value,
  91. sendMode: SendMode.PAY_GAS_SEPARATELY,
  92. body: beginCell().endCell(),
  93. });
  94. }
  95. async getPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) {
  96. const result = await provider.get("test_get_price_unsafe", [
  97. { type: "int", value: BigInt(priceFeedId) },
  98. ]);
  99. const price = result.stack.readNumber();
  100. const conf = result.stack.readNumber();
  101. const expo = result.stack.readNumber();
  102. const publishTime = result.stack.readNumber();
  103. return {
  104. price,
  105. conf,
  106. expo,
  107. publishTime,
  108. };
  109. }
  110. async getPriceNoOlderThan(
  111. provider: ContractProvider,
  112. timePeriod: number,
  113. priceFeedId: HexString
  114. ) {
  115. const result = await provider.get("test_get_price_no_older_than", [
  116. { type: "int", value: BigInt(timePeriod) },
  117. { type: "int", value: BigInt(priceFeedId) },
  118. ]);
  119. const price = result.stack.readNumber();
  120. const conf = result.stack.readNumber();
  121. const expo = result.stack.readNumber();
  122. const publishTime = result.stack.readNumber();
  123. return {
  124. price,
  125. conf,
  126. expo,
  127. publishTime,
  128. };
  129. }
  130. async getEmaPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) {
  131. const result = await provider.get("test_get_ema_price_unsafe", [
  132. { type: "int", value: BigInt(priceFeedId) },
  133. ]);
  134. const price = result.stack.readNumber();
  135. const conf = result.stack.readNumber();
  136. const expo = result.stack.readNumber();
  137. const publishTime = result.stack.readNumber();
  138. return {
  139. price,
  140. conf,
  141. expo,
  142. publishTime,
  143. };
  144. }
  145. async getEmaPriceNoOlderThan(
  146. provider: ContractProvider,
  147. timePeriod: number,
  148. priceFeedId: HexString
  149. ) {
  150. const result = await provider.get("test_get_ema_price_no_older_than", [
  151. { type: "int", value: BigInt(timePeriod) },
  152. { type: "int", value: BigInt(priceFeedId) },
  153. ]);
  154. const price = result.stack.readNumber();
  155. const conf = result.stack.readNumber();
  156. const expo = result.stack.readNumber();
  157. const publishTime = result.stack.readNumber();
  158. return {
  159. price,
  160. conf,
  161. expo,
  162. publishTime,
  163. };
  164. }
  165. async getUpdateFee(provider: ContractProvider, vm: Buffer) {
  166. const result = await provider.get("test_get_update_fee", [
  167. { type: "slice", cell: createCellChain(vm) },
  168. ]);
  169. return result.stack.readNumber();
  170. }
  171. }