PythTest.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import {
  2. beginCell,
  3. Cell,
  4. contractAddress,
  5. ContractProvider,
  6. Sender,
  7. SendMode,
  8. toNano,
  9. Address,
  10. } from "@ton/core";
  11. import { BaseWrapper } from "./BaseWrapper";
  12. import { HexString, Price } from "@pythnetwork/price-service-sdk";
  13. import {
  14. createCellChain,
  15. parseDataSource,
  16. parseDataSources,
  17. } from "@pythnetwork/pyth-ton-js";
  18. import { DataSource } from "@pythnetwork/xc-admin-common";
  19. export type PythTestConfig = {
  20. priceFeedId: HexString;
  21. price: Price;
  22. emaPrice: Price;
  23. singleUpdateFee: number;
  24. dataSources: DataSource[];
  25. guardianSetIndex: number;
  26. guardianSet: string[];
  27. chainId: number;
  28. governanceChainId: number;
  29. governanceContract: string;
  30. governanceDataSource?: DataSource;
  31. };
  32. export class PythTest extends BaseWrapper {
  33. static createFromConfig(config: PythTestConfig, code: Cell, workchain = 0) {
  34. const data = PythTest.getPythInitData(config);
  35. const init = { code, data };
  36. return new PythTest(contractAddress(workchain, init), init);
  37. }
  38. static getPythInitData(config: PythTestConfig): Cell {
  39. return BaseWrapper.createInitData(config);
  40. }
  41. async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
  42. await super.sendDeploy(provider, via, value);
  43. }
  44. async getPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) {
  45. return await super.getPriceUnsafe(
  46. provider,
  47. priceFeedId,
  48. "test_get_price_unsafe",
  49. );
  50. }
  51. async getPriceNoOlderThan(
  52. provider: ContractProvider,
  53. timePeriod: number,
  54. priceFeedId: HexString,
  55. ) {
  56. return await super.getPriceNoOlderThan(
  57. provider,
  58. timePeriod,
  59. priceFeedId,
  60. "test_get_price_no_older_than",
  61. );
  62. }
  63. async getEmaPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) {
  64. return await super.getEmaPriceUnsafe(
  65. provider,
  66. priceFeedId,
  67. "test_get_ema_price_unsafe",
  68. );
  69. }
  70. async getEmaPriceNoOlderThan(
  71. provider: ContractProvider,
  72. timePeriod: number,
  73. priceFeedId: HexString,
  74. ) {
  75. return await super.getEmaPriceNoOlderThan(
  76. provider,
  77. timePeriod,
  78. priceFeedId,
  79. "test_get_ema_price_no_older_than",
  80. );
  81. }
  82. async getUpdateFee(provider: ContractProvider, vm: Buffer) {
  83. return await super.getUpdateFee(provider, vm, "test_get_update_fee");
  84. }
  85. async getSingleUpdateFee(provider: ContractProvider) {
  86. return await super.getSingleUpdateFee(
  87. provider,
  88. "test_get_single_update_fee",
  89. );
  90. }
  91. async sendUpdatePriceFeeds(
  92. provider: ContractProvider,
  93. via: Sender,
  94. updateData: Buffer,
  95. updateFee: bigint,
  96. ) {
  97. await super.sendUpdatePriceFeeds(provider, via, updateData, updateFee);
  98. }
  99. async sendUpdateGuardianSet(
  100. provider: ContractProvider,
  101. via: Sender,
  102. vm: Buffer,
  103. ) {
  104. await super.sendUpdateGuardianSet(provider, via, vm);
  105. }
  106. async getChainId(provider: ContractProvider) {
  107. return await super.getChainId(provider, "test_get_chain_id");
  108. }
  109. // Add PythTest-specific methods here
  110. async getLastExecutedGovernanceSequence(provider: ContractProvider) {
  111. const result = await provider.get(
  112. "test_get_last_executed_governance_sequence",
  113. [],
  114. );
  115. return result.stack.readNumber();
  116. }
  117. async getGovernanceDataSourceIndex(provider: ContractProvider) {
  118. const result = await provider.get(
  119. "test_get_governance_data_source_index",
  120. [],
  121. );
  122. return result.stack.readNumber();
  123. }
  124. async getGovernanceDataSource(provider: ContractProvider) {
  125. const result = await provider.get("test_get_governance_data_source", []);
  126. return parseDataSource(result.stack.readCell());
  127. }
  128. async sendExecuteGovernanceAction(
  129. provider: ContractProvider,
  130. via: Sender,
  131. governanceAction: Buffer,
  132. ) {
  133. const messageBody = beginCell()
  134. .storeUint(3, 32) // OP_EXECUTE_GOVERNANCE_ACTION
  135. .storeRef(createCellChain(governanceAction))
  136. .endCell();
  137. await provider.internal(via, {
  138. value: toNano("0.1"),
  139. sendMode: SendMode.PAY_GAS_SEPARATELY,
  140. body: messageBody,
  141. });
  142. }
  143. async sendUpgradeContract(
  144. provider: ContractProvider,
  145. via: Sender,
  146. newCode: Cell,
  147. ) {
  148. const messageBody = beginCell()
  149. .storeUint(4, 32) // OP_UPGRADE_CONTRACT
  150. .storeRef(newCode)
  151. .endCell();
  152. await provider.internal(via, {
  153. value: toNano("0.1"),
  154. sendMode: SendMode.PAY_GAS_SEPARATELY,
  155. body: messageBody,
  156. });
  157. }
  158. async getIsValidDataSource(
  159. provider: ContractProvider,
  160. dataSource: DataSource,
  161. ) {
  162. const result = await provider.get("test_get_is_valid_data_source", [
  163. {
  164. type: "cell",
  165. cell: beginCell()
  166. .storeUint(dataSource.emitterChain, 16)
  167. .storeUint(BigInt("0x" + dataSource.emitterAddress), 256)
  168. .endCell(),
  169. },
  170. ]);
  171. return result.stack.readBoolean();
  172. }
  173. async getDataSources(provider: ContractProvider) {
  174. const result = await provider.get("test_get_data_sources", []);
  175. return parseDataSources(result.stack.readCell());
  176. }
  177. private createPriceFeedMessage(
  178. op: number,
  179. updateData: Buffer,
  180. priceIds: HexString[],
  181. time1: number,
  182. time2: number,
  183. targetAddress: Address,
  184. customPayload: Buffer,
  185. ): Cell {
  186. // Create a buffer for price IDs: 1 byte length + (32 bytes per ID)
  187. const priceIdsBuffer = Buffer.alloc(1 + priceIds.length * 32);
  188. priceIdsBuffer.writeUint8(priceIds.length, 0);
  189. // Write each price ID as a 32-byte value
  190. priceIds.forEach((id, index) => {
  191. // Remove '0x' prefix if present and pad to 64 hex chars (32 bytes)
  192. const hexId = id.replace("0x", "").padStart(64, "0");
  193. Buffer.from(hexId, "hex").copy(priceIdsBuffer, 1 + index * 32);
  194. });
  195. return beginCell()
  196. .storeUint(op, 32)
  197. .storeRef(createCellChain(updateData))
  198. .storeRef(createCellChain(priceIdsBuffer))
  199. .storeUint(time1, 64)
  200. .storeUint(time2, 64)
  201. .storeAddress(targetAddress)
  202. .storeRef(createCellChain(customPayload))
  203. .endCell();
  204. }
  205. async sendParsePriceFeedUpdates(
  206. provider: ContractProvider,
  207. via: Sender,
  208. updateData: Buffer,
  209. updateFee: bigint,
  210. priceIds: HexString[],
  211. minPublishTime: number,
  212. maxPublishTime: number,
  213. targetAddress: Address,
  214. customPayload: Buffer,
  215. ) {
  216. const messageCell = this.createPriceFeedMessage(
  217. 5, // OP_PARSE_PRICE_FEED_UPDATES
  218. updateData,
  219. priceIds,
  220. minPublishTime,
  221. maxPublishTime,
  222. targetAddress,
  223. customPayload,
  224. );
  225. await provider.internal(via, {
  226. value: updateFee,
  227. sendMode: SendMode.PAY_GAS_SEPARATELY,
  228. body: messageCell,
  229. });
  230. }
  231. async sendParseUniquePriceFeedUpdates(
  232. provider: ContractProvider,
  233. via: Sender,
  234. updateData: Buffer,
  235. updateFee: bigint,
  236. priceIds: HexString[],
  237. publishTime: number,
  238. maxStaleness: number,
  239. targetAddress: Address,
  240. customPayload: Buffer,
  241. ) {
  242. const messageCell = this.createPriceFeedMessage(
  243. 6, // OP_PARSE_UNIQUE_PRICE_FEED_UPDATES
  244. updateData,
  245. priceIds,
  246. publishTime,
  247. maxStaleness,
  248. targetAddress,
  249. customPayload,
  250. );
  251. await provider.internal(via, {
  252. value: updateFee,
  253. sendMode: SendMode.PAY_GAS_SEPARATELY,
  254. body: messageCell,
  255. });
  256. }
  257. async getNewFunction(provider: ContractProvider) {
  258. const result = await provider.get("test_new_function", []);
  259. return result.stack.readNumber();
  260. }
  261. }