@@ -47,6 +47,7 @@ function setNestedValue(obj: any, path: string[], value: any): void {
4747 } , obj ) ;
4848 target [ lastKey ] = value ;
4949}
50+
5051import { NTT , SolanaNtt } from "@wormhole-foundation/sdk-solana-ntt" ;
5152import type { EvmNtt , EvmNttWormholeTranceiver } from "@wormhole-foundation/sdk-evm-ntt" ;
5253import type { EvmChains , EvmNativeSigner , EvmUnsignedTransaction } from "@wormhole-foundation/sdk-evm" ;
@@ -1657,6 +1658,8 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
16571658) : Promise < ChainAddress < C > > {
16581659 ensureNttRoot ( pwd ) ;
16591660
1661+ checkSolanaVersion ( pwd ) ;
1662+
16601663 // TODO: if the binary is provided, we should not check addresses in the source tree. (so we should move around the control flow a bit)
16611664 // TODO: factor out some of this into separate functions to help readability of this function (maybe even move to a different file)
16621665
@@ -1790,7 +1793,7 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
17901793 } else {
17911794 // build the program
17921795 // TODO: build with docker
1793- checkAnchorVersion ( ) ;
1796+ checkAnchorVersion ( pwd ) ;
17941797 const proc = Bun . spawn (
17951798 [ "anchor" ,
17961799 "build" ,
@@ -2413,22 +2416,120 @@ export function ensureNttRoot(pwd: string = ".") {
24132416 }
24142417}
24152418
2416- function checkAnchorVersion ( ) {
2417- const expected = "0.29.0" ;
2419+ // Check Solana toolchain version against Anchor.toml requirements
2420+ function checkSolanaVersion ( pwd : string ) : void {
24182421 try {
2419- execSync ( "which anchor" ) ;
2420- } catch {
2421- console . error ( "Anchor CLI is not installed.\nSee https://www.anchor-lang.com/docs/installation" )
2422- process . exit ( 1 ) ;
2422+ // Read required version from Anchor.toml
2423+ const anchorToml = fs . readFileSync ( `${ pwd } /solana/Anchor.toml` , 'utf8' ) ;
2424+ const versionMatch = anchorToml . match ( / s o l a n a _ v e r s i o n = " ( .+ ) " / ) ;
2425+
2426+ if ( ! versionMatch ) {
2427+ console . warn ( chalk . yellow ( "Warning: Could not find solana_version in Anchor.toml" ) ) ;
2428+ return ;
2429+ }
2430+
2431+ const requiredVersion = versionMatch [ 1 ] ;
2432+
2433+ // Get current Solana version and detect client type
2434+ let currentVersion : string ;
2435+ let clientType : 'agave' | 'solanalabs' ;
2436+ try {
2437+ const output = execSync ( 'solana --version' , { encoding : 'utf8' , stdio : 'pipe' } ) ;
2438+ const versionMatch = output . match ( / s o l a n a - c l i ( \d + \. \d + \. \d + ) / ) ;
2439+ if ( ! versionMatch ) {
2440+ console . error ( chalk . red ( "Error: Could not parse solana CLI version" ) ) ;
2441+ process . exit ( 1 ) ;
2442+ }
2443+ currentVersion = versionMatch [ 1 ] ;
2444+
2445+ // Detect client type
2446+ if ( output . includes ( 'Agave' ) ) {
2447+ clientType = 'agave' ;
2448+ } else if ( output . includes ( 'SolanaLabs' ) ) {
2449+ clientType = 'solanalabs' ;
2450+ } else {
2451+ // Default to agave if we can't detect
2452+ clientType = 'agave' ;
2453+ }
2454+ } catch ( error ) {
2455+ console . error ( chalk . red ( "Error: solana CLI not found. Please install the Solana toolchain." ) ) ;
2456+ console . error ( chalk . yellow ( "Install with: sh -c \"$(curl -sSfL https://release.anza.xyz/stable/install)\"" ) ) ;
2457+ process . exit ( 1 ) ;
2458+ }
2459+
2460+ if ( currentVersion !== requiredVersion ) {
2461+ console . log ( chalk . yellow ( `Solana version mismatch detected:` ) ) ;
2462+ console . log ( chalk . yellow ( ` Required: ${ requiredVersion } (from Anchor.toml)` ) ) ;
2463+ console . log ( chalk . yellow ( ` Current: ${ currentVersion } ` ) ) ;
2464+ console . log ( chalk . yellow ( `\nSwitching to required version...` ) ) ;
2465+
2466+ // Run the appropriate version switch command
2467+ const installCommand = clientType === 'agave'
2468+ ? `agave-install init ${ requiredVersion } `
2469+ : `solana-install init ${ requiredVersion } ` ;
2470+
2471+ try {
2472+ execSync ( installCommand , { stdio : 'inherit' } ) ;
2473+ console . log ( chalk . green ( `Successfully switched to Solana version ${ requiredVersion } ` ) ) ;
2474+ } catch ( error ) {
2475+ console . error ( chalk . red ( `Failed to switch Solana version using ${ installCommand } ` ) ) ;
2476+ console . error ( chalk . red ( `Please run manually: ${ installCommand } ` ) ) ;
2477+ process . exit ( 1 ) ;
2478+ }
2479+ }
2480+ } catch ( error ) {
2481+ if ( error instanceof Error && 'code' in error && error . code === 'ENOENT' ) {
2482+ console . warn ( chalk . yellow ( "Warning: Could not read Anchor.toml file" ) ) ;
2483+ } else {
2484+ console . warn ( chalk . yellow ( `Warning: Failed to check Solana version: ${ error instanceof Error ? error . message : error } ` ) ) ;
2485+ }
24232486 }
2424- const version = execSync ( "anchor --version" ) . toString ( ) . trim ( ) ;
2425- // version looks like "anchor-cli 0.14.0"
2426- const [ _ , v ] = version . split ( " " ) ;
2427- if ( v !== expected ) {
2428- console . error ( `Anchor CLI version must be ${ expected } but is ${ v } ` ) ;
2429- process . exit ( 1 ) ;
2487+ }
2488+
2489+ function checkAnchorVersion ( pwd : string ) {
2490+ try {
2491+ // Read required version from Anchor.toml
2492+ const anchorToml = fs . readFileSync ( `${ pwd } /solana/Anchor.toml` , 'utf8' ) ;
2493+ const versionMatch = anchorToml . match ( / a n c h o r _ v e r s i o n = " ( .+ ) " / ) ;
2494+
2495+ if ( ! versionMatch ) {
2496+ console . error ( chalk . red ( "Error: Could not find anchor_version in Anchor.toml" ) ) ;
2497+ process . exit ( 1 ) ;
2498+ }
2499+
2500+ const expected = versionMatch [ 1 ] ;
2501+
2502+ // Check if Anchor CLI is installed
2503+ try {
2504+ execSync ( "which anchor" ) ;
2505+ } catch {
2506+ console . error ( "Anchor CLI is not installed.\nSee https://www.anchor-lang.com/docs/installation" )
2507+ process . exit ( 1 ) ;
2508+ }
2509+
2510+ // Get current Anchor version
2511+ const version = execSync ( "anchor --version" ) . toString ( ) . trim ( ) ;
2512+ // version looks like "anchor-cli 0.14.0"
2513+ const [ _ , v ] = version . split ( " " ) ;
2514+ if ( v !== expected ) {
2515+ console . error ( chalk . red ( `Anchor CLI version mismatch!` ) ) ;
2516+ console . error ( chalk . red ( ` Required: ${ expected } (from Anchor.toml)` ) ) ;
2517+ console . error ( chalk . red ( ` Current: ${ v } ` ) ) ;
2518+ console . error ( chalk . yellow ( `\nTo fix this, install the correct version of Anchor` ) ) ;
2519+ console . error ( chalk . gray ( "See https://www.anchor-lang.com/docs/installation" ) ) ;
2520+ process . exit ( 1 ) ;
2521+ }
2522+ } catch ( error ) {
2523+ if ( error instanceof Error && 'code' in error && error . code === 'ENOENT' ) {
2524+ console . error ( chalk . red ( "Error: Could not read Anchor.toml file" ) ) ;
2525+ console . error ( chalk . yellow ( `Expected file at: ${ pwd } /solana/Anchor.toml` ) ) ;
2526+ process . exit ( 1 ) ;
2527+ } else {
2528+ throw error ;
2529+ }
24302530 }
24312531}
2532+
24322533function loadConfig ( path : string ) : Config {
24332534 if ( ! fs . existsSync ( path ) ) {
24342535 console . error ( `File not found: ${ path } ` ) ;
0 commit comments