diff --git a/target_chains/ton/contracts/wrappers/BaseWrapper.ts b/target_chains/ton/contracts/wrappers/BaseWrapper.ts new file mode 100644 index 000000000..4b5178707 --- /dev/null +++ b/target_chains/ton/contracts/wrappers/BaseWrapper.ts @@ -0,0 +1,328 @@ +import { + Address, + beginCell, + Cell, + Contract, + ContractProvider, + Dictionary, + Sender, + SendMode, + toNano, +} from "@ton/core"; +import { createCellChain } from "../tests/utils"; +import { createGuardianSetsDict } from "../tests/utils/wormhole"; +import { HexString, Price } from "@pythnetwork/price-service-sdk"; +import { DataSource } from "@pythnetwork/xc-admin-common"; + +export class BaseWrapper implements Contract { + constructor( + readonly address: Address, + readonly init?: { code: Cell; data: Cell } + ) {} + + static createFromAddress(address: Address) { + return new this(address); + } + + static createInitData(config: { + priceFeedId?: HexString; + timePeriod?: number; + price?: Price; + emaPrice?: Price; + singleUpdateFee?: number; + dataSources?: DataSource[]; + guardianSetIndex: number; + guardianSet: string[]; + chainId: number; + governanceChainId: number; + governanceContract: string; + governanceDataSource?: DataSource; + }): Cell { + const priceDict = Dictionary.empty( + Dictionary.Keys.BigUint(256), + Dictionary.Values.Cell() + ); + + if ( + config.priceFeedId && + config.price && + config.emaPrice && + config.timePeriod + ) { + const priceCell = beginCell() + .storeInt( + config.price.getPriceAsNumberUnchecked() * 10 ** -config.price.expo, + 64 + ) + .storeUint( + config.price.getConfAsNumberUnchecked() * 10 ** -config.price.expo, + 64 + ) + .storeInt(config.price.expo, 32) + .storeUint(config.price.publishTime, 64) + .endCell(); + + const emaPriceCell = beginCell() + .storeInt( + config.emaPrice.getPriceAsNumberUnchecked() * + 10 ** -config.emaPrice.expo, + 64 + ) + .storeUint( + config.emaPrice.getConfAsNumberUnchecked() * + 10 ** -config.emaPrice.expo, + 64 + ) + .storeInt(config.emaPrice.expo, 32) + .storeUint(config.emaPrice.publishTime, 64) + .endCell(); + + const priceFeedCell = beginCell() + .storeRef(priceCell) + .storeRef(emaPriceCell) + .storeUint(config.timePeriod, 32) + .endCell(); + + priceDict.set(BigInt(config.priceFeedId), priceFeedCell); + } + + // Create a dictionary for data sources + const dataSourcesDict = Dictionary.empty( + Dictionary.Keys.Uint(32), + Dictionary.Values.Cell() + ); + // Create a dictionary for valid data sources + const isValidDataSourceDict = Dictionary.empty( + Dictionary.Keys.BigUint(256), + Dictionary.Values.Bool() + ); + + if (config.dataSources) { + config.dataSources.forEach((source, index) => { + const sourceCell = beginCell() + .storeUint(source.emitterChain, 16) + .storeBuffer(Buffer.from(source.emitterAddress, "hex")) + .endCell(); + dataSourcesDict.set(index, sourceCell); + const cellHash = BigInt("0x" + sourceCell.hash().toString("hex")); + isValidDataSourceDict.set(cellHash, true); + }); + } + + // Group price feeds and update fee + const priceFeedsCell = beginCell() + .storeDict(priceDict) + .storeUint(config.singleUpdateFee || 0, 256) + .endCell(); + + // Group data sources information + const dataSourcesCell = beginCell() + .storeDict(dataSourcesDict) + .storeUint(config.dataSources ? config.dataSources.length : 0, 32) + .storeDict(isValidDataSourceDict) + .endCell(); + + // Group guardian set information + const guardianSetCell = beginCell() + .storeUint(config.guardianSetIndex, 32) + .storeDict( + createGuardianSetsDict(config.guardianSet, config.guardianSetIndex) + ) + .endCell(); + + // Group chain and governance information + const governanceCell = beginCell() + .storeUint(config.chainId, 16) + .storeUint(config.governanceChainId, 16) + .storeBuffer(Buffer.from(config.governanceContract, "hex")) + .storeDict(Dictionary.empty()) // consumed_governance_actions + .storeRef( + config.governanceDataSource + ? beginCell() + .storeUint(config.governanceDataSource.emitterChain, 16) + .storeBuffer( + Buffer.from(config.governanceDataSource.emitterAddress, "hex") + ) + .endCell() + : beginCell().endCell() + ) // governance_data_source + .storeUint(0, 64) // last_executed_governance_sequence, set to 0 for initial state + .storeUint(0, 32) // governance_data_source_index, set to 0 for initial state + .storeUint(0, 256) // upgrade_code_hash, set to 0 for initial state + .endCell(); + + // Create the main cell with references to grouped data + return beginCell() + .storeRef(priceFeedsCell) + .storeRef(dataSourcesCell) + .storeRef(guardianSetCell) + .storeRef(governanceCell) + .endCell(); + } + + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell().endCell(), + }); + } + + async getCurrentGuardianSetIndex( + provider: ContractProvider, + methodName: string + ) { + const result = await provider.get(methodName, []); + return result.stack.readNumber(); + } + + async sendUpdateGuardianSet( + provider: ContractProvider, + via: Sender, + vm: Buffer + ) { + const messageBody = beginCell() + .storeUint(1, 32) // OP_UPDATE_GUARDIAN_SET + .storeRef(createCellChain(vm)) + .endCell(); + + await provider.internal(via, { + value: toNano("0.1"), + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: messageBody, + }); + } + + async sendUpdatePriceFeeds( + provider: ContractProvider, + via: Sender, + updateData: Buffer, + updateFee: bigint + ) { + const messageBody = beginCell() + .storeUint(2, 32) // OP_UPDATE_PRICE_FEEDS + .storeRef(createCellChain(updateData)) + .endCell(); + + await provider.internal(via, { + value: updateFee, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: messageBody, + }); + } + + async getChainId(provider: ContractProvider, methodName: string) { + const result = await provider.get(methodName, []); + return result.stack.readNumber(); + } + + async getPriceUnsafe( + provider: ContractProvider, + priceFeedId: HexString, + methodName: string + ) { + const result = await provider.get(methodName, [ + { type: "int", value: BigInt(priceFeedId) }, + ]); + + const price = result.stack.readNumber(); + const conf = result.stack.readNumber(); + const expo = result.stack.readNumber(); + const publishTime = result.stack.readNumber(); + + return { + price, + conf, + expo, + publishTime, + }; + } + + async getPriceNoOlderThan( + provider: ContractProvider, + timePeriod: number, + priceFeedId: HexString, + methodName: string + ) { + const result = await provider.get(methodName, [ + { type: "int", value: BigInt(timePeriod) }, + { type: "int", value: BigInt(priceFeedId) }, + ]); + + const price = result.stack.readNumber(); + const conf = result.stack.readNumber(); + const expo = result.stack.readNumber(); + const publishTime = result.stack.readNumber(); + + return { + price, + conf, + expo, + publishTime, + }; + } + + async getEmaPriceUnsafe( + provider: ContractProvider, + priceFeedId: HexString, + methodName: string + ) { + const result = await provider.get(methodName, [ + { type: "int", value: BigInt(priceFeedId) }, + ]); + + const price = result.stack.readNumber(); + const conf = result.stack.readNumber(); + const expo = result.stack.readNumber(); + const publishTime = result.stack.readNumber(); + + return { + price, + conf, + expo, + publishTime, + }; + } + + async getEmaPriceNoOlderThan( + provider: ContractProvider, + timePeriod: number, + priceFeedId: HexString, + methodName: string + ) { + const result = await provider.get(methodName, [ + { type: "int", value: BigInt(timePeriod) }, + { type: "int", value: BigInt(priceFeedId) }, + ]); + + const price = result.stack.readNumber(); + const conf = result.stack.readNumber(); + const expo = result.stack.readNumber(); + const publishTime = result.stack.readNumber(); + + return { + price, + conf, + expo, + publishTime, + }; + } + + async getUpdateFee( + provider: ContractProvider, + vm: Buffer, + methodName: string + ) { + const result = await provider.get(methodName, [ + { type: "slice", cell: createCellChain(vm) }, + ]); + + return result.stack.readNumber(); + } + + async getSingleUpdateFee(provider: ContractProvider, methodName: string) { + const result = await provider.get(methodName, []); + + return result.stack.readNumber(); + } +} diff --git a/target_chains/ton/contracts/wrappers/Main.ts b/target_chains/ton/contracts/wrappers/Main.ts index bc452430a..0c04af135 100644 --- a/target_chains/ton/contracts/wrappers/Main.ts +++ b/target_chains/ton/contracts/wrappers/Main.ts @@ -1,19 +1,8 @@ -import { DataSource } from "@pythnetwork/xc-admin-common"; -import { - Address, - beginCell, - Cell, - Contract, - contractAddress, - ContractProvider, - Dictionary, - Sender, - SendMode, - toNano, -} from "@ton/core"; +import { Cell, contractAddress, ContractProvider, Sender } from "@ton/core"; import { HexString } from "@pythnetwork/price-service-sdk"; -import { createGuardianSetsDict } from "../tests/utils/wormhole"; -import { createCellChain } from "@pythnetwork/pyth-ton-js"; + +import { BaseWrapper } from "./BaseWrapper"; +import { DataSource } from "@pythnetwork/xc-admin-common"; export type MainConfig = { singleUpdateFee: number; @@ -26,105 +15,26 @@ export type MainConfig = { governanceDataSource?: DataSource; }; -export class Main implements Contract { - constructor( - readonly address: Address, - readonly init?: { code: Cell; data: Cell } - ) {} - - static createFromAddress(address: Address) { - return new Main(address); - } - - static mainConfigToCell(config: MainConfig): Cell { - const priceDict = Dictionary.empty( - Dictionary.Keys.BigUint(256), - Dictionary.Values.Cell() - ); - - // Create a dictionary for data sources - const dataSourcesDict = Dictionary.empty( - Dictionary.Keys.Uint(32), - Dictionary.Values.Cell() - ); - // Create a dictionary for valid data sources - const isValidDataSourceDict = Dictionary.empty( - Dictionary.Keys.BigUint(256), - Dictionary.Values.Bool() - ); - - config.dataSources.forEach((source, index) => { - const sourceCell = beginCell() - .storeUint(source.emitterChain, 16) - .storeBuffer(Buffer.from(source.emitterAddress, "hex")) - .endCell(); - dataSourcesDict.set(index, sourceCell); - const cellHash = BigInt("0x" + sourceCell.hash().toString("hex")); - isValidDataSourceDict.set(cellHash, true); - }); - - // Group price feeds and update fee - const priceFeedsCell = beginCell() - .storeDict(priceDict) - .storeUint(config.singleUpdateFee, 256) - .endCell(); - - // Group data sources information - const dataSourcesCell = beginCell() - .storeDict(dataSourcesDict) - .storeUint(config.dataSources.length, 32) - .storeDict(isValidDataSourceDict) - .endCell(); - - // Group guardian set information - const guardianSetCell = beginCell() - .storeUint(config.guardianSetIndex, 32) - .storeDict( - createGuardianSetsDict(config.guardianSet, config.guardianSetIndex) - ) - .endCell(); - - // Group chain and governance information - const governanceCell = beginCell() - .storeUint(config.chainId, 16) - .storeUint(config.governanceChainId, 16) - .storeBuffer(Buffer.from(config.governanceContract, "hex")) - .storeDict(Dictionary.empty()) // consumed_governance_actions - .storeRef( - config.governanceDataSource - ? beginCell() - .storeUint(config.governanceDataSource.emitterChain, 16) - .storeBuffer( - Buffer.from(config.governanceDataSource.emitterAddress, "hex") - ) - .endCell() - : beginCell().endCell() - ) // governance_data_source - .storeUint(0, 64) // last_executed_governance_sequence, set to 0 for initial state - .storeUint(0, 32) // governance_data_source_index, set to 0 for initial state - .storeUint(0, 256) // upgrade_code_hash, set to 0 for initial state - .endCell(); - - return beginCell() - .storeRef(priceFeedsCell) - .storeRef(dataSourcesCell) - .storeRef(guardianSetCell) - .storeRef(governanceCell) - .endCell(); - } - +export class Main extends BaseWrapper { static createFromConfig(config: MainConfig, code: Cell, workchain = 0) { const data = Main.mainConfigToCell(config); const init = { code, data }; return new Main(contractAddress(workchain, init), init); } + static mainConfigToCell(config: MainConfig): Cell { + return BaseWrapper.createInitData(config); + } + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell().endCell(), - }); + await super.sendDeploy(provider, via, value); + } + + async getCurrentGuardianSetIndex(provider: ContractProvider) { + return await super.getCurrentGuardianSetIndex( + provider, + "get_current_guardian_set_index" + ); } async sendUpdateGuardianSet( @@ -132,22 +42,7 @@ export class Main implements Contract { via: Sender, vm: Buffer ) { - const messageBody = beginCell() - .storeUint(1, 32) // OP_UPDATE_GUARDIAN_SET - .storeRef(createCellChain(vm)) - .endCell(); - - await provider.internal(via, { - value: toNano("0.1"), - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: messageBody, - }); - } - - async getCurrentGuardianSetIndex(provider: ContractProvider) { - const result = await provider.get("get_current_guardian_set_index", []); - - return result.stack.readNumber(); + await super.sendUpdateGuardianSet(provider, via, vm); } async sendUpdatePriceFeeds( @@ -156,34 +51,15 @@ export class Main implements Contract { updateData: Buffer, updateFee: bigint ) { - const messageBody = beginCell() - .storeUint(2, 32) // OP_UPDATE_PRICE_FEEDS - .storeRef(createCellChain(updateData)) - .endCell(); - - await provider.internal(via, { - value: updateFee, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: messageBody, - }); + await super.sendUpdatePriceFeeds(provider, via, updateData, updateFee); } async getPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) { - const result = await provider.get("get_price_unsafe", [ - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getPriceUnsafe( + provider, + priceFeedId, + "get_price_unsafe" + ); } async getPriceNoOlderThan( @@ -191,40 +67,20 @@ export class Main implements Contract { timePeriod: number, priceFeedId: HexString ) { - const result = await provider.get("get_price_no_older_than", [ - { type: "int", value: BigInt(timePeriod) }, - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getPriceNoOlderThan( + provider, + timePeriod, + priceFeedId, + "get_price_no_older_than" + ); } async getEmaPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) { - const result = await provider.get("get_ema_price_unsafe", [ - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getEmaPriceUnsafe( + provider, + priceFeedId, + "get_ema_price_unsafe" + ); } async getEmaPriceNoOlderThan( @@ -232,35 +88,23 @@ export class Main implements Contract { timePeriod: number, priceFeedId: HexString ) { - const result = await provider.get("get_ema_price_no_older_than", [ - { type: "int", value: BigInt(timePeriod) }, - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getEmaPriceNoOlderThan( + provider, + timePeriod, + priceFeedId, + "get_ema_price_no_older_than" + ); } async getUpdateFee(provider: ContractProvider, vm: Buffer) { - const result = await provider.get("get_update_fee", [ - { type: "slice", cell: createCellChain(vm) }, - ]); - - return result.stack.readNumber(); + return await super.getUpdateFee(provider, vm, "get_update_fee"); } async getSingleUpdateFee(provider: ContractProvider) { - const result = await provider.get("get_single_update_fee", []); + return await super.getSingleUpdateFee(provider, "get_single_update_fee"); + } - return result.stack.readNumber(); + async getChainId(provider: ContractProvider) { + return await super.getChainId(provider, "get_chain_id"); } } diff --git a/target_chains/ton/contracts/wrappers/PythTest.ts b/target_chains/ton/contracts/wrappers/PythTest.ts index bd256d25f..809219dce 100644 --- a/target_chains/ton/contracts/wrappers/PythTest.ts +++ b/target_chains/ton/contracts/wrappers/PythTest.ts @@ -1,18 +1,15 @@ import { - Address, beginCell, Cell, - Contract, contractAddress, ContractProvider, - Dictionary, Sender, SendMode, toNano, } from "@ton/core"; +import { BaseWrapper } from "./BaseWrapper"; import { HexString, Price } from "@pythnetwork/price-service-sdk"; import { createCellChain } from "@pythnetwork/pyth-ton-js"; -import { createGuardianSetsDict } from "../tests/utils/wormhole"; import { DataSource } from "@pythnetwork/xc-admin-common"; export type PythTestConfig = { @@ -30,170 +27,27 @@ export type PythTestConfig = { governanceDataSource?: DataSource; }; -export class PythTest implements Contract { - constructor( - readonly address: Address, - readonly init?: { code: Cell; data: Cell } - ) {} - - static createFromAddress(address: Address) { - return new PythTest(address); - } - +export class PythTest extends BaseWrapper { static createFromConfig(config: PythTestConfig, code: Cell, workchain = 0) { - const data = PythTest.getPythInitData( - config.priceFeedId, - config.timePeriod, - config.price, - config.emaPrice, - config.singleUpdateFee, - config.dataSources, - config.guardianSetIndex, - config.guardianSet, - config.chainId, - config.governanceChainId, - config.governanceContract, - config.governanceDataSource - ); + const data = PythTest.getPythInitData(config); const init = { code, data }; return new PythTest(contractAddress(workchain, init), init); } - static getPythInitData( - priceFeedId: HexString, - timePeriod: number, - price: Price, - emaPrice: Price, - singleUpdateFee: number, - dataSources: DataSource[], - guardianSetIndex: number, - guardianSet: string[], - chainId: number, - governanceChainId: number, - governanceContract: string, - governanceDataSource?: DataSource - ): Cell { - const priceDict = Dictionary.empty( - Dictionary.Keys.BigUint(256), - Dictionary.Values.Cell() - ); - - const priceCell = beginCell() - .storeInt(price.getPriceAsNumberUnchecked() * 10 ** -price.expo, 64) - .storeUint(price.getConfAsNumberUnchecked() * 10 ** -price.expo, 64) - .storeInt(price.expo, 32) - .storeUint(price.publishTime, 64) - .endCell(); - - const emaPriceCell = beginCell() - .storeInt(emaPrice.getPriceAsNumberUnchecked() * 10 ** -emaPrice.expo, 64) - .storeUint(emaPrice.getConfAsNumberUnchecked() * 10 ** -emaPrice.expo, 64) - .storeInt(emaPrice.expo, 32) - .storeUint(emaPrice.publishTime, 64) - .endCell(); - - const priceFeedCell = beginCell() - .storeRef(priceCell) - .storeRef(emaPriceCell) - .storeUint(timePeriod, 32) - .endCell(); - - priceDict.set(BigInt(priceFeedId), priceFeedCell); - - // Create a dictionary for data sources - const dataSourcesDict = Dictionary.empty( - Dictionary.Keys.Uint(32), - Dictionary.Values.Cell() - ); - // Create a dictionary for valid data sources - const isValidDataSourceDict = Dictionary.empty( - Dictionary.Keys.BigUint(256), - Dictionary.Values.Bool() - ); - - dataSources.forEach((source, index) => { - const sourceCell = beginCell() - .storeUint(source.emitterChain, 16) - .storeBuffer(Buffer.from(source.emitterAddress, "hex")) - .endCell(); - dataSourcesDict.set(index, sourceCell); - const cellHash = BigInt("0x" + sourceCell.hash().toString("hex")); - isValidDataSourceDict.set(cellHash, true); - }); - - // Group price feeds and update fee - const priceFeedsCell = beginCell() - .storeDict(priceDict) - .storeUint(singleUpdateFee, 256) - .endCell(); - - // Group data sources information - const dataSourcesCell = beginCell() - .storeDict(dataSourcesDict) - .storeUint(dataSources.length, 32) - .storeDict(isValidDataSourceDict) - .endCell(); - - // Group guardian set information - const guardianSetCell = beginCell() - .storeUint(guardianSetIndex, 32) - .storeDict(createGuardianSetsDict(guardianSet, guardianSetIndex)) - .endCell(); - - // Group chain and governance information - const governanceCell = beginCell() - .storeUint(chainId, 16) - .storeUint(governanceChainId, 16) - .storeBuffer(Buffer.from(governanceContract, "hex")) - .storeDict(Dictionary.empty()) // consumed_governance_actions - .storeRef( - governanceDataSource - ? beginCell() - .storeUint(governanceDataSource.emitterChain, 16) - .storeBuffer( - Buffer.from(governanceDataSource.emitterAddress, "hex") - ) - .endCell() - : beginCell().endCell() - ) // governance_data_source - .storeUint(0, 64) // last_executed_governance_sequence, set to 0 for initial state - .storeUint(0, 32) // governance_data_source_index, set to 0 for initial state - .storeUint(0, 256) // upgrade_code_hash, set to 0 for initial state - .endCell(); - - // Create the main cell with references to grouped data - return beginCell() - .storeRef(priceFeedsCell) - .storeRef(dataSourcesCell) - .storeRef(guardianSetCell) - .storeRef(governanceCell) - .endCell(); + static getPythInitData(config: PythTestConfig): Cell { + return BaseWrapper.createInitData(config); } async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell().endCell(), - }); + await super.sendDeploy(provider, via, value); } async getPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) { - const result = await provider.get("test_get_price_unsafe", [ - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getPriceUnsafe( + provider, + priceFeedId, + "test_get_price_unsafe" + ); } async getPriceNoOlderThan( @@ -201,40 +55,20 @@ export class PythTest implements Contract { timePeriod: number, priceFeedId: HexString ) { - const result = await provider.get("test_get_price_no_older_than", [ - { type: "int", value: BigInt(timePeriod) }, - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getPriceNoOlderThan( + provider, + timePeriod, + priceFeedId, + "test_get_price_no_older_than" + ); } async getEmaPriceUnsafe(provider: ContractProvider, priceFeedId: HexString) { - const result = await provider.get("test_get_ema_price_unsafe", [ - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getEmaPriceUnsafe( + provider, + priceFeedId, + "test_get_ema_price_unsafe" + ); } async getEmaPriceNoOlderThan( @@ -242,35 +76,23 @@ export class PythTest implements Contract { timePeriod: number, priceFeedId: HexString ) { - const result = await provider.get("test_get_ema_price_no_older_than", [ - { type: "int", value: BigInt(timePeriod) }, - { type: "int", value: BigInt(priceFeedId) }, - ]); - - const price = result.stack.readNumber(); - const conf = result.stack.readNumber(); - const expo = result.stack.readNumber(); - const publishTime = result.stack.readNumber(); - - return { - price, - conf, - expo, - publishTime, - }; + return await super.getEmaPriceNoOlderThan( + provider, + timePeriod, + priceFeedId, + "test_get_ema_price_no_older_than" + ); } async getUpdateFee(provider: ContractProvider, vm: Buffer) { - const result = await provider.get("test_get_update_fee", [ - { type: "slice", cell: createCellChain(vm) }, - ]); - - return result.stack.readNumber(); + return await super.getUpdateFee(provider, vm, "test_get_update_fee"); } async getSingleUpdateFee(provider: ContractProvider) { - const result = await provider.get("test_get_single_update_fee", []); - return result.stack.readNumber(); + return await super.getSingleUpdateFee( + provider, + "test_get_single_update_fee" + ); } async sendUpdatePriceFeeds( @@ -279,16 +101,7 @@ export class PythTest implements Contract { updateData: Buffer, updateFee: bigint ) { - const messageBody = beginCell() - .storeUint(2, 32) // OP_UPDATE_PRICE_FEEDS - .storeRef(createCellChain(updateData)) - .endCell(); - - await provider.internal(via, { - value: updateFee, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: messageBody, - }); + await super.sendUpdatePriceFeeds(provider, via, updateData, updateFee); } async sendUpdateGuardianSet( @@ -296,23 +109,14 @@ export class PythTest implements Contract { via: Sender, vm: Buffer ) { - const messageBody = beginCell() - .storeUint(1, 32) // OP_UPDATE_GUARDIAN_SET - .storeRef(createCellChain(vm)) - .endCell(); - - await provider.internal(via, { - value: toNano("0.1"), - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: messageBody, - }); + await super.sendUpdateGuardianSet(provider, via, vm); } async getChainId(provider: ContractProvider) { - const result = await provider.get("test_get_chain_id", []); - return result.stack.readNumber(); + return await super.getChainId(provider, "test_get_chain_id"); } + // Add PythTest-specific methods here async getLastExecutedGovernanceSequence(provider: ContractProvider) { const result = await provider.get( "test_get_last_executed_governance_sequence", diff --git a/target_chains/ton/contracts/wrappers/WormholeTest.ts b/target_chains/ton/contracts/wrappers/WormholeTest.ts index d173b416f..946e5f00b 100644 --- a/target_chains/ton/contracts/wrappers/WormholeTest.ts +++ b/target_chains/ton/contracts/wrappers/WormholeTest.ts @@ -1,20 +1,7 @@ -import { - Address, - beginCell, - Cell, - Contract, - contractAddress, - ContractProvider, - Dictionary, - Sender, - SendMode, - toNano, -} from "@ton/core"; +import { Cell, contractAddress, ContractProvider, Sender } from "@ton/core"; +import { BaseWrapper } from "./BaseWrapper"; import { createCellChain } from "@pythnetwork/pyth-ton-js"; -import { - createGuardianSetsDict, - parseGuardianSetKeys, -} from "../tests/utils/wormhole"; +import { parseGuardianSetKeys } from "../tests/utils/wormhole"; export type WormholeTestConfig = { guardianSetIndex: number; @@ -24,88 +11,31 @@ export type WormholeTestConfig = { governanceContract: string; }; -export class WormholeTest implements Contract { - constructor( - readonly address: Address, - readonly init?: { code: Cell; data: Cell } - ) {} - - static createFromAddress(address: Address) { - return new WormholeTest(address); - } - +export class WormholeTest extends BaseWrapper { static createFromConfig( config: WormholeTestConfig, code: Cell, workchain = 0 ) { - const data = WormholeTest.getWormholeInitData( - config.guardianSetIndex, - config.guardianSet, - config.chainId, - config.governanceChainId, - config.governanceContract - ); + const data = WormholeTest.getWormholeInitData(config); const init = { code, data }; return new WormholeTest(contractAddress(workchain, init), init); } - static getWormholeInitData( - guardianSetIndex: number, - guardianSet: string[], - chainId: number, - governanceChainId: number, - governanceContract: string - ): Cell { - // Group price feeds and update fee (empty for Wormhole) - const priceFeedsCell = beginCell() - .storeDict(Dictionary.empty()) // latest_price_feeds, empty for initial state - .storeUint(0, 256) // single_update_fee, set to 0 for testing - .endCell(); - - // Group data sources information (empty for initial state) - const dataSourcesCell = beginCell() - .storeDict(Dictionary.empty()) // data_sources, empty for initial state - .storeUint(0, 32) // num_data_sources, set to 0 for initial state - .storeDict(Dictionary.empty()) // is_valid_data_source, empty for initial state - .endCell(); - - // Group guardian set information - const guardianSetCell = beginCell() - .storeUint(guardianSetIndex, 32) - .storeDict(createGuardianSetsDict(guardianSet, guardianSetIndex)) - .endCell(); - - // Group chain and governance information - const governanceCell = beginCell() - .storeUint(chainId, 16) - .storeUint(governanceChainId, 16) - .storeBuffer(Buffer.from(governanceContract, "hex")) - .storeDict(Dictionary.empty()) // consumed_governance_actions, empty for initial state - .storeRef(beginCell()) // governance_data_source, empty for initial state - .storeUint(0, 64) // last_executed_governance_sequence, set to 0 for initial state - .storeUint(0, 32) // governance_data_source_index, set to 0 for initial state - .storeUint(0, 256) // upgrade_code_hash, set to 0 for initial state - .endCell(); - - // Create the main cell with references to grouped data - return beginCell() - .storeRef(priceFeedsCell) - .storeRef(dataSourcesCell) - .storeRef(guardianSetCell) - .storeRef(governanceCell) - .endCell(); + static getWormholeInitData(config: WormholeTestConfig): Cell { + return BaseWrapper.createInitData({ + guardianSetIndex: config.guardianSetIndex, + guardianSet: config.guardianSet, + chainId: config.chainId, + governanceChainId: config.governanceChainId, + governanceContract: config.governanceContract, + }); } async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell().endCell(), - }); + await super.sendDeploy(provider, via, value); } - // NOTE: the function name has to start with "send" or "get" so that it automatically inserts `provider` as a first argument async getParseEncodedUpgrade( provider: ContractProvider, currentGuardianSetIndex: number, @@ -172,12 +102,10 @@ export class WormholeTest implements Contract { } async getCurrentGuardianSetIndex(provider: ContractProvider) { - const result = await provider.get( - "test_get_current_guardian_set_index", - [] + return await super.getCurrentGuardianSetIndex( + provider, + "test_get_current_guardian_set_index" ); - - return result.stack.readNumber(); } async getGuardianSet(provider: ContractProvider, index: number) { @@ -202,8 +130,7 @@ export class WormholeTest implements Contract { } async getChainId(provider: ContractProvider) { - const result = await provider.get("test_get_chain_id", []); - return result.stack.readNumber(); + return await super.getChainId(provider, "test_get_chain_id"); } async getGovernanceContract(provider: ContractProvider) { @@ -227,15 +154,6 @@ export class WormholeTest implements Contract { via: Sender, vm: Buffer ) { - const messageBody = beginCell() - .storeUint(1, 32) // OP_UPDATE_GUARDIAN_SET - .storeRef(createCellChain(vm)) - .endCell(); - - await provider.internal(via, { - value: toNano("0.1"), - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: messageBody, - }); + await super.sendUpdateGuardianSet(provider, via, vm); } }