gmsol/utils/workarounds/
optional.rs

1use anchor_client::{
2    anchor_lang::ToAccountMetas,
3    solana_sdk::{instruction::AccountMeta, pubkey::Pubkey},
4};
5
6/// Change the `pubkey` of any readonly, non-signer [`AccountMeta`]
7/// with the `pubkey` equal to the original program id to the new one.
8///
9/// This is a workaround since Anchor will automatically set optional accounts
10/// to the Program ID of the program that defines them when they are `None`s,
11/// if we use the same program but with different Program IDs, the optional
12/// accounts will be set to the wrong addresses.
13///
14/// ## Warning
15/// Use this function only if you fully understand the implications.
16pub fn fix_optional_account_metas(
17    accounts: impl ToAccountMetas,
18    original: &Pubkey,
19    current: &Pubkey,
20) -> Vec<AccountMeta> {
21    let mut metas = accounts.to_account_metas(None);
22    if *original == *current {
23        // No-op in this case.
24        return metas;
25    }
26    metas.iter_mut().for_each(|meta| {
27        if !meta.is_signer && !meta.is_writable && meta.pubkey == *original {
28            // We consider it a `None` account. If it is not, please do not use this function.
29            meta.pubkey = *current;
30        }
31    });
32    metas
33}