use bon::bon;
use solana_invoke::{invoke, invoke_signed};
use solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
};
use crate::UipEndpoint;
#[repr(u8)]
pub enum Commitment {
Confirmed,
Finalized,
}
const REGISTER_EXTENSION_DISCRIMINATOR: &[u8; 8] = b"reg_extn";
const PROPOSE_DISCRIMINATOR: &[u8; 8] = b"propose2";
#[bon]
impl UipEndpoint {
#[builder]
pub fn register_extension<'info>(
extension: AccountInfo<'info>,
program_signer: AccountInfo<'info>,
payer: AccountInfo<'info>,
system_program: AccountInfo<'info>,
program_signer_bump: u8,
program_id: &Pubkey,
ipfs_cid: [u8; 36],
) -> ProgramResult {
const DISC_LEN: usize = REGISTER_EXTENSION_DISCRIMINATOR.len();
let mut data = [0; { DISC_LEN + 32 + 36 }];
data[..DISC_LEN].copy_from_slice(REGISTER_EXTENSION_DISCRIMINATOR);
data[DISC_LEN..DISC_LEN + 32].copy_from_slice(program_id.as_ref());
data[DISC_LEN + 32..DISC_LEN + 32 + 36].copy_from_slice(&ipfs_cid);
let accounts = vec![
AccountMeta::new(*payer.key, true),
AccountMeta::new(*extension.key, false),
AccountMeta::new_readonly(*program_signer.key, true),
AccountMeta::new_readonly(*system_program.key, false),
];
let ix = Instruction::new_with_bytes(UipEndpoint::id(), &data, accounts);
invoke_signed(
&ix,
&[extension, program_signer, payer, system_program],
&[&[b"UIP_SIGNER", &[program_signer_bump]]],
)
}
#[builder]
pub fn propose<'info, 'a>(
proposer: AccountInfo<'info>,
endpoint_config: AccountInfo<'info>,
uts_connector: AccountInfo<'info>,
system_program: AccountInfo<'info>,
total_fee: u64,
dest_chain_id: u128,
selector: Option<&'a [u8; 32]>,
dest_addr: &'a [u8],
payload: &'a [u8],
proposal_commitment: Commitment,
custom_gas_limit: u128,
) -> ProgramResult {
const DISC_LEN: usize = PROPOSE_DISCRIMINATOR.len();
let mut data = Vec::with_capacity(
DISC_LEN + 8 + 16 + 1 + 16 + 32 + 4 + dest_addr.len() + 4 + payload.len(),
);
data.extend(PROPOSE_DISCRIMINATOR);
data.extend(total_fee.to_le_bytes());
data.extend(dest_chain_id.to_le_bytes());
data.push(proposal_commitment as u8);
data.extend(custom_gas_limit.to_le_bytes());
data.extend(selector.unwrap_or(&Default::default()));
data.extend((dest_addr.len() as u32).to_le_bytes());
data.extend(dest_addr);
data.extend((payload.len() as u32).to_le_bytes());
data.extend(payload);
let accounts = vec![
AccountMeta::new(*proposer.key, true),
AccountMeta::new_readonly(*endpoint_config.key, false),
AccountMeta::new(*uts_connector.key, false),
AccountMeta::new_readonly(*system_program.key, false),
];
let ix = Instruction::new_with_bytes(UipEndpoint::id(), &data, accounts);
invoke(&ix, &[proposer, endpoint_config, uts_connector, system_program])
}
}
#[cfg(test)]
mod tests {
use anchor_lang::prelude::*;
use uip_endpoint::instruction::{Propose, RegisterExtension};
use super::*;
#[test]
fn test_discriminators() {
assert_eq!(REGISTER_EXTENSION_DISCRIMINATOR, RegisterExtension::DISCRIMINATOR);
assert_eq!(PROPOSE_DISCRIMINATOR, Propose::DISCRIMINATOR);
}
}