Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 90 additions & 5 deletions crates/cmds-solana/src/mint_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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<Signature>,
instructions: Option<Vec<Instruction>>,
}

const SOLANA_MINT_TOKEN: &str = "mint_token";
Expand Down Expand Up @@ -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> {
[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()
}

Expand All @@ -155,6 +172,71 @@ impl CommandTrait for SolanaMintToken {
)
.await?;

if input.generate_instructions {
return Ok(value::to_map(&Output {
signature: None,
instructions: Some(instructions),
})?);
}

// 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), 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! }
//
// 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(),
Expand All @@ -177,7 +259,10 @@ impl CommandTrait for SolanaMintToken {
None
};

Ok(value::to_map(&Output { signature })?)
Ok(value::to_map(&Output {
signature,
instructions: None,
})?)
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/cmds-solana/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down