Bridge Converted to Solitaire
Change-Id: I6223c5d51d6bda7f3581339a93f9519725a337b9
This commit is contained in:
parent
2202a38c65
commit
32b2f11def
|
@ -1,3 +1,5 @@
|
|||
mod initialize;
|
||||
mod post_vaa;
|
||||
|
||||
pub use initialize::*;
|
||||
pub use post_vaa::*;
|
||||
|
|
|
@ -1,45 +1,22 @@
|
|||
use crate::types::*;
|
||||
use solitaire::*;
|
||||
|
||||
type Payer<'a> = Signer<Info<'a>>;
|
||||
type Payer<'a> = Signer<Info<'a>>;
|
||||
type GuardianSet<'a> = Derive<Data<'a, GuardianSetData, Uninitialized>, "GuardianSet">;
|
||||
type Bridge<'a> = Derive<Data<'a, BridgeData, Uninitialized>, "Bridge">;
|
||||
type Bridge<'a> = Derive<Data<'a, BridgeData, Uninitialized>, "Bridge">;
|
||||
|
||||
#[derive(FromAccounts, ToAccounts)]
|
||||
pub struct Initialize<'b> {
|
||||
pub payer: Payer<'b>,
|
||||
pub bridge: Bridge<'b>,
|
||||
pub guardian_set: GuardianSet<'b>,
|
||||
pub bridge: Bridge<'b>,
|
||||
pub transfer: Transfer<'b>,
|
||||
pub payer: Payer<'b>,
|
||||
}
|
||||
|
||||
impl<'b> InstructionContext<'b> for Initialize<'b> {
|
||||
}
|
||||
|
||||
#[derive(FromAccounts, ToAccounts)]
|
||||
pub struct Transfer<'b> {
|
||||
pub mint: Data<'b, Test, Initialized>,
|
||||
pub from: Data<'b, Test, Initialized>,
|
||||
pub to: Data<'b, Test, Initialized>,
|
||||
}
|
||||
|
||||
impl<'b> InstructionContext<'b> for Transfer<'b> {
|
||||
fn verify(&self) -> Result<()> {
|
||||
return if self.mint.mint == self.from.mint {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SolitaireError::InvalidDerive(*self.mint.0.key).into())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BorshDeserialize, BorshSerialize)]
|
||||
pub struct Test {
|
||||
mint: Pubkey,
|
||||
}
|
||||
|
||||
pub fn initialize(
|
||||
ctx: &ExecutionContext,
|
||||
_ctx: &ExecutionContext,
|
||||
accs: &mut Initialize,
|
||||
config: BridgeConfig,
|
||||
) -> Result<()> {
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
use solitaire::*;
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
use sha3::Digest;
|
||||
use solana_program::{self, sysvar::clock::Clock};
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
use crate::{
|
||||
types::{self, Bridge},
|
||||
Error,
|
||||
VAA_TX_FEE,
|
||||
};
|
||||
|
||||
const MIN_BRIDGE_BALANCE: u64 = (((solana_program::rent::ACCOUNT_STORAGE_OVERHEAD
|
||||
+ std::mem::size_of::<Bridge>() as u64)
|
||||
* solana_program::rent::DEFAULT_LAMPORTS_PER_BYTE_YEAR) as f64
|
||||
* solana_program::rent::DEFAULT_EXEMPTION_THRESHOLD) as u64;
|
||||
|
||||
type GuardianSet<'b> = Derive<Data<'b, types::GuardianSet>, "GuardianSet">;
|
||||
type SignatureSet<'b> = Derive<Data<'b, types::SignatureSet>, "Signatures">;
|
||||
type Message<'b> = Derive<Data<'b, types::PostedMessage>, "Message">;
|
||||
|
||||
#[derive(FromAccounts)]
|
||||
pub struct PostVAA<'b> {
|
||||
/// Required by Anchor for associated accounts.
|
||||
pub system_program: Info<'b>,
|
||||
|
||||
/// Required by Anchor for associated accounts.
|
||||
pub rent: Info<'b>,
|
||||
|
||||
/// Clock used for timestamping.
|
||||
pub clock: Sysvar<Info<'b>, Clock>,
|
||||
|
||||
/// State struct, derived by #[state], used for associated accounts.
|
||||
pub state: Info<'b>,
|
||||
|
||||
/// Information about the current guardian set.
|
||||
pub guardian_set: GuardianSet<'b>,
|
||||
|
||||
/// Bridge Info
|
||||
pub bridge_info: Info<'b>,
|
||||
|
||||
/// Claim Info
|
||||
pub claim: Info<'b>,
|
||||
|
||||
/// Signature Info
|
||||
pub signature_set: SignatureSet<'b>,
|
||||
|
||||
/// Account used to pay for auxillary instructions.
|
||||
pub payer: Info<'b>,
|
||||
|
||||
/// Message the VAA is associated with.
|
||||
pub message: Message<'b>,
|
||||
}
|
||||
|
||||
impl<'b> InstructionContext<'b> for PostVAA<'b> {
|
||||
}
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Signature {
|
||||
pub index: u8,
|
||||
pub r: [u8; 32],
|
||||
pub s: [u8; 32],
|
||||
pub v: u8,
|
||||
}
|
||||
|
||||
pub type ForeignAddress = [u8; 32];
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
pub struct PostVAAData {
|
||||
// Header part
|
||||
pub version: u8,
|
||||
pub guardian_set_index: u32,
|
||||
pub signatures: Vec<Signature>,
|
||||
|
||||
// Body part
|
||||
pub timestamp: u32,
|
||||
pub nonce: u32,
|
||||
pub emitter_chain: u8,
|
||||
pub emitter_address: ForeignAddress,
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
pub fn post_vaa(
|
||||
_ctx: &ExecutionContext,
|
||||
accs: &mut PostVAA,
|
||||
vaa: PostVAAData
|
||||
) -> Result<()> {
|
||||
// Verify any required invariants before we process the instruction.
|
||||
check_active(&accs.guardian_set, &accs.clock)?;
|
||||
check_valid_sigs(&accs.guardian_set, &accs.signature_set)?;
|
||||
check_integrity(&vaa, &accs.signature_set)?;
|
||||
|
||||
// Count the numnber of signatures currently present.
|
||||
let signature_count: usize = accs
|
||||
.signature_set
|
||||
.signatures
|
||||
.iter()
|
||||
.filter(|v| v.iter().filter(|v| **v != 0).count() != 0)
|
||||
.count();
|
||||
|
||||
// Calculate how many signatures are required to reach consensus. This calculation is in
|
||||
// expanded form to ease auditing.
|
||||
let required_consensus_count = {
|
||||
let len = accs.guardian_set.keys.len();
|
||||
// Fixed point number transformation with one decimal to deal with rounding.
|
||||
let len = (len * 10) / 3;
|
||||
// Multiplication by two to get a 2/3 quorum.
|
||||
let len = len * 2;
|
||||
// Division by 10+1 to bring the number back into range.
|
||||
len / (10 + 1)
|
||||
};
|
||||
|
||||
if signature_count < required_consensus_count {
|
||||
return Err(Error::PostVAAConsensusFailed.into());
|
||||
}
|
||||
|
||||
// Store VAA data in associated message.
|
||||
accs.message.vaa_version = vaa.version;
|
||||
accs.message.vaa_time = vaa.timestamp;
|
||||
accs.message.vaa_signature_account = *accs.signature_set.pubkey();
|
||||
|
||||
// If the bridge has enough balance, refund the SOL to the transaction payer.
|
||||
if VAA_TX_FEE + MIN_BRIDGE_BALANCE < accs.state.to_account_info().lamports() {
|
||||
transfer_sol(
|
||||
&ctx.accounts.state.to_account_info(),
|
||||
&ctx.accounts.payer,
|
||||
VAA_TX_FEE,
|
||||
)?;
|
||||
}
|
||||
//
|
||||
// // Claim the VAA
|
||||
// ctx.accounts.claim.vaa_time = ctx.accounts.clock.unix_timestamp as u32;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer_sol(sender: &Info, recipient: &Info, amount: u64) -> Result<()> {
|
||||
// let mut payer_balance = sender.try_borrow_mut_lamports()?;
|
||||
// **payer_balance = payer_balance
|
||||
// .checked_sub(amount)
|
||||
// .ok_or(ProgramError::InsufficientFunds)?;
|
||||
// let mut recipient_balance = recipient.try_borrow_mut_lamports()?;
|
||||
// **recipient_balance = recipient_balance
|
||||
// .checked_add(amount)
|
||||
// .ok_or(ProgramError::InvalidArgument)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A guardian set must not have expired.
|
||||
#[inline(always)]
|
||||
fn check_active<'r>(guardian_set: &GuardianSet, clock: &Sysvar<Info<'r>, Clock>) -> Result<()> {
|
||||
// if guardian_set.expiration_time != 0
|
||||
// && (guardian_set.expiration_time as i64) < clock.unix_timestamp
|
||||
// {
|
||||
// return Err(ErrorCode::PostVAAGuardianSetExpired.into());
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The signatures in this instruction must be from the right guardian set.
|
||||
#[inline(always)]
|
||||
fn check_valid_sigs<'r>(
|
||||
guardian_set: &GuardianSet,
|
||||
signatures: &SignatureSet<'r>,
|
||||
) -> Result<()> {
|
||||
// if sig_info.guardian_set_index != guardian_set.index {
|
||||
// return Err(ErrorCode::PostVAAGuardianSetMismatch.into());
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_integrity<'r>(
|
||||
vaa: &PostVAAData,
|
||||
signatures: &SignatureSet<'r>,
|
||||
) -> Result<()> {
|
||||
// // Serialize the VAA body into an array of bytes.
|
||||
// let body = {
|
||||
// let mut v = Cursor::new(Vec::new());
|
||||
// v.write_u32::<BigEndian>(vaa.timestamp)?;
|
||||
// v.write_u32::<BigEndian>(vaa.nonce)?;
|
||||
// v.write_u8(vaa.emitter_chain)?;
|
||||
// v.write(&vaa.emitter_address)?;
|
||||
// v.write(&vaa.payload)?;
|
||||
// v.into_inner()
|
||||
// };
|
||||
// // Hash this body, which is expected to be the same as the hash currently stored in the
|
||||
// // signature account, binding that set of signatures to this VAA.
|
||||
// let body_hash: [u8; 32] = {
|
||||
// let mut h = sha3::Keccak256::default();
|
||||
// h.write(body.as_slice())
|
||||
// .map_err(|_| ProgramError::InvalidArgument);
|
||||
// h.finalize().into()
|
||||
// };
|
||||
// if signatures.hash != body_hash {
|
||||
// return Err(ProgramError::InvalidAccountData.into());
|
||||
// }
|
||||
Ok(())
|
||||
}
|
|
@ -5,11 +5,30 @@
|
|||
mod api;
|
||||
mod types;
|
||||
|
||||
use solitaire::*;
|
||||
|
||||
use api::{initialize, Initialize};
|
||||
use api::{post_vaa, PostVAA, PostVAAData};
|
||||
use types::BridgeConfig;
|
||||
|
||||
use solitaire::*;
|
||||
const VAA_TX_FEE: u64 = 0;
|
||||
const MAX_LEN_GUARDIAN_KEYS: u64 = 0;
|
||||
|
||||
enum Error {
|
||||
InvalidSysVar,
|
||||
InsufficientFees,
|
||||
PostVAAGuardianSetExpired,
|
||||
PostVAAGuardianSetMismatch,
|
||||
PostVAAConsensusFailed,
|
||||
}
|
||||
|
||||
impl From<Error> for SolitaireError {
|
||||
fn from(e: Error) -> SolitaireError {
|
||||
SolitaireError::Custom(e as u64)
|
||||
}
|
||||
}
|
||||
|
||||
solitaire! {
|
||||
Initialize(BridgeConfig) => initialize,
|
||||
PostVAA(PostVAAData) => post_vaa,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solana_program::pubkey::Pubkey;
|
||||
|
||||
#[derive(Default, Clone, Copy, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Index(u8);
|
||||
|
@ -45,3 +46,79 @@ pub struct BridgeData {
|
|||
/// Bridge configuration, which is set once upon initialization.
|
||||
pub config: BridgeConfig,
|
||||
}
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Bridge {
|
||||
/// The current guardian set index, used to decide which signature sets to accept.
|
||||
pub guardian_set_index: Index,
|
||||
|
||||
/// Bridge configuration, which is set once upon initialization.
|
||||
pub config: BridgeConfig,
|
||||
}
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
pub struct SignatureSet {
|
||||
/// Signatures of validators
|
||||
pub signatures: Vec<[u8; 32]>,
|
||||
|
||||
/// Hash of the data
|
||||
pub hash: [u8; 32],
|
||||
|
||||
/// Index of the guardian set
|
||||
pub guardian_set_index: Index,
|
||||
}
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
pub struct GuardianSet {
|
||||
/// Index of this guardian set.
|
||||
pub index: Index,
|
||||
|
||||
/// Public key hashes of the guardian set
|
||||
pub keys: Vec<[u8; 20]>,
|
||||
|
||||
/// Creation time
|
||||
pub creation_time: u32,
|
||||
|
||||
/// Expiration time when VAAs issued by this set are no longer valid
|
||||
pub expiration_time: u32,
|
||||
}
|
||||
|
||||
#[derive(Default, BorshSerialize, BorshDeserialize)]
|
||||
pub struct PostedMessage {
|
||||
/// Header of the posted VAA
|
||||
pub vaa_version: u8,
|
||||
|
||||
/// Time the vaa was submitted
|
||||
pub vaa_time: u32,
|
||||
|
||||
/// Account where signatures are stored
|
||||
pub vaa_signature_account: Pubkey,
|
||||
|
||||
/// Time the posted message was created
|
||||
pub submission_time: u32,
|
||||
|
||||
/// Unique nonce for this message
|
||||
pub nonce: u32,
|
||||
|
||||
/// Emitter of the message
|
||||
pub emitter_chain: Chain,
|
||||
|
||||
/// Emitter of the message
|
||||
pub emitter_address: [u8; 32],
|
||||
|
||||
/// Message payload
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(BorshSerialize, BorshDeserialize)]
|
||||
pub enum Chain {
|
||||
Unknown,
|
||||
Solana = 1u8,
|
||||
}
|
||||
|
||||
impl Default for Chain {
|
||||
fn default() -> Self {
|
||||
Chain::Unknown
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
use solana_program::{program_error::ProgramError, pubkey::Pubkey};
|
||||
|
||||
/// Quality of life Result type for the Solitaire stack.
|
||||
pub type Result<T> = std::result::Result<T, SolitaireError>;
|
||||
|
||||
/// Quality of life type alias for wrapping up boxed errors.
|
||||
pub type ErrBox = Box<dyn std::error::Error>;
|
||||
|
||||
/// There are several places in Solitaire that might fail, we want descriptive errors.
|
||||
#[derive(Debug)]
|
||||
pub enum SolitaireError {
|
||||
/// The AccountInfo parser expected a Signer, but the account did not sign.
|
||||
InvalidSigner(Pubkey),
|
||||
|
||||
/// The AccountInfo parser expected a Sysvar, but the key was invalid.
|
||||
InvalidSysvar(Pubkey),
|
||||
|
||||
/// The AccountInfo parser tried to derive the provided key, but it did not match.
|
||||
InvalidDerive(Pubkey),
|
||||
|
||||
/// The instruction payload itself could not be deserialized.
|
||||
InstructionDeserializeFailed,
|
||||
|
||||
/// An IO error was captured, wrap it up and forward it along.
|
||||
IoError(std::io::Error),
|
||||
|
||||
/// An solana program error
|
||||
ProgramError(ProgramError),
|
||||
|
||||
Custom(u64),
|
||||
}
|
||||
|
||||
impl From<ProgramError> for SolitaireError {
|
||||
fn from(e: ProgramError) -> Self {
|
||||
SolitaireError::ProgramError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for SolitaireError {
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
SolitaireError::IoError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ProgramError> for SolitaireError {
|
||||
fn into(self) -> ProgramError {
|
||||
if let SolitaireError::ProgramError(e) = self {
|
||||
return e;
|
||||
}
|
||||
// TODO
|
||||
ProgramError::Custom(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13,88 +13,37 @@ pub use rocksalt::*;
|
|||
// - Client generation incomplete.
|
||||
|
||||
// We need a few Solana things in scope in order to properly abstract Solana.
|
||||
pub use solana_program::{
|
||||
account_info::AccountInfo,
|
||||
use solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
entrypoint,
|
||||
entrypoint::ProgramResult,
|
||||
instruction::AccountMeta,
|
||||
program::invoke_signed,
|
||||
program_error::ProgramError,
|
||||
program_pack::Pack,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
system_instruction,
|
||||
system_program,
|
||||
sysvar::{self, SysvarId},
|
||||
};
|
||||
|
||||
// Later on we will define types that don't actually contain data, PhantomData will help us.
|
||||
pub use std::marker::PhantomData;
|
||||
|
||||
// We'll need these traits to make any wrappers we define more ergonomic for users.
|
||||
pub use std::ops::{Deref, DerefMut};
|
||||
|
||||
// Borsh is Solana's goto serialization target, so we'll need this if we want to do any
|
||||
// serialization on the users behalf.
|
||||
pub use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solana_program::{
|
||||
account_info::next_account_info,
|
||||
instruction::AccountMeta,
|
||||
program::invoke_signed,
|
||||
program_error::ProgramError,
|
||||
program_pack::Pack,
|
||||
rent::Rent,
|
||||
};
|
||||
use std::{
|
||||
io::{ErrorKind, Write},
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
slice::Iter,
|
||||
string::FromUtf8Error,
|
||||
};
|
||||
|
||||
/// There are several places in Solitaire that might fail, we want descriptive errors.
|
||||
#[derive(Debug)]
|
||||
pub enum SolitaireError {
|
||||
/// The AccountInfo parser expected a Signer, but the account did not sign.
|
||||
InvalidSigner(Pubkey),
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
/// The AccountInfo parser expected a Sysvar, but the key was invalid.
|
||||
InvalidSysvar(Pubkey),
|
||||
pub use crate::{
|
||||
error::{ErrBox, Result, SolitaireError},
|
||||
seeded::Creatable,
|
||||
};
|
||||
|
||||
/// The AccountInfo parser tried to derive the provided key, but it did not match.
|
||||
InvalidDerive(Pubkey),
|
||||
|
||||
/// The instruction payload itself could not be deserialized.
|
||||
InstructionDeserializeFailed,
|
||||
|
||||
/// An IO error was captured, wrap it up and forward it along.
|
||||
IoError(std::io::Error),
|
||||
|
||||
/// An solana program error
|
||||
ProgramError(ProgramError),
|
||||
|
||||
Custom(u64),
|
||||
}
|
||||
|
||||
impl From<ProgramError> for SolitaireError {
|
||||
fn from(e: ProgramError) -> Self {
|
||||
SolitaireError::ProgramError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for SolitaireError {
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
SolitaireError::IoError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ProgramError> for SolitaireError {
|
||||
fn into(self) -> ProgramError {
|
||||
if let SolitaireError::ProgramError(e) = self {
|
||||
return e;
|
||||
}
|
||||
// TODO
|
||||
ProgramError::Custom(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Quality of life Result type for the Solitaire stack.
|
||||
pub type Result<T> = std::result::Result<T, SolitaireError>;
|
||||
pub type ErrBox = Box<dyn std::error::Error>;
|
||||
mod error;
|
||||
|
||||
pub trait Persist {
|
||||
fn persist(self);
|
||||
|
@ -160,8 +109,8 @@ pub type Info<'r> = AccountInfo<'r>;
|
|||
/// But here, we must write `Lazy: bool = true` for now unfortunately.
|
||||
#[rustfmt::skip]
|
||||
pub struct Data < 'r, T, const IsInitialized: bool = true, const Lazy: bool = false > (
|
||||
pub Info<'r >,
|
||||
pub T,
|
||||
pub Info<'r >,
|
||||
pub T,
|
||||
);
|
||||
|
||||
/// A tag for accounts that should be deserialized lazily.
|
||||
|
@ -561,7 +510,12 @@ macro_rules! solitaire {
|
|||
mod instruction {
|
||||
use super::*;
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solitaire::{Persist, FromAccounts, Result};
|
||||
use solana_program::{
|
||||
account_info::AccountInfo,
|
||||
entrypoint::ProgramResult,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use solitaire::{FromAccounts, Persist, Result};
|
||||
|
||||
/// Generated:
|
||||
/// This Instruction contains a 1-1 mapping for each enum variant to function call. The
|
||||
|
@ -602,7 +556,8 @@ macro_rules! solitaire {
|
|||
/// can be matched to the Instruction found above.
|
||||
mod client {
|
||||
use super::*;
|
||||
use solana_program::instruction::Instruction;
|
||||
use borsh::BorshSerialize;
|
||||
use solana_program::{instruction::Instruction, pubkey::Pubkey};
|
||||
|
||||
/// Generated from Instruction Field
|
||||
$(pub(crate) fn $fn(pid: &Pubkey, accounts: $row, ix_data: $kind) -> std::result::Result<Instruction, ErrBox> {
|
||||
|
@ -615,7 +570,7 @@ macro_rules! solitaire {
|
|||
}
|
||||
|
||||
use instruction::solitaire;
|
||||
entrypoint!(solitaire);
|
||||
solana_program::entrypoint!(solitaire);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#![feature(const_generics)]
|
||||
#![feature(const_generics_defaults)]
|
||||
#![allow(warnings)]
|
||||
|
||||
// #![cfg(all(target_arch = "bpf", not(feature = "no-entrypoint")))]
|
||||
|
||||
mod api;
|
||||
mod messages;
|
||||
mod types;
|
||||
mod vaa;
|
||||
|
||||
use api::{initialize, Initialize};
|
||||
|
||||
use solitaire::*;
|
||||
use std::error::Error;
|
||||
|
||||
pub enum TokenBridgeError {
|
||||
InvalidPayload,
|
||||
Unknown(String),
|
||||
InvalidMint,
|
||||
WrongAccountOwner,
|
||||
InvalidUTF8String,
|
||||
AlreadyExecuted,
|
||||
}
|
||||
|
||||
impl<T: Error> From<T> for TokenBridgeError {
|
||||
fn from(t: T) -> Self {
|
||||
return TokenBridgeError::Unknown(t.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<SolitaireError> for TokenBridgeError {
|
||||
fn into(self) -> SolitaireError {
|
||||
SolitaireError::Custom(0)
|
||||
}
|
||||
}
|
||||
|
||||
solitaire! {
|
||||
Initialize(Pubkey) => initialize,
|
||||
}
|
|
@ -85,12 +85,12 @@ 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, AccountInfo<'b>>, data: &'a DataType) -> solitaire::Result<(Self, Vec<solana_program::pubkey::Pubkey>)> {
|
||||
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, Vec<solana_program::pubkey::Pubkey>)> {
|
||||
#from_method
|
||||
}
|
||||
}
|
||||
|
||||
impl #combined_impl_g Peel<'a, 'b, 'c> for #name #type_g {
|
||||
impl #combined_impl_g solitaire::Peel<'a, 'b, 'c> for #name #type_g {
|
||||
fn peel<I>(ctx: &'c mut Context<'a, 'b, 'c, I>) -> solitaire::Result<Self> where Self: Sized {
|
||||
let v: #name #type_g = FromAccounts::from(ctx.this, ctx.iter, ctx.data).map(|v| v.0)?;
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# Merge similar crates together to avoid multiple use statements.
|
||||
imports_granularity = "Crate"
|
||||
|
||||
# Consistency in formatting makes tool based searching/editing better.
|
||||
empty_item_single_line = false
|
||||
|
||||
# Easier editing when arbitrary mixed use statements do not collapse.
|
||||
imports_layout = "HorizontalVertical"
|
||||
|
||||
# Default rustfmt formatting of match arms with branches is awful.
|
||||
match_arm_leading_pipes = "Preserve"
|
Loading…
Reference in New Issue