diff --git a/contract_manager/store/chains/TonChains.yaml b/contract_manager/store/chains/TonChains.yaml index 40b4e769c6..118c077702 100644 --- a/contract_manager/store/chains/TonChains.yaml +++ b/contract_manager/store/chains/TonChains.yaml @@ -3,3 +3,8 @@ mainnet: false rpcUrl: https://testnet.toncenter.com/api/v2/jsonRPC type: TonChain +- id: ton_mainnet + wormholeChainName: ton_mainnet + mainnet: true + rpcUrl: https://toncenter.com/api/v2/jsonRPC + type: TonChain diff --git a/contract_manager/store/contracts/TonPriceFeedContracts.yaml b/contract_manager/store/contracts/TonPriceFeedContracts.yaml index e1ec02fd9d..e62dbb18f5 100644 --- a/contract_manager/store/contracts/TonPriceFeedContracts.yaml +++ b/contract_manager/store/contracts/TonPriceFeedContracts.yaml @@ -1,3 +1,6 @@ - chain: ton_testnet - address: "EQDwGkJmcj7MMmWAHmhldnY-lAKI6hcTQ2tAEcapmwCnztQU" + address: "EQB4ZnrI5qsP_IUJgVJNwEGKLzZWsQOFhiaqDbD7pTt_f9oU" + type: TonPriceFeedContract +- chain: ton_mainnet + address: "EQBU6k8HH6yX4Jf3d18swWbnYr31D3PJI7PgjXT-flsKHqql" type: TonPriceFeedContract diff --git a/contract_manager/store/contracts/TonWormholeContracts.yaml b/contract_manager/store/contracts/TonWormholeContracts.yaml index b51348614b..94db317abd 100644 --- a/contract_manager/store/contracts/TonWormholeContracts.yaml +++ b/contract_manager/store/contracts/TonWormholeContracts.yaml @@ -1,3 +1,6 @@ - chain: ton_testnet - address: "EQDwGkJmcj7MMmWAHmhldnY-lAKI6hcTQ2tAEcapmwCnztQU" + address: "EQB4ZnrI5qsP_IUJgVJNwEGKLzZWsQOFhiaqDbD7pTt_f9oU" + type: TonWormholeContract +- chain: ton_mainnet + address: "EQBU6k8HH6yX4Jf3d18swWbnYr31D3PJI7PgjXT-flsKHqql" type: TonWormholeContract diff --git a/governance/xc_admin/packages/xc_admin_common/src/chains.ts b/governance/xc_admin/packages/xc_admin_common/src/chains.ts index 97149e3c66..5d9dfd9ad5 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/chains.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/chains.ts @@ -93,6 +93,7 @@ export const RECEIVER_CHAINS = { superseed_mainnet: 60066, fuel_mainnet: 60067, // Note: Currently deployed at 50084 (fuel_testnet) but we should use 60067 for future deployments hemi_mainnet: 60068, + ton_mainnet: 60069, // Testnets as a separate chain ids (to use stable data sources and governance for them) injective_testnet: 60013, osmosis_testnet_4: 60015, diff --git a/target_chains/ton/contracts/README.md b/target_chains/ton/contracts/README.md index 111c0bab01..6105cd2a1e 100644 --- a/target_chains/ton/contracts/README.md +++ b/target_chains/ton/contracts/README.md @@ -19,7 +19,13 @@ ### Deploy or run another script -`npx blueprint run` or `yarn blueprint run` +First, visit [TON Center](https://toncenter.com/) and register to get an API key to bypass rate limits. Replace `` with the API key you obtained from TON Center. `` is either `testnet` or `mainnet`. `` is the chain ID of the chain you want to deploy to. + +Then run: + +```bash +CHAIN_ID= npx blueprint run --custom https://testnet.toncenter.com/api/v2/jsonRPC --custom-version v2 --custom-type --custom-key +``` ### Add a new contract diff --git a/target_chains/ton/contracts/contracts/Pyth.fc b/target_chains/ton/contracts/contracts/Pyth.fc index 3704910593..11f1528b39 100644 --- a/target_chains/ton/contracts/contracts/Pyth.fc +++ b/target_chains/ton/contracts/contracts/Pyth.fc @@ -357,9 +357,9 @@ cell create_price_feed_cell_chain(tuple price_feeds) { ;; - 6 bits: optimized way of serializing the tag and the first 4 fields ;; - 256 bits: owner address ;; - 128 bits: coins (VarUInteger 16) from grams$_ amount:(VarUInteger 16) = Grams - ;; - 107 bits: other data (extra_currencies + ihr_fee + fwd_fee + lt of transaction + unixtime of transaction + no init-field flag + inplace message body flag) + ;; - 107 bits: MSG_SERIALIZE_BITS ;; - PRICE_FEED_BITS * num_price_feeds: space for each price feed - int bits = 6 + 256 + 128 + 107 + (PRICE_FEED_BITS * num_price_feeds); + int bits = 6 + 256 + 128 + MSG_SERIALIZE_BITS + (PRICE_FEED_BITS * num_price_feeds); int fwd_fee = get_forward_fee(cells, bits, WORKCHAIN); ;; Calculate all fees @@ -375,7 +375,7 @@ cell create_price_feed_cell_chain(tuple price_feeds) { .store_uint(0x18, 6) .store_slice(sender_address) .store_coins(excess) - .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1) + .store_uint(1, MSG_SERIALIZE_BITS) .store_ref(response.end_cell()) .end_cell(), 0); diff --git a/target_chains/ton/contracts/contracts/common/constants.fc b/target_chains/ton/contracts/contracts/common/constants.fc index a087175755..2d7674cdd9 100644 --- a/target_chains/ton/contracts/contracts/common/constants.fc +++ b/target_chains/ton/contracts/contracts/common/constants.fc @@ -15,6 +15,16 @@ const int WORMHOLE_MERKLE_UPDATE_TYPE = 0; const int PRICE_FEED_MESSAGE_TYPE = 0; +;; Bit layout: (https://docs.ton.org/v3/documentation/smart-contracts/message-management/sending-messages#message-layout) +;; 1 - extra-currencies dictionary (0 = empty) +;; 4 - ihr_fee (VarUInteger 16) +;; 4 - fwd_fee (VarUInteger 16) +;; 64 - created_lt (uint64) +;; 32 - created_at (uint32) +;; 1 - init field presence (0 = no init) +;; 1 - body serialization (0 = in-place) +const int MSG_SERIALIZE_BITS = 1 + 4 + 4 + 64 + 32 + 1 + 1; ;; 107 bits total + ;; Structure: ;; - 256 bits: price_id ;; Price: diff --git a/target_chains/ton/contracts/scripts/deployPyth.ts b/target_chains/ton/contracts/scripts/deployPyth.ts index 4cd1f33be1..c14ec522fe 100644 --- a/target_chains/ton/contracts/scripts/deployPyth.ts +++ b/target_chains/ton/contracts/scripts/deployPyth.ts @@ -10,6 +10,7 @@ import { MAINNET_UPGRADE_VAAS, } from "../tests/utils/wormhole"; import { BTC_PRICE_FEED_ID, ETH_PRICE_FEED_ID } from "../tests/utils/pyth"; +import { calculateUpdatePriceFeedsFee } from "@pythnetwork/pyth-ton-js"; export async function run(provider: NetworkProvider) { const SINGLE_UPDATE_FEE = 1; @@ -21,12 +22,28 @@ export async function run(provider: NetworkProvider) { }, ]; + // Require CHAIN_ID environment variable + if (!process.env.CHAIN_ID) { + throw new Error( + "CHAIN_ID environment variable is required. Example usage: CHAIN_ID=2 npx blueprint run ..." + ); + } + + const chainId = parseInt(process.env.CHAIN_ID, 10); + + // Validate that chainId is a valid number + if (isNaN(chainId)) { + throw new Error("CHAIN_ID must be a valid number"); + } + + console.log("Chain ID:", chainId); + const config: MainConfig = { singleUpdateFee: SINGLE_UPDATE_FEE, dataSources: DATA_SOURCES, guardianSetIndex: 0, guardianSet: GUARDIAN_SET_0, - chainId: 1, + chainId, governanceChainId: 1, governanceContract: "0000000000000000000000000000000000000000000000000000000000000004", @@ -97,12 +114,14 @@ export async function run(provider: NetworkProvider) { // NOTE: As of 2024/10/14 There's a bug with TON Access (https://ton.access.orbs.network) RPC service where if you provide an update data buffer with length of more than ~320 then the rpc returns error 404 and the function fails const updateFee = await main.getUpdateFee(updateData); - console.log("Update fee:", updateFee); - await main.sendUpdatePriceFeeds( + const totalFee = + calculateUpdatePriceFeedsFee(BigInt(updateFee)) + BigInt(updateFee); + + const result = await main.sendUpdatePriceFeeds( provider.sender(), updateData, - toNano(updateFee) + totalFee ); console.log("Price feeds updated successfully."); diff --git a/target_chains/ton/contracts/tests/PythTest.spec.ts b/target_chains/ton/contracts/tests/PythTest.spec.ts index f435f0588b..9f4f5d34c6 100644 --- a/target_chains/ton/contracts/tests/PythTest.spec.ts +++ b/target_chains/ton/contracts/tests/PythTest.spec.ts @@ -23,12 +23,10 @@ import { HERMES_BTC_EMA_CONF, HERMES_BTC_EMA_EXPO, HERMES_BTC_EMA_PRICE, - HERMES_BTC_EMA_PUBLISH_TIME, HERMES_ETH_CONF, HERMES_ETH_EMA_CONF, HERMES_ETH_EMA_EXPO, HERMES_ETH_EMA_PRICE, - HERMES_ETH_EMA_PUBLISH_TIME, HERMES_ETH_EXPO, HERMES_BTC_ETH_UNIQUE_UPDATE, HERMES_ETH_UNIQUE_EMA_PRICE, diff --git a/target_chains/ton/contracts/tests/utils/wormhole.ts b/target_chains/ton/contracts/tests/utils/wormhole.ts index c81e6c0c9a..707b8bb2c4 100644 --- a/target_chains/ton/contracts/tests/utils/wormhole.ts +++ b/target_chains/ton/contracts/tests/utils/wormhole.ts @@ -174,5 +174,5 @@ export const MAINNET_UPGRADE_VAAS = [ export const GOVERNANCE_DATA_SOURCE: DataSource = { emitterChain: 1, emitterAddress: - "0000000000000000000000000000000000000000000000000000000000000029", + "5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e", }; diff --git a/target_chains/ton/sdk/js/package.json b/target_chains/ton/sdk/js/package.json index 7c96f56e9d..bcf9dd682e 100644 --- a/target_chains/ton/sdk/js/package.json +++ b/target_chains/ton/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/pyth-ton-js", - "version": "0.1.0", + "version": "0.1.1", "description": "Pyth Network TON Utilities", "homepage": "https://pyth.network", "author": { diff --git a/target_chains/ton/sdk/js/src/index.ts b/target_chains/ton/sdk/js/src/index.ts index 0145f799ed..b4517bac05 100644 --- a/target_chains/ton/sdk/js/src/index.ts +++ b/target_chains/ton/sdk/js/src/index.ts @@ -10,8 +10,10 @@ import { } from "@ton/core"; import { ContractProvider } from "@ton/ton"; +export const PYTH_CONTRACT_ADDRESS_MAINNET = + "EQBU6k8HH6yX4Jf3d18swWbnYr31D3PJI7PgjXT-flsKHqql"; export const PYTH_CONTRACT_ADDRESS_TESTNET = - "EQDwGkJmcj7MMmWAHmhldnY-lAKI6hcTQ2tAEcapmwCnztQU"; + "EQB4ZnrI5qsP_IUJgVJNwEGKLzZWsQOFhiaqDbD7pTt_f9oU"; // This is defined in target_chains/ton/contracts/common/gas.fc export const UPDATE_PRICE_FEEDS_BASE_GAS = 300000n; export const UPDATE_PRICE_FEEDS_PER_UPDATE_GAS = 90000n;