rust_template.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. use crate::{
  2. config::ProgramWorkspace, create_files, override_or_create_files, solidity_template, Files,
  3. VERSION,
  4. };
  5. use anchor_syn::idl::types::Idl;
  6. use anyhow::Result;
  7. use clap::{Parser, ValueEnum};
  8. use heck::{ToLowerCamelCase, ToSnakeCase, ToUpperCamelCase};
  9. use solana_sdk::{
  10. pubkey::Pubkey,
  11. signature::{read_keypair_file, write_keypair_file, Keypair},
  12. signer::Signer,
  13. };
  14. use std::{
  15. fmt::Write as _,
  16. fs::{self, File},
  17. io::Write as _,
  18. path::Path,
  19. process::Stdio,
  20. };
  21. /// Program initialization template
  22. #[derive(Clone, Debug, Default, Eq, PartialEq, Parser, ValueEnum)]
  23. pub enum ProgramTemplate {
  24. /// Program with a single `lib.rs` file
  25. #[default]
  26. Single,
  27. /// Program with multiple files for instructions, state...
  28. Multiple,
  29. }
  30. /// Create a program from the given name and template.
  31. pub fn create_program(name: &str, template: ProgramTemplate) -> Result<()> {
  32. let program_path = Path::new("programs").join(name);
  33. let common_files = vec![
  34. ("Cargo.toml".into(), workspace_manifest().into()),
  35. (program_path.join("Cargo.toml"), cargo_toml(name)),
  36. (program_path.join("Xargo.toml"), xargo_toml().into()),
  37. ];
  38. let template_files = match template {
  39. ProgramTemplate::Single => create_program_template_single(name, &program_path),
  40. ProgramTemplate::Multiple => create_program_template_multiple(name, &program_path),
  41. };
  42. create_files(&[common_files, template_files].concat())
  43. }
  44. /// Create a program with a single `lib.rs` file.
  45. fn create_program_template_single(name: &str, program_path: &Path) -> Files {
  46. vec![(
  47. program_path.join("src").join("lib.rs"),
  48. format!(
  49. r#"use anchor_lang::prelude::*;
  50. declare_id!("{}");
  51. #[program]
  52. pub mod {} {{
  53. use super::*;
  54. pub fn initialize(ctx: Context<Initialize>) -> Result<()> {{
  55. Ok(())
  56. }}
  57. }}
  58. #[derive(Accounts)]
  59. pub struct Initialize {{}}
  60. "#,
  61. get_or_create_program_id(name),
  62. name.to_snake_case(),
  63. ),
  64. )]
  65. }
  66. /// Create a program with multiple files for instructions, state...
  67. fn create_program_template_multiple(name: &str, program_path: &Path) -> Files {
  68. let src_path = program_path.join("src");
  69. vec![
  70. (
  71. src_path.join("lib.rs"),
  72. format!(
  73. r#"pub mod constants;
  74. pub mod error;
  75. pub mod instructions;
  76. pub mod state;
  77. use anchor_lang::prelude::*;
  78. pub use constants::*;
  79. pub use instructions::*;
  80. pub use state::*;
  81. declare_id!("{}");
  82. #[program]
  83. pub mod {} {{
  84. use super::*;
  85. pub fn initialize(ctx: Context<Initialize>) -> Result<()> {{
  86. initialize::handler(ctx)
  87. }}
  88. }}
  89. "#,
  90. get_or_create_program_id(name),
  91. name.to_snake_case(),
  92. ),
  93. ),
  94. (
  95. src_path.join("constants.rs"),
  96. r#"use anchor_lang::prelude::*;
  97. #[constant]
  98. pub const SEED: &str = "anchor";
  99. "#
  100. .into(),
  101. ),
  102. (
  103. src_path.join("error.rs"),
  104. r#"use anchor_lang::prelude::*;
  105. #[error_code]
  106. pub enum ErrorCode {
  107. #[msg("Custom error message")]
  108. CustomError,
  109. }
  110. "#
  111. .into(),
  112. ),
  113. (
  114. src_path.join("instructions").join("mod.rs"),
  115. r#"pub mod initialize;
  116. pub use initialize::*;
  117. "#
  118. .into(),
  119. ),
  120. (
  121. src_path.join("instructions").join("initialize.rs"),
  122. r#"use anchor_lang::prelude::*;
  123. #[derive(Accounts)]
  124. pub struct Initialize {}
  125. pub fn handler(ctx: Context<Initialize>) -> Result<()> {
  126. Ok(())
  127. }
  128. "#
  129. .into(),
  130. ),
  131. (src_path.join("state").join("mod.rs"), r#""#.into()),
  132. ]
  133. }
  134. const fn workspace_manifest() -> &'static str {
  135. r#"[workspace]
  136. members = [
  137. "programs/*"
  138. ]
  139. resolver = "2"
  140. [profile.release]
  141. overflow-checks = true
  142. lto = "fat"
  143. codegen-units = 1
  144. [profile.release.build-override]
  145. opt-level = 3
  146. incremental = false
  147. codegen-units = 1
  148. "#
  149. }
  150. fn cargo_toml(name: &str) -> String {
  151. format!(
  152. r#"[package]
  153. name = "{0}"
  154. version = "0.1.0"
  155. description = "Created with Anchor"
  156. edition = "2021"
  157. [lib]
  158. crate-type = ["cdylib", "lib"]
  159. name = "{1}"
  160. [features]
  161. no-entrypoint = []
  162. no-idl = []
  163. no-log-ix-name = []
  164. cpi = ["no-entrypoint"]
  165. default = []
  166. [dependencies]
  167. anchor-lang = "{2}"
  168. "#,
  169. name,
  170. name.to_snake_case(),
  171. VERSION,
  172. )
  173. }
  174. fn xargo_toml() -> &'static str {
  175. r#"[target.bpfel-unknown-unknown.dependencies.std]
  176. features = []
  177. "#
  178. }
  179. /// Read the program keypair file or create a new one if it doesn't exist.
  180. pub fn get_or_create_program_id(name: &str) -> Pubkey {
  181. let keypair_path = Path::new("target")
  182. .join("deploy")
  183. .join(format!("{}-keypair.json", name.to_snake_case()));
  184. read_keypair_file(&keypair_path)
  185. .unwrap_or_else(|_| {
  186. let keypair = Keypair::new();
  187. write_keypair_file(&keypair, keypair_path).expect("Unable to create program keypair");
  188. keypair
  189. })
  190. .pubkey()
  191. }
  192. pub fn credentials(token: &str) -> String {
  193. format!(
  194. r#"[registry]
  195. token = "{token}"
  196. "#
  197. )
  198. }
  199. pub fn idl_ts(idl: &Idl) -> Result<String> {
  200. let mut idl = idl.clone();
  201. for acc in idl.accounts.iter_mut() {
  202. acc.name = acc.name.to_lower_camel_case();
  203. }
  204. let idl_json = serde_json::to_string_pretty(&idl)?;
  205. Ok(format!(
  206. r#"export type {} = {};
  207. export const IDL: {} = {};
  208. "#,
  209. idl.name.to_upper_camel_case(),
  210. idl_json,
  211. idl.name.to_upper_camel_case(),
  212. idl_json
  213. ))
  214. }
  215. pub fn deploy_js_script_host(cluster_url: &str, script_path: &str) -> String {
  216. format!(
  217. r#"
  218. const anchor = require('@coral-xyz/anchor');
  219. // Deploy script defined by the user.
  220. const userScript = require("{script_path}");
  221. async function main() {{
  222. const url = "{cluster_url}";
  223. const preflightCommitment = 'recent';
  224. const connection = new anchor.web3.Connection(url, preflightCommitment);
  225. const wallet = anchor.Wallet.local();
  226. const provider = new anchor.AnchorProvider(connection, wallet, {{
  227. preflightCommitment,
  228. commitment: 'recent',
  229. }});
  230. // Run the user's deploy script.
  231. userScript(provider);
  232. }}
  233. main();
  234. "#,
  235. )
  236. }
  237. pub fn deploy_ts_script_host(cluster_url: &str, script_path: &str) -> String {
  238. format!(
  239. r#"import * as anchor from '@coral-xyz/anchor';
  240. // Deploy script defined by the user.
  241. const userScript = require("{script_path}");
  242. async function main() {{
  243. const url = "{cluster_url}";
  244. const preflightCommitment = 'recent';
  245. const connection = new anchor.web3.Connection(url, preflightCommitment);
  246. const wallet = anchor.Wallet.local();
  247. const provider = new anchor.AnchorProvider(connection, wallet, {{
  248. preflightCommitment,
  249. commitment: 'recent',
  250. }});
  251. // Run the user's deploy script.
  252. userScript(provider);
  253. }}
  254. main();
  255. "#,
  256. )
  257. }
  258. pub fn deploy_script() -> &'static str {
  259. r#"// Migrations are an early feature. Currently, they're nothing more than this
  260. // single deploy script that's invoked from the CLI, injecting a provider
  261. // configured from the workspace's Anchor.toml.
  262. const anchor = require("@coral-xyz/anchor");
  263. module.exports = async function (provider) {
  264. // Configure client to use the provider.
  265. anchor.setProvider(provider);
  266. // Add your deploy script here.
  267. };
  268. "#
  269. }
  270. pub fn ts_deploy_script() -> &'static str {
  271. r#"// Migrations are an early feature. Currently, they're nothing more than this
  272. // single deploy script that's invoked from the CLI, injecting a provider
  273. // configured from the workspace's Anchor.toml.
  274. const anchor = require("@coral-xyz/anchor");
  275. module.exports = async function (provider) {
  276. // Configure client to use the provider.
  277. anchor.setProvider(provider);
  278. // Add your deploy script here.
  279. };
  280. "#
  281. }
  282. pub fn mocha(name: &str) -> String {
  283. format!(
  284. r#"const anchor = require("@coral-xyz/anchor");
  285. describe("{}", () => {{
  286. // Configure the client to use the local cluster.
  287. anchor.setProvider(anchor.AnchorProvider.env());
  288. it("Is initialized!", async () => {{
  289. // Add your test here.
  290. const program = anchor.workspace.{};
  291. const tx = await program.methods.initialize().rpc();
  292. console.log("Your transaction signature", tx);
  293. }});
  294. }});
  295. "#,
  296. name,
  297. name.to_upper_camel_case(),
  298. )
  299. }
  300. pub fn jest(name: &str) -> String {
  301. format!(
  302. r#"const anchor = require("@coral-xyz/anchor");
  303. describe("{}", () => {{
  304. // Configure the client to use the local cluster.
  305. anchor.setProvider(anchor.AnchorProvider.env());
  306. it("Is initialized!", async () => {{
  307. // Add your test here.
  308. const program = anchor.workspace.{};
  309. const tx = await program.methods.initialize().rpc();
  310. console.log("Your transaction signature", tx);
  311. }});
  312. }});
  313. "#,
  314. name,
  315. name.to_upper_camel_case(),
  316. )
  317. }
  318. pub fn package_json(jest: bool) -> String {
  319. if jest {
  320. format!(
  321. r#"{{
  322. "scripts": {{
  323. "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
  324. "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
  325. }},
  326. "dependencies": {{
  327. "@coral-xyz/anchor": "^{VERSION}"
  328. }},
  329. "devDependencies": {{
  330. "jest": "^29.0.3",
  331. "prettier": "^2.6.2"
  332. }}
  333. }}
  334. "#
  335. )
  336. } else {
  337. format!(
  338. r#"{{
  339. "scripts": {{
  340. "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
  341. "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
  342. }},
  343. "dependencies": {{
  344. "@coral-xyz/anchor": "^{VERSION}"
  345. }},
  346. "devDependencies": {{
  347. "chai": "^4.3.4",
  348. "mocha": "^9.0.3",
  349. "prettier": "^2.6.2"
  350. }}
  351. }}
  352. "#
  353. )
  354. }
  355. }
  356. pub fn ts_package_json(jest: bool) -> String {
  357. if jest {
  358. format!(
  359. r#"{{
  360. "scripts": {{
  361. "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
  362. "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
  363. }},
  364. "dependencies": {{
  365. "@coral-xyz/anchor": "^{VERSION}"
  366. }},
  367. "devDependencies": {{
  368. "@types/bn.js": "^5.1.0",
  369. "@types/jest": "^29.0.3",
  370. "jest": "^29.0.3",
  371. "prettier": "^2.6.2",
  372. "ts-jest": "^29.0.2",
  373. "typescript": "^4.3.5"
  374. }}
  375. }}
  376. "#
  377. )
  378. } else {
  379. format!(
  380. r#"{{
  381. "scripts": {{
  382. "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
  383. "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
  384. }},
  385. "dependencies": {{
  386. "@coral-xyz/anchor": "^{VERSION}"
  387. }},
  388. "devDependencies": {{
  389. "chai": "^4.3.4",
  390. "mocha": "^9.0.3",
  391. "ts-mocha": "^10.0.0",
  392. "@types/bn.js": "^5.1.0",
  393. "@types/chai": "^4.3.0",
  394. "@types/mocha": "^9.0.0",
  395. "typescript": "^4.3.5",
  396. "prettier": "^2.6.2"
  397. }}
  398. }}
  399. "#
  400. )
  401. }
  402. }
  403. pub fn ts_mocha(name: &str) -> String {
  404. format!(
  405. r#"import * as anchor from "@coral-xyz/anchor";
  406. import {{ Program }} from "@coral-xyz/anchor";
  407. import {{ {} }} from "../target/types/{}";
  408. describe("{}", () => {{
  409. // Configure the client to use the local cluster.
  410. anchor.setProvider(anchor.AnchorProvider.env());
  411. const program = anchor.workspace.{} as Program<{}>;
  412. it("Is initialized!", async () => {{
  413. // Add your test here.
  414. const tx = await program.methods.initialize().rpc();
  415. console.log("Your transaction signature", tx);
  416. }});
  417. }});
  418. "#,
  419. name.to_upper_camel_case(),
  420. name.to_snake_case(),
  421. name,
  422. name.to_upper_camel_case(),
  423. name.to_upper_camel_case(),
  424. )
  425. }
  426. pub fn ts_jest(name: &str) -> String {
  427. format!(
  428. r#"import * as anchor from "@coral-xyz/anchor";
  429. import {{ Program }} from "@coral-xyz/anchor";
  430. import {{ {} }} from "../target/types/{}";
  431. describe("{}", () => {{
  432. // Configure the client to use the local cluster.
  433. anchor.setProvider(anchor.AnchorProvider.env());
  434. const program = anchor.workspace.{} as Program<{}>;
  435. it("Is initialized!", async () => {{
  436. // Add your test here.
  437. const tx = await program.methods.initialize().rpc();
  438. console.log("Your transaction signature", tx);
  439. }});
  440. }});
  441. "#,
  442. name.to_upper_camel_case(),
  443. name.to_snake_case(),
  444. name,
  445. name.to_upper_camel_case(),
  446. name.to_upper_camel_case(),
  447. )
  448. }
  449. pub fn ts_config(jest: bool) -> &'static str {
  450. if jest {
  451. r#"{
  452. "compilerOptions": {
  453. "types": ["jest"],
  454. "typeRoots": ["./node_modules/@types"],
  455. "lib": ["es2015"],
  456. "module": "commonjs",
  457. "target": "es6",
  458. "esModuleInterop": true
  459. }
  460. }
  461. "#
  462. } else {
  463. r#"{
  464. "compilerOptions": {
  465. "types": ["mocha", "chai"],
  466. "typeRoots": ["./node_modules/@types"],
  467. "lib": ["es2015"],
  468. "module": "commonjs",
  469. "target": "es6",
  470. "esModuleInterop": true
  471. }
  472. }
  473. "#
  474. }
  475. }
  476. pub fn git_ignore() -> &'static str {
  477. r#"
  478. .anchor
  479. .DS_Store
  480. target
  481. **/*.rs.bk
  482. node_modules
  483. test-ledger
  484. .yarn
  485. "#
  486. }
  487. pub fn prettier_ignore() -> &'static str {
  488. r#"
  489. .anchor
  490. .DS_Store
  491. target
  492. node_modules
  493. dist
  494. build
  495. test-ledger
  496. "#
  497. }
  498. pub fn node_shell(
  499. cluster_url: &str,
  500. wallet_path: &str,
  501. programs: Vec<ProgramWorkspace>,
  502. ) -> Result<String> {
  503. let mut eval_string = format!(
  504. r#"
  505. const anchor = require('@coral-xyz/anchor');
  506. const web3 = anchor.web3;
  507. const PublicKey = anchor.web3.PublicKey;
  508. const Keypair = anchor.web3.Keypair;
  509. const __wallet = new anchor.Wallet(
  510. Keypair.fromSecretKey(
  511. Buffer.from(
  512. JSON.parse(
  513. require('fs').readFileSync(
  514. "{wallet_path}",
  515. {{
  516. encoding: "utf-8",
  517. }},
  518. ),
  519. ),
  520. ),
  521. ),
  522. );
  523. const __connection = new web3.Connection("{cluster_url}", "processed");
  524. const provider = new anchor.AnchorProvider(__connection, __wallet, {{
  525. commitment: "processed",
  526. preflightcommitment: "processed",
  527. }});
  528. anchor.setProvider(provider);
  529. "#,
  530. );
  531. for program in programs {
  532. write!(
  533. &mut eval_string,
  534. r#"
  535. anchor.workspace.{} = new anchor.Program({}, new PublicKey("{}"), provider);
  536. "#,
  537. program.name.to_upper_camel_case(),
  538. serde_json::to_string(&program.idl)?,
  539. program.program_id
  540. )?;
  541. }
  542. Ok(eval_string)
  543. }
  544. /// Test initialization template
  545. #[derive(Clone, Debug, Default, Eq, PartialEq, Parser, ValueEnum)]
  546. pub enum TestTemplate {
  547. /// Generate template for Mocha unit-test
  548. #[default]
  549. Mocha,
  550. /// Generate template for Jest unit-test
  551. Jest,
  552. /// Generate template for Rust unit-test
  553. Rust,
  554. }
  555. impl TestTemplate {
  556. pub fn get_test_script(&self, js: bool) -> &str {
  557. match &self {
  558. Self::Mocha => {
  559. if js {
  560. "yarn run mocha -t 1000000 tests/"
  561. } else {
  562. "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
  563. }
  564. }
  565. Self::Jest => {
  566. if js {
  567. "yarn run jest"
  568. } else {
  569. "yarn run jest --preset ts-jest"
  570. }
  571. }
  572. Self::Rust => "cargo test",
  573. }
  574. }
  575. pub fn create_test_files(
  576. &self,
  577. project_name: &str,
  578. js: bool,
  579. solidity: bool,
  580. program_id: &str,
  581. ) -> Result<()> {
  582. match self {
  583. Self::Mocha => {
  584. // Build the test suite.
  585. fs::create_dir_all("tests")?;
  586. if js {
  587. let mut test = File::create(format!("tests/{}.js", &project_name))?;
  588. if solidity {
  589. test.write_all(solidity_template::mocha(project_name).as_bytes())?;
  590. } else {
  591. test.write_all(mocha(project_name).as_bytes())?;
  592. }
  593. } else {
  594. let mut mocha = File::create(format!("tests/{}.ts", &project_name))?;
  595. if solidity {
  596. mocha.write_all(solidity_template::ts_mocha(project_name).as_bytes())?;
  597. } else {
  598. mocha.write_all(ts_mocha(project_name).as_bytes())?;
  599. }
  600. }
  601. }
  602. Self::Jest => {
  603. // Build the test suite.
  604. fs::create_dir_all("tests")?;
  605. let mut test = File::create(format!("tests/{}.test.js", &project_name))?;
  606. if solidity {
  607. test.write_all(solidity_template::jest(project_name).as_bytes())?;
  608. } else {
  609. test.write_all(jest(project_name).as_bytes())?;
  610. }
  611. }
  612. Self::Rust => {
  613. // Do not initilize git repo
  614. let exit = std::process::Command::new("cargo")
  615. .arg("new")
  616. .arg("--vcs")
  617. .arg("none")
  618. .arg("--lib")
  619. .arg("tests")
  620. .stderr(Stdio::inherit())
  621. .output()
  622. .map_err(|e| anyhow::format_err!("{}", e.to_string()))?;
  623. if !exit.status.success() {
  624. eprintln!("'cargo new --lib tests' failed");
  625. std::process::exit(exit.status.code().unwrap_or(1));
  626. }
  627. let mut files = Vec::new();
  628. let tests_path = Path::new("tests");
  629. files.extend(vec![(
  630. tests_path.join("Cargo.toml"),
  631. tests_cargo_toml(project_name),
  632. )]);
  633. files.extend(create_program_template_rust_test(
  634. project_name,
  635. tests_path,
  636. program_id,
  637. ));
  638. override_or_create_files(&files)?;
  639. }
  640. }
  641. Ok(())
  642. }
  643. }
  644. pub fn tests_cargo_toml(name: &str) -> String {
  645. format!(
  646. r#"[package]
  647. name = "tests"
  648. version = "0.1.0"
  649. description = "Created with Anchor"
  650. edition = "2021"
  651. [dependencies]
  652. anchor-client = "{0}"
  653. {1} = {{ version = "0.1.0", path = "../programs/{1}" }}
  654. "#,
  655. VERSION, name,
  656. )
  657. }
  658. /// Generate template for Rust unit-test
  659. fn create_program_template_rust_test(name: &str, tests_path: &Path, program_id: &str) -> Files {
  660. let src_path = tests_path.join("src");
  661. vec![
  662. (
  663. src_path.join("lib.rs"),
  664. r#"#[cfg(test)]
  665. mod test_initialize;
  666. "#
  667. .into(),
  668. ),
  669. (
  670. src_path.join("test_initialize.rs"),
  671. format!(
  672. r#"use std::str::FromStr;
  673. use anchor_client::{{
  674. solana_sdk::{{
  675. commitment_config::CommitmentConfig, pubkey::Pubkey, signature::read_keypair_file,
  676. }},
  677. Client, Cluster,
  678. }};
  679. #[test]
  680. fn test_initialize() {{
  681. let program_id = "{0}";
  682. let anchor_wallet = std::env::var("ANCHOR_WALLET").unwrap();
  683. let payer = read_keypair_file(&anchor_wallet).unwrap();
  684. let client = Client::new_with_options(Cluster::Localnet, &payer, CommitmentConfig::confirmed());
  685. let program_id = Pubkey::from_str(program_id).unwrap();
  686. let program = client.program(program_id).unwrap();
  687. let tx = program
  688. .request()
  689. .accounts({1}::accounts::Initialize {{}})
  690. .args({1}::instruction::Initialize {{}})
  691. .send()
  692. .expect("");
  693. println!("Your transaction signature {{}}", tx);
  694. }}
  695. "#,
  696. program_id,
  697. name.to_snake_case(),
  698. ),
  699. ),
  700. ]
  701. }