diff --git a/examples/send-donation/Znap.toml b/examples/send-donation/Znap.toml index 2f4177a..a2c245c 100644 --- a/examples/send-donation/Znap.toml +++ b/examples/send-donation/Znap.toml @@ -1,4 +1,5 @@ identity = "~/.config/solana/id.json" +rpc_url = "http://api.devnet.solana.com" [[collections]] name = "my-actions" diff --git a/tests/paths/Znap.toml b/tests/paths/Znap.toml index 9d1b3a3..ea75527 100644 --- a/tests/paths/Znap.toml +++ b/tests/paths/Znap.toml @@ -1,4 +1,5 @@ identity = "~/.config/solana/id.json" +rpc_url = "http://api.devnet.solana.com" [[collections]] name = "prefix" diff --git a/tests/send-donation/Cargo.toml b/tests/send-donation/Cargo.toml index aacbb12..3049ad0 100644 --- a/tests/send-donation/Cargo.toml +++ b/tests/send-donation/Cargo.toml @@ -1,2 +1,6 @@ +[workspace] +members = ["collections/*"] +resolver = "2" + [patch.crates-io] curve25519-dalek = { git = "https://github.com/dalek-cryptography/curve25519-dalek", rev = "8274d5cbb6fc3f38cdc742b4798173895cd2a290" } diff --git a/tests/send-donation/Znap.toml b/tests/send-donation/Znap.toml index 2f4177a..a2c245c 100644 --- a/tests/send-donation/Znap.toml +++ b/tests/send-donation/Znap.toml @@ -1,4 +1,5 @@ identity = "~/.config/solana/id.json" +rpc_url = "http://api.devnet.solana.com" [[collections]] name = "my-actions" diff --git a/znap-cli/src/commands/deploy.rs b/znap-cli/src/commands/deploy.rs index b34ac8a..13e8933 100644 --- a/znap-cli/src/commands/deploy.rs +++ b/znap-cli/src/commands/deploy.rs @@ -12,7 +12,7 @@ pub fn run(name: &str, project: &str) { generate_collection_executable_files(&config, collection); // Deploy to shuttle - deploy_to_shuttle(project, &config, collection); + deploy_to_shuttle(project, collection); } else { panic!("Collection not found in the workspace.") } diff --git a/znap-cli/src/commands/new.rs b/znap-cli/src/commands/new.rs index 5088945..284b4aa 100644 --- a/znap-cli/src/commands/new.rs +++ b/znap-cli/src/commands/new.rs @@ -70,6 +70,7 @@ pub fn run(name: &str, dry_run: bool) { &toml::to_string(&Config { collections, identity: Some("~/.config/solana/id.json".to_string()), + rpc_url: Some("http://localhost:8899".to_string()), }) .unwrap(), ); diff --git a/znap-cli/src/template/collection_deploy_binary.rs b/znap-cli/src/template/collection_deploy_binary.rs index 91a8395..ebabc79 100644 --- a/znap-cli/src/template/collection_deploy_binary.rs +++ b/znap-cli/src/template/collection_deploy_binary.rs @@ -15,6 +15,12 @@ async fn main( .unwrap(); std::env::set_var("IDENTITY_KEYPAIR", identity_keypair); + let rpc_url = secrets + .get("RPC_URL") + .or_else(|| panic!("RPC_URL is missing")) + .unwrap(); + std::env::set_var("RPC_URL", rpc_url); + Ok({}::collection_router().into()) }} "#, diff --git a/znap-cli/src/utils/mod.rs b/znap-cli/src/utils/mod.rs index 4e338eb..fb83d50 100644 --- a/znap-cli/src/utils/mod.rs +++ b/znap-cli/src/utils/mod.rs @@ -27,6 +27,7 @@ pub struct Collection { pub struct Config { pub collections: Option>, pub identity: Option, + pub rpc_url: Option, } pub fn get_cwd() -> PathBuf { @@ -38,13 +39,8 @@ pub fn get_config() -> Config { let znap_file_path = cwd.join("Znap.toml"); let znap_file = read_to_string(znap_file_path) .expect("Should be able to read Znap.toml file. Make sure you are in a Znap workspace."); - let config: Config = - toml::from_str(&znap_file).expect("Znap.toml file should have the proper format"); - Config { - collections: config.collections, - identity: config.identity, - } + toml::from_str(&znap_file).expect("Znap.toml file should have the proper format") } fn get_identity(identity: &str) -> String { @@ -74,6 +70,10 @@ pub fn get_envs( env_vars.insert("IDENTITY_KEYPAIR_PATH", get_identity(i)); } + if let Some(rpc_url) = &config.rpc_url { + env_vars.insert("RPC_URL", rpc_url.to_string()); + } + if let Some(address) = address.or(Some(&collection.address)) { env_vars.insert("COLLECTION_ADDRESS", address.to_owned()); } @@ -157,18 +157,15 @@ pub fn wait_for_server(address: &str, port: &u16, protocol: &str) { } } -pub fn deploy_to_shuttle(project: &str, config: &Config, collection: &Collection) { - let working_dir = get_cwd().join(format!(".znap/collections/{}", collection.name)); - +pub fn deploy_to_shuttle(project: &str, collection: &Collection) { std::process::Command::new("cargo") - .envs(get_envs(config, collection, None, None, None)) .arg("shuttle") .arg("deploy") .arg("--allow-dirty") .arg("--name") .arg(project) .arg("--working-directory") - .arg(&working_dir) + .arg(get_cwd().join(format!(".znap/collections/{}", collection.name))) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .output() @@ -242,9 +239,14 @@ pub fn generate_collection_executable_files(config: &Config, collection: &Collec .unwrap_or_else(|_| panic!("Could not create .znap/{} folder", &collection.name)); let identity_keypair = get_identity_keypair(config, collection); + let rpc_url = config + .rpc_url + .as_ref() + .unwrap_or_else(|| panic!("RPC url is not defined")); let secrets_content = format!( - "IDENTITY_KEYPAIR=\"{}\"", - identity_keypair.to_base58_string() + "IDENTITY_KEYPAIR=\"{}\"\nRPC_URL=\"{}\"", + identity_keypair.to_base58_string(), + rpc_url, ); let secrets_path = znap_collection_path.join("Secrets.toml"); diff --git a/znap-syn/src/codegen/collection/handle_post.rs b/znap-syn/src/codegen/collection/handle_post.rs index 169d0ff..82a6649 100644 --- a/znap-syn/src/codegen/collection/handle_post.rs +++ b/znap-syn/src/codegen/collection/handle_post.rs @@ -45,7 +45,19 @@ pub fn generate(collection_mod: &CollectionMod) -> TokenStream { env: znap::env::Env::default(), }; let znap::ActionTransaction { transaction, message } = #create_transaction_fn(&context).await?; - let transaction_with_identity = znap::add_action_identity_proof(transaction, &context.env.keypair); + let mut transaction_with_identity = znap::add_action_identity_proof(transaction, &context.env.keypair); + let rpc_client = solana_client::rpc_client::RpcClient::new_with_commitment( + context.env.rpc_url, + solana_sdk::commitment_config::CommitmentConfig::confirmed(), + ); + let recent_blockhash = rpc_client + .get_latest_blockhash() + .or_else(|_| Err(Error::new( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + "FetchBlockhashRequestFailed".to_string(), + "The server could not fetch the blockhash".to_string(), + )))?; + transaction_with_identity.message.recent_blockhash = recent_blockhash; let serialized_transaction = bincode::serialize(&transaction_with_identity).unwrap(); let encoded_transaction = BASE64_STANDARD.encode(serialized_transaction); diff --git a/znap/Cargo.toml b/znap/Cargo.toml index 10a2232..403c282 100644 --- a/znap/Cargo.toml +++ b/znap/Cargo.toml @@ -19,6 +19,7 @@ solana-sdk = { workspace = true } base64 = "0.22.1" bincode = "1.3.3" handlebars = "5.1.2" +solana-client = "2.0.1" # local znap-macros = { path = "../znap-macros", version = "0.1.30" } diff --git a/znap/src/env.rs b/znap/src/env.rs index 1f093ae..31d0dbd 100644 --- a/znap/src/env.rs +++ b/znap/src/env.rs @@ -6,6 +6,7 @@ use solana_sdk::signature::Keypair; pub struct Env { pub identity: Vec, pub keypair: Keypair, + pub rpc_url: String, } impl Default for Env { @@ -28,6 +29,12 @@ impl Default for Env { let identity = keypair.to_bytes().to_vec(); - Self { identity, keypair } + let rpc_url = var("RPC_URL").expect("Cannot found `RPC_URL` env var"); + + Self { + identity, + keypair, + rpc_url, + } } } diff --git a/znap/src/lib.rs b/znap/src/lib.rs index c71364c..3dcea4a 100644 --- a/znap/src/lib.rs +++ b/znap/src/lib.rs @@ -89,6 +89,7 @@ use solana_sdk::transaction::Transaction; pub extern crate base64; pub extern crate bincode; pub extern crate colored; +pub extern crate solana_client; pub extern crate tower_http; pub extern crate znap_macros; @@ -102,6 +103,7 @@ pub mod prelude { pub use base64; pub use bincode; pub use colored; + pub use solana_client; pub use tower_http; pub use znap_macros::{collection, Action, ErrorCode}; }