Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e45af05
feat: add new map type for patch
aspnxdd Mar 28, 2026
f9b5f24
feat: add patch functionality
aspnxdd Mar 28, 2026
b09900b
feat: add field type
aspnxdd Mar 28, 2026
33dec0f
feat: add parse_num macro
aspnxdd Mar 28, 2026
fdd1a2c
feat: add test for test_parse_num
aspnxdd Mar 29, 2026
392684f
fix: add missing cfg test proc macro
aspnxdd Mar 29, 2026
bee4b13
feat: add test for from_map fns
aspnxdd Mar 29, 2026
01225fc
refactor: improve code
aspnxdd Mar 29, 2026
e1d0f11
feat: add SET_ACCOUNT_PATCH_IDL
aspnxdd Mar 29, 2026
ddfae40
feat: add fn to obtain field offset and len
aspnxdd Mar 29, 2026
26c8a64
feat: implement patch via idl
aspnxdd Mar 29, 2026
4ed37c2
feat: add fixtures for idl test
aspnxdd Mar 29, 2026
923daee
feat: add test idl
aspnxdd Mar 29, 2026
8bb9e0c
feat: make field_value Value
aspnxdd Mar 29, 2026
ff60e19
fix: update SET_ACCOUNT_PATCH_IDL
aspnxdd Mar 29, 2026
1ee657d
fix: update SET_ACCOUNT_PATCH
aspnxdd Mar 29, 2026
62e7346
chore: update docs
aspnxdd Mar 29, 2026
a58bd9d
feat: add len checks
aspnxdd Mar 29, 2026
d2a9699
refactor: improve code semantics
aspnxdd Mar 29, 2026
773e058
feat: add tests for apply_patches
aspnxdd Mar 29, 2026
98195a6
Merge branch 'feat/patch-set-account-mutation' into feat/add-mutation…
aspnxdd Mar 29, 2026
30ed2ee
refactor: extract fn apply_patches_idl
aspnxdd Mar 29, 2026
70c250c
fix: change docs
aspnxdd Mar 29, 2026
34f3dab
refactor: rename patch to patch_raw
aspnxdd Mar 29, 2026
3751313
Merge branch 'feat/patch-set-account-mutation' into feat/add-mutation…
aspnxdd Mar 29, 2026
b1a8461
Update addons/svm/core/src/commands/setup_surfnet/set_account.rs
aspnxdd Apr 2, 2026
1aa7148
feat: make acc data bytes optional
aspnxdd Apr 2, 2026
1ea231f
feat: make patch_raw a single block item
aspnxdd Apr 2, 2026
6873a32
feat: rename to type/value
aspnxdd Apr 2, 2026
1302e59
Merge branch 'feat/patch-set-account-mutation' into feat/add-mutation…
aspnxdd Apr 2, 2026
b422994
fix: revert r#type
aspnxdd Apr 2, 2026
19d93ad
Merge branch 'feat/patch-set-account-mutation' into feat/add-mutation…
aspnxdd Apr 2, 2026
4e56316
fix: remove field_ from fields
aspnxdd Apr 2, 2026
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
98 changes: 83 additions & 15 deletions addons/svm/core/src/codec/idl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use std::str::FromStr;
use crate::typing::anchor as anchor_lang_idl;
use crate::typing::SvmValue;
use anchor_lang_idl::types::{
Idl, IdlArrayLen, IdlDefinedFields, IdlGenericArg, IdlInstruction, IdlType, IdlTypeDef,
IdlTypeDefGeneric, IdlTypeDefTy,
Idl, IdlAccount, IdlArrayLen, IdlDefinedFields, IdlGenericArg, IdlInstruction, IdlType,
IdlTypeDef, IdlTypeDefGeneric, IdlTypeDefTy,
};
use convert_idl::classic_idl_to_anchor_idl;
use solana_pubkey::Pubkey;
use std::fmt::Display;
use txtx_addon_kit::types::diagnostics::Diagnostic;
use txtx_addon_kit::{helpers::fs::FileLocation, indexmap::IndexMap, types::types::Value};
use txtx_addon_network_svm_types::idl::parse_bytes_to_value_with_expected_idl_type_with_leftover_bytes;
use txtx_addon_network_svm_types::I256;
use txtx_addon_network_svm_types::U256;

Expand Down Expand Up @@ -62,10 +63,26 @@ impl IdlRef {
.ok_or_else(|| diagnosed_error!("instruction '{instruction_name}' not found in IDL"))
}

pub fn get_account(&self, account_name: &str) -> Result<&IdlAccount, Diagnostic> {
self.idl
.accounts
.iter()
.find(|a| a.name == account_name)
.ok_or_else(|| diagnosed_error!("account '{account_name}' not found in IDL"))
}

pub fn get_types(&self) -> Vec<IdlTypeDef> {
self.idl.types.clone()
}

pub fn get_type(&self, type_name: &str) -> Result<&IdlTypeDef, Diagnostic> {
self.idl
.types
.iter()
.find(|t| t.name == type_name)
.ok_or_else(|| diagnosed_error!("type '{}' not found in IDL", type_name))
}

/// Encodes the arguments for a given instruction into a map of argument names to byte arrays.
pub fn get_encoded_args_map(
&self,
Expand Down Expand Up @@ -351,7 +368,9 @@ pub fn borsh_encode_value_to_idl_type(
// Handle two enum formats:
// 1. {"variant": "VariantName", "value": ...} (explicit format)
// 2. {"VariantName": ...} (decoded format from parse_bytes_to_value)
let (enum_variant, enum_variant_value) = if let Some(variant_field) = enum_value.get("variant") {
let (enum_variant, enum_variant_value) = if let Some(variant_field) =
enum_value.get("variant")
{
// Format 1: explicit variant field
let variant_name = variant_field.as_string().ok_or_else(|| {
format!(
Expand All @@ -374,12 +393,13 @@ pub fn borsh_encode_value_to_idl_type(
value.to_string(),
));
}
let (variant_name, variant_value) = enum_value.iter().next().ok_or_else(|| {
format!(
"unable to encode value ({}) as borsh enum: empty object",
value.to_string(),
)
})?;
let (variant_name, variant_value) =
enum_value.iter().next().ok_or_else(|| {
format!(
"unable to encode value ({}) as borsh enum: empty object",
value.to_string(),
)
})?;
(variant_name.as_str(), variant_value)
};

Expand Down Expand Up @@ -711,12 +731,10 @@ fn borsh_encode_bytes_to_idl_type(
name
))
}
IdlType::Generic(name) => {
Err(format!(
"cannot convert raw bytes to generic type '{}'; type must be resolved first",
name
))
}
IdlType::Generic(name) => Err(format!(
"cannot convert raw bytes to generic type '{}'; type must be resolved first",
name
)),
t => Err(format!("IDL type {:?} is not yet supported for bytes encoding", t)),
}
}
Expand Down Expand Up @@ -747,3 +765,53 @@ fn parse_generic_expected_type(
};
Ok(ty.clone())
}

/// Given account data bytes, the discriminator length, the type definition,
/// and a target field name, returns `(offset, byte_length, IdlType)` for that
/// field within the data buffer.
pub fn get_field_offset_in_account(
data: &[u8],
discriminator_len: usize,
type_def_ty: &IdlTypeDefTy,
field_name: &str,
idl_types: &Vec<IdlTypeDef>,
) -> Result<(usize, usize, IdlType), Diagnostic> {
let fields = match type_def_ty {
IdlTypeDefTy::Struct { fields: Some(IdlDefinedFields::Named(fields)) } => fields,
_ => {
return Err(diagnosed_error!("expected a struct with named fields for field patching"))
}
};

let mut offset = discriminator_len;
let mut cursor = &data[discriminator_len..];

for field in fields {
let before_len = cursor.len();
let (_value, rest) = parse_bytes_to_value_with_expected_idl_type_with_leftover_bytes(
cursor,
&field.ty,
idl_types,
&vec![],
&vec![],
)
.map_err(|e| {
diagnosed_error!(
"failed to decode field '{}' while computing offset: {}",
field.name,
e
)
})?;

let consumed = before_len - rest.len();

if field.name == field_name {
return Ok((offset, consumed, field.ty.clone()));
}

offset += consumed;
cursor = rest;
}

Err(diagnosed_error!("field '{}' not found in account type definition", field_name))
}
Loading
Loading