From b6771f02bbca3f346bf05fc05d50b4a773c1d6ae Mon Sep 17 00:00:00 2001 From: nilz3ro Date: Thu, 29 Dec 2022 16:08:14 -0500 Subject: [PATCH 1/2] add comments --- crates/cmds-solana/src/mint_token.rs | 67 +++++++++++++++++++++++++--- crates/cmds-solana/src/utils.rs | 3 ++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/crates/cmds-solana/src/mint_token.rs b/crates/cmds-solana/src/mint_token.rs index 0a7d085..cb885fe 100644 --- a/crates/cmds-solana/src/mint_token.rs +++ b/crates/cmds-solana/src/mint_token.rs @@ -3,6 +3,7 @@ use crate::{ utils::{execute, submit_transaction, ui_amount_to_amount}, }; use solana_program::instruction::Instruction; +use solana_sdk::transaction::Transaction; use spl_token::instruction::mint_to_checked; #[derive(Debug)] @@ -64,12 +65,14 @@ pub struct Input { amount: Decimal, #[serde(default = "value::default::bool_true")] submit: bool, + generate_instructions: bool, } #[derive(Serialize, Deserialize, Debug)] pub struct Output { #[serde(with = "value::signature::opt")] signature: Option, + instructions: Option>, } const SOLANA_MINT_TOKEN: &str = "mint_token"; @@ -129,15 +132,29 @@ impl CommandTrait for SolanaMintToken { required: false, passthrough: false, }, + CmdInput { + name: "generate_instructions".into(), + type_bounds: [ValueType::Bool].to_vec(), + required: false, // TODO: should this be required? + passthrough: false, + }, ] .to_vec() } fn outputs(&self) -> Vec { - [CmdOutput { - name: SIGNATURE.into(), - r#type: ValueType::String, - }] + [ + CmdOutput { + name: SIGNATURE.into(), + r#type: ValueType::String, + }, + CmdOutput { + name: "instructions".into(), + // We can add Instruction as a new variant to the ValueType enum + // or we could just use Json or a String to represent the encoded instructions. + r#type: ValueType::Json, + }, + ] .to_vec() } @@ -155,6 +172,43 @@ impl CommandTrait for SolanaMintToken { ) .await?; + if input.generate_instructions { + return Ok(value::to_map(&Output { + signature: None, + instructions: Some(instructions), + })?); + } + + // 1. create instructions (one or more nodes in the flow) + // 2. collect instructions from nodes that created instructions and collect the list of required signers, + // somewhere after the flow graph is constructed and all of the commands have run, + // 3. have a way of knowing if we need to dispatch a transaction after the flow has run. + // maybe we could add a new node to the graph and run that. + // 4. batch the instructions into as few transactions as possible (1232 bytes per tx); + // + // if we need to we can use TxV0/TxV1 to batch instructions into a single transaction, + // using the solana Look Up Table Program. + + // https://solana.wiki/docs/solidity-guide/transactions/#:~:text=The%20entire%20encoded%20size%20of%20a%20Solana%20transaction%20cannot%20exceed%201232%20bytes. + + // client.get_recent_blockhash(); + // let tx = Transaction::new(&[signers], &[instructions], recent_blockhash); + // let serialized = tx.s + + // update_an_nft(which_nft, authority) { + // is authority amir? + // if no { abort! } + // + // pda_signer = &[seed, seed2, persons_pubkey]; + // update_nft(which_nft, pda_signer_seeds) + // } + // + // new_program(args, outside_signers, persons_pubkey) { + // pda_signer = &[seed, seed2, persons_pubkey]; + // let signers = [...outside_signers, pda_signer]; + // token_metadata_program(args, [signers]) + // } + let (mut transaction, recent_blockhash) = execute( &ctx.solana_client, &input.fee_payer.pubkey(), @@ -177,7 +231,10 @@ impl CommandTrait for SolanaMintToken { None }; - Ok(value::to_map(&Output { signature })?) + Ok(value::to_map(&Output { + signature, + instructions: None, + })?) } } diff --git a/crates/cmds-solana/src/utils.rs b/crates/cmds-solana/src/utils.rs index 1b8ca0e..961ceee 100644 --- a/crates/cmds-solana/src/utils.rs +++ b/crates/cmds-solana/src/utils.rs @@ -40,6 +40,9 @@ impl KeypairExt for Keypair { } } +// TODO: Make this into a new command? +// the new Execute command can wrap the output of nodes that generate instructions, +// the output of this command could be a signature that can be used to track the status of the transaction pub async fn execute( client: &RpcClient, fee_payer: &Pubkey, From d53164810b557a7e7a4c6a6cbe64bd3a857253ff Mon Sep 17 00:00:00 2001 From: enzotar Date: Thu, 29 Dec 2022 15:04:32 -0800 Subject: [PATCH 2/2] add details --- crates/cmds-solana/src/mint_token.rs | 44 +++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/crates/cmds-solana/src/mint_token.rs b/crates/cmds-solana/src/mint_token.rs index cb885fe..3036f5e 100644 --- a/crates/cmds-solana/src/mint_token.rs +++ b/crates/cmds-solana/src/mint_token.rs @@ -179,22 +179,50 @@ impl CommandTrait for SolanaMintToken { })?); } - // 1. create instructions (one or more nodes in the flow) + // BUNDLING + // + // + // Option 1 - add execute as command + // - We keep what have and add the utils/execute() as a command + // - User deciding to bundle transactions changes instruction input to true on commands and + // connects the output(instruction, signers?) to the execute input + // which bundles the instructions into one transaction for the user to sign. + // + // Option 2 - add execute as command with auto-execute + // - We allow commands to auto-execute without having to add the execute command/connect all the edges. + // - We still add execute() as a command as it is really useful to have for users to bundle and run instructions + // + // + // + // + // Implementation + // + // 1. output instructions in the commands + // // 2. collect instructions from nodes that created instructions and collect the list of required signers, // somewhere after the flow graph is constructed and all of the commands have run, + // // 3. have a way of knowing if we need to dispatch a transaction after the flow has run. - // maybe we could add a new node to the graph and run that. - // 4. batch the instructions into as few transactions as possible (1232 bytes per tx); + // maybe we could add a new node to the graph and run that. // - // if we need to we can use TxV0/TxV1 to batch instructions into a single transaction, - // using the solana Look Up Table Program. - + // 4. batch the instructions into as few transactions as possible (1232 bytes per tx), ideally only one // https://solana.wiki/docs/solidity-guide/transactions/#:~:text=The%20entire%20encoded%20size%20of%20a%20Solana%20transaction%20cannot%20exceed%201232%20bytes. - + // + // If 1232 bytes are not enough, we can later upgrade to Solana new transaction version + // TxV0/TxV1 to batch instructions into a single transaction, + // using the solana Look Up Table Program. + // // client.get_recent_blockhash(); // let tx = Transaction::new(&[signers], &[instructions], recent_blockhash); // let serialized = tx.s + // + // 5. For later. Validation will be required to prevent tampering + // - we send transaction unsigned to user + // - we receive signed transaction, serialize, and check that message has not be tampered with + // - we partial sign and submit + // PDA + // // update_an_nft(which_nft, authority) { // is authority amir? // if no { abort! } @@ -203,12 +231,12 @@ impl CommandTrait for SolanaMintToken { // update_nft(which_nft, pda_signer_seeds) // } // + // new_program(args, outside_signers, persons_pubkey) { // pda_signer = &[seed, seed2, persons_pubkey]; // let signers = [...outside_signers, pda_signer]; // token_metadata_program(args, [signers]) // } - let (mut transaction, recent_blockhash) = execute( &ctx.solana_client, &input.fee_payer.pubkey(),