Update instruction encoding format (#11363)
* Rework parsed instruction format * Rework parsed message accounts * Review comments
This commit is contained in:
@ -7,8 +7,10 @@ pub mod parse_accounts;
|
|||||||
pub mod parse_instruction;
|
pub mod parse_instruction;
|
||||||
pub mod parse_token;
|
pub mod parse_token;
|
||||||
|
|
||||||
use crate::{parse_accounts::parse_accounts, parse_instruction::parse};
|
use crate::{
|
||||||
use serde_json::{json, Value};
|
parse_accounts::{parse_accounts, ParsedAccount},
|
||||||
|
parse_instruction::{parse, ParsedInstruction},
|
||||||
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, UnixTimestamp},
|
clock::{Slot, UnixTimestamp},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
@ -23,7 +25,14 @@ use solana_sdk::{
|
|||||||
#[serde(rename_all = "camelCase", untagged)]
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
pub enum UiInstruction {
|
pub enum UiInstruction {
|
||||||
Compiled(UiCompiledInstruction),
|
Compiled(UiCompiledInstruction),
|
||||||
Parsed(Value),
|
Parsed(UiParsedInstruction),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
|
pub enum UiParsedInstruction {
|
||||||
|
Parsed(ParsedInstruction),
|
||||||
|
PartiallyDecoded(UiPartiallyDecodedInstruction),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A duplicate representation of a CompiledInstruction for pretty JSON serialization
|
/// A duplicate representation of a CompiledInstruction for pretty JSON serialization
|
||||||
@ -183,7 +192,7 @@ pub struct UiRawMessage {
|
|||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct UiParsedMessage {
|
pub struct UiParsedMessage {
|
||||||
pub account_keys: Value,
|
pub account_keys: Vec<ParsedAccount>,
|
||||||
pub recent_blockhash: String,
|
pub recent_blockhash: String,
|
||||||
pub instructions: Vec<UiInstruction>,
|
pub instructions: Vec<UiInstruction>,
|
||||||
}
|
}
|
||||||
@ -250,13 +259,15 @@ impl EncodedTransaction {
|
|||||||
instruction,
|
instruction,
|
||||||
&transaction.message.account_keys,
|
&transaction.message.account_keys,
|
||||||
) {
|
) {
|
||||||
UiInstruction::Parsed(parsed_instruction)
|
UiInstruction::Parsed(UiParsedInstruction::Parsed(
|
||||||
|
parsed_instruction,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
UiInstruction::Parsed(json!(
|
UiInstruction::Parsed(UiParsedInstruction::PartiallyDecoded(
|
||||||
UiPartiallyDecodedInstruction::from(
|
UiPartiallyDecodedInstruction::from(
|
||||||
instruction,
|
instruction,
|
||||||
&transaction.message.account_keys
|
&transaction.message.account_keys,
|
||||||
)
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
use serde_json::{json, Map, Value};
|
|
||||||
use solana_sdk::message::Message;
|
use solana_sdk::message::Message;
|
||||||
|
|
||||||
type AccountAttributes = Vec<AccountAttribute>;
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
enum AccountAttribute {
|
pub struct ParsedAccount {
|
||||||
Signer,
|
pub pubkey: String,
|
||||||
Writable,
|
pub writable: bool,
|
||||||
|
pub signer: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_accounts(message: &Message) -> Value {
|
pub fn parse_accounts(message: &Message) -> Vec<ParsedAccount> {
|
||||||
let mut accounts: Map<String, Value> = Map::new();
|
let mut accounts: Vec<ParsedAccount> = vec![];
|
||||||
for (i, account_key) in message.account_keys.iter().enumerate() {
|
for (i, account_key) in message.account_keys.iter().enumerate() {
|
||||||
let mut attributes: AccountAttributes = vec![];
|
accounts.push(ParsedAccount {
|
||||||
if message.is_writable(i) {
|
pubkey: account_key.to_string(),
|
||||||
attributes.push(AccountAttribute::Writable);
|
writable: message.is_writable(i),
|
||||||
|
signer: message.is_signer(i),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if message.is_signer(i) {
|
accounts
|
||||||
attributes.push(AccountAttribute::Signer);
|
|
||||||
}
|
|
||||||
accounts.insert(account_key.to_string(), json!(attributes));
|
|
||||||
}
|
|
||||||
json!(accounts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -44,13 +39,30 @@ mod test {
|
|||||||
};
|
};
|
||||||
message.account_keys = vec![pubkey0, pubkey1, pubkey2, pubkey3];
|
message.account_keys = vec![pubkey0, pubkey1, pubkey2, pubkey3];
|
||||||
|
|
||||||
let expected_json = json!({
|
assert_eq!(
|
||||||
pubkey0.to_string(): ["writable", "signer"],
|
parse_accounts(&message),
|
||||||
pubkey1.to_string(): ["signer"],
|
vec![
|
||||||
pubkey2.to_string(): ["writable"],
|
ParsedAccount {
|
||||||
pubkey3.to_string(): [],
|
pubkey: pubkey0.to_string(),
|
||||||
});
|
writable: true,
|
||||||
|
signer: true,
|
||||||
assert_eq!(parse_accounts(&message), expected_json);
|
},
|
||||||
|
ParsedAccount {
|
||||||
|
pubkey: pubkey1.to_string(),
|
||||||
|
writable: false,
|
||||||
|
signer: true,
|
||||||
|
},
|
||||||
|
ParsedAccount {
|
||||||
|
pubkey: pubkey2.to_string(),
|
||||||
|
writable: true,
|
||||||
|
signer: false,
|
||||||
|
},
|
||||||
|
ParsedAccount {
|
||||||
|
pubkey: pubkey3.to_string(),
|
||||||
|
writable: false,
|
||||||
|
signer: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::parse_token::parse_token;
|
use crate::parse_token::parse_token;
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use serde_json::{json, Value};
|
use serde_json::Value;
|
||||||
use solana_account_decoder::parse_token::spl_token_id_v1_0;
|
use solana_account_decoder::parse_token::spl_token_id_v1_0;
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use std::{
|
use std::{
|
||||||
@ -21,7 +21,7 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ParseInstructionError {
|
pub enum ParseInstructionError {
|
||||||
#[error("{0:?} instruction not parsable")]
|
#[error("{0:?} instruction not parsable")]
|
||||||
InstructionNotParsable(ParsableProgram),
|
InstructionNotParsable(ParsableProgram),
|
||||||
@ -31,6 +31,25 @@ pub enum ParseInstructionError {
|
|||||||
|
|
||||||
#[error("Program not parsable")]
|
#[error("Program not parsable")]
|
||||||
ProgramNotParsable,
|
ProgramNotParsable,
|
||||||
|
|
||||||
|
#[error("Internal error, please report")]
|
||||||
|
SerdeJsonError(#[from] serde_json::error::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ParsedInstruction {
|
||||||
|
pub program: String,
|
||||||
|
pub program_id: String,
|
||||||
|
pub parsed: Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ParsedInstructionEnum {
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub instruction_type: String,
|
||||||
|
pub info: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
@ -44,17 +63,19 @@ pub fn parse(
|
|||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
instruction: &CompiledInstruction,
|
instruction: &CompiledInstruction,
|
||||||
account_keys: &[Pubkey],
|
account_keys: &[Pubkey],
|
||||||
) -> Result<Value, ParseInstructionError> {
|
) -> Result<ParsedInstruction, ParseInstructionError> {
|
||||||
let program_name = PARSABLE_PROGRAM_IDS
|
let program_name = PARSABLE_PROGRAM_IDS
|
||||||
.get(program_id)
|
.get(program_id)
|
||||||
.ok_or_else(|| ParseInstructionError::ProgramNotParsable)?;
|
.ok_or_else(|| ParseInstructionError::ProgramNotParsable)?;
|
||||||
let parsed_json = match program_name {
|
let parsed_json = match program_name {
|
||||||
ParsableProgram::SplMemo => parse_memo(instruction),
|
ParsableProgram::SplMemo => parse_memo(instruction),
|
||||||
ParsableProgram::SplToken => parse_token(instruction, account_keys)?,
|
ParsableProgram::SplToken => serde_json::to_value(parse_token(instruction, account_keys)?)?,
|
||||||
};
|
};
|
||||||
Ok(json!({
|
Ok(ParsedInstruction {
|
||||||
format!("{:?}", program_name).to_kebab_case(): parsed_json
|
program: format!("{:?}", program_name).to_kebab_case(),
|
||||||
}))
|
program_id: program_id.to_string(),
|
||||||
|
parsed: parsed_json,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_memo(instruction: &CompiledInstruction) -> Value {
|
fn parse_memo(instruction: &CompiledInstruction) -> Value {
|
||||||
@ -64,6 +85,7 @@ fn parse_memo(instruction: &CompiledInstruction) -> Value {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse() {
|
fn test_parse() {
|
||||||
@ -72,18 +94,16 @@ mod test {
|
|||||||
accounts: vec![],
|
accounts: vec![],
|
||||||
data: vec![240, 159, 166, 150],
|
data: vec![240, 159, 166, 150],
|
||||||
};
|
};
|
||||||
let expected_json = json!({
|
|
||||||
"spl-memo": "🦖"
|
|
||||||
});
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(&MEMO_PROGRAM_ID, &memo_instruction, &[]).unwrap(),
|
parse(&MEMO_PROGRAM_ID, &memo_instruction, &[]).unwrap(),
|
||||||
expected_json
|
ParsedInstruction {
|
||||||
|
program: "spl-memo".to_string(),
|
||||||
|
program_id: MEMO_PROGRAM_ID.to_string(),
|
||||||
|
parsed: json!("🦖"),
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let non_parsable_program_id = Pubkey::new(&[1; 32]);
|
let non_parsable_program_id = Pubkey::new(&[1; 32]);
|
||||||
assert_eq!(
|
assert!(parse(&non_parsable_program_id, &memo_instruction, &[]).is_err());
|
||||||
parse(&non_parsable_program_id, &memo_instruction, &[]).unwrap_err(),
|
|
||||||
ParseInstructionError::ProgramNotParsable
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::parse_instruction::{ParsableProgram, ParseInstructionError};
|
use crate::parse_instruction::{ParsableProgram, ParseInstructionError, ParsedInstructionEnum};
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
use solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey};
|
||||||
use spl_token_v1_0::instruction::TokenInstruction;
|
use spl_token_v1_0::instruction::TokenInstruction;
|
||||||
@ -6,7 +6,7 @@ use spl_token_v1_0::instruction::TokenInstruction;
|
|||||||
pub fn parse_token(
|
pub fn parse_token(
|
||||||
instruction: &CompiledInstruction,
|
instruction: &CompiledInstruction,
|
||||||
account_keys: &[Pubkey],
|
account_keys: &[Pubkey],
|
||||||
) -> Result<Value, ParseInstructionError> {
|
) -> Result<ParsedInstructionEnum, ParseInstructionError> {
|
||||||
let token_instruction = TokenInstruction::unpack(&instruction.data)
|
let token_instruction = TokenInstruction::unpack(&instruction.data)
|
||||||
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?;
|
.map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::SplToken))?;
|
||||||
if instruction.accounts.len() > account_keys.len() {
|
if instruction.accounts.len() > account_keys.len() {
|
||||||
@ -23,7 +23,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "initializeMint",
|
|
||||||
"mint": account_keys[instruction.accounts[0] as usize].to_string(),
|
"mint": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
"decimals":decimals,
|
"decimals":decimals,
|
||||||
@ -46,7 +45,10 @@ pub fn parse_token(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "initializeMint".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::InitializeAccount => {
|
TokenInstruction::InitializeAccount => {
|
||||||
if instruction.accounts.len() < 3 {
|
if instruction.accounts.len() < 3 {
|
||||||
@ -54,12 +56,14 @@ pub fn parse_token(
|
|||||||
ParsableProgram::SplToken,
|
ParsableProgram::SplToken,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(json!({
|
Ok(ParsedInstructionEnum {
|
||||||
"type": "initializeAccount",
|
instruction_type: "initializeAccount".to_string(),
|
||||||
|
info: json!({
|
||||||
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"mint": account_keys[instruction.accounts[1] as usize].to_string(),
|
"mint": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"owner": account_keys[instruction.accounts[2] as usize].to_string(),
|
"owner": account_keys[instruction.accounts[2] as usize].to_string(),
|
||||||
}))
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::InitializeMultisig { m } => {
|
TokenInstruction::InitializeMultisig { m } => {
|
||||||
if instruction.accounts.len() < 2 {
|
if instruction.accounts.len() < 2 {
|
||||||
@ -71,12 +75,14 @@ pub fn parse_token(
|
|||||||
for i in instruction.accounts[1..].iter() {
|
for i in instruction.accounts[1..].iter() {
|
||||||
signers.push(account_keys[*i as usize].to_string());
|
signers.push(account_keys[*i as usize].to_string());
|
||||||
}
|
}
|
||||||
Ok(json!({
|
Ok(ParsedInstructionEnum {
|
||||||
"type": "initializeMultisig",
|
instruction_type: "initializeMultisig".to_string(),
|
||||||
|
info: json!({
|
||||||
"multisig": account_keys[instruction.accounts[0] as usize].to_string(),
|
"multisig": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"signers": signers,
|
"signers": signers,
|
||||||
"m": m,
|
"m": m,
|
||||||
}))
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::Transfer { amount } => {
|
TokenInstruction::Transfer { amount } => {
|
||||||
if instruction.accounts.len() < 3 {
|
if instruction.accounts.len() < 3 {
|
||||||
@ -85,7 +91,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "transfer",
|
|
||||||
"source": account_keys[instruction.accounts[0] as usize].to_string(),
|
"source": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"destination": account_keys[instruction.accounts[1] as usize].to_string(),
|
"destination": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
@ -99,7 +104,10 @@ pub fn parse_token(
|
|||||||
"authority",
|
"authority",
|
||||||
"multisigAuthority",
|
"multisigAuthority",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "transfer".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::Approve { amount } => {
|
TokenInstruction::Approve { amount } => {
|
||||||
if instruction.accounts.len() < 3 {
|
if instruction.accounts.len() < 3 {
|
||||||
@ -108,7 +116,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "approve",
|
|
||||||
"source": account_keys[instruction.accounts[0] as usize].to_string(),
|
"source": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"delegate": account_keys[instruction.accounts[1] as usize].to_string(),
|
"delegate": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
@ -122,7 +129,10 @@ pub fn parse_token(
|
|||||||
"owner",
|
"owner",
|
||||||
"multisigOwner",
|
"multisigOwner",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "approve".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::Revoke => {
|
TokenInstruction::Revoke => {
|
||||||
if instruction.accounts.len() < 2 {
|
if instruction.accounts.len() < 2 {
|
||||||
@ -131,7 +141,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "revoke",
|
|
||||||
"source": account_keys[instruction.accounts[0] as usize].to_string(),
|
"source": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
});
|
});
|
||||||
let mut map = value.as_object_mut().unwrap();
|
let mut map = value.as_object_mut().unwrap();
|
||||||
@ -143,7 +152,10 @@ pub fn parse_token(
|
|||||||
"owner",
|
"owner",
|
||||||
"multisigOwner",
|
"multisigOwner",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "revoke".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::SetOwner => {
|
TokenInstruction::SetOwner => {
|
||||||
if instruction.accounts.len() < 3 {
|
if instruction.accounts.len() < 3 {
|
||||||
@ -152,7 +164,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "setOwner",
|
|
||||||
"owned": account_keys[instruction.accounts[0] as usize].to_string(),
|
"owned": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"newOwner": account_keys[instruction.accounts[1] as usize].to_string(),
|
"newOwner": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
});
|
});
|
||||||
@ -165,7 +176,10 @@ pub fn parse_token(
|
|||||||
"owner",
|
"owner",
|
||||||
"multisigOwner",
|
"multisigOwner",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "setOwner".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::MintTo { amount } => {
|
TokenInstruction::MintTo { amount } => {
|
||||||
if instruction.accounts.len() < 3 {
|
if instruction.accounts.len() < 3 {
|
||||||
@ -174,7 +188,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "mintTo",
|
|
||||||
"mint": account_keys[instruction.accounts[0] as usize].to_string(),
|
"mint": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"account": account_keys[instruction.accounts[1] as usize].to_string(),
|
"account": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
@ -188,7 +201,10 @@ pub fn parse_token(
|
|||||||
"owner",
|
"owner",
|
||||||
"multisigOwner",
|
"multisigOwner",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "mintTo".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::Burn { amount } => {
|
TokenInstruction::Burn { amount } => {
|
||||||
if instruction.accounts.len() < 2 {
|
if instruction.accounts.len() < 2 {
|
||||||
@ -197,7 +213,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "burn",
|
|
||||||
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"amount": amount,
|
"amount": amount,
|
||||||
});
|
});
|
||||||
@ -210,7 +225,10 @@ pub fn parse_token(
|
|||||||
"authority",
|
"authority",
|
||||||
"multisigAuthority",
|
"multisigAuthority",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "burn".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
TokenInstruction::CloseAccount => {
|
TokenInstruction::CloseAccount => {
|
||||||
if instruction.accounts.len() < 3 {
|
if instruction.accounts.len() < 3 {
|
||||||
@ -219,7 +237,6 @@ pub fn parse_token(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let mut value = json!({
|
let mut value = json!({
|
||||||
"type": "closeAccount",
|
|
||||||
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
"account": account_keys[instruction.accounts[0] as usize].to_string(),
|
||||||
"destination": account_keys[instruction.accounts[1] as usize].to_string(),
|
"destination": account_keys[instruction.accounts[1] as usize].to_string(),
|
||||||
});
|
});
|
||||||
@ -232,7 +249,10 @@ pub fn parse_token(
|
|||||||
"owner",
|
"owner",
|
||||||
"multisigOwner",
|
"multisigOwner",
|
||||||
);
|
);
|
||||||
Ok(value)
|
Ok(ParsedInstructionEnum {
|
||||||
|
instruction_type: "closeAccount".to_string(),
|
||||||
|
info: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,14 +331,16 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "initializeMint",
|
instruction_type: "initializeMint".to_string(),
|
||||||
|
info: json!({
|
||||||
"mint": keys[0].to_string(),
|
"mint": keys[0].to_string(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"decimals": 2,
|
"decimals": 2,
|
||||||
"account": keys[1].to_string(),
|
"account": keys[1].to_string(),
|
||||||
"owner": keys[2].to_string(),
|
"owner": keys[2].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let initialize_mint_ix = initialize_mint(
|
let initialize_mint_ix = initialize_mint(
|
||||||
@ -334,13 +356,15 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "initializeMint",
|
instruction_type: "initializeMint".to_string(),
|
||||||
|
info: json!({
|
||||||
"mint": keys[0].to_string(),
|
"mint": keys[0].to_string(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"decimals": 2,
|
"decimals": 2,
|
||||||
"account": keys[1].to_string(),
|
"account": keys[1].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let initialize_mint_ix = initialize_mint(
|
let initialize_mint_ix = initialize_mint(
|
||||||
@ -356,13 +380,15 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "initializeMint",
|
instruction_type: "initializeMint".to_string(),
|
||||||
|
info: json!({
|
||||||
"mint": keys[0].to_string(),
|
"mint": keys[0].to_string(),
|
||||||
"amount": 0,
|
"amount": 0,
|
||||||
"decimals": 2,
|
"decimals": 2,
|
||||||
"owner": keys[1].to_string(),
|
"owner": keys[1].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test InitializeAccount
|
// Test InitializeAccount
|
||||||
@ -377,12 +403,14 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "initializeAccount",
|
instruction_type: "initializeAccount".to_string(),
|
||||||
|
info: json!({
|
||||||
"account": keys[0].to_string(),
|
"account": keys[0].to_string(),
|
||||||
"mint": keys[1].to_string(),
|
"mint": keys[1].to_string(),
|
||||||
"owner": keys[2].to_string(),
|
"owner": keys[2].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test InitializeMultisig
|
// Test InitializeMultisig
|
||||||
@ -401,12 +429,14 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "initializeMultisig",
|
instruction_type: "initializeMultisig".to_string(),
|
||||||
|
info: json!({
|
||||||
"multisig": keys[0].to_string(),
|
"multisig": keys[0].to_string(),
|
||||||
"m": 2,
|
"m": 2,
|
||||||
"signers": keys[1..4].iter().map(|key| key.to_string()).collect::<Vec<String>>(),
|
"signers": keys[1..4].iter().map(|key| key.to_string()).collect::<Vec<String>>(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Transfer, incl multisig
|
// Test Transfer, incl multisig
|
||||||
@ -423,13 +453,15 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "transfer",
|
instruction_type: "transfer".to_string(),
|
||||||
|
info: json!({
|
||||||
"source": keys[1].to_string(),
|
"source": keys[1].to_string(),
|
||||||
"destination": keys[2].to_string(),
|
"destination": keys[2].to_string(),
|
||||||
"authority": keys[0].to_string(),
|
"authority": keys[0].to_string(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let transfer_ix = transfer(
|
let transfer_ix = transfer(
|
||||||
@ -445,14 +477,16 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "transfer",
|
instruction_type: "transfer".to_string(),
|
||||||
|
info: json!({
|
||||||
"source": keys[2].to_string(),
|
"source": keys[2].to_string(),
|
||||||
"destination": keys[3].to_string(),
|
"destination": keys[3].to_string(),
|
||||||
"multisigAuthority": keys[4].to_string(),
|
"multisigAuthority": keys[4].to_string(),
|
||||||
"signers": keys[0..2].iter().map(|key| key.to_string()).collect::<Vec<String>>(),
|
"signers": keys[0..2].iter().map(|key| key.to_string()).collect::<Vec<String>>(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Approve, incl multisig
|
// Test Approve, incl multisig
|
||||||
@ -469,13 +503,15 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "approve",
|
instruction_type: "approve".to_string(),
|
||||||
|
info: json!({
|
||||||
"source": keys[1].to_string(),
|
"source": keys[1].to_string(),
|
||||||
"delegate": keys[2].to_string(),
|
"delegate": keys[2].to_string(),
|
||||||
"owner": keys[0].to_string(),
|
"owner": keys[0].to_string(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let approve_ix = approve(
|
let approve_ix = approve(
|
||||||
@ -491,14 +527,16 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "approve",
|
instruction_type: "approve".to_string(),
|
||||||
|
info: json!({
|
||||||
"source": keys[2].to_string(),
|
"source": keys[2].to_string(),
|
||||||
"delegate": keys[3].to_string(),
|
"delegate": keys[3].to_string(),
|
||||||
"multisigOwner": keys[4].to_string(),
|
"multisigOwner": keys[4].to_string(),
|
||||||
"signers": keys[0..2].iter().map(|key| key.to_string()).collect::<Vec<String>>(),
|
"signers": keys[0..2].iter().map(|key| key.to_string()).collect::<Vec<String>>(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Revoke
|
// Test Revoke
|
||||||
@ -513,11 +551,13 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "revoke",
|
instruction_type: "revoke".to_string(),
|
||||||
|
info: json!({
|
||||||
"source": keys[1].to_string(),
|
"source": keys[1].to_string(),
|
||||||
"owner": keys[0].to_string(),
|
"owner": keys[0].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test SetOwner
|
// Test SetOwner
|
||||||
@ -533,12 +573,14 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "setOwner",
|
instruction_type: "setOwner".to_string(),
|
||||||
|
info: json!({
|
||||||
"owned": keys[1].to_string(),
|
"owned": keys[1].to_string(),
|
||||||
"newOwner": keys[2].to_string(),
|
"newOwner": keys[2].to_string(),
|
||||||
"owner": keys[0].to_string(),
|
"owner": keys[0].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test MintTo
|
// Test MintTo
|
||||||
@ -555,13 +597,15 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "mintTo",
|
instruction_type: "mintTo".to_string(),
|
||||||
|
info: json!({
|
||||||
"mint": keys[1].to_string(),
|
"mint": keys[1].to_string(),
|
||||||
"account": keys[2].to_string(),
|
"account": keys[2].to_string(),
|
||||||
"owner": keys[0].to_string(),
|
"owner": keys[0].to_string(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Burn
|
// Test Burn
|
||||||
@ -577,12 +621,14 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "burn",
|
instruction_type: "burn".to_string(),
|
||||||
|
info: json!({
|
||||||
"account": keys[1].to_string(),
|
"account": keys[1].to_string(),
|
||||||
"authority": keys[0].to_string(),
|
"authority": keys[0].to_string(),
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test CloseAccount
|
// Test CloseAccount
|
||||||
@ -598,12 +644,14 @@ mod test {
|
|||||||
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
let compiled_instruction = convert_compiled_instruction(&message.instructions[0]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_token(&compiled_instruction, &keys).unwrap(),
|
parse_token(&compiled_instruction, &keys).unwrap(),
|
||||||
json!({
|
ParsedInstructionEnum {
|
||||||
"type": "closeAccount",
|
instruction_type: "closeAccount".to_string(),
|
||||||
|
info: json!({
|
||||||
"account": keys[1].to_string(),
|
"account": keys[1].to_string(),
|
||||||
"destination": keys[2].to_string(),
|
"destination": keys[2].to_string(),
|
||||||
"owner": keys[0].to_string(),
|
"owner": keys[0].to_string(),
|
||||||
})
|
})
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user