solitaire: remove recursive FromAccounts and 'c lifetime.
Solitaire parses accounts using two traits, FromAccounts and Peel. The FromAccounts derive macro generates a function, `FromAccounts::from()`, which calls `Peel::peel` to construct each field in the struct: ``` let example = Example { foo: Peel::peel(next_account_iter(accs)?), bar: Peel::peel(next_account_iter(accs)?), baz: Peel::peel(next_account_iter(accs)?), ..., } ``` The FromAccounts derivation also attempts to implement Peel for the structure itself however, which means `Example` itself is embeddable as a field in another accounts struct. This is only used in ClaimableVAA which is a large source of confusion and the complexity is not worth maintaining. This commit removes the recursion by: 1) Removing the `impl Peel` derived by FromAccounts. 2) Removes the AccountInfo iterator from Context as it is no longer needed. 3) Adds the current parsed account to Context instead, safe thanks to (2) 4) Move message out of ClaimableVAA and pass in to verify everywhere instead. 5) Removes Peel/FromAccounts from ClaimableVAA.
This commit is contained in:
parent
ec3bcfb40c
commit
82ea938317
|
@ -33,20 +33,18 @@ use crate::{
|
|||
},
|
||||
vaa::ClaimableVAA,
|
||||
DeserializePayload,
|
||||
PayloadMessage,
|
||||
CHAIN_ID_SOLANA,
|
||||
};
|
||||
|
||||
fn verify_governance<T>(vaa: &ClaimableVAA<T>) -> Result<()>
|
||||
fn verify_governance<T>(vaa: &PayloadMessage<T>) -> Result<()>
|
||||
where
|
||||
T: DeserializePayload,
|
||||
{
|
||||
let expected_emitter = std::env!("EMITTER_ADDRESS");
|
||||
let current_emitter = format!(
|
||||
"{}",
|
||||
Pubkey::new_from_array(vaa.message.meta().emitter_address)
|
||||
);
|
||||
let current_emitter = format!("{}", Pubkey::new_from_array(vaa.meta().emitter_address));
|
||||
// Fail if the emitter is not the known governance key, or the emitting chain is not Solana.
|
||||
if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA {
|
||||
if expected_emitter != current_emitter || vaa.meta().emitter_chain != CHAIN_ID_SOLANA {
|
||||
Err(InvalidGovernanceKey.into())
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -62,7 +60,10 @@ pub struct UpgradeContract<'b> {
|
|||
pub bridge: Mut<Bridge<'b, { AccountState::Initialized }>>,
|
||||
|
||||
/// GuardianSet change VAA
|
||||
pub vaa: ClaimableVAA<'b, GovernancePayloadUpgrade>,
|
||||
pub vaa: PayloadMessage<'b, GovernancePayloadUpgrade>,
|
||||
|
||||
/// Claim account representing whether the vaa has already been consumed.
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
/// PDA authority for the loader
|
||||
pub upgrade_authority: Derive<Info<'b>, "upgrade">,
|
||||
|
@ -95,12 +96,11 @@ pub fn upgrade_contract(
|
|||
_data: UpgradeContractData,
|
||||
) -> Result<()> {
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
let upgrade_ix = solana_program::bpf_loader_upgradeable::upgrade(
|
||||
ctx.program_id,
|
||||
&accs.vaa.message.new_contract,
|
||||
&accs.vaa.new_contract,
|
||||
accs.upgrade_authority.key,
|
||||
accs.spill.key,
|
||||
);
|
||||
|
@ -124,7 +124,10 @@ pub struct UpgradeGuardianSet<'b> {
|
|||
pub bridge: Mut<Bridge<'b, { AccountState::Initialized }>>,
|
||||
|
||||
/// GuardianSet change VAA
|
||||
pub vaa: ClaimableVAA<'b, GovernancePayloadGuardianSetChange>,
|
||||
pub vaa: PayloadMessage<'b, GovernancePayloadGuardianSetChange>,
|
||||
|
||||
/// Claim account representing whether the vaa has already been consumed.
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
/// Old guardian set
|
||||
pub guardian_set_old: Mut<GuardianSet<'b, { AccountState::Initialized }>>,
|
||||
|
@ -152,7 +155,6 @@ pub fn upgrade_guardian_set(
|
|||
}
|
||||
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.guardian_set_old.verify_derivation(
|
||||
ctx.program_id,
|
||||
&GuardianSetDerivationData {
|
||||
|
@ -166,7 +168,7 @@ pub fn upgrade_guardian_set(
|
|||
},
|
||||
)?;
|
||||
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
// Set expiration time for the old set
|
||||
accs.guardian_set_old.expiration_time =
|
||||
|
@ -203,7 +205,10 @@ pub struct SetFees<'b> {
|
|||
pub bridge: Mut<Bridge<'b, { AccountState::Initialized }>>,
|
||||
|
||||
/// Governance VAA
|
||||
pub vaa: ClaimableVAA<'b, GovernancePayloadSetMessageFee>,
|
||||
pub vaa: PayloadMessage<'b, GovernancePayloadSetMessageFee>,
|
||||
|
||||
/// Claim account representing whether the vaa has already been consumed.
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
}
|
||||
|
||||
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
||||
|
@ -211,8 +216,7 @@ pub struct SetFeesData {}
|
|||
|
||||
pub fn set_fees(ctx: &ExecutionContext, accs: &mut SetFees, _data: SetFeesData) -> Result<()> {
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
accs.bridge.config.fee = accs.vaa.fee.as_u64();
|
||||
|
||||
Ok(())
|
||||
|
@ -227,7 +231,10 @@ pub struct TransferFees<'b> {
|
|||
pub bridge: Mut<Bridge<'b, { AccountState::Initialized }>>,
|
||||
|
||||
/// Governance VAA
|
||||
pub vaa: ClaimableVAA<'b, GovernancePayloadTransferFees>,
|
||||
pub vaa: PayloadMessage<'b, GovernancePayloadTransferFees>,
|
||||
|
||||
/// Claim account representing whether the vaa has already been consumed.
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
/// Account collecting tx fees
|
||||
pub fee_collector: Mut<Derive<Info<'b>, "fee_collector">>,
|
||||
|
@ -266,7 +273,8 @@ pub fn transfer_fees(
|
|||
|
||||
accs.bridge.last_lamports = new_balance;
|
||||
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
// Transfer fees
|
||||
let transfer_ix = solana_program::system_instruction::transfer(
|
||||
|
|
|
@ -115,8 +115,8 @@ pub struct PayloadMessage<'b, T: DeserializePayload>(
|
|||
T,
|
||||
);
|
||||
|
||||
impl<'a, 'b: 'a, 'c, T: DeserializePayload> Peel<'a, 'b, 'c> for PayloadMessage<'b, T> {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self>
|
||||
impl<'a, 'b: 'a, T: DeserializePayload> Peel<'a, 'b> for PayloadMessage<'b, T> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -148,62 +148,73 @@ impl<'b, T: DeserializePayload> PayloadMessage<'b, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(FromAccounts)]
|
||||
pub struct ClaimableVAA<'b, T: DeserializePayload> {
|
||||
// Signed message for the transfer
|
||||
pub message: PayloadMessage<'b, T>,
|
||||
/// Claim account to prevent double spending.
|
||||
pub struct ClaimableVAA<'b>(Mut<Claim<'b, { AccountState::Uninitialized }>>);
|
||||
|
||||
// Claim account to prevent double spending
|
||||
pub claim: Mut<Claim<'b, { AccountState::Uninitialized }>>,
|
||||
}
|
||||
impl<'a, 'b: 'a> Peel<'a, 'b> for ClaimableVAA<'b> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
Mut::<Claim<'b, { AccountState::Uninitialized }>>::peel(ctx).map(|c| Self(c))
|
||||
}
|
||||
|
||||
impl<'b, T: DeserializePayload> Deref for ClaimableVAA<'b, T> {
|
||||
type Target = PayloadMessage<'b, T>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.message
|
||||
fn persist(&self, program_id: &Pubkey) -> Result<()> {
|
||||
Mut::<Claim<'b, { AccountState::Uninitialized }>>::persist(&self.0, program_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: DeserializePayload> ClaimableVAA<'b, T> {
|
||||
pub fn verify(&self, program_id: &Pubkey) -> Result<()> {
|
||||
trace!("Seq: {}", self.message.meta().sequence);
|
||||
impl<'b> ClaimableVAA<'b> {
|
||||
pub fn verify<T>(&self, ctx: &ExecutionContext, message: &PayloadMessage<'b, T>) -> Result<()>
|
||||
where
|
||||
T: DeserializePayload,
|
||||
{
|
||||
trace!("Seq: {}", message.meta().sequence);
|
||||
|
||||
// Verify that the claim account is derived correctly
|
||||
self.claim.verify_derivation(
|
||||
program_id,
|
||||
self.0.verify_derivation(
|
||||
ctx.program_id,
|
||||
&ClaimDerivationData {
|
||||
emitter_address: self.message.meta().emitter_address,
|
||||
emitter_chain: self.message.meta().emitter_chain,
|
||||
sequence: self.message.meta().sequence,
|
||||
emitter_address: message.meta().emitter_address,
|
||||
emitter_chain: message.meta().emitter_chain,
|
||||
sequence: message.meta().sequence,
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, T: DeserializePayload> ClaimableVAA<'b, T> {
|
||||
pub fn is_claimed(&self) -> bool {
|
||||
self.claim.claimed
|
||||
self.0.claimed
|
||||
}
|
||||
|
||||
pub fn claim(&mut self, ctx: &ExecutionContext, payer: &Pubkey) -> Result<()> {
|
||||
pub fn claim<T>(
|
||||
&mut self,
|
||||
ctx: &ExecutionContext,
|
||||
payer: &Pubkey,
|
||||
message: &PayloadMessage<'b, T>,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: DeserializePayload,
|
||||
{
|
||||
// Verify that the claim account is derived correctly before claiming.
|
||||
self.verify(ctx, message)?;
|
||||
|
||||
// Exit if the claim has already been made.
|
||||
if self.is_claimed() {
|
||||
return Err(VAAAlreadyExecuted.into());
|
||||
}
|
||||
|
||||
self.claim.create(
|
||||
// Claim the account by initializing it with a true boolean.
|
||||
self.0.create(
|
||||
&ClaimDerivationData {
|
||||
emitter_address: self.message.meta().emitter_address,
|
||||
emitter_chain: self.message.meta().emitter_chain,
|
||||
sequence: self.message.meta().sequence,
|
||||
emitter_address: message.meta().emitter_address,
|
||||
emitter_chain: message.meta().emitter_chain,
|
||||
sequence: message.meta().sequence,
|
||||
},
|
||||
ctx,
|
||||
payer,
|
||||
Exempt,
|
||||
)?;
|
||||
|
||||
self.claim.claimed = true;
|
||||
self.0.claimed = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -44,7 +44,8 @@ pub struct CompleteNative<'b> {
|
|||
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
||||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub vaa: ClaimableVAA<'b, PayloadTransfer>,
|
||||
pub vaa: PayloadMessage<'b, PayloadTransfer>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub to: Mut<Data<'b, SplAccount, { AccountState::MaybeInitialized }>>,
|
||||
|
@ -119,8 +120,7 @@ pub fn complete_native(
|
|||
}
|
||||
|
||||
// Prevent vaa double signing
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
if !accs.to.is_initialized() {
|
||||
let associated_addr = spl_associated_token_account::get_associated_token_address(
|
||||
|
@ -161,7 +161,8 @@ pub struct CompleteWrapped<'b> {
|
|||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
// Signed message for the transfer
|
||||
pub vaa: ClaimableVAA<'b, PayloadTransfer>,
|
||||
pub vaa: PayloadMessage<'b, PayloadTransfer>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
|
||||
|
@ -226,8 +227,7 @@ pub fn complete_wrapped(
|
|||
return Err(InvalidRecipient.into());
|
||||
}
|
||||
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
// Initialize the NFT if it doesn't already exist
|
||||
if !accs.meta.is_initialized() {
|
||||
|
|
|
@ -18,6 +18,7 @@ use bridge::{
|
|||
ClaimableVAA,
|
||||
DeserializePayload,
|
||||
},
|
||||
PayloadMessage,
|
||||
CHAIN_ID_SOLANA,
|
||||
};
|
||||
use solana_program::{
|
||||
|
@ -36,17 +37,14 @@ use solitaire::{
|
|||
};
|
||||
|
||||
// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
|
||||
fn verify_governance<T>(vaa: &ClaimableVAA<T>) -> Result<()>
|
||||
fn verify_governance<T>(vaa: &PayloadMessage<T>) -> Result<()>
|
||||
where
|
||||
T: DeserializePayload,
|
||||
{
|
||||
let expected_emitter = std::env!("EMITTER_ADDRESS");
|
||||
let current_emitter = format!(
|
||||
"{}",
|
||||
Pubkey::new_from_array(vaa.message.meta().emitter_address)
|
||||
);
|
||||
let current_emitter = format!("{}", Pubkey::new_from_array(vaa.meta().emitter_address));
|
||||
// Fail if the emitter is not the known governance key, or the emitting chain is not Solana.
|
||||
if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA {
|
||||
if expected_emitter != current_emitter || vaa.meta().emitter_chain != CHAIN_ID_SOLANA {
|
||||
Err(InvalidGovernanceKey.into())
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -59,7 +57,10 @@ pub struct UpgradeContract<'b> {
|
|||
pub payer: Mut<Signer<Info<'b>>>,
|
||||
|
||||
/// GuardianSet change VAA
|
||||
pub vaa: ClaimableVAA<'b, GovernancePayloadUpgrade>,
|
||||
pub vaa: PayloadMessage<'b, GovernancePayloadUpgrade>,
|
||||
|
||||
/// Claim account representing whether the vaa has already been consumed.
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
/// PDA authority for the loader
|
||||
pub upgrade_authority: Derive<Info<'b>, "upgrade">,
|
||||
|
@ -92,13 +93,11 @@ pub fn upgrade_contract(
|
|||
_data: UpgradeContractData,
|
||||
) -> Result<()> {
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
let upgrade_ix = solana_program::bpf_loader_upgradeable::upgrade(
|
||||
ctx.program_id,
|
||||
&accs.vaa.message.new_contract,
|
||||
&accs.vaa.new_contract,
|
||||
accs.upgrade_authority.key,
|
||||
accs.spill.key,
|
||||
);
|
||||
|
@ -117,10 +116,9 @@ pub fn upgrade_contract(
|
|||
pub struct RegisterChain<'b> {
|
||||
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
||||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub endpoint: Mut<Endpoint<'b, { AccountState::Uninitialized }>>,
|
||||
|
||||
pub vaa: ClaimableVAA<'b, PayloadGovernanceRegisterChain>,
|
||||
pub vaa: PayloadMessage<'b, PayloadGovernanceRegisterChain>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
}
|
||||
|
||||
impl<'a> From<&RegisterChain<'a>> for EndpointDerivationData {
|
||||
|
@ -146,8 +144,7 @@ pub fn register_chain(
|
|||
|
||||
// Claim VAA
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
if accs.vaa.chain == CHAIN_ID_SOLANA {
|
||||
return Err(InvalidChain.into());
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
};
|
||||
use bridge::{
|
||||
vaa::ClaimableVAA,
|
||||
PayloadMessage,
|
||||
CHAIN_ID_SOLANA,
|
||||
};
|
||||
use solana_program::account_info::AccountInfo;
|
||||
|
@ -35,7 +36,8 @@ pub struct CompleteNative<'b> {
|
|||
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
||||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub vaa: ClaimableVAA<'b, PayloadTransfer>,
|
||||
pub vaa: PayloadMessage<'b, PayloadTransfer>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub to: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||
|
@ -108,13 +110,12 @@ pub fn complete_native(
|
|||
if accs.vaa.to != accs.to.info().key.to_bytes() {
|
||||
return Err(InvalidRecipient.into());
|
||||
}
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.message.info().key.to_string()) {
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.info().key.to_string()) {
|
||||
return Err(InvalidVAA.into());
|
||||
}
|
||||
|
||||
// Prevent vaa double signing
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
let mut amount = accs.vaa.amount.as_u64();
|
||||
let mut fee = accs.vaa.fee.as_u64();
|
||||
|
@ -156,7 +157,8 @@ pub struct CompleteWrapped<'b> {
|
|||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
// Signed message for the transfer
|
||||
pub vaa: ClaimableVAA<'b, PayloadTransfer>,
|
||||
pub vaa: PayloadMessage<'b, PayloadTransfer>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
|
||||
|
@ -227,12 +229,11 @@ pub fn complete_wrapped(
|
|||
if accs.vaa.to != accs.to.info().key.to_bytes() {
|
||||
return Err(InvalidRecipient.into());
|
||||
}
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.message.info().key.to_string()) {
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.info().key.to_string()) {
|
||||
return Err(InvalidVAA.into());
|
||||
}
|
||||
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
// Mint tokens
|
||||
let mint_ix = spl_token::instruction::mint_to(
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::{
|
|||
};
|
||||
use bridge::{
|
||||
vaa::ClaimableVAA,
|
||||
PayloadMessage,
|
||||
CHAIN_ID_SOLANA,
|
||||
};
|
||||
use solana_program::account_info::AccountInfo;
|
||||
|
@ -94,7 +95,8 @@ pub struct CompleteNativeWithPayload<'b> {
|
|||
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
||||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub vaa: ClaimableVAA<'b, PayloadTransferWithPayload>,
|
||||
pub vaa: PayloadMessage<'b, PayloadTransferWithPayload>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub to: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||
|
@ -179,8 +181,7 @@ pub fn complete_native_with_payload(
|
|||
}
|
||||
|
||||
// Prevent vaa double signing
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
let mut amount = accs.vaa.amount.as_u64();
|
||||
|
||||
|
@ -209,7 +210,8 @@ pub struct CompleteWrappedWithPayload<'b> {
|
|||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
/// Signed message for the transfer
|
||||
pub vaa: ClaimableVAA<'b, PayloadTransferWithPayload>,
|
||||
pub vaa: PayloadMessage<'b, PayloadTransferWithPayload>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
|
||||
|
@ -291,8 +293,7 @@ pub fn complete_wrapped_with_payload(
|
|||
return Err(InvalidRecipient.into());
|
||||
}
|
||||
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
// Mint tokens
|
||||
let mint_ix = spl_token::instruction::mint_to(
|
||||
|
|
|
@ -21,6 +21,7 @@ use crate::{
|
|||
};
|
||||
use bridge::{
|
||||
vaa::ClaimableVAA,
|
||||
PayloadMessage,
|
||||
CHAIN_ID_SOLANA,
|
||||
};
|
||||
use solana_program::{
|
||||
|
@ -48,7 +49,8 @@ pub struct CreateWrapped<'b> {
|
|||
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||
|
||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||
pub vaa: ClaimableVAA<'b, PayloadAssetMeta>,
|
||||
pub vaa: PayloadMessage<'b, PayloadAssetMeta>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
// New Wrapped
|
||||
pub mint: Mut<WrappedMint<'b, { AccountState::MaybeInitialized }>>,
|
||||
|
@ -111,12 +113,11 @@ pub fn create_wrapped(
|
|||
accs.chain_registration
|
||||
.verify_derivation(ctx.program_id, &derivation_data)?;
|
||||
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.message.info().key.to_string()) {
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.info().key.to_string()) {
|
||||
return Err(InvalidVAA.into());
|
||||
}
|
||||
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
if accs.mint.is_initialized() {
|
||||
update_accounts(ctx, accs, data)
|
||||
|
|
|
@ -19,6 +19,7 @@ use bridge::{
|
|||
ClaimableVAA,
|
||||
DeserializePayload,
|
||||
},
|
||||
PayloadMessage,
|
||||
CHAIN_ID_SOLANA,
|
||||
};
|
||||
use solana_program::{
|
||||
|
@ -36,18 +37,15 @@ use solitaire::{
|
|||
*,
|
||||
};
|
||||
|
||||
/// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
|
||||
fn verify_governance<T>(vaa: &ClaimableVAA<T>) -> Result<()>
|
||||
// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
|
||||
fn verify_governance<T>(vaa: &PayloadMessage<T>) -> Result<()>
|
||||
where
|
||||
T: DeserializePayload,
|
||||
{
|
||||
let expected_emitter = std::env!("EMITTER_ADDRESS");
|
||||
let current_emitter = format!(
|
||||
"{}",
|
||||
Pubkey::new_from_array(vaa.message.meta().emitter_address)
|
||||
);
|
||||
let current_emitter = format!("{}", Pubkey::new_from_array(vaa.meta().emitter_address));
|
||||
// Fail if the emitter is not the known governance key, or the emitting chain is not Solana.
|
||||
if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA {
|
||||
if expected_emitter != current_emitter || vaa.meta().emitter_chain != CHAIN_ID_SOLANA {
|
||||
Err(InvalidGovernanceKey.into())
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -60,7 +58,8 @@ pub struct UpgradeContract<'b> {
|
|||
pub payer: Mut<Signer<Info<'b>>>,
|
||||
|
||||
/// GuardianSet change VAA
|
||||
pub vaa: ClaimableVAA<'b, GovernancePayloadUpgrade>,
|
||||
pub vaa: PayloadMessage<'b, GovernancePayloadUpgrade>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
|
||||
/// PDA authority for the loader
|
||||
pub upgrade_authority: Derive<Info<'b>, "upgrade">,
|
||||
|
@ -92,17 +91,16 @@ pub fn upgrade_contract(
|
|||
accs: &mut UpgradeContract,
|
||||
_data: UpgradeContractData,
|
||||
) -> Result<()> {
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.message.info().key.to_string()) {
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.info().key.to_string()) {
|
||||
return Err(InvalidVAA.into());
|
||||
}
|
||||
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
let upgrade_ix = solana_program::bpf_loader_upgradeable::upgrade(
|
||||
ctx.program_id,
|
||||
&accs.vaa.message.new_contract,
|
||||
&accs.vaa.new_contract,
|
||||
accs.upgrade_authority.key,
|
||||
accs.spill.key,
|
||||
);
|
||||
|
@ -124,7 +122,8 @@ pub struct RegisterChain<'b> {
|
|||
|
||||
pub endpoint: Mut<Endpoint<'b, { AccountState::Uninitialized }>>,
|
||||
|
||||
pub vaa: ClaimableVAA<'b, PayloadGovernanceRegisterChain>,
|
||||
pub vaa: PayloadMessage<'b, PayloadGovernanceRegisterChain>,
|
||||
pub vaa_claim: ClaimableVAA<'b>,
|
||||
}
|
||||
|
||||
impl<'a> From<&RegisterChain<'a>> for EndpointDerivationData {
|
||||
|
@ -148,14 +147,13 @@ pub fn register_chain(
|
|||
accs.endpoint
|
||||
.verify_derivation(ctx.program_id, &derivation_data)?;
|
||||
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.message.info().key.to_string()) {
|
||||
if INVALID_VAAS.contains(&&*accs.vaa.info().key.to_string()) {
|
||||
return Err(InvalidVAA.into());
|
||||
}
|
||||
|
||||
// Claim VAA
|
||||
verify_governance(&accs.vaa)?;
|
||||
accs.vaa.verify(ctx.program_id)?;
|
||||
accs.vaa.claim(ctx, accs.payer.key)?;
|
||||
accs.vaa_claim.claim(ctx, accs.payer.key, &accs.vaa)?;
|
||||
|
||||
// Create endpoint
|
||||
accs.endpoint
|
||||
|
|
|
@ -83,8 +83,8 @@ impl CreationLamports {
|
|||
|
||||
/// Trait definition that describes types that can be constructed from a list of solana account
|
||||
/// references. A list of dependent accounts is produced as a side effect of the parsing stage.
|
||||
pub trait FromAccounts<'a, 'b: 'a, 'c> {
|
||||
fn from<T>(_: &'a Pubkey, _: &'c mut Iter<'a, AccountInfo<'b>>, _: &'a T) -> Result<Self>
|
||||
pub trait FromAccounts<'a, 'b: 'a> {
|
||||
fn from<T>(_: &'a Pubkey, _: &mut Iter<'a, AccountInfo<'b>>, _: &'a T) -> Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ use borsh::BorshSerialize;
|
|||
|
||||
/// Generic Peel trait. This provides a way to describe what each "peeled"
|
||||
/// layer of our constraints should check.
|
||||
pub trait Peel<'a, 'b: 'a, 'c> {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self>
|
||||
pub trait Peel<'a, 'b: 'a> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
|
@ -34,10 +34,10 @@ pub trait Peel<'a, 'b: 'a, 'c> {
|
|||
}
|
||||
|
||||
/// Peel a nullable value (0-account means None)
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Option<T> {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
impl<'a, 'b: 'a, T: Peel<'a, 'b>> Peel<'a, 'b> for Option<T> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
// Check for 0-account
|
||||
if ctx.info().key == &Pubkey::new_from_array([0u8; 32]) {
|
||||
if ctx.info.key == &Pubkey::new_from_array([0u8; 32]) {
|
||||
trace!(&format!(
|
||||
"Peeled {} is None, returning",
|
||||
std::any::type_name::<Option<T>>()
|
||||
|
@ -62,15 +62,13 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Option<T> {
|
|||
}
|
||||
|
||||
/// Peel a Derived Key
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>, const SEED: &'static str> Peel<'a, 'b, 'c>
|
||||
for Derive<T, SEED>
|
||||
{
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
// Attempt to Derive Seed
|
||||
impl<'a, 'b: 'a, T: Peel<'a, 'b>, const SEED: &'static str> Peel<'a, 'b> for Derive<T, SEED> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
// Attempt to Derive SEED
|
||||
let (derived, _bump) = Pubkey::find_program_address(&[SEED.as_ref()], ctx.this);
|
||||
match derived == *ctx.info().key {
|
||||
match derived == *ctx.info.key {
|
||||
true => T::peel(ctx).map(|v| Derive(v)),
|
||||
_ => Err(SolitaireError::InvalidDerive(*ctx.info().key, derived)),
|
||||
_ => Err(SolitaireError::InvalidDerive(*ctx.info.key, derived)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,14 +78,15 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>, const SEED: &'static str> Peel<'a, 'b,
|
|||
}
|
||||
|
||||
/// Peel a Mutable key.
|
||||
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> {
|
||||
impl<'a, 'b: 'a, T: Peel<'a, 'b>> Peel<'a, 'b> for Mut<T> {
|
||||
fn peel<I>(mut ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
ctx.immutable = false;
|
||||
match ctx.info().is_writable {
|
||||
match ctx.info.is_writable {
|
||||
true => T::peel(ctx).map(|v| Mut(v)),
|
||||
_ => Err(
|
||||
SolitaireError::InvalidMutability(*ctx.info().key, ctx.info().is_writable),
|
||||
),
|
||||
_ => Err(SolitaireError::InvalidMutability(
|
||||
*ctx.info.key,
|
||||
ctx.info.is_writable,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,9 +95,9 @@ 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 MaybeMut<T> {
|
||||
fn peel<I>(mut ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
ctx.immutable = !ctx.info().is_writable;
|
||||
impl<'a, 'b: 'a, T: Peel<'a, 'b>> Peel<'a, 'b> for MaybeMut<T> {
|
||||
fn peel<I>(mut ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
ctx.immutable = !ctx.info.is_writable;
|
||||
T::peel(ctx).map(|v| MaybeMut(v))
|
||||
}
|
||||
|
||||
|
@ -108,11 +107,11 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for MaybeMut<T> {
|
|||
}
|
||||
|
||||
/// Peel a Signer.
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Signer<T> {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
match ctx.info().is_signer {
|
||||
impl<'a, 'b: 'a, T: Peel<'a, 'b>> Peel<'a, 'b> for Signer<T> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
match ctx.info.is_signer {
|
||||
true => T::peel(ctx).map(|v| Signer(v)),
|
||||
_ => Err(SolitaireError::InvalidSigner(*ctx.info().key)),
|
||||
_ => Err(SolitaireError::InvalidSigner(*ctx.info.key)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,8 +121,8 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Signer<T> {
|
|||
}
|
||||
|
||||
/// Expicitly depend upon the System account.
|
||||
impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for System<T> {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
impl<'a, 'b: 'a, T: Peel<'a, 'b>> Peel<'a, 'b> for System<T> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
match true {
|
||||
true => T::peel(ctx).map(|v| System(v)),
|
||||
_ => panic!(),
|
||||
|
@ -136,17 +135,14 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for System<T> {
|
|||
}
|
||||
|
||||
/// Peel a Sysvar
|
||||
impl<'a, 'b: 'a, 'c, Var> Peel<'a, 'b, 'c> for Sysvar<'b, Var>
|
||||
impl<'a, 'b: 'a, Var> Peel<'a, 'b> for Sysvar<'b, Var>
|
||||
where
|
||||
Var: SolanaSysvar,
|
||||
{
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
match Var::check_id(ctx.info().key) {
|
||||
true => Ok(Sysvar(
|
||||
ctx.info().clone(),
|
||||
Var::from_account_info(ctx.info())?,
|
||||
)),
|
||||
_ => Err(SolitaireError::InvalidSysvar(*ctx.info().key)),
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
match Var::check_id(ctx.info.key) {
|
||||
true => Ok(Sysvar(ctx.info.clone(), Var::from_account_info(ctx.info)?)),
|
||||
_ => Err(SolitaireError::InvalidSysvar(*ctx.info.key)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,15 +153,16 @@ where
|
|||
|
||||
/// This is our structural recursion base case, the trait system will stop generating new nested
|
||||
/// calls here.
|
||||
impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
if ctx.immutable && ctx.info().is_writable {
|
||||
return Err(
|
||||
SolitaireError::InvalidMutability(*ctx.info().key, ctx.info().is_writable),
|
||||
);
|
||||
impl<'a, 'b: 'a> Peel<'a, 'b> for Info<'b> {
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
if ctx.immutable && ctx.info.is_writable {
|
||||
return Err(SolitaireError::InvalidMutability(
|
||||
*ctx.info.key,
|
||||
ctx.info.is_writable,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ctx.info().clone())
|
||||
Ok(ctx.info.clone())
|
||||
}
|
||||
|
||||
fn persist(&self, _program_id: &Pubkey) -> Result<()> {
|
||||
|
@ -178,34 +175,32 @@ impl<'a, 'b: 'a, 'c> Peel<'a, 'b, 'c> for Info<'b> {
|
|||
impl<
|
||||
'a,
|
||||
'b: 'a,
|
||||
'c,
|
||||
T: BorshDeserialize + BorshSerialize + Owned + Default,
|
||||
const IS_INITIALIZED: AccountState,
|
||||
> Peel<'a, 'b, 'c> for Data<'b, T, IS_INITIALIZED>
|
||||
> Peel<'a, 'b> for Data<'b, T, IS_INITIALIZED>
|
||||
{
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> Result<Self> {
|
||||
if ctx.immutable && ctx.info().is_writable {
|
||||
return Err(
|
||||
SolitaireError::InvalidMutability(*ctx.info().key, ctx.info().is_writable),
|
||||
);
|
||||
fn peel<I>(ctx: &mut Context<'a, 'b, I>) -> Result<Self> {
|
||||
if ctx.immutable && ctx.info.is_writable {
|
||||
return Err(SolitaireError::InvalidMutability(
|
||||
*ctx.info.key,
|
||||
ctx.info.is_writable,
|
||||
));
|
||||
}
|
||||
|
||||
// If we're initializing the type, we should emit system/rent as deps.
|
||||
let (initialized, data): (bool, T) = match IS_INITIALIZED {
|
||||
AccountState::Uninitialized => {
|
||||
if !ctx.info().data.borrow().is_empty() {
|
||||
return Err(SolitaireError::AlreadyInitialized(*ctx.info().key));
|
||||
if !ctx.info.data.borrow().is_empty() {
|
||||
return Err(SolitaireError::AlreadyInitialized(*ctx.info.key));
|
||||
}
|
||||
(false, T::default())
|
||||
}
|
||||
AccountState::Initialized => {
|
||||
(true, T::try_from_slice(*ctx.info().data.borrow_mut())?)
|
||||
}
|
||||
AccountState::Initialized => (true, T::try_from_slice(*ctx.info.data.borrow_mut())?),
|
||||
AccountState::MaybeInitialized => {
|
||||
if ctx.info().data.borrow().is_empty() {
|
||||
if ctx.info.data.borrow().is_empty() {
|
||||
(false, T::default())
|
||||
} else {
|
||||
(true, T::try_from_slice(*ctx.info().data.borrow_mut())?)
|
||||
(true, T::try_from_slice(*ctx.info.data.borrow_mut())?)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -213,20 +208,20 @@ impl<
|
|||
if initialized {
|
||||
match data.owner() {
|
||||
AccountOwner::This => {
|
||||
if ctx.info().owner != ctx.this {
|
||||
return Err(SolitaireError::InvalidOwner(*ctx.info().owner));
|
||||
if ctx.info.owner != ctx.this {
|
||||
return Err(SolitaireError::InvalidOwner(*ctx.info.owner));
|
||||
}
|
||||
}
|
||||
AccountOwner::Other(v) => {
|
||||
if *ctx.info().owner != v {
|
||||
return Err(SolitaireError::InvalidOwner(*ctx.info().owner));
|
||||
if *ctx.info.owner != v {
|
||||
return Err(SolitaireError::InvalidOwner(*ctx.info.owner));
|
||||
}
|
||||
}
|
||||
AccountOwner::Any => {}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Data(Box::new(ctx.info().clone()), data))
|
||||
Ok(Data(Box::new(ctx.info.clone()), data))
|
||||
}
|
||||
|
||||
fn persist(&self, program_id: &Pubkey) -> Result<()> {
|
||||
|
|
|
@ -1,54 +1,31 @@
|
|||
use crate::trace;
|
||||
use solana_program::{
|
||||
account_info::{
|
||||
next_account_info,
|
||||
AccountInfo,
|
||||
},
|
||||
account_info::AccountInfo,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use std::slice::Iter;
|
||||
|
||||
/// The context is threaded through each check. Include anything within this structure that you
|
||||
/// would like to have access to as each layer of dependency is peeled off.
|
||||
pub struct Context<'a, 'b: 'a, 'c, T> {
|
||||
pub struct Context<'a, 'b: 'a, T> {
|
||||
/// A reference to the program_id of the current program.
|
||||
pub this: &'a Pubkey,
|
||||
|
||||
/// A reference to the instructions account list, one or more keys may be extracted during
|
||||
/// the peeling process.
|
||||
pub iter: &'c mut Iter<'a, AccountInfo<'b>>,
|
||||
/// This is a reference to the AccountInfo of the field that is currently being parsed.
|
||||
pub info: &'a AccountInfo<'b>,
|
||||
|
||||
/// Reference to the data passed to the current instruction.
|
||||
pub data: &'a T,
|
||||
|
||||
/// An optional account info for this Peelable item, some fields may be other structures that
|
||||
/// do not themselves have an account info associated with the field.
|
||||
pub info: Option<&'a AccountInfo<'b>>,
|
||||
|
||||
/// Whether to enforce immutability.
|
||||
pub immutable: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, 'c, T> Context<'a, 'b, 'c, T> {
|
||||
pub fn new(program: &'a Pubkey, iter: &'c mut Iter<'a, AccountInfo<'b>>, data: &'a T) -> Self {
|
||||
impl<'a, 'b: 'a, T> Context<'a, 'b, T> {
|
||||
pub fn new(this: &'a Pubkey, info: &'a AccountInfo<'b>, data: &'a T) -> Self {
|
||||
Context {
|
||||
this: program,
|
||||
info: None,
|
||||
immutable: true,
|
||||
iter,
|
||||
this,
|
||||
info,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info<'d>(&'d mut self) -> &'a AccountInfo<'b> {
|
||||
match self.info {
|
||||
None => {
|
||||
let info = next_account_info(self.iter).unwrap();
|
||||
trace!("{}", info.key);
|
||||
self.info = Some(info);
|
||||
info
|
||||
}
|
||||
Some(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
|
|||
|
||||
// Generics lifetimes of the peel type
|
||||
let mut peel_g = input.generics.clone();
|
||||
peel_g.params = parse_quote!('a, 'b: 'a, 'c);
|
||||
peel_g.params = parse_quote!('a, 'b: 'a);
|
||||
let (_, peel_type_g, _) = peel_g.split_for_impl();
|
||||
|
||||
// Params of the instruction context
|
||||
|
@ -53,22 +53,11 @@ pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
|
|||
let expanded = quote! {
|
||||
/// Macro generated implementation of FromAccounts by Solitaire.
|
||||
impl #combined_impl_g solitaire::FromAccounts #peel_type_g for #name #type_g {
|
||||
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> {
|
||||
fn from<DataType>(pid: &'a solana_program::pubkey::Pubkey, iter: &mut std::slice::Iter<'a, solana_program::account_info::AccountInfo<'b>>, data: &'a DataType) -> solitaire::Result<Self> {
|
||||
#from_method
|
||||
}
|
||||
}
|
||||
|
||||
impl #combined_impl_g solitaire::Peel<'a, 'b, 'c> for #name #type_g {
|
||||
fn peel<I>(ctx: &'c mut solitaire::Context<'a, 'b, 'c, I>) -> solitaire::Result<Self> where Self: Sized {
|
||||
let v: #name #type_g = FromAccounts::from(ctx.this, ctx.iter, ctx.data)?;
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn persist(&self, program_id: &solana_program::pubkey::Pubkey) -> solitaire::Result<()> {
|
||||
solitaire::Persist::persist(self, program_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Macro generated implementation of Persist by Solitaire.
|
||||
impl #type_impl_g solitaire::Persist for #name #type_g {
|
||||
fn persist(&self, program_id: &solana_program::pubkey::Pubkey) -> solitaire::Result<()> {
|
||||
|
@ -102,7 +91,7 @@ fn generate_fields(name: &syn::Ident, data: &Data) -> TokenStream2 {
|
|||
trace!(stringify!(#name));
|
||||
let #name: #ty = solitaire::Peel::peel(&mut solitaire::Context::new(
|
||||
pid,
|
||||
iter,
|
||||
next_account_info(iter)?,
|
||||
data,
|
||||
))?;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue