Revert "Solitaire: Serialize CPI accounts as an AccountMeta vect..."
Revert submission 693 Reason for revert: Moving away from CPI abstraction Reverted Changes: I8c252e137:bridge, token_bridge: Use Many<T> I6a721e8a8:Solitaire: Add an explicit Many<T> type for nested... Ibdc94b4c6:Solitaire: Serialize CPI accounts as an AccountMet... Iefa59f5d4:Solitaire: Extend Peel to support CPI re-wrapping Change-Id: I01733d16862aeac79ad76dff4f58386641488b3e
This commit is contained in:
parent
f2490339de
commit
cbc5ae3ed1
|
@ -17,10 +17,7 @@ use byteorder::{
|
|||
BigEndian,
|
||||
ReadBytesExt,
|
||||
};
|
||||
use solana_program::{
|
||||
instruction::AccountMeta,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use solana_program::{instruction::AccountMeta, pubkey::Pubkey};
|
||||
use solitaire::{
|
||||
processors::seeded::Seeded,
|
||||
trace,
|
||||
|
@ -106,8 +103,8 @@ impl<'a, 'b: 'a, 'c, T: DeserializePayload> Peel<'a, 'b, 'c> for PayloadMessage<
|
|||
Data::persist(&self.0, program_id)
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut std::slice::Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
Data::<'b, PostedMessage, {AccountState::Initialized}>::to_partial_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
Data::to_partial_cpi_meta(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,10 +23,7 @@ use borsh::BorshSerialize;
|
|||
|
||||
use solitaire::{
|
||||
AccountState,
|
||||
CPICall,
|
||||
FromAccounts,
|
||||
Info,
|
||||
Mut,
|
||||
Sysvar,
|
||||
};
|
||||
pub use solitaire::{
|
||||
|
@ -55,9 +52,9 @@ pub enum AccEntry {
|
|||
SignerRO(Keypair),
|
||||
|
||||
/// Program addresses for unprivileged cross calls
|
||||
CPIProgram(Pubkey, Box<dyn ToInstruction>),
|
||||
CPIProgram(Pubkey),
|
||||
/// Program addresses for privileged cross calls
|
||||
CPIProgramSigner(Keypair, Box<dyn ToInstruction>),
|
||||
CPIProgramSigner(Keypair),
|
||||
|
||||
/// Key decided from SPL constants
|
||||
Sysvar(Pubkey),
|
||||
|
@ -74,16 +71,13 @@ pub trait Wrap {
|
|||
fn wrap(_: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox>;
|
||||
|
||||
/// If the implementor wants to sign using other AccEntry
|
||||
/// variants, they should override this. Multiple keypairs may be
|
||||
/// used in multi-account AccEntry variants.
|
||||
fn partial_signer_keypairs(a: &AccEntry) -> Vec<Keypair> {
|
||||
/// variants, they should override this.
|
||||
fn keypair(a: AccEntry) -> Option<Keypair> {
|
||||
use AccEntry::*;
|
||||
match a {
|
||||
// A panic on unwrap below here would imply solana keypair code does not understand its own bytes
|
||||
Signer(pair) | SignerRO(pair) => {
|
||||
vec![Keypair::from_bytes(pair.to_bytes().to_vec().as_slice()).unwrap()]
|
||||
}
|
||||
_other => vec![],
|
||||
Signer(pair) => Some(pair),
|
||||
SignerRO(pair) => Some(pair),
|
||||
_other => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -193,67 +187,11 @@ impl<'b> Wrap for Info<'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'b, T: Wrap> Wrap for Mut<T> {
|
||||
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
|
||||
match a {
|
||||
AccEntry::Unprivileged(_) | AccEntry::Signer(_) | AccEntry::Derived(_) => {
|
||||
Ok(T::wrap(a)?)
|
||||
}
|
||||
_other => Err(format!(
|
||||
"{} must be passed as a mutable AccEntry, such as Unprivileged, Signer or Derived",
|
||||
std::any::type_name::<Self>()
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, 'c, T> Wrap for CPICall<T> {
|
||||
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
|
||||
match a {
|
||||
AccEntry::CPIProgram(xprog_k, xprog_accs) => {
|
||||
let mut v = vec![AccountMeta::new_readonly(xprog_k.clone(), false)];
|
||||
v.append(&mut xprog_accs.acc_metas(&xprog_k)?);
|
||||
Ok(v)
|
||||
}
|
||||
AccEntry::CPIProgramSigner(xprog_pair, xprog_accs) => {
|
||||
let mut v = vec![AccountMeta::new_readonly(
|
||||
xprog_pair.pubkey().clone(),
|
||||
false,
|
||||
)];
|
||||
v.append(&mut xprog_accs.acc_metas(&xprog_pair.pubkey())?);
|
||||
Ok(v)
|
||||
}
|
||||
_other => Err(format!(
|
||||
"{} must be passed as CPIProgram or CPIProgramSigner",
|
||||
std::any::type_name::<Self>()
|
||||
)
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn partial_signer_keypairs(a: &AccEntry) -> Vec<Keypair> {
|
||||
match a {
|
||||
AccEntry::CPIProgram(xprog_k, xprog_accs) => xprog_accs.signer_keypairs(),
|
||||
AccEntry::CPIProgramSigner(xprog_pair, xprog_accs) => {
|
||||
let mut v = vec![Keypair::from_bytes(&xprog_pair.to_bytes()[..]).unwrap()];
|
||||
v.append(&mut xprog_accs.signer_keypairs());
|
||||
v
|
||||
}
|
||||
_other => vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used on client side to easily validate a program account struct + ix_data for a bare Solana call
|
||||
pub trait ToInstruction: std::fmt::Debug {
|
||||
/// Trait used on client side to easily validate a program accounts + ix_data for a bare Solana call
|
||||
pub trait ToInstruction {
|
||||
fn to_ix(
|
||||
&self,
|
||||
self,
|
||||
program_id: Pubkey,
|
||||
ix_data: &[u8],
|
||||
) -> StdResult<(Instruction, Vec<Keypair>), ErrBox>;
|
||||
|
||||
fn acc_metas(&self, program_id: &Pubkey) -> StdResult<Vec<AccountMeta>, ErrBox>;
|
||||
|
||||
fn signer_keypairs(&self) -> Vec<Keypair>;
|
||||
}
|
||||
|
|
|
@ -124,9 +124,6 @@ pub trait FromAccounts<'a, 'b: 'a, 'c> {
|
|||
where
|
||||
Self: Sized;
|
||||
|
||||
/// How many accounts do we expect to use for reconstructing Self?
|
||||
fn size_in_accounts() -> usize;
|
||||
|
||||
/// Turn a bunch of infos into relevant metas to facilitate CPI calls.
|
||||
fn to_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>>;
|
||||
/// Converts the accounts back to vector form to facilitate CPI calls.
|
||||
fn to_cpi_metas(&self) -> Vec<AccountMeta>;
|
||||
}
|
||||
|
|
|
@ -156,8 +156,8 @@ macro_rules! data_wrapper {
|
|||
Data::<'_, $embed, { $state }>::persist(self, program_id)
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut std::slice::Iter<solitaire::Info<'b>>) -> solitaire::Result<Vec<solana_program::instruction::AccountMeta>> {
|
||||
solitaire::Data::<'b, $embed, {$state}>::to_partial_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<solana_program::instruction::AccountMeta> {
|
||||
self.0.to_partial_cpi_meta()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
use borsh::BorshDeserialize;
|
||||
use solana_program::{
|
||||
instruction::AccountMeta,
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
system_program,
|
||||
sysvar::{
|
||||
|
@ -16,10 +15,7 @@ use solana_program::{
|
|||
SysvarId,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
slice::Iter,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
processors::seeded::{
|
||||
|
@ -28,7 +24,6 @@ use crate::{
|
|||
},
|
||||
types::*,
|
||||
Context,
|
||||
FromAccounts,
|
||||
Result,
|
||||
SolitaireError,
|
||||
};
|
||||
|
@ -45,15 +40,8 @@ pub trait Peel<'a, 'b: 'a, 'c> {
|
|||
|
||||
fn persist(&self, program_id: &Pubkey) -> Result<()>;
|
||||
|
||||
/// How many accounts from the on-chain account iterator
|
||||
/// constitute this peelable type? Important to customizefor
|
||||
/// multi-account types like FromAccounts implementors.
|
||||
fn partial_size_in_accounts() -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
/// Special method for turning an iterator into AccountMetas for CPI use cases.
|
||||
fn to_partial_cpi_metas(_: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>>;
|
||||
/// Special method for turning the type back into AccountMeta for CPI use cases.
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta>;
|
||||
}
|
||||
|
||||
/// Peel a Derived Key
|
||||
|
@ -77,13 +65,14 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>, const Seed: &'static str> Peel<'a, 'b,
|
|||
T::persist(self, program_id)
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
T::to_partial_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
self.0.to_partial_cpi_meta()
|
||||
}
|
||||
}
|
||||
|
||||
/// Peel a Mutable key.
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Mut<T> {
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Mut<T>
|
||||
{
|
||||
fn peel<I>(mut ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
ctx.immutable = false;
|
||||
match ctx.info().is_writable {
|
||||
|
@ -99,9 +88,6 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Mut<T> {
|
|||
fn persist(&self, program_id: &Pubkey) -> Result<()> {
|
||||
T::persist(self, program_id)
|
||||
}
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
T::to_partial_cpi_metas(infos)
|
||||
}
|
||||
}
|
||||
|
||||
/// Peel a Signer.
|
||||
|
@ -121,8 +107,8 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Signer<T> {
|
|||
T::persist(self, program_id)
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
T::to_partial_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
self.0.to_partial_cpi_meta()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,8 +129,8 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for System<T> {
|
|||
T::persist(self, program_id)
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
T::to_partial_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
self.0.to_partial_cpi_meta()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,8 +157,8 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
Info::to_partial_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
self.to_partial_cpi_meta()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,17 +179,14 @@ impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
let acc = infos
|
||||
.next()
|
||||
.ok_or_else(|| SolitaireError::ProgramError(ProgramError::AccountDataTooSmall))?;
|
||||
let meta = if acc.is_writable {
|
||||
AccountMeta::new(acc.key.clone(), acc.is_signer)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
let meta = if self.is_writable {
|
||||
AccountMeta::new(self.key.clone(), self.is_signer)
|
||||
} else {
|
||||
AccountMeta::new_readonly(acc.key.clone(), acc.is_signer)
|
||||
AccountMeta::new_readonly(self.key.clone(), self.is_signer)
|
||||
};
|
||||
|
||||
Ok(vec![meta])
|
||||
vec![meta]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,51 +268,7 @@ impl<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
Info::to_partial_cpi_metas(infos)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c> + FromAccounts<'a, 'b, 'c>> Peel<'a, 'b, 'c>
|
||||
for CPICall<T>
|
||||
{
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let xprog = ctx
|
||||
.iter
|
||||
.next()
|
||||
.ok_or_else(|| SolitaireError::ProgramError(ProgramError::AccountDataTooSmall))?;
|
||||
|
||||
let xprog_accounts = T::to_cpi_metas(ctx.iter)?;
|
||||
|
||||
if xprog_accounts.len() != T::size_in_accounts() {
|
||||
return Err(SolitaireError::ProgramError(
|
||||
ProgramError::AccountDataTooSmall,
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
xprog_id: xprog.key.clone(),
|
||||
xprog_accounts,
|
||||
callee_type: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn deps() -> Vec<Pubkey> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn persist(&self, program_id: &Pubkey) -> Result<()> {
|
||||
// Persisting cross accounts is not our business
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut Iter<Info<'b>>) -> Result<Vec<AccountMeta>> {
|
||||
T::to_cpi_metas(infos)
|
||||
}
|
||||
|
||||
fn partial_size_in_accounts() -> usize {
|
||||
T::size_in_accounts() + 1 // Nested type size + 1 for cross program ID
|
||||
fn to_partial_cpi_meta(&self) -> Vec<AccountMeta> {
|
||||
self.0.to_partial_cpi_meta()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
//! types that describe different kinds of accounts to target.
|
||||
|
||||
use borsh::BorshSerialize;
|
||||
use solana_program::{account_info::AccountInfo, instruction::AccountMeta, program::invoke_signed, pubkey::Pubkey, system_instruction, sysvar::Sysvar as SolanaSysvar};
|
||||
use std::{marker::PhantomData, ops::{
|
||||
use solana_program::{
|
||||
account_info::AccountInfo,
|
||||
program::invoke_signed,
|
||||
pubkey::Pubkey,
|
||||
system_instruction,
|
||||
sysvar::Sysvar as SolanaSysvar,
|
||||
};
|
||||
use std::ops::{
|
||||
Deref,
|
||||
DerefMut,
|
||||
}};
|
||||
};
|
||||
|
||||
use crate::{
|
||||
processors::seeded::Owned,
|
||||
|
@ -120,11 +126,3 @@ impl<const Seed: &'static str, T: BorshSerialize + Owned + Default>
|
|||
invoke_signed(&ix, ctx.accounts, &[&[Seed.as_bytes(), &[bump_seed]]]).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CPICall<T> {
|
||||
pub xprog_id: Pubkey,
|
||||
pub xprog_accounts: Vec<AccountMeta>,
|
||||
/// Helps preserve information about the type of cross program's arguments
|
||||
pub callee_type: PhantomData<T>,
|
||||
}
|
||||
|
|
|
@ -109,7 +109,6 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
|
|||
|
||||
let from_method = generate_from(&name, &input.data);
|
||||
let to_cpi_metas_method = generate_to_cpi_metas(&name, &input.data);
|
||||
let size_in_accounts_method = generate_size_in_accounts(&name, &input.data);
|
||||
let persist_method = generate_persist(&name, &input.data);
|
||||
let deps_method = generate_deps_fields(&name, &input.data);
|
||||
let expanded = quote! {
|
||||
|
@ -118,10 +117,7 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
|
|||
fn from<DataType>(pid: &'a solana_program::pubkey::Pubkey, iter: &'c mut std::slice::Iter<'a, solana_program::account_info::AccountInfo<'b>>, data: &'a DataType) -> solitaire::Result<Self> {
|
||||
#from_method
|
||||
}
|
||||
fn size_in_accounts() -> usize {
|
||||
#size_in_accounts_method
|
||||
}
|
||||
fn to_cpi_metas(infos: &'c mut std::slice::Iter<Info<'b>>) -> solitaire::Result<Vec<solana_program::instruction::AccountMeta>> {
|
||||
fn to_cpi_metas(&self) -> Vec<solana_program::instruction::AccountMeta> {
|
||||
#to_cpi_metas_method
|
||||
}
|
||||
}
|
||||
|
@ -145,12 +141,8 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
|
|||
solitaire::Persist::persist(self, program_id)
|
||||
}
|
||||
|
||||
fn partial_size_in_accounts() -> usize {
|
||||
Self::size_in_accounts()
|
||||
}
|
||||
|
||||
fn to_partial_cpi_metas(infos: &'c mut std::slice::Iter<Info<'b>>) -> solitaire::Result<Vec<solana_program::instruction::AccountMeta>> {
|
||||
Self::to_cpi_metas(infos)
|
||||
fn to_partial_cpi_meta(&self) -> Vec<solana_program::instruction::AccountMeta> {
|
||||
self.to_cpi_metas()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,10 +223,10 @@ fn generate_to_cpi_metas(name: &syn::Ident, data: &Data) -> TokenStream2 {
|
|||
let v_appends = fields.named.iter().map(|f| {
|
||||
// Field name, to assign to.
|
||||
let field_name = &f.ident;
|
||||
let field_ty = &f.ty;
|
||||
let ty = &f.ty;
|
||||
|
||||
quote! {
|
||||
v.append(&mut <#field_ty as Peel>::to_partial_cpi_metas(infos)?);
|
||||
v.append(&mut self.#field_name.to_partial_cpi_meta());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -246,11 +238,8 @@ fn generate_to_cpi_metas(name: &syn::Ident, data: &Data) -> TokenStream2 {
|
|||
quote! {
|
||||
let mut v = Vec::new();
|
||||
#(#v_appends;)*
|
||||
if v.len() != Self::size_in_accounts() {
|
||||
return Err(solitaire::SolitaireError::ProgramError(solana_program::program_error::ProgramError::InvalidAccountData));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
v
|
||||
}
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -337,30 +326,3 @@ fn generate_persist(name: &syn::Ident, data: &Data) -> TokenStream2 {
|
|||
Data::Enum(_) | Data::Union(_) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_size_in_accounts(name: &syn::Ident, data: &Data) -> TokenStream2 {
|
||||
if let Data::Struct(DataStruct {
|
||||
fields: Fields::Named(fields),
|
||||
..
|
||||
}) = data
|
||||
{
|
||||
// For each field, call the relevant partial_size_in_accounts method
|
||||
let size_additions = fields.named.iter().map(|f| {
|
||||
// Field name, to assign to.
|
||||
let field_name = &f.ident;
|
||||
let ty = &f.ty;
|
||||
|
||||
quote! {
|
||||
size += <#ty as Peel>::partial_size_in_accounts(); // #field_name
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
let mut size = 0;
|
||||
#(#size_additions;)*
|
||||
size
|
||||
}
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,13 @@ use syn::{
|
|||
DataStruct,
|
||||
DeriveInput,
|
||||
Fields,
|
||||
FieldsNamed,
|
||||
GenericParam,
|
||||
Generics,
|
||||
Index,
|
||||
};
|
||||
|
||||
pub fn generate_to_instruction(
|
||||
orig_struct_ident: &syn::Ident,
|
||||
name: &syn::Ident,
|
||||
impl_generics: &syn::ImplGenerics,
|
||||
data: &Data,
|
||||
) -> TokenStream2 {
|
||||
|
@ -33,144 +32,87 @@ pub fn generate_to_instruction(
|
|||
fields: Fields::Named(ref fields),
|
||||
..
|
||||
}) => {
|
||||
let client_struct_ident = syn::Ident::new(
|
||||
&format!("{}Accounts", orig_struct_ident.to_string()),
|
||||
Span::call_site(),
|
||||
);
|
||||
let client_struct_decl =
|
||||
generate_clientside_struct(&orig_struct_ident, &client_struct_ident, &fields);
|
||||
let expanded_appends = fields.named.iter().map(|field| {
|
||||
let name = &field.ident;
|
||||
let ty = &field.ty;
|
||||
|
||||
let acc_metas_ident = syn::Ident::new("acc_metas", Span::call_site());
|
||||
let acc_metas_appends = generate_acc_metas_appends(&acc_metas_ident, &fields);
|
||||
quote! {
|
||||
deps.append(&mut <#ty as solitaire::Peel>::deps());
|
||||
account_metas.append(&mut <#ty as solitaire_client::Wrap>::wrap(&self.#name)?);
|
||||
if let Some(pair) = <#ty as solitaire_client::Wrap>::keypair(self.#name) {
|
||||
signers.push(pair);
|
||||
}
|
||||
}
|
||||
});
|
||||
let client_struct_name =
|
||||
syn::Ident::new(&format!("{}Accounts", name.to_string()), Span::call_site());
|
||||
|
||||
let signers_ident = syn::Ident::new("signers", Span::call_site());
|
||||
let signers_appends = generate_signers_appends(&signers_ident, &fields);
|
||||
|
||||
let deps_ident = syn::Ident::new("deps", Span::call_site());
|
||||
let deps_appends = generate_deps_appends(&deps_ident, &fields);
|
||||
let client_struct_decl = generate_clientside_struct(&name, &client_struct_name, &data);
|
||||
|
||||
quote! {
|
||||
/// Solitaire-generated client-side #orig_struct_ident representation
|
||||
#[cfg(feature = "client")]
|
||||
#[derive(Debug)]
|
||||
#client_struct_decl
|
||||
/// Solitaire-generated client-side #name representation
|
||||
#[cfg(feature = "client")]
|
||||
#client_struct_decl
|
||||
|
||||
/// Solitaire-generatied ToInstruction implementation
|
||||
#[cfg(feature = "client")]
|
||||
impl #impl_generics solitaire_client::ToInstruction for #client_struct_ident {
|
||||
/// Solitaire-generatied ToInstruction implementation
|
||||
#[cfg(feature = "client")]
|
||||
impl #impl_generics solitaire_client::ToInstruction for #client_struct_name {
|
||||
fn to_ix(
|
||||
self,
|
||||
program_id: solana_program::pubkey::Pubkey,
|
||||
ix_data: &[u8]) -> std::result::Result<
|
||||
(solitaire_client::Instruction, Vec<solitaire_client::Keypair>),
|
||||
solitaire::ErrBox
|
||||
> {
|
||||
use solana_program::{pubkey::Pubkey, instruction::Instruction};
|
||||
let mut account_metas = Vec::new();
|
||||
let mut signers = Vec::new();
|
||||
let mut deps = Vec::new();
|
||||
|
||||
fn to_ix(
|
||||
&self,
|
||||
program_id: solana_program::pubkey::Pubkey,
|
||||
ix_data: &[u8]) -> std::result::Result<
|
||||
(solitaire_client::Instruction, Vec<solitaire_client::Keypair>),
|
||||
solitaire::ErrBox> {
|
||||
#(#expanded_appends;)*
|
||||
|
||||
use solana_program::{pubkey::Pubkey, instruction::Instruction};
|
||||
let mut #acc_metas_ident = Vec::new();
|
||||
let mut #signers_ident = Vec::new();
|
||||
let mut #deps_ident = Vec::new();
|
||||
// Add dependencies
|
||||
deps.dedup();
|
||||
let mut dep_ams = deps.iter().map(|v| solana_program::instruction::AccountMeta::new_readonly(*v, false)).collect();
|
||||
account_metas.append(&mut dep_ams);
|
||||
|
||||
#acc_metas_appends
|
||||
#deps_appends
|
||||
#signers_appends
|
||||
Ok((solana_program::instruction::Instruction::new_with_bytes(program_id,
|
||||
ix_data,
|
||||
account_metas), signers))
|
||||
|
||||
// Add dependencies
|
||||
#deps_ident.dedup();
|
||||
let mut dep_ams = deps.iter().map(|v| solana_program::instruction::AccountMeta::new_readonly(*v, false)).collect();
|
||||
#acc_metas_ident.append(&mut dep_ams);
|
||||
}
|
||||
|
||||
Ok((solana_program::instruction::Instruction::new_with_bytes(program_id,
|
||||
ix_data,
|
||||
#acc_metas_ident), #signers_ident))
|
||||
|
||||
}
|
||||
|
||||
fn acc_metas(&self, aprogram_id: &solana_program::pubkey::Pubkey) -> std::result::Result <Vec<solana_program::instruction::AccountMeta>, solitaire::ErrBox> {
|
||||
let mut #acc_metas_ident = Vec::new();
|
||||
|
||||
#acc_metas_appends
|
||||
|
||||
Ok(#acc_metas_ident)
|
||||
}
|
||||
|
||||
fn signer_keypairs(&self) -> Vec<solitaire_client::solana_sdk::signature::Keypair> {
|
||||
let mut #signers_ident = Vec::new();
|
||||
|
||||
#signers_appends
|
||||
|
||||
#signers_ident
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates Wrap::wrap() calls and appends to the account metas vec
|
||||
/// for the specified vec name ident and provided field data.
|
||||
pub fn generate_acc_metas_appends(vec_ident: &syn::Ident, data: &FieldsNamed) -> TokenStream2 {
|
||||
let appends = data.named.iter().map(|f| {
|
||||
let f_ty = &f.ty;
|
||||
let f_ident = &f.ident;
|
||||
quote! {
|
||||
#vec_ident.append(&mut <#f_ty as solitaire_client::Wrap>::wrap(&self.#f_ident)?);
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
#(#appends;)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates Peel::deps() calls and appends to the dependency pubkey
|
||||
/// vec for the specified vec name ident and provided field data.
|
||||
pub fn generate_deps_appends(vec_ident: &syn::Ident, data: &FieldsNamed) -> TokenStream2 {
|
||||
let appends = data.named.iter().map(|f| {
|
||||
let f_ty = &f.ty;
|
||||
quote! {
|
||||
#vec_ident.append(&mut <#f_ty as solitaire::Peel>::deps());
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
#(#appends;)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates Wrap::partial_signer_keypairs() calls and appends to the
|
||||
/// dependency pubkey vec for the specified vec name ident and
|
||||
/// provided field data.
|
||||
pub fn generate_signers_appends(vec_ident: &syn::Ident, data: &FieldsNamed) -> TokenStream2 {
|
||||
let appends = data.named.iter().map(|f| {
|
||||
let f_ty = &f.ty;
|
||||
let f_ident = &f.ident;
|
||||
quote! {
|
||||
#vec_ident.append(&mut <#f_ty as solitaire_client::Wrap>::partial_signer_keypairs(&self.#f_ident));
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
#(#appends;)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a client-side struct for sending relevant account pubkeys/keypairs/sysvars to RPC
|
||||
pub fn generate_clientside_struct(
|
||||
orig_struct_ident: &syn::Ident,
|
||||
client_struct_ident: &syn::Ident,
|
||||
fields: &FieldsNamed,
|
||||
name: &syn::Ident,
|
||||
client_struct_name: &syn::Ident,
|
||||
data: &Data,
|
||||
) -> TokenStream2 {
|
||||
let expanded_fields = fields.named.iter().map(|field| {
|
||||
let field_name = &field.ident;
|
||||
match *data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(ref fields),
|
||||
..
|
||||
}) => {
|
||||
let expanded_fields = fields.named.iter().map(|field| {
|
||||
let field_name = &field.ident;
|
||||
|
||||
quote! {
|
||||
#field_name: solitaire_client::AccEntry
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
#field_name: solitaire_client::AccEntry
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
/// This Solitaire-generated account represents #orig_struct_ident off-chain on client side.
|
||||
pub struct #client_struct_ident {
|
||||
#(pub #expanded_fields,)*
|
||||
quote! {
|
||||
pub struct #client_struct_name {
|
||||
#(pub #expanded_fields,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue