@@ -47,6 +47,7 @@ function setNestedValue(obj: any, path: string[], value: any): void {
47
47
} , obj ) ;
48
48
target [ lastKey ] = value ;
49
49
}
50
+
50
51
import { NTT , SolanaNtt } from "@wormhole-foundation/sdk-solana-ntt" ;
51
52
import type { EvmNtt , EvmNttWormholeTranceiver } from "@wormhole-foundation/sdk-evm-ntt" ;
52
53
import type { EvmChains , EvmNativeSigner , EvmUnsignedTransaction } from "@wormhole-foundation/sdk-evm" ;
@@ -1657,6 +1658,8 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
1657
1658
) : Promise < ChainAddress < C > > {
1658
1659
ensureNttRoot ( pwd ) ;
1659
1660
1661
+ checkSolanaVersion ( pwd ) ;
1662
+
1660
1663
// 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)
1661
1664
// TODO: factor out some of this into separate functions to help readability of this function (maybe even move to a different file)
1662
1665
@@ -1790,7 +1793,7 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
1790
1793
} else {
1791
1794
// build the program
1792
1795
// TODO: build with docker
1793
- checkAnchorVersion ( ) ;
1796
+ checkAnchorVersion ( pwd ) ;
1794
1797
const proc = Bun . spawn (
1795
1798
[ "anchor" ,
1796
1799
"build" ,
@@ -2413,22 +2416,120 @@ export function ensureNttRoot(pwd: string = ".") {
2413
2416
}
2414
2417
}
2415
2418
2416
- function checkAnchorVersion ( ) {
2417
- const expected = "0.29.0" ;
2419
+ // Check Solana toolchain version against Anchor.toml requirements
2420
+ function checkSolanaVersion ( pwd : string ) : void {
2418
2421
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
+ }
2423
2486
}
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
+ }
2430
2530
}
2431
2531
}
2532
+
2432
2533
function loadConfig ( path : string ) : Config {
2433
2534
if ( ! fs . existsSync ( path ) ) {
2434
2535
console . error ( `File not found: ${ path } ` ) ;
0 commit comments