diff --git a/contract_manager/package.json b/contract_manager/package.json index 502fbc8a9e..3812ab9cd3 100644 --- a/contract_manager/package.json +++ b/contract_manager/package.json @@ -37,10 +37,13 @@ "@pythnetwork/pyth-starknet-js": "^0.2.1", "@pythnetwork/pyth-sui-js": "workspace:*", "@pythnetwork/pyth-ton-js": "workspace:*", + "@pythnetwork/pyth-ton": "workspace:*", "@pythnetwork/solana-utils": "workspace:^", "@pythnetwork/xc-admin-common": "workspace:*", "@solana/web3.js": "^1.73.0", "@sqds/mesh": "^1.0.6", + "@ton/blueprint": "^0.22.0", + "@ton/core": "^0.59.0", "@ton/crypto": "^3.3.0", "@ton/ton": "^15.1.0", "@types/yargs": "^17.0.32", diff --git a/contract_manager/scripts/upgrade_ton_contract.ts b/contract_manager/scripts/upgrade_ton_contract.ts new file mode 100644 index 0000000000..5fa35f3151 --- /dev/null +++ b/contract_manager/scripts/upgrade_ton_contract.ts @@ -0,0 +1,88 @@ +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; +import { DefaultStore, loadHotWallet } from "../src"; +import { TonChain } from "../src/chains"; +import { CHAINS, toChainName } from "@pythnetwork/xc-admin-common"; +import fs from "fs"; +import path from "path"; + +const parser = yargs(hideBin(process.argv)) + .usage( + "Upgrades the Pyth contract on TON and creates a governance proposal for it.\n" + + "Usage: $0 --network --contract-address
--ops-key-path " + ) + .options({ + network: { + type: "string", + choices: ["mainnet", "testnet"], + description: "Network to deploy to", + demandOption: true, + }, + "contract-address": { + type: "string", + description: "Address of the contract to upgrade", + demandOption: true, + }, + "ops-key-path": { + type: "string", + description: "Path to operations key file", + demandOption: true, + }, + }); + +async function main() { + const argv = await parser.argv; + const isMainnet = argv.network === "mainnet"; + + // Get chain ID and name from CHAINS mapping + const chainId = isMainnet ? CHAINS.ton_mainnet : CHAINS.ton_testnet; + const wormholeChainName = toChainName(chainId); + + // Get the TON chain instance with appropriate RPC URL based on network + const chain = new TonChain( + chainId.toString(), + isMainnet, + wormholeChainName, + undefined, + isMainnet + ? "https://toncenter.com/api/v2/jsonRPC" + : "https://testnet.toncenter.com/api/v2/jsonRPC" + ); + + const vault = + DefaultStore.vaults[ + "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj" + ]; + + console.log( + `Upgrading contract on TON ${argv.network} (Chain ID: ${chainId}, Wormhole Chain Name: ${wormholeChainName})` + ); + + // Read the compiled contract from the build directory + // NOTE: Remember to rebuild contract_manager before running this script because it will also build the ton contract + const compiledPath = path.resolve( + __dirname, + "../../target_chains/ton/contracts/build/Main.compiled.json" + ); + const compiled = JSON.parse(fs.readFileSync(compiledPath, "utf8")); + const newCodeHash = compiled.hash; + console.log("New code hash:", newCodeHash); + + // Generate governance payload for the upgrade + const payload = chain.generateGovernanceUpgradePayload(newCodeHash); + console.log("Generated governance payload"); + console.log("Payload:", payload); + + // Create and submit governance proposal + console.log("Using vault for proposal:", vault.getId()); + const keypair = await loadHotWallet(argv["ops-key-path"] as string); + console.log("Using wallet:", keypair.publicKey.toBase58()); + vault.connect(keypair); + const proposal = await vault.proposeWormholeMessage([payload]); + console.log("Proposal address:", proposal.address.toBase58()); +} + +main().catch((error) => { + console.error("Error during upgrade:", error); + process.exit(1); +}); diff --git a/contract_manager/src/chains.ts b/contract_manager/src/chains.ts index 189765eb81..6bbcbd3305 100644 --- a/contract_manager/src/chains.ts +++ b/contract_manager/src/chains.ts @@ -807,7 +807,6 @@ export class TonChain extends Chain { * @param digest hex string of the 32 byte digest for the new package without the 0x prefix */ generateGovernanceUpgradePayload(digest: string): Buffer { - // This might throw an error because the Fuel contract doesn't support upgrades yet (blocked on Fuel releasing Upgradeability standard) return new UpgradeContract256Bit(this.wormholeChainName, digest).encode(); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d3cd6fe5b..d137bb852a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -807,6 +807,9 @@ importers: '@pythnetwork/pyth-sui-js': specifier: workspace:* version: link:../target_chains/sui/sdk/js + '@pythnetwork/pyth-ton': + specifier: workspace:* + version: link:../target_chains/ton/contracts '@pythnetwork/pyth-ton-js': specifier: workspace:* version: link:../target_chains/ton/sdk/js @@ -822,6 +825,12 @@ importers: '@sqds/mesh': specifier: ^1.0.6 version: 1.0.6(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@ton/blueprint': + specifier: ^0.22.0 + version: 0.22.0(@ton/core@0.59.0(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)(@ton/ton@15.1.0(@ton/core@0.59.0(@ton/crypto@3.3.0))(@ton/crypto@3.3.0))(@types/node@22.8.2)(encoding@0.1.13)(typescript@5.4.5) + '@ton/core': + specifier: ^0.59.0 + version: 0.59.0(@ton/crypto@3.3.0) '@ton/crypto': specifier: ^3.3.0 version: 3.3.0 @@ -15732,10 +15741,6 @@ packages: inline-style-parser@0.2.3: resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==} - inquirer@8.2.5: - resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} - engines: {node: '>=12.0.0'} - inquirer@8.2.6: resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} engines: {node: '>=12.0.0'} @@ -38612,7 +38617,7 @@ snapshots: arg: 5.0.2 chalk: 4.1.2 dotenv: 16.4.5 - inquirer: 8.2.5 + inquirer: 8.2.6 qrcode-terminal: 0.12.0 ton-x: 2.1.0 ts-node: 10.9.2(@types/node@20.14.15)(typescript@5.5.4) @@ -38625,6 +38630,31 @@ snapshots: - supports-color - typescript + '@ton/blueprint@0.22.0(@ton/core@0.59.0(@ton/crypto@3.3.0))(@ton/crypto@3.3.0)(@ton/ton@15.1.0(@ton/core@0.59.0(@ton/crypto@3.3.0))(@ton/crypto@3.3.0))(@types/node@22.8.2)(encoding@0.1.13)(typescript@5.4.5)': + dependencies: + '@orbs-network/ton-access': 2.3.3(encoding@0.1.13) + '@tact-lang/compiler': 1.4.4(encoding@0.1.13) + '@ton-community/func-js': 0.7.0 + '@ton/core': 0.59.0(@ton/crypto@3.3.0) + '@ton/crypto': 3.3.0 + '@ton/ton': 15.1.0(@ton/core@0.59.0(@ton/crypto@3.3.0))(@ton/crypto@3.3.0) + '@tonconnect/sdk': 2.2.0(encoding@0.1.13) + arg: 5.0.2 + chalk: 4.1.2 + dotenv: 16.4.5 + inquirer: 8.2.6 + qrcode-terminal: 0.12.0 + ton-x: 2.1.0 + ts-node: 10.9.2(@types/node@22.8.2)(typescript@5.4.5) + transitivePeerDependencies: + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - debug + - encoding + - supports-color + - typescript + '@ton/core@0.56.3(@ton/crypto@3.3.0)': dependencies: '@ton/crypto': 3.3.0 @@ -49240,24 +49270,6 @@ snapshots: inline-style-parser@0.2.3: {} - inquirer@8.2.5: - dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.1 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 7.0.0 - inquirer@8.2.6: dependencies: ansi-escapes: 4.3.2 diff --git a/target_chains/ton/contracts/package.json b/target_chains/ton/contracts/package.json index 750649e98b..be24b04819 100644 --- a/target_chains/ton/contracts/package.json +++ b/target_chains/ton/contracts/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "start": "blueprint run", - "build:blueprint": "echo Pyth | blueprint build", + "build": "blueprint build Main", "test:unit": "jest --verbose" }, "devDependencies": {