Solana fix warnings (#1226)

* solana: fix all rustc warnings

* solana: fix clippy warnings

* Remove manual memcpy + other warning suppressions

Co-authored-by: Csongor Kiss <ckiss@jumptrading.com>
This commit is contained in:
Csongor Kiss 2022-06-10 17:59:15 +01:00 committed by GitHub
parent 5fd54db369
commit 2e220a6f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 492 additions and 1180 deletions

View File

@ -1,6 +1,5 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#![allow(warnings)]
use std::{
fmt::Display,
@ -9,12 +8,10 @@ use std::{
};
use borsh::BorshDeserialize;
use bridge::{
accounts::{
Bridge,
BridgeData,
FeeCollector,
},
use bridge::accounts::{
Bridge,
BridgeData,
FeeCollector,
};
use clap::{
crate_description,
@ -26,7 +23,6 @@ use clap::{
Arg,
SubCommand,
};
use hex;
use solana_clap_utils::{
input_parsers::{
keypair_of,
@ -50,7 +46,6 @@ use solana_sdk::{
CommitmentLevel,
},
native_token::*,
program_error::ProgramError::AccountAlreadyInitialized,
pubkey::Pubkey,
signature::{
read_keypair_file,
@ -77,6 +72,10 @@ struct Config {
type Error = Box<dyn std::error::Error>;
type CommmandResult = Result<Option<Transaction>, Error>;
// [`get_recent_blockhash`] is deprecated, but devnet deployment hangs using the
// recommended method, so allowing deprecated here. This is only the client, so
// no risk.
#[allow(deprecated)]
fn command_deploy_bridge(
config: &Config,
bridge: &Pubkey,
@ -98,18 +97,22 @@ fn command_deploy_bridge(
initial_guardians.as_slice(),
)
.unwrap();
println!("config account: {}, ", ix.accounts[0].pubkey.to_string());
println!("config account: {}, ", ix.accounts[0].pubkey);
let mut transaction = Transaction::new_with_payer(&[ix], Some(&config.fee_payer.pubkey()));
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
check_fee_payer_balance(
config,
minimum_balance_for_rent_exemption + fee_calculator.calculate_fee(&transaction.message()),
minimum_balance_for_rent_exemption + fee_calculator.calculate_fee(transaction.message()),
)?;
transaction.sign(&[&config.fee_payer, &config.owner], recent_blockhash);
Ok(Some(transaction))
}
// [`get_recent_blockhash`] is deprecated, but devnet deployment hangs using the
// recommended method, so allowing deprecated here. This is only the client, so
// no risk.
#[allow(deprecated)]
fn command_post_message(
config: &Config,
bridge: &Pubkey,
@ -164,7 +167,7 @@ fn command_post_message(
Transaction::new_with_payer(&[transfer_ix, ix], Some(&config.fee_payer.pubkey()));
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
check_fee_payer_balance(config, fee_calculator.calculate_fee(&transaction.message()))?;
check_fee_payer_balance(config, fee_calculator.calculate_fee(transaction.message()))?;
transaction.sign(
&[&config.fee_payer, &config.owner, &message],
recent_blockhash,
@ -186,7 +189,7 @@ fn main() {
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE {
arg.default_value(&config_file)
arg.default_value(config_file)
} else {
arg
}
@ -360,10 +363,9 @@ fn main() {
("create-bridge", Some(arg_matches)) => {
let bridge = pubkey_of(arg_matches, "bridge").unwrap();
let initial_guardians = values_of::<String>(arg_matches, "guardian").unwrap();
let initial_data: Vec<Vec<u8>> = initial_guardians
let initial_data = initial_guardians
.into_iter()
.map(|key| hex::decode(key).unwrap())
.collect::<Vec<Vec<u8>>>();
.map(|key| hex::decode(key).unwrap());
let guardians: Vec<[u8; 20]> = initial_data
.into_iter()
.map(|key| {

View File

@ -7,6 +7,7 @@ use solana_program::{
pubkey::Pubkey,
};
#[allow(clippy::too_many_arguments)]
pub fn post_message(
program_id: Pubkey,
bridge_id: Pubkey,

View File

@ -26,6 +26,7 @@ pub type PostedMessage<'a, const State: AccountState> = Data<'a, PostedMessageDa
// This is using the same payload as the PostedVAA for backwards compatibility.
// This will be deprecated in a future release.
#[repr(transparent)]
#[derive(Default)]
pub struct PostedMessageData(pub MessageData);
#[derive(Debug, Default, BorshSerialize, BorshDeserialize, Clone, Serialize, Deserialize)]
@ -63,7 +64,7 @@ pub struct MessageData {
impl BorshSerialize for PostedMessageData {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write(b"msg")?;
writer.write_all(b"msg")?;
BorshSerialize::serialize(&self.0, writer)
}
}
@ -91,12 +92,6 @@ impl DerefMut for PostedMessageData {
}
}
impl Default for PostedMessageData {
fn default() -> Self {
PostedMessageData(MessageData::default())
}
}
impl Clone for PostedMessageData {
fn clone(&self) -> Self {
PostedMessageData(self.0.clone())

View File

@ -31,11 +31,12 @@ impl<'a, const State: AccountState> Seeded<&PostedVAADerivationData> for PostedV
}
#[repr(transparent)]
#[derive(Default)]
pub struct PostedVAAData(pub MessageData);
impl BorshSerialize for PostedVAAData {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write(b"vaa")?;
writer.write_all(b"vaa")?;
BorshSerialize::serialize(&self.0, writer)
}
}
@ -63,12 +64,6 @@ impl DerefMut for PostedVAAData {
}
}
impl Default for PostedVAAData {
fn default() -> Self {
PostedVAAData(MessageData::default())
}
}
impl Clone for PostedVAAData {
fn clone(&self) -> Self {
PostedVAAData(self.0.clone())

View File

@ -1,9 +1,7 @@
use solitaire::*;
use solana_program::{
log::sol_log,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
sysvar::{
clock::Clock,
@ -38,7 +36,7 @@ use crate::{
CHAIN_ID_SOLANA,
};
fn verify_governance<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()>
fn verify_governance<T>(vaa: &ClaimableVAA<T>) -> Result<()>
where
T: DeserializePayload,
{

View File

@ -34,10 +34,7 @@ use serde::{
Serialize,
};
use sha3::Digest;
use solana_program::{
program_error::ProgramError,
pubkey::Pubkey,
};
use solana_program::program_error::ProgramError;
use solitaire::{
processors::seeded::Seeded,
CreationLamports::Exempt,
@ -179,7 +176,7 @@ fn check_active<'r>(
}
// Static list of invalid signature accounts that are not allowed to post VAAs.
static INVALID_SIGNATURES: &'static [&'static str; 16] = &[
static INVALID_SIGNATURES: &[&str; 16] = &[
"18eK1799CaNMGCUnnCt1Kq2uwKkax6T2WmtrDsZuVFQ",
"2g6NCUUPaD6AxdHPQMVLpjpAvBfKMek6dDiGUe2A6T33",
"3hYV5968hNzbqUfcvnQ6v9D5h32hEwGJn19c47N3unNj",
@ -227,10 +224,10 @@ fn check_integrity<'r>(
v.write_u32::<BigEndian>(vaa.timestamp)?;
v.write_u32::<BigEndian>(vaa.nonce)?;
v.write_u16::<BigEndian>(vaa.emitter_chain)?;
v.write(&vaa.emitter_address)?;
v.write_all(&vaa.emitter_address)?;
v.write_u64::<BigEndian>(vaa.sequence)?;
v.write_u8(vaa.consistency_level)?;
v.write(&vaa.payload)?;
v.write_all(&vaa.payload)?;
v.into_inner()
};

View File

@ -1,3 +1,4 @@
#![allow(clippy::collapsible_if)]
use solitaire::*;
use crate::{
@ -83,10 +84,10 @@ pub fn verify_signatures(
return None;
}
return Some(SigInfo {
Some(SigInfo {
sig_index: *p as u8,
signer_index: i as u8,
});
})
})
.collect();

View File

@ -121,7 +121,7 @@ pub fn post_message(
crate::instruction::Instruction::PostMessage,
PostMessageData {
nonce,
payload: payload.clone(),
payload,
consistency_level: commitment,
},
)
@ -178,7 +178,7 @@ pub fn post_vaa(
};
let message =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &program_id);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, &program_id);
Instruction {
program_id,
@ -268,7 +268,7 @@ pub fn upgrade_guardian_set(
&ClaimDerivationData {
emitter_address: emitter.to_bytes(),
emitter_chain: CHAIN_ID_SOLANA,
sequence: sequence,
sequence,
},
&program_id,
);
@ -389,10 +389,10 @@ pub fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
v.write_u32::<BigEndian>(vaa.timestamp).unwrap();
v.write_u32::<BigEndian>(vaa.nonce).unwrap();
v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
v.write(&vaa.emitter_address).unwrap();
v.write_all(&vaa.emitter_address).unwrap();
v.write_u64::<BigEndian>(vaa.sequence).unwrap();
v.write_u8(vaa.consistency_level).unwrap();
v.write(&vaa.payload).unwrap();
v.write_all(&vaa.payload).unwrap();
v.into_inner()
}
@ -400,6 +400,6 @@ pub fn serialize_vaa(vaa: &PostVAAData) -> Vec<u8> {
pub fn hash_vaa(vaa: &PostVAAData) -> [u8; 32] {
let body = serialize_vaa(vaa);
let mut h = sha3::Keccak256::default();
h.write(body.as_slice()).unwrap();
h.write_all(body.as_slice()).unwrap();
h.finalize().into()
}

View File

@ -51,7 +51,7 @@ pub struct GovernancePayloadUpgrade {
impl SerializePayload for GovernancePayloadUpgrade {
fn serialize<W: Write>(&self, v: &mut W) -> std::result::Result<(), SolitaireError> {
v.write(&self.new_contract.to_bytes())?;
v.write_all(&self.new_contract.to_bytes())?;
Ok(())
}
}
@ -99,7 +99,7 @@ impl SerializePayload for GovernancePayloadGuardianSetChange {
v.write_u32::<BigEndian>(self.new_guardian_set_index)?;
v.write_u8(self.new_guardian_set.len() as u8)?;
for key in self.new_guardian_set.iter() {
v.write(key)?;
v.write_all(key)?;
}
Ok(())
}
@ -119,7 +119,7 @@ where
let mut keys = Vec::with_capacity(keys_len as usize);
for _ in 0..keys_len {
let mut key: [u8; 20] = [0; 20];
c.read(&mut key)?;
c.read_exact(&mut key)?;
keys.push(key);
}
@ -151,7 +151,7 @@ impl SerializePayload for GovernancePayloadSetMessageFee {
fn serialize<W: Write>(&self, v: &mut W) -> std::result::Result<(), SolitaireError> {
let mut fee_data = [0u8; 32];
self.fee.to_big_endian(&mut fee_data);
v.write(&fee_data[..])?;
v.write_all(&fee_data[..])?;
Ok(())
}
@ -197,8 +197,8 @@ impl SerializePayload for GovernancePayloadTransferFees {
fn serialize<W: Write>(&self, v: &mut W) -> std::result::Result<(), SolitaireError> {
let mut amount_data = [0u8; 32];
self.amount.to_big_endian(&mut amount_data);
v.write(&amount_data)?;
v.write(&self.to)?;
v.write_all(&amount_data)?;
v.write_all(&self.to)?;
Ok(())
}
}

View File

@ -8,7 +8,6 @@ use crate::{
InvalidGovernanceChain,
InvalidGovernanceModule,
VAAAlreadyExecuted,
VAAInvalid,
},
Claim,
ClaimDerivationData,
@ -80,7 +79,7 @@ pub trait SerializeGovernancePayload: SerializePayload {
use byteorder::WriteBytesExt;
let module = format!("{:\0>32}", Self::MODULE);
let module = module.as_bytes();
c.write(&module)?;
c.write_all(module)?;
c.write_u8(Self::ACTION)?;
c.write_u16::<BigEndian>(CHAIN_ID_SOLANA)?;
Ok(())
@ -248,39 +247,49 @@ impl VAA {
pub fn deserialize(data: &[u8]) -> std::result::Result<VAA, std::io::Error> {
let mut rdr = Cursor::new(data);
let mut v = VAA::default();
v.version = rdr.read_u8()?;
v.guardian_set_index = rdr.read_u32::<BigEndian>()?;
let version = rdr.read_u8()?;
let guardian_set_index = rdr.read_u32::<BigEndian>()?;
let len_sig = rdr.read_u8()?;
let mut sigs: Vec<VAASignature> = Vec::with_capacity(len_sig as usize);
let mut signatures: Vec<VAASignature> = Vec::with_capacity(len_sig as usize);
for _i in 0..len_sig {
let mut sig = VAASignature::default();
sig.guardian_index = rdr.read_u8()?;
let guardian_index = rdr.read_u8()?;
let mut signature_data = [0u8; 65];
rdr.read_exact(&mut signature_data)?;
sig.signature = signature_data.to_vec();
let signature = signature_data.to_vec();
sigs.push(sig);
signatures.push(VAASignature {
guardian_index,
signature,
});
}
v.signatures = sigs;
v.timestamp = rdr.read_u32::<BigEndian>()?;
v.nonce = rdr.read_u32::<BigEndian>()?;
v.emitter_chain = rdr.read_u16::<BigEndian>()?;
let timestamp = rdr.read_u32::<BigEndian>()?;
let nonce = rdr.read_u32::<BigEndian>()?;
let emitter_chain = rdr.read_u16::<BigEndian>()?;
let mut emitter_address = [0u8; 32];
rdr.read_exact(&mut emitter_address)?;
v.emitter_address = emitter_address;
v.sequence = rdr.read_u64::<BigEndian>()?;
v.consistency_level = rdr.read_u8()?;
let sequence = rdr.read_u64::<BigEndian>()?;
let consistency_level = rdr.read_u8()?;
rdr.read_to_end(&mut v.payload)?;
let mut payload = Vec::new();
rdr.read_to_end(&mut payload)?;
Ok(v)
Ok(VAA {
version,
guardian_set_index,
signatures,
timestamp,
nonce,
emitter_chain,
emitter_address,
sequence,
consistency_level,
payload,
})
}
}

View File

@ -1,35 +1,18 @@
#![allow(warnings)]
use borsh::{
BorshDeserialize,
BorshSerialize,
};
use borsh::BorshDeserialize;
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use libsecp256k1::{
Message as Secp256k1Message,
PublicKey,
SecretKey,
};
use sha3::Digest;
use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{
AccountMeta,
Instruction,
},
program_pack::Pack,
instruction::Instruction,
pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar,
system_instruction,
};
use solana_program_test::{
BanksClient,
@ -37,12 +20,9 @@ use solana_program_test::{
};
use solana_sdk::{
commitment_config::CommitmentLevel,
hash::Hash,
secp256k1_instruction::new_secp256k1_instruction,
signature::{
read_keypair_file,
Keypair,
Signature,
Signer,
},
signers::Signers,
@ -50,48 +30,24 @@ use solana_sdk::{
transport::TransportError,
};
use std::{
convert::TryInto,
env,
io::{
Cursor,
Write,
},
time::{
Duration,
SystemTime,
},
time::SystemTime,
};
use bridge::{
accounts::{
Bridge,
BridgeConfig,
FeeCollector,
GuardianSet,
GuardianSetDerivationData,
PostedVAAData,
PostedVAADerivationData,
Sequence,
SequenceDerivationData,
SequenceTracker,
SignatureSet,
},
accounts::FeeCollector,
instruction,
instructions,
types::ConsistencyLevel,
Initialize,
InitializeData,
PostMessageData,
PostVAAData,
UninitializedMessage,
VerifySignaturesData,
};
use solitaire::{
processors::seeded::Seeded,
AccountSize,
AccountState,
};
use solitaire::processors::seeded::Seeded;
pub use helpers::*;
@ -113,31 +69,17 @@ pub async fn execute<T: Signers>(
}
mod helpers {
use bridge::{
BridgeData,
GuardianSetData,
};
use solana_program::rent::Rent;
use solana_program_test::{
processor,
ProgramTestContext,
};
use solana_sdk::account::Account;
use solitaire::{
CreationLamports,
Derive,
};
use solana_program_test::processor;
use super::*;
/// Initialize the test environment, spins up a solana-test-validator in the background so that
/// each test has a fresh environment to work within.
pub async fn setup() -> (BanksClient, Keypair, Pubkey) {
let program = env::var("BRIDGE_PROGRAM")
.unwrap_or("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
.unwrap_or_else(|_| "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
.parse::<Pubkey>()
.unwrap();
let mut builder = ProgramTest::new(
let builder = ProgramTest::new(
"bridge",
program,
processor!(instruction::solitaire),
@ -185,9 +127,6 @@ mod helpers {
/// Generate `count` secp256k1 private keys, along with their ethereum-styled public key
/// encoding: 0x0123456789ABCDEF01234
pub fn generate_keys(count: u8) -> (Vec<[u8; 20]>, Vec<SecretKey>) {
use rand::Rng;
use sha3::Digest;
let mut rng = rand::thread_rng();
// Generate Guardian Keys
@ -199,9 +138,9 @@ mod helpers {
secret_keys
.iter()
.map(|key| {
let public_key = PublicKey::from_secret_key(&key);
let public_key = PublicKey::from_secret_key(key);
let mut h = sha3::Keccak256::default();
h.write(&public_key.serialize()[1..]).unwrap();
h.write_all(&public_key.serialize()[1..]).unwrap();
let key: [u8; 32] = h.finalize().into();
let mut address = [0u8; 20];
address.copy_from_slice(&key[12..]);
@ -221,7 +160,7 @@ mod helpers {
guardian_set_index: u32,
emitter_chain: u16,
) -> (PostVAAData, [u8; 32], [u8; 32]) {
let mut vaa = PostVAAData {
let vaa = PostVAAData {
version: 0,
guardian_set_index,
@ -244,10 +183,10 @@ mod helpers {
v.write_u32::<BigEndian>(vaa.timestamp).unwrap();
v.write_u32::<BigEndian>(vaa.nonce).unwrap();
v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
v.write(&vaa.emitter_address).unwrap();
v.write_all(&vaa.emitter_address).unwrap();
v.write_u64::<BigEndian>(vaa.sequence).unwrap();
v.write_u8(vaa.consistency_level).unwrap();
v.write(&vaa.payload).unwrap();
v.write_all(&vaa.payload).unwrap();
v.into_inner()
};
@ -255,35 +194,19 @@ mod helpers {
// signature account, binding that set of signatures to this VAA.
let body: [u8; 32] = {
let mut h = sha3::Keccak256::default();
h.write(body.as_slice()).unwrap();
h.write_all(body.as_slice()).unwrap();
h.finalize().into()
};
let body_hash: [u8; 32] = {
let mut h = sha3::Keccak256::default();
h.write(&body).unwrap();
h.write_all(&body).unwrap();
h.finalize().into()
};
(vaa, body, body_hash)
}
pub async fn transfer(
client: &mut BanksClient,
from: &Keypair,
to: &Pubkey,
lamports: u64,
) -> Result<(), TransportError> {
execute(
client,
from,
&[from],
&[system_instruction::transfer(&from.pubkey(), to, lamports)],
CommitmentLevel::Processed,
)
.await
}
pub async fn initialize(
client: &mut BanksClient,
program: Pubkey,
@ -410,6 +333,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn upgrade_guardian_set(
client: &mut BanksClient,
program: &Pubkey,
@ -438,6 +362,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn upgrade_contract(
client: &mut BanksClient,
program: &Pubkey,

View File

@ -1,33 +1,8 @@
#![allow(warnings)]
use borsh::BorshSerialize;
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use libsecp256k1::{
Message as Secp256k1Message,
PublicKey,
SecretKey,
};
use libsecp256k1::SecretKey;
use rand::Rng;
use sha3::Digest;
use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{
AccountMeta,
Instruction,
},
program_pack::Pack,
pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar,
system_instruction,
};
use solana_program_test::{
tokio,
@ -36,46 +11,28 @@ use solana_program_test::{
use solana_sdk::{
commitment_config::CommitmentLevel,
signature::{
read_keypair_file,
Keypair,
Signer,
},
transaction::Transaction,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use std::{
convert::TryInto,
io::{
Cursor,
Write,
},
time::{
Duration,
SystemTime,
},
};
use bridge::{
accounts::{
Bridge,
BridgeConfig,
BridgeData,
FeeCollector,
GuardianSet,
GuardianSetData,
GuardianSetDerivationData,
MessageData,
PostedVAA,
PostedVAAData,
PostedVAADerivationData,
SequenceTracker,
SignatureSet,
SignatureSetData,
},
instruction,
instructions,
types::{
ConsistencyLevel,
@ -84,15 +41,10 @@ use bridge::{
GovernancePayloadTransferFees,
GovernancePayloadUpgrade,
},
Initialize,
PostVAA,
PostVAAData,
SerializeGovernancePayload,
Signature,
};
use primitive_types::U256;
use solana_program::rent::Rent;
use solana_sdk::hash::hashv;
mod common;
@ -124,15 +76,11 @@ impl Sequencer {
*entry += 1;
*entry - 1
}
fn peek(&mut self, emitter: [u8; 32]) -> u64 {
*self.sequences.entry(emitter).or_insert(0)
}
}
async fn initialize() -> (Context, BanksClient, Keypair, Pubkey) {
let (public_keys, secret_keys) = common::generate_keys(6);
let mut context = Context {
let context = Context {
public: public_keys,
secret: secret_keys,
seq: Sequencer {
@ -218,7 +166,7 @@ async fn bridge_messages() {
);
// Emulate Guardian behaviour, verifying the data and publishing signatures/VAA.
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let vaa_time = vaa.timestamp;
@ -232,7 +180,7 @@ async fn bridge_messages() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
common::post_vaa(client, program, payer, signature_set, vaa)
.await
@ -265,8 +213,8 @@ async fn bridge_messages() {
assert_eq!(signatures.hash, body);
assert_eq!(signatures.guardian_set_index, 0);
for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert_eq!(*signature, true);
for (signature, _secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert!(*signature);
}
}
@ -302,7 +250,7 @@ async fn bridge_messages() {
);
// Emulate Guardian behaviour, verifying the data and publishing signatures/VAA.
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let vaa_time = vaa.timestamp;
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
@ -314,7 +262,7 @@ async fn bridge_messages() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
common::post_vaa(client, program, payer, signature_set, vaa)
.await
@ -347,8 +295,8 @@ async fn bridge_messages() {
assert_eq!(signatures.hash, body);
assert_eq!(signatures.guardian_set_index, 0);
for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert_eq!(*signature, true);
for (signature, _secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert!(*signature);
}
}
@ -434,9 +382,9 @@ async fn invalid_emitter() {
let message = [0u8; 32].to_vec();
let emitter = Keypair::new();
let nonce = rand::thread_rng().gen();
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let _sequence = context.seq.next(emitter.pubkey().to_bytes());
let fee_collector = FeeCollector::key(None, &program);
let fee_collector = FeeCollector::key(None, program);
let msg_account = Keypair::new();
// Manually send a message that isn't signed by the emitter, which should be rejected to
@ -520,7 +468,7 @@ async fn guardian_set_change() {
emitter.pubkey().to_bytes()
);
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let vaa_time = vaa.timestamp;
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
@ -530,7 +478,7 @@ async fn guardian_set_change() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
common::post_vaa(client, program, payer, signature_set, vaa)
.await
@ -550,10 +498,10 @@ async fn guardian_set_change() {
common::sync(client, payer).await;
// Derive keys for accounts we want to check.
let bridge_key = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program);
let bridge_key = Bridge::<'_, { AccountState::Uninitialized }>::key(None, program);
let guardian_set_key = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
&GuardianSetDerivationData { index: 1 },
&program,
program,
);
// Fetch account states.
@ -591,7 +539,7 @@ async fn guardian_set_change() {
// Submit the message a second time with a new nonce.
let nonce = rand::thread_rng().gen();
let message_key = common::post_message(
let _message_key = common::post_message(
client,
program,
payer,
@ -607,7 +555,7 @@ async fn guardian_set_change() {
context.secret = new_secret_keys;
// Emulate Guardian behaviour, verifying the data and publishing signatures/VAA.
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 1, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 1)
.await
@ -617,7 +565,7 @@ async fn guardian_set_change() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
common::post_vaa(client, program, payer, signature_set, vaa)
.await
@ -649,8 +597,8 @@ async fn guardian_set_change() {
assert_eq!(signatures.hash, body);
assert_eq!(signatures.guardian_set_index, 1);
for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert_eq!(*signature, true);
for (signature, _secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert!(*signature);
}
}
@ -664,7 +612,7 @@ async fn guardian_set_change_fails() {
let sequence = context.seq.next(emitter.pubkey().to_bytes());
// Upgrade the guardian set with a new set of guardians.
let (new_public_keys, new_secret_keys) = common::generate_keys(6);
let (new_public_keys, _new_secret_keys) = common::generate_keys(6);
let nonce = rand::thread_rng().gen();
let message = GovernancePayloadGuardianSetChange {
new_guardian_set_index: 2,
@ -684,8 +632,6 @@ async fn guardian_set_change_fails() {
)
.await
.unwrap();
let (vaa, body, body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
assert!(common::upgrade_guardian_set(
client,
@ -727,7 +673,7 @@ async fn set_fees() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -748,8 +694,8 @@ async fn set_fees() {
common::sync(client, payer).await;
// Fetch Bridge to check on-state value.
let bridge_key = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program);
let fee_collector = FeeCollector::key(None, &program);
let bridge_key = Bridge::<'_, { AccountState::Uninitialized }>::key(None, program);
let fee_collector = FeeCollector::key(None, program);
let bridge: BridgeData = common::get_account_data(client, bridge_key).await;
assert_eq!(bridge.config.fee, 100);
@ -775,7 +721,7 @@ async fn set_fees() {
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let nonce = rand::thread_rng().gen();
let message = [0u8; 32].to_vec();
let message_key = common::post_message(
let _message_key = common::post_message(
client,
program,
payer,
@ -787,7 +733,7 @@ async fn set_fees() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -797,7 +743,7 @@ async fn set_fees() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
common::post_vaa(client, program, payer, signature_set, vaa)
.await
@ -836,8 +782,8 @@ async fn set_fees() {
assert_eq!(signatures.hash, body);
assert_eq!(signatures.guardian_set_index, 0);
for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert_eq!(*signature, true);
for (signature, _secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert!(*signature);
}
}
@ -869,7 +815,7 @@ async fn set_fees_fails() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -917,7 +863,7 @@ async fn free_fees() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -938,8 +884,8 @@ async fn free_fees() {
common::sync(client, payer).await;
// Fetch Bridge to check on-state value.
let bridge_key = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program);
let fee_collector = FeeCollector::key(None, &program);
let bridge_key = Bridge::<'_, { AccountState::Uninitialized }>::key(None, program);
let fee_collector = FeeCollector::key(None, program);
let bridge: BridgeData = common::get_account_data(client, bridge_key).await;
assert_eq!(bridge.config.fee, 0);
@ -949,12 +895,12 @@ async fn free_fees() {
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let nonce = rand::thread_rng().gen();
let message = [0u8; 32].to_vec();
let message_key =
let _message_key =
common::post_message(client, program, payer, &emitter, nonce, message.clone(), 0)
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -964,7 +910,7 @@ async fn free_fees() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
common::post_vaa(client, program, payer, signature_set, vaa)
.await
@ -1003,8 +949,8 @@ async fn free_fees() {
assert_eq!(signatures.hash, body);
assert_eq!(signatures.guardian_set_index, 0);
for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert_eq!(*signature, true);
for (signature, _secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert!(*signature);
}
}
@ -1015,7 +961,6 @@ async fn transfer_fees() {
let emitter = Keypair::from_bytes(&GOVERNANCE_KEY).unwrap();
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let recipient = Keypair::new();
let nonce = rand::thread_rng().gen();
let message = GovernancePayloadTransferFees {
amount: 100u128.into(),
@ -1025,8 +970,7 @@ async fn transfer_fees() {
.unwrap();
// Fetch accounts for chain state checking.
let fee_collector = FeeCollector::key(None, &program);
let account_balance = common::get_account_balance(client, fee_collector).await;
let fee_collector = FeeCollector::key(None, program);
let message_key = common::post_message(
client,
@ -1040,7 +984,7 @@ async fn transfer_fees() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -1078,7 +1022,6 @@ async fn transfer_fees_fails() {
let emitter = Keypair::new();
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let recipient = Keypair::new();
let nonce = rand::thread_rng().gen();
let message = GovernancePayloadTransferFees {
amount: 100u128.into(),
@ -1088,8 +1031,7 @@ async fn transfer_fees_fails() {
.unwrap();
// Fetch accounts for chain state checking.
let fee_collector = FeeCollector::key(None, &program);
let account_balance = common::get_account_balance(client, fee_collector).await;
let fee_collector = FeeCollector::key(None, program);
let message_key = common::post_message(
client,
@ -1103,7 +1045,7 @@ async fn transfer_fees_fails() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -1139,7 +1081,6 @@ async fn transfer_too_much() {
let emitter = Keypair::from_bytes(&GOVERNANCE_KEY).unwrap();
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let recipient = Keypair::new();
let nonce = rand::thread_rng().gen();
let message = GovernancePayloadTransferFees {
amount: 100_000_000_000u64.into(),
@ -1149,8 +1090,7 @@ async fn transfer_too_much() {
.unwrap();
// Fetch accounts for chain state checking.
let fee_collector = FeeCollector::key(None, &program);
let account_balance = common::get_account_balance(client, fee_collector).await;
let fee_collector = FeeCollector::key(None, program);
let message_key = common::post_message(
client,
@ -1164,7 +1104,7 @@ async fn transfer_too_much() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -1204,7 +1144,7 @@ async fn foreign_bridge_messages() {
let sequence = context.seq.next(emitter.pubkey().to_bytes());
// Verify the VAA generated on a foreign chain.
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 2);
// Derive where we expect created accounts to be.
@ -1212,7 +1152,7 @@ async fn foreign_bridge_messages() {
&PostedVAADerivationData {
payload_hash: body.to_vec(),
},
&program,
program,
);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
@ -1242,8 +1182,8 @@ async fn foreign_bridge_messages() {
assert_eq!(signatures.hash, body);
assert_eq!(signatures.guardian_set_index, 0);
for (signature, secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert_eq!(*signature, true);
for (signature, _secret_key) in signatures.signatures.iter().zip(context.secret.iter()) {
assert!(*signature);
}
}
@ -1257,11 +1197,10 @@ async fn transfer_total_fails() {
// Be sure any previous tests have fully committed.
common::sync(client, payer).await;
let fee_collector = FeeCollector::key(None, &program);
let fee_collector = FeeCollector::key(None, program);
let account_balance = common::get_account_balance(client, fee_collector).await;
// Prepare to remove total balance, adding 10_000 to include the fee we're about to pay.
let recipient = Keypair::new();
let nonce = rand::thread_rng().gen();
let message = GovernancePayloadTransferFees {
amount: (account_balance + 10_000).into(),
@ -1282,7 +1221,7 @@ async fn transfer_total_fails() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await
@ -1323,9 +1262,6 @@ async fn upgrade_contract() {
// Initialize a wormhole bridge on Solana to test with.
let (ref mut context, ref mut client, ref payer, ref program) = initialize().await;
// Upgrade the guardian set with a new set of guardians.
let (new_public_keys, new_secret_keys) = common::generate_keys(1);
// New Contract Address
// let new_contract = Pubkey::new_unique();
let new_contract = *program;
@ -1333,11 +1269,9 @@ async fn upgrade_contract() {
let nonce = rand::thread_rng().gen();
let emitter = Keypair::from_bytes(&GOVERNANCE_KEY).unwrap();
let sequence = context.seq.next(emitter.pubkey().to_bytes());
let message = GovernancePayloadUpgrade {
new_contract: new_contract.clone(),
}
.try_to_vec()
.unwrap();
let message = GovernancePayloadUpgrade { new_contract }
.try_to_vec()
.unwrap();
let message_key = common::post_message(
client,
@ -1351,7 +1285,7 @@ async fn upgrade_contract() {
.await
.unwrap();
let (vaa, body, body_hash) =
let (vaa, body, _body_hash) =
common::generate_vaa(&emitter, message.clone(), nonce, sequence, 0, 1);
let signature_set = common::verify_signatures(client, program, payer, body, &context.secret, 0)
.await

View File

@ -12,13 +12,11 @@ use solana_program::{
use bridge::{
accounts::{
Bridge,
GuardianSetDerivationData,
PostedVAA,
PostedVAADerivationData,
},
instructions::hash_vaa,
PostVAAData,
CHAIN_ID_SOLANA,
};
use solitaire::{
processors::seeded::Seeded,
@ -60,7 +58,7 @@ pub struct Signature {
pub type ForeignAddress = [u8; 32];
pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) -> Result<()> {
let mut msg_derivation = PostedVAADerivationData {
let msg_derivation = PostedVAADerivationData {
payload_hash: hash_vaa(&vaa).to_vec(),
};

View File

@ -20,8 +20,6 @@ pub use api::{
UninitializedMessage,
};
use bridge::PostVAAData;
solitaire! {
Initialize => initialize,
PostMessage => post_message,

View File

@ -214,7 +214,6 @@ pub fn complete_wrapped(
accs: &mut CompleteWrapped,
_data: CompleteWrappedData,
) -> Result<()> {
use bstr::ByteSlice;
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();

View File

@ -36,7 +36,7 @@ use solitaire::{
};
// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
fn verify_governance<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()>
fn verify_governance<T>(vaa: &ClaimableVAA<T>) -> Result<()>
where
T: DeserializePayload,
{
@ -95,7 +95,7 @@ pub fn upgrade_contract(
_data: UpgradeContractData,
) -> Result<()> {
verify_governance(&accs.vaa)?;
accs.vaa.verify(&ctx.program_id)?;
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?;
@ -152,7 +152,7 @@ pub fn register_chain(
// Claim VAA
verify_governance(&accs.vaa)?;
accs.vaa.verify(&ctx.program_id)?;
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?;
if accs.vaa.chain == CHAIN_ID_SOLANA {

View File

@ -36,24 +36,13 @@ use borsh::BorshSerialize;
use bridge::{
accounts::{
Bridge,
BridgeConfig,
Claim,
ClaimDerivationData,
FeeCollector,
PostedVAA,
PostedVAAData,
PostedVAADerivationData,
Sequence,
SequenceDerivationData,
},
api::ForeignAddress,
instructions::hash_vaa,
vaa::{
ClaimableVAA,
PayloadMessage,
SerializePayload,
},
PostVAA,
PostVAAData,
CHAIN_ID_SOLANA,
};
@ -69,8 +58,6 @@ use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use spl_token::state::Mint;
use std::str::FromStr;
pub fn initialize(
program_id: Pubkey,
@ -91,6 +78,7 @@ pub fn initialize(
})
}
#[allow(clippy::too_many_arguments)]
pub fn complete_native(
program_id: Pubkey,
bridge_id: Pubkey,
@ -143,6 +131,7 @@ pub fn complete_native(
})
}
#[allow(clippy::too_many_arguments)]
pub fn complete_wrapped(
program_id: Pubkey,
bridge_id: Pubkey,
@ -215,7 +204,7 @@ pub fn complete_wrapped_meta(
data: CompleteWrappedMetaData,
) -> solitaire::Result<Instruction> {
let config_key = ConfigAccount::<'_, { AccountState::Uninitialized }>::key(None, &program_id);
let (message_acc, claim_acc) = claimable_vaa(program_id, message_key, vaa.clone());
let (message_acc, _claim_acc) = claimable_vaa(program_id, message_key, vaa.clone());
let endpoint = Endpoint::<'_, { AccountState::Initialized }>::key(
&EndpointDerivationData {
emitter_chain: vaa.emitter_chain,
@ -345,7 +334,7 @@ pub fn transfer_native(
// SPL Metadata
let spl_metadata = SplTokenMeta::key(
&SplTokenMetaDerivationData { mint: mint },
&SplTokenMetaDerivationData { mint },
&spl_token_metadata::id(),
);
@ -387,6 +376,7 @@ pub fn transfer_native(
})
}
#[allow(clippy::too_many_arguments)]
pub fn transfer_wrapped(
program_id: Pubkey,
bridge_id: Pubkey,

View File

@ -21,10 +21,13 @@ use solana_program::{
pubkey::Pubkey,
};
use solitaire::SolitaireError;
use std::io::{
Cursor,
Read,
Write,
use std::{
cmp,
io::{
Cursor,
Read,
Write,
},
};
pub const MODULE: &str = "NFTBridge";
@ -117,29 +120,28 @@ impl SerializePayload for PayloadTransfer {
// Payload ID
writer.write_u8(1)?;
writer.write(&self.token_address)?;
writer.write_all(&self.token_address)?;
writer.write_u16::<BigEndian>(self.token_chain)?;
let mut symbol: [u8; 32] = [0; 32];
for i in 0..self.symbol.len() {
symbol[i] = self.symbol.as_bytes()[i];
}
writer.write(&symbol)?;
let count = cmp::min(symbol.len(), self.symbol.len());
symbol[..count].copy_from_slice(self.symbol[..count].as_bytes());
writer.write_all(&symbol)?;
let mut name: [u8; 32] = [0; 32];
for i in 0..self.name.len() {
name[i] = self.name.as_bytes()[i];
}
writer.write(&name)?;
let count = cmp::min(name.len(), self.name.len());
name[..count].copy_from_slice(self.name[..count].as_bytes());
writer.write_all(&name)?;
let mut id_data: [u8; 32] = [0; 32];
self.token_id.to_big_endian(&mut id_data);
writer.write(&id_data)?;
writer.write_all(&id_data)?;
writer.write_u8(self.uri.len() as u8)?;
writer.write(self.uri.as_bytes())?;
writer.write_all(self.uri.as_bytes())?;
writer.write(&self.to)?;
writer.write_all(&self.to)?;
writer.write_u16::<BigEndian>(self.to_chain)?;
Ok(())
@ -193,7 +195,7 @@ where
self.write_governance_header(writer)?;
// Payload ID
writer.write_u16::<BigEndian>(self.chain)?;
writer.write(&self.endpoint_address[..])?;
writer.write_all(&self.endpoint_address[..])?;
Ok(())
}
@ -208,7 +210,7 @@ pub struct GovernancePayloadUpgrade {
impl SerializePayload for GovernancePayloadUpgrade {
fn serialize<W: Write>(&self, v: &mut W) -> std::result::Result<(), SolitaireError> {
self.write_governance_header(v)?;
v.write(&self.new_contract.to_bytes())?;
v.write_all(&self.new_contract.to_bytes())?;
Ok(())
}
}
@ -243,6 +245,7 @@ impl DeserializeGovernancePayload for GovernancePayloadUpgrade {
}
#[cfg(feature = "no-entrypoint")]
#[allow(unused_imports)]
mod tests {
use crate::messages::{
GovernancePayloadUpgrade,
@ -275,7 +278,7 @@ mod tests {
token_id: U256::from(1234),
};
let mut data = transfer_original.try_to_vec().unwrap();
let data = transfer_original.try_to_vec().unwrap();
let transfer_deser = PayloadTransfer::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(transfer_original, transfer_deser);
@ -287,7 +290,7 @@ mod tests {
new_contract: Pubkey::new_unique(),
};
let mut data = original.try_to_vec().unwrap();
let data = original.try_to_vec().unwrap();
let deser = GovernancePayloadUpgrade::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(original, deser);
@ -303,7 +306,7 @@ mod tests {
endpoint_address,
};
let mut data = original.try_to_vec().unwrap();
let data = original.try_to_vec().unwrap();
let deser = PayloadGovernanceRegisterChain::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(original, deser);

View File

@ -1,35 +1,20 @@
#![allow(warnings)]
use borsh::{
BorshDeserialize,
BorshSerialize,
};
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use libsecp256k1::{
Message as Secp256k1Message,
PublicKey,
SecretKey,
};
use sha3::Digest;
use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{
AccountMeta,
Instruction,
},
instruction::Instruction,
program_pack::Pack,
pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar,
system_instruction,
};
use solana_program_test::{
BanksClient,
@ -40,39 +25,26 @@ use solana_sdk::{
rent::Rent,
secp256k1_instruction::new_secp256k1_instruction,
signature::{
read_keypair_file,
Keypair,
Signature,
Signer,
},
signers::Signers,
transaction::Transaction,
transport::TransportError,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use spl_token::state::Mint;
use solitaire::processors::seeded::Seeded;
use std::{
convert::TryInto,
env,
io::{
Cursor,
Write,
},
time::{
Duration,
SystemTime,
},
time::SystemTime,
};
use nft_bridge::{
accounts::*,
instruction,
instructions,
types::*,
Initialize,
};
pub use helpers::*;
@ -96,13 +68,9 @@ pub async fn execute<T: Signers>(
mod helpers {
use super::*;
use bridge::{
accounts::{
FeeCollector,
PostedVAADerivationData,
},
accounts::FeeCollector,
types::ConsistencyLevel,
PostVAAData,
PostedVAAData,
};
use nft_bridge::{
CompleteNativeData,
@ -119,14 +87,10 @@ mod helpers {
PayloadGovernanceRegisterChain,
PayloadTransfer,
};
use std::ops::Add;
/// Generate `count` secp256k1 private keys, along with their ethereum-styled public key
/// encoding: 0x0123456789ABCDEF01234
pub fn generate_keys(count: u8) -> (Vec<[u8; 20]>, Vec<SecretKey>) {
use rand::Rng;
use sha3::Digest;
let mut rng = rand::thread_rng();
// Generate Guardian Keys
@ -138,9 +102,9 @@ mod helpers {
secret_keys
.iter()
.map(|key| {
let public_key = PublicKey::from_secret_key(&key);
let public_key = PublicKey::from_secret_key(key);
let mut h = sha3::Keccak256::default();
h.write(&public_key.serialize()[1..]).unwrap();
h.write_all(&public_key.serialize()[1..]).unwrap();
let key: [u8; 32] = h.finalize().into();
let mut address = [0u8; 20];
address.copy_from_slice(&key[12..]);
@ -156,11 +120,11 @@ mod helpers {
pub async fn setup() -> (BanksClient, Keypair, Pubkey, Pubkey) {
let (program, token_program) = (
env::var("BRIDGE_PROGRAM")
.unwrap_or("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
.unwrap_or_else(|_| "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
.parse::<Pubkey>()
.unwrap(),
env::var("NFT_BRIDGE_PROGRAM")
.unwrap_or("NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA".to_string())
.unwrap_or_else(|_| "NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA".to_string())
.parse::<Pubkey>()
.unwrap(),
);
@ -236,6 +200,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn transfer_native(
client: &mut BanksClient,
program: Pubkey,
@ -282,6 +247,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn transfer_wrapped(
client: &mut BanksClient,
program: Pubkey,
@ -363,13 +329,14 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn complete_native(
client: &mut BanksClient,
program: Pubkey,
bridge: Pubkey,
message_acc: Pubkey,
vaa: PostVAAData,
payload: PayloadTransfer,
_payload: PayloadTransfer,
payer: &Keypair,
to_authority: Pubkey,
mint: Pubkey,
@ -396,6 +363,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn complete_wrapped(
client: &mut BanksClient,
program: Pubkey,
@ -524,6 +492,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn create_spl_metadata(
client: &mut BanksClient,
payer: &Keypair,
@ -593,7 +562,7 @@ mod helpers {
nonce: u32,
sequence: u64,
) -> (PostVAAData, [u8; 32], [u8; 32]) {
let mut vaa = PostVAAData {
let vaa = PostVAAData {
version: 0,
guardian_set_index: 0,
@ -616,10 +585,10 @@ mod helpers {
v.write_u32::<BigEndian>(vaa.timestamp).unwrap();
v.write_u32::<BigEndian>(vaa.nonce).unwrap();
v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
v.write(&vaa.emitter_address).unwrap();
v.write_all(&vaa.emitter_address).unwrap();
v.write_u64::<BigEndian>(vaa.sequence).unwrap();
v.write_u8(vaa.consistency_level).unwrap();
v.write(&vaa.payload).unwrap();
v.write_all(&vaa.payload).unwrap();
v.into_inner()
};
@ -627,13 +596,13 @@ mod helpers {
// signature account, binding that set of signatures to this VAA.
let body: [u8; 32] = {
let mut h = sha3::Keccak256::default();
h.write(body.as_slice()).unwrap();
h.write_all(body.as_slice()).unwrap();
h.finalize().into()
};
let body_hash: [u8; 32] = {
let mut h = sha3::Keccak256::default();
h.write(&body).unwrap();
h.write_all(&body).unwrap();
h.finalize().into()
};
@ -699,6 +668,9 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
// This function is not used, but looks useful...
#[allow(dead_code)]
pub async fn post_message(
client: &mut BanksClient,
program: Pubkey,

View File

@ -1,51 +1,15 @@
#![allow(warnings)]
use borsh::BorshSerialize;
use bridge::{
accounts::{
Bridge,
FeeCollector,
GuardianSet,
GuardianSetDerivationData,
PostedVAA,
PostedVAADerivationData,
SignatureSet,
},
instruction,
types::{
GovernancePayloadGuardianSetChange,
GovernancePayloadSetMessageFee,
GovernancePayloadTransferFees,
},
BridgeConfig,
BridgeData,
GuardianSetData,
Initialize,
MessageData,
PostVAA,
PostVAAData,
PostedVAAData,
SequenceTracker,
SerializePayload,
Signature,
SignatureSet as SignatureSetData,
};
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use libsecp256k1::{
Message as Secp256k1Message,
PublicKey,
SecretKey,
};
use libsecp256k1::SecretKey;
use nft_bridge::{
accounts::{
ConfigAccount,
EmitterAccount,
SplTokenMeta,
SplTokenMetaDerivationData,
WrappedDerivationData,
WrappedMint,
},
@ -53,63 +17,27 @@ use nft_bridge::{
PayloadGovernanceRegisterChain,
PayloadTransfer,
},
types::{
Address,
Config,
},
types::Config,
};
use primitive_types::U256;
use rand::Rng;
use sha3::Digest;
use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{
AccountMeta,
Instruction,
},
program_pack::Pack,
pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar,
};
use solana_program::pubkey::Pubkey;
use solana_program_test::{
tokio,
BanksClient,
};
use solana_sdk::{
commitment_config::CommitmentLevel,
signature::{
read_keypair_file,
Keypair,
Signer,
},
transaction::Transaction,
transport::TransportError,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use spl_token::state::Mint;
use std::{
collections::HashMap,
convert::TryInto,
io::{
Cursor,
Write,
},
str::FromStr,
time::{
Duration,
SystemTime,
UNIX_EPOCH,
},
};
use std::str::FromStr;
mod common;
@ -121,9 +49,6 @@ const GOVERNANCE_KEY: [u8; 64] = [
];
struct Context {
/// Guardian public keys.
guardians: Vec<[u8; 20]>,
/// Guardian secret keys.
guardian_keys: Vec<SecretKey>,
@ -142,7 +67,6 @@ struct Context {
/// Keypairs for mint information, required in multiple tests.
mint_authority: Keypair,
mint: Keypair,
mint_meta: Pubkey,
/// Keypairs for test token accounts.
token_authority: Keypair,
@ -170,22 +94,13 @@ async fn set_up() -> Result<Context, TransportError> {
mint_pubkey.as_ref(),
];
let (metadata_key, metadata_bump_seed) = Pubkey::find_program_address(
let (metadata_key, _metadata_bump_seed) = Pubkey::find_program_address(
metadata_seeds,
&Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap(),
);
// Token Bridge Meta
use nft_bridge::accounts::WrappedTokenMeta;
let metadata_account = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key(
&nft_bridge::accounts::WrappedMetaDerivationData {
mint_key: mint_pubkey.clone(),
},
&nft_bridge,
);
let mut context = Context {
guardians,
guardian_keys,
bridge,
client,
@ -193,7 +108,6 @@ async fn set_up() -> Result<Context, TransportError> {
nft_bridge,
mint_authority: Keypair::new(),
mint,
mint_meta: metadata_account,
token_account: Keypair::new(),
token_authority: Keypair::new(),
metadata_account: metadata_key,
@ -270,9 +184,7 @@ async fn transfer_native() {
ref mut client,
bridge,
nft_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_account,
ref token_authority,
..
@ -300,10 +212,6 @@ async fn register_chain(context: &mut Context) {
ref mut client,
ref bridge,
ref nft_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_authority,
ref guardian_keys,
..
} = context;
@ -317,18 +225,18 @@ async fn register_chain(context: &mut Context) {
let message = payload.try_to_vec().unwrap();
let (vaa, body, _) = common::generate_vaa(emitter.pubkey().to_bytes(), 1, message, nonce, 0);
let signature_set = common::verify_signatures(client, &bridge, payer, body, guardian_keys, 0)
let signature_set = common::verify_signatures(client, bridge, payer, body, guardian_keys, 0)
.await
.unwrap();
common::post_vaa(client, *bridge, payer, signature_set, vaa.clone())
.await
.unwrap();
let mut msg_derivation_data = &PostedVAADerivationData {
let msg_derivation_data = &PostedVAADerivationData {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, bridge);
common::register_chain(
client,
@ -352,9 +260,8 @@ async fn transfer_native_in() {
ref mut client,
bridge,
nft_bridge,
ref mint_authority,
mint_authority: _,
ref mint,
ref mint_meta,
ref token_account,
ref token_authority,
ref guardian_keys,
@ -388,8 +295,8 @@ async fn transfer_native_in() {
);
let payload = PayloadTransfer {
token_address: [1u8; 32],
token_chain: 1,
token_address,
token_chain,
symbol: "NFT".into(),
name: "Non-Fungible Token".into(),
token_id,
@ -410,7 +317,7 @@ async fn transfer_native_in() {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, &bridge);
common::complete_native(
client,
@ -437,13 +344,12 @@ async fn transfer_wrapped() {
ref mut client,
bridge,
nft_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_account,
mint_authority: _,
mint: _,
token_account: _,
ref token_authority,
ref guardian_keys,
metadata_account,
metadata_account: _,
..
} = context;
@ -489,11 +395,11 @@ async fn transfer_wrapped() {
common::post_vaa(client, bridge, payer, signature_set, vaa.clone())
.await
.unwrap();
let mut msg_derivation_data = &PostedVAADerivationData {
let msg_derivation_data = &PostedVAADerivationData {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, &bridge);
common::complete_wrapped(
client,

View File

@ -1,6 +1,5 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#![allow(warnings)]
use std::{
fmt::Display,
@ -8,7 +7,6 @@ use std::{
process::exit,
};
use borsh::BorshDeserialize;
use clap::{
crate_description,
crate_name,
@ -19,7 +17,6 @@ use clap::{
Arg,
SubCommand,
};
use hex;
use solana_clap_utils::{
input_parsers::{
keypair_of,
@ -36,26 +33,22 @@ use solana_client::{
rpc_client::RpcClient,
rpc_config::RpcSendTransactionConfig,
};
use solana_program::account_info::AccountInfo;
use solana_sdk::{
commitment_config::{
CommitmentConfig,
CommitmentLevel,
},
native_token::*,
program_error::ProgramError::AccountAlreadyInitialized,
pubkey::Pubkey,
signature::{
read_keypair_file,
Keypair,
Signer,
},
system_instruction::transfer,
transaction::Transaction,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
Info,
};
use solitaire_client::Derive;
@ -70,6 +63,10 @@ struct Config {
type Error = Box<dyn std::error::Error>;
type CommmandResult = Result<Option<Transaction>, Error>;
// [`get_recent_blockhash`] is deprecated, but devnet deployment hangs using the
// recommended method, so allowing deprecated here. This is only the client, so
// no risk.
#[allow(deprecated)]
fn command_init_bridge(config: &Config, bridge: &Pubkey, core_bridge: &Pubkey) -> CommmandResult {
println!("Initializing Token bridge {}", bridge);
@ -79,13 +76,13 @@ fn command_init_bridge(config: &Config, bridge: &Pubkey, core_bridge: &Pubkey) -
let ix = token_bridge::instructions::initialize(*bridge, config.owner.pubkey(), *core_bridge)
.unwrap();
println!("config account: {}, ", ix.accounts[1].pubkey.to_string());
println!("config account: {}, ", ix.accounts[1].pubkey);
let mut transaction = Transaction::new_with_payer(&[ix], Some(&config.fee_payer.pubkey()));
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
check_fee_payer_balance(
config,
minimum_balance_for_rent_exemption + fee_calculator.calculate_fee(&transaction.message()),
minimum_balance_for_rent_exemption + fee_calculator.calculate_fee(transaction.message()),
)?;
transaction.sign(&[&config.fee_payer, &config.owner], recent_blockhash);
Ok(Some(transaction))
@ -127,7 +124,7 @@ fn command_create_meta(
);
let mut transaction = Transaction::new_with_payer(&[ix], Some(&config.fee_payer.pubkey()));
let (recent_blockhash, _) = config.rpc_client.get_recent_blockhash()?;
let recent_blockhash = config.rpc_client.get_latest_blockhash()?;
transaction.sign(&[&config.fee_payer, &config.owner], recent_blockhash);
Ok(Some(transaction))
}
@ -146,7 +143,7 @@ fn main() {
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE {
arg.default_value(&config_file)
arg.default_value(config_file)
} else {
arg
}
@ -338,7 +335,8 @@ fn main() {
)
.0;
let meta_info = config.rpc_client.get_account(&meta_acc).unwrap();
let meta_info = spl_token_metadata::state::Metadata::from_bytes(&meta_info.data).unwrap();
let meta_info =
spl_token_metadata::state::Metadata::from_bytes(&meta_info.data).unwrap();
println!("Key: {:?}", meta_info.key);
println!("Mint: {}", meta_info.mint);
println!("Metadata Key: {}", meta_acc);

View File

@ -2,10 +2,6 @@ use crate::types::*;
use bridge::{
accounts::BridgeData,
api::ForeignAddress,
vaa::{
DeserializePayload,
PayloadMessage,
},
};
use solana_program::pubkey::Pubkey;
use solitaire::{
@ -17,35 +13,35 @@ pub type AuthoritySigner<'b> = Derive<Info<'b>, "authority_signer">;
pub type CustodySigner<'b> = Derive<Info<'b>, "custody_signer">;
pub type MintSigner<'b> = Derive<Info<'b>, "mint_signer">;
pub type CoreBridge<'a, const State: AccountState> = Data<'a, BridgeData, { State }>;
pub type CoreBridge<'a, const STATE: AccountState> = Data<'a, BridgeData, { STATE }>;
pub type EmitterAccount<'b> = Derive<Info<'b>, "emitter">;
pub type ConfigAccount<'b, const State: AccountState> =
Derive<Data<'b, Config, { State }>, "config">;
pub type ConfigAccount<'b, const STATE: AccountState> =
Derive<Data<'b, Config, { STATE }>, "config">;
pub type CustodyAccount<'b, const State: AccountState> = Data<'b, SplAccount, { State }>;
pub type CustodyAccount<'b, const STATE: AccountState> = Data<'b, SplAccount, { STATE }>;
pub struct CustodyAccountDerivationData {
pub mint: Pubkey,
}
impl<'b, const State: AccountState> Seeded<&CustodyAccountDerivationData>
for CustodyAccount<'b, { State }>
impl<'b, const STATE: AccountState> Seeded<&CustodyAccountDerivationData>
for CustodyAccount<'b, { STATE }>
{
fn seeds(accs: &CustodyAccountDerivationData) -> Vec<Vec<u8>> {
vec![accs.mint.to_bytes().to_vec()]
}
}
pub type WrappedMint<'b, const State: AccountState> = Data<'b, SplMint, { State }>;
pub type WrappedMint<'b, const STATE: AccountState> = Data<'b, SplMint, { STATE }>;
pub struct WrappedDerivationData {
pub token_chain: ChainID,
pub token_address: ForeignAddress,
}
impl<'b, const State: AccountState> Seeded<&WrappedDerivationData> for WrappedMint<'b, { State }> {
impl<'b, const STATE: AccountState> Seeded<&WrappedDerivationData> for WrappedMint<'b, { STATE }> {
fn seeds(data: &WrappedDerivationData) -> Vec<Vec<u8>> {
vec![
String::from("wrapped").as_bytes().to_vec(),
@ -55,14 +51,14 @@ impl<'b, const State: AccountState> Seeded<&WrappedDerivationData> for WrappedMi
}
}
pub type WrappedTokenMeta<'b, const State: AccountState> = Data<'b, WrappedMeta, { State }>;
pub type WrappedTokenMeta<'b, const STATE: AccountState> = Data<'b, WrappedMeta, { STATE }>;
pub struct WrappedMetaDerivationData {
pub mint_key: Pubkey,
}
impl<'b, const State: AccountState> Seeded<&WrappedMetaDerivationData>
for WrappedTokenMeta<'b, { State }>
impl<'b, const STATE: AccountState> Seeded<&WrappedMetaDerivationData>
for WrappedTokenMeta<'b, { STATE }>
{
fn seeds(data: &WrappedMetaDerivationData) -> Vec<Vec<u8>> {
vec![
@ -73,7 +69,7 @@ impl<'b, const State: AccountState> Seeded<&WrappedMetaDerivationData>
}
/// Registered chain endpoint
pub type Endpoint<'b, const State: AccountState> = Data<'b, EndpointRegistration, { State }>;
pub type Endpoint<'b, const STATE: AccountState> = Data<'b, EndpointRegistration, { STATE }>;
pub struct EndpointDerivationData {
pub emitter_chain: u16,
@ -81,7 +77,7 @@ pub struct EndpointDerivationData {
}
/// Seeded implementation based on an incoming VAA
impl<'b, const State: AccountState> Seeded<&EndpointDerivationData> for Endpoint<'b, { State }> {
impl<'b, const STATE: AccountState> Seeded<&EndpointDerivationData> for Endpoint<'b, { STATE }> {
fn seeds(data: &EndpointDerivationData) -> Vec<Vec<u8>> {
vec![
data.emitter_chain.to_be_bytes().to_vec(),

View File

@ -8,62 +8,33 @@ use crate::{
WrappedMetaDerivationData,
WrappedTokenMeta,
},
messages::{
PayloadAssetMeta,
PayloadTransfer,
},
messages::PayloadAssetMeta,
types::*,
TokenBridgeError::{
self,
*,
},
TokenBridgeError::*,
};
use bridge::{
accounts::Bridge,
api::{
PostMessage,
PostMessageData,
},
api::PostMessageData,
types::ConsistencyLevel,
vaa::SerializePayload,
CHAIN_ID_SOLANA,
};
use primitive_types::U256;
use solana_program::{
account_info::AccountInfo,
instruction::{
AccountMeta,
Instruction,
},
program::{
invoke,
invoke_signed,
},
program_error::ProgramError,
pubkey::Pubkey,
program::invoke,
sysvar::clock::Clock,
};
use solitaire::{
processors::seeded::{
invoke_seeded,
Owned,
Seeded,
},
CreationLamports::Exempt,
*,
};
use spl_token::{
error::TokenError::OwnerMismatch,
state::{
Account,
Mint,
},
};
use spl_token_metadata::state::Metadata;
use std::ops::{
Deref,
DerefMut,
};
#[derive(FromAccounts)]
pub struct AttestToken<'b> {
@ -161,7 +132,7 @@ pub fn attest_token(
let metadata: Metadata =
Metadata::from_account_info(accs.spl_metadata.info()).ok_or(InvalidMetadata)?;
payload.name = metadata.data.name.clone();
payload.symbol = metadata.data.symbol.clone();
payload.symbol = metadata.data.symbol;
}
let params = (

View File

@ -21,28 +21,14 @@ use bridge::{
vaa::ClaimableVAA,
CHAIN_ID_SOLANA,
};
use solana_program::{
account_info::AccountInfo,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
};
use solana_program::account_info::AccountInfo;
use solitaire::{
processors::seeded::{
invoke_seeded,
Seeded,
},
CreationLamports::Exempt,
*,
};
use spl_token::state::{
Account,
Mint,
};
use std::ops::{
Deref,
DerefMut,
};
#[derive(FromAccounts)]
pub struct CompleteNative<'b> {
@ -86,7 +72,7 @@ pub struct CompleteNativeData {}
pub fn complete_native(
ctx: &ExecutionContext,
accs: &mut CompleteNative,
data: CompleteNativeData,
_data: CompleteNativeData,
) -> Result<()> {
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();
@ -212,7 +198,7 @@ pub struct CompleteWrappedData {}
pub fn complete_wrapped(
ctx: &ExecutionContext,
accs: &mut CompleteWrapped,
data: CompleteWrappedData,
_data: CompleteWrappedData,
) -> Result<()> {
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();

View File

@ -12,10 +12,7 @@ use crate::{
WrappedMint,
WrappedTokenMeta,
},
messages::{
PayloadTransfer,
PayloadTransferWithPayload,
},
messages::PayloadTransferWithPayload,
types::*,
TokenBridgeError::*,
};
@ -23,28 +20,14 @@ use bridge::{
vaa::ClaimableVAA,
CHAIN_ID_SOLANA,
};
use solana_program::{
account_info::AccountInfo,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
};
use solana_program::account_info::AccountInfo;
use solitaire::{
processors::seeded::{
invoke_seeded,
Seeded,
},
CreationLamports::Exempt,
*,
};
use spl_token::state::{
Account,
Mint,
};
use std::ops::{
Deref,
DerefMut,
};
#[derive(FromAccounts)]
pub struct CompleteNativeWithPayload<'b> {
@ -99,7 +82,7 @@ pub struct CompleteNativeWithPayloadData {}
pub fn complete_native_with_payload(
ctx: &ExecutionContext,
accs: &mut CompleteNativeWithPayload,
data: CompleteNativeWithPayloadData,
_data: CompleteNativeWithPayloadData,
) -> Result<()> {
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();
@ -187,7 +170,7 @@ pub struct CompleteWrappedWithPayload<'b> {
pub payer: Mut<Signer<AccountInfo<'b>>>,
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
// Signed message for the transfer
/// Signed message for the transfer
pub vaa: ClaimableVAA<'b, PayloadTransferWithPayload>,
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
@ -238,7 +221,7 @@ pub struct CompleteWrappedWithPayloadData {}
pub fn complete_wrapped_with_payload(
ctx: &ExecutionContext,
accs: &mut CompleteWrappedWithPayload,
data: CompleteWrappedWithPayloadData,
_data: CompleteWrappedWithPayloadData,
) -> Result<()> {
// Verify the chain registration
let derivation_data: EndpointDerivationData = (&*accs).into();

View File

@ -12,7 +12,6 @@ use crate::{
WrappedTokenMeta,
},
messages::PayloadAssetMeta,
types::*,
TokenBridgeError::{
InvalidChain,
InvalidMetadata,
@ -27,8 +26,6 @@ use bridge::{
use solana_program::{
account_info::AccountInfo,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
};
use solitaire::{
processors::seeded::{
@ -38,24 +35,12 @@ use solitaire::{
CreationLamports::Exempt,
*,
};
use spl_token::{
error::TokenError::OwnerMismatch,
state::{
Account,
Mint,
},
};
use spl_token_metadata::state::{
Data as SplData,
Metadata,
};
use std::{
cmp::min,
ops::{
Deref,
DerefMut,
},
};
use std::cmp::min;
#[derive(FromAccounts)]
pub struct CreateWrapped<'b> {
@ -146,7 +131,7 @@ pub fn create_wrapped(
pub fn create_accounts(
ctx: &ExecutionContext,
accs: &mut CreateWrapped,
data: CreateWrappedData,
_data: CreateWrappedData,
) -> Result<()> {
// Create mint account
accs.mint
@ -206,7 +191,7 @@ pub fn create_accounts(
pub fn update_accounts(
ctx: &ExecutionContext,
accs: &mut CreateWrapped,
data: CreateWrappedData,
_data: CreateWrappedData,
) -> Result<()> {
accs.spl_metadata.verify_derivation(
&spl_token_metadata::id(),
@ -250,14 +235,6 @@ pub fn truncate_utf8(data: impl AsRef<[u8]>, len: usize) -> String {
#[cfg(test)]
mod tests {
fn extend_string(n: &str) -> Vec<u8> {
let mut bytes = vec![0u8; 32];
for i in 0..n.len() {
bytes[i] = n.as_bytes()[i];
}
bytes.to_vec()
}
#[test]
fn test_unicode_truncation() {
#[rustfmt::skip]

View File

@ -8,9 +8,7 @@ use crate::{
GovernancePayloadUpgrade,
PayloadGovernanceRegisterChain,
},
types::*,
TokenBridgeError::{
InvalidChain,
InvalidGovernanceKey,
InvalidVAA,
},
@ -20,14 +18,12 @@ use bridge::{
vaa::{
ClaimableVAA,
DeserializePayload,
PayloadMessage,
},
CHAIN_ID_SOLANA,
};
use solana_program::{
account_info::AccountInfo,
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
sysvar::{
clock::Clock,
@ -39,13 +35,9 @@ use solitaire::{
CreationLamports::Exempt,
*,
};
use std::ops::{
Deref,
DerefMut,
};
// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
fn verify_governance<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()>
/// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter.
fn verify_governance<T>(vaa: &ClaimableVAA<T>) -> Result<()>
where
T: DeserializePayload,
{

View File

@ -1,21 +1,12 @@
use crate::{
accounts::ConfigAccount,
types::*,
};
use crate::accounts::ConfigAccount;
use solana_program::{
account_info::AccountInfo,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};
use solitaire::{
CreationLamports::Exempt,
*,
};
use std::ops::{
Deref,
DerefMut,
};
#[derive(FromAccounts)]
pub struct Initialize<'b> {

View File

@ -26,11 +26,7 @@ use crate::{
},
};
use bridge::{
accounts::Bridge,
api::{
PostMessage,
PostMessageData,
},
api::PostMessageData,
types::ConsistencyLevel,
vaa::SerializePayload,
CHAIN_ID_SOLANA,
@ -46,9 +42,7 @@ use solana_program::{
invoke,
invoke_signed,
},
program_error::ProgramError,
program_option::COption,
pubkey::Pubkey,
sysvar::clock::Clock,
};
use solitaire::{
@ -59,17 +53,6 @@ use solitaire::{
CreationLamports::Exempt,
*,
};
use spl_token::{
error::TokenError::OwnerMismatch,
state::{
Account,
Mint,
},
};
use std::ops::{
Deref,
DerefMut,
};
pub type TransferNativeWithPayload<'b> = TransferNative<'b>;

View File

@ -43,28 +43,16 @@ use borsh::BorshSerialize;
use bridge::{
accounts::{
Bridge,
BridgeConfig,
Claim,
ClaimDerivationData,
FeeCollector,
PostedVAA,
PostedVAAData,
PostedVAADerivationData,
Sequence,
SequenceDerivationData,
},
api::ForeignAddress,
instructions::hash_vaa,
vaa::{
ClaimableVAA,
PayloadMessage,
SerializePayload,
},
PostVAA,
PostVAAData,
CHAIN_ID_SOLANA,
};
use primitive_types::U256;
use solana_program::{
instruction::{
AccountMeta,
@ -76,11 +64,6 @@ use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use spl_token::state::Mint;
use std::{
cmp::min,
str::FromStr,
};
pub fn initialize(
program_id: Pubkey,
@ -101,6 +84,7 @@ pub fn initialize(
})
}
#[allow(clippy::too_many_arguments)]
pub fn complete_native(
program_id: Pubkey,
bridge_id: Pubkey,
@ -155,6 +139,7 @@ pub fn complete_native(
})
}
#[allow(clippy::too_many_arguments)]
pub fn complete_native_with_payload(
program_id: Pubkey,
bridge_id: Pubkey,
@ -215,6 +200,7 @@ pub fn complete_native_with_payload(
})
}
#[allow(clippy::too_many_arguments)]
pub fn complete_wrapped(
program_id: Pubkey,
bridge_id: Pubkey,
@ -276,6 +262,7 @@ pub fn complete_wrapped(
})
}
#[allow(clippy::too_many_arguments)]
pub fn complete_wrapped_with_payload(
program_id: Pubkey,
bridge_id: Pubkey,
@ -560,6 +547,7 @@ fn transfer_native_raw(
})
}
#[allow(clippy::too_many_arguments)]
pub fn transfer_wrapped(
program_id: Pubkey,
bridge_id: Pubkey,
@ -584,6 +572,7 @@ pub fn transfer_wrapped(
)
}
#[allow(clippy::too_many_arguments)]
pub fn transfer_wrapped_with_payload(
program_id: Pubkey,
bridge_id: Pubkey,
@ -612,6 +601,7 @@ pub fn transfer_wrapped_with_payload(
)
}
#[allow(clippy::too_many_arguments)]
fn transfer_wrapped_raw(
program_id: Pubkey,
bridge_id: Pubkey,

View File

@ -1,4 +1,5 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]
#![deny(unused_must_use)]
// #![cfg(all(target_arch = "bpf", not(feature = "no-entrypoint")))]
@ -62,10 +63,9 @@ pub use api::{
};
use solitaire::*;
use std::error::Error;
// Static list of invalid VAA Message accounts.
pub(crate) static INVALID_VAAS: &'static [&'static str; 7] = &[
pub(crate) static INVALID_VAAS: &[&str; 7] = &[
"28Tx7c3W8rggVNyUQEAL9Uq6pUng4xJLAeLA6V8nLH1Z",
"32YEuzLCvSyHoV6NFpaTXfiAB8sHiAnYcvP2BBeLeGWq",
"427N2RrDHYooLvyWCiEiNR4KtGsGFTMuXiGwtuChWRSd",

View File

@ -1,13 +1,6 @@
use crate::{
types::{
Address,
ChainID,
},
TokenBridgeError,
};
use borsh::{
BorshDeserialize,
BorshSerialize,
use crate::types::{
Address,
ChainID,
};
use bridge::{
vaa::{
@ -24,38 +17,32 @@ use byteorder::{
};
use primitive_types::U256;
use solana_program::{
native_token::Sol,
program_error::{
ProgramError,
ProgramError::InvalidAccountData,
},
program_error::ProgramError::InvalidAccountData,
pubkey::Pubkey,
};
use solitaire::SolitaireError;
use std::{
error::Error,
cmp,
io::{
Cursor,
Read,
Write,
},
str::Utf8Error,
string::FromUtf8Error,
};
#[derive(PartialEq, Debug, Clone)]
pub struct PayloadTransfer {
// Amount being transferred (big-endian uint256)
/// Amount being transferred (big-endian uint256)
pub amount: U256,
// Address of the token. Left-zero-padded if shorter than 32 bytes
/// Address of the token. Left-zero-padded if shorter than 32 bytes
pub token_address: Address,
// Chain ID of the token
/// Chain ID of the token
pub token_chain: ChainID,
// Address of the recipient. Left-zero-padded if shorter than 32 bytes
/// Address of the recipient. Left-zero-padded if shorter than 32 bytes
pub to: Address,
// Chain ID of the recipient
/// Chain ID of the recipient
pub to_chain: ChainID,
// Amount of tokens (big-endian uint256) that the user is willing to pay as relayer fee. Must be <= Amount.
/// Amount of tokens (big-endian uint256) that the user is willing to pay as relayer fee. Must be <= Amount.
pub fee: U256,
}
@ -107,16 +94,16 @@ impl SerializePayload for PayloadTransfer {
let mut am_data: [u8; 32] = [0; 32];
self.amount.to_big_endian(&mut am_data);
writer.write(&am_data)?;
writer.write_all(&am_data)?;
writer.write(&self.token_address)?;
writer.write_all(&self.token_address)?;
writer.write_u16::<BigEndian>(self.token_chain)?;
writer.write(&self.to)?;
writer.write_all(&self.to)?;
writer.write_u16::<BigEndian>(self.to_chain)?;
let mut fee_data: [u8; 32] = [0; 32];
self.fee.to_big_endian(&mut fee_data);
writer.write(&fee_data)?;
writer.write_all(&fee_data)?;
Ok(())
}
@ -170,18 +157,18 @@ impl SerializePayload for PayloadTransferWithPayload {
let mut am_data: [u8; 32] = [0; 32];
self.amount.to_big_endian(&mut am_data);
writer.write(&am_data)?;
writer.write_all(&am_data)?;
writer.write(&self.token_address)?;
writer.write_all(&self.token_address)?;
writer.write_u16::<BigEndian>(self.token_chain)?;
writer.write(&self.to)?;
writer.write_all(&self.to)?;
writer.write_u16::<BigEndian>(self.to_chain)?;
let mut fee_data: [u8; 32] = [0; 32];
self.fee.to_big_endian(&mut fee_data);
writer.write(&fee_data)?;
writer.write_all(&fee_data)?;
writer.write(self.payload.as_slice())?;
writer.write_all(self.payload.as_slice())?;
Ok(())
}
@ -189,33 +176,33 @@ impl SerializePayload for PayloadTransferWithPayload {
#[derive(PartialEq, Debug, Clone)]
pub struct PayloadTransferWithPayload {
// Amount being transferred (big-endian uint256)
/// Amount being transferred (big-endian uint256)
pub amount: U256,
// Address of the token. Left-zero-padded if shorter than 32 bytes
/// Address of the token. Left-zero-padded if shorter than 32 bytes
pub token_address: Address,
// Chain ID of the token
/// Chain ID of the token
pub token_chain: ChainID,
// Address of the recipient. Left-zero-padded if shorter than 32 bytes
/// Address of the recipient. Left-zero-padded if shorter than 32 bytes
pub to: Address,
// Chain ID of the recipient
/// Chain ID of the recipient
pub to_chain: ChainID,
// Amount of tokens (big-endian uint256) that the user is willing to pay as relayer fee. Must be <= Amount.
/// Amount of tokens (big-endian uint256) that the user is willing to pay as relayer fee. Must be <= Amount.
pub fee: U256,
// Arbitrary payload
/// Arbitrary payload
pub payload: Vec<u8>,
}
#[derive(PartialEq, Debug)]
pub struct PayloadAssetMeta {
// Address of the token. Left-zero-padded if shorter than 32 bytes
/// Address of the token. Left-zero-padded if shorter than 32 bytes
pub token_address: Address,
// Chain ID of the token
/// Chain ID of the token
pub token_chain: ChainID,
// Number of decimals of the token
/// Number of decimals of the token
pub decimals: u8,
// Symbol of the token
/// Symbol of the token
pub symbol: String,
// Name of the token
/// Name of the token
pub name: String,
}
@ -268,22 +255,22 @@ impl SerializePayload for PayloadAssetMeta {
// Payload ID
writer.write_u8(2)?;
writer.write(&self.token_address)?;
writer.write_all(&self.token_address)?;
writer.write_u16::<BigEndian>(self.token_chain)?;
writer.write_u8(self.decimals)?;
let mut symbol: [u8; 32] = [0; 32];
for i in 0..self.symbol.len() {
symbol[i] = self.symbol.as_bytes()[i];
}
writer.write(&symbol)?;
let count = cmp::min(symbol.len(), self.symbol.len());
symbol[..count].copy_from_slice(self.symbol[..count].as_bytes());
writer.write_all(&symbol)?;
let mut name: [u8; 32] = [0; 32];
for i in 0..self.name.len() {
name[i] = self.name.as_bytes()[i];
}
writer.write(&name)?;
let count = cmp::min(name.len(), self.name.len());
name[..count].copy_from_slice(self.name[..count].as_bytes());
writer.write_all(&name)?;
Ok(())
}
@ -291,9 +278,9 @@ impl SerializePayload for PayloadAssetMeta {
#[derive(PartialEq, Debug)]
pub struct PayloadGovernanceRegisterChain {
// Chain ID of the chain to be registered
/// Chain ID of the chain to be registered
pub chain: ChainID,
// Address of the endpoint on the chain
/// Address of the endpoint on the chain
pub endpoint_address: Address,
}
@ -336,7 +323,7 @@ where
self.write_governance_header(writer)?;
// Payload ID
writer.write_u16::<BigEndian>(self.chain)?;
writer.write(&self.endpoint_address[..])?;
writer.write_all(&self.endpoint_address[..])?;
Ok(())
}
@ -344,14 +331,14 @@ where
#[derive(PartialEq, Debug)]
pub struct GovernancePayloadUpgrade {
// Address of the new Implementation
/// Address of the new Implementation
pub new_contract: Pubkey,
}
impl SerializePayload for GovernancePayloadUpgrade {
fn serialize<W: Write>(&self, v: &mut W) -> std::result::Result<(), SolitaireError> {
self.write_governance_header(v)?;
v.write(&self.new_contract.to_bytes())?;
v.write_all(&self.new_contract.to_bytes())?;
Ok(())
}
}
@ -386,6 +373,7 @@ impl DeserializeGovernancePayload for GovernancePayloadUpgrade {
}
#[cfg(feature = "no-entrypoint")]
#[allow(unused_imports)]
mod tests {
use crate::messages::{
GovernancePayloadUpgrade,
@ -417,7 +405,7 @@ mod tests {
fee: U256::from(1139),
};
let mut data = transfer_original.try_to_vec().unwrap();
let data = transfer_original.try_to_vec().unwrap();
let transfer_deser = PayloadTransfer::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(transfer_original, transfer_deser);
@ -436,7 +424,7 @@ mod tests {
name: "ZAC".to_string(),
};
let mut data = am_original.try_to_vec().unwrap();
let data = am_original.try_to_vec().unwrap();
let am_deser = PayloadAssetMeta::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(am_original, am_deser);
@ -448,7 +436,7 @@ mod tests {
new_contract: Pubkey::new_unique(),
};
let mut data = original.try_to_vec().unwrap();
let data = original.try_to_vec().unwrap();
let deser = GovernancePayloadUpgrade::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(original, deser);
@ -464,7 +452,7 @@ mod tests {
endpoint_address,
};
let mut data = original.try_to_vec().unwrap();
let data = original.try_to_vec().unwrap();
let deser = PayloadGovernanceRegisterChain::deserialize(&mut data.as_slice()).unwrap();
assert_eq!(original, deser);

View File

@ -18,7 +18,6 @@ use spl_token::state::{
Account,
Mint,
};
use spl_token_metadata::state::Metadata;
pub type Address = [u8; 32];
pub type ChainID = u16;
@ -38,7 +37,6 @@ impl Owned for Config {
#[cfg(feature = "cpi")]
impl Owned for Config {
fn owner(&self) -> AccountOwner {
use solana_program::pubkey::Pubkey;
use std::str::FromStr;
AccountOwner::Other(Pubkey::from_str(env!("TOKEN_BRIDGE_ADDRESS")).unwrap())
}
@ -60,7 +58,6 @@ impl Owned for EndpointRegistration {
#[cfg(feature = "cpi")]
impl Owned for EndpointRegistration {
fn owner(&self) -> AccountOwner {
use solana_program::pubkey::Pubkey;
use std::str::FromStr;
AccountOwner::Other(Pubkey::from_str(env!("TOKEN_BRIDGE_ADDRESS")).unwrap())
}
@ -83,7 +80,6 @@ impl Owned for WrappedMeta {
#[cfg(feature = "cpi")]
impl Owned for WrappedMeta {
fn owner(&self) -> AccountOwner {
use solana_program::pubkey::Pubkey;
use std::str::FromStr;
AccountOwner::Other(Pubkey::from_str(env!("TOKEN_BRIDGE_ADDRESS")).unwrap())
}

View File

@ -1,35 +1,22 @@
#![allow(warnings)]
use borsh::{
BorshDeserialize,
BorshSerialize,
};
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use libsecp256k1::{
Message as Secp256k1Message,
PublicKey,
SecretKey,
};
use sha3::Digest;
use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{
AccountMeta,
Instruction,
},
program_pack::Pack,
pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar,
system_instruction,
};
use solana_program_test::{
BanksClient,
@ -40,40 +27,29 @@ use solana_sdk::{
rent::Rent,
secp256k1_instruction::new_secp256k1_instruction,
signature::{
read_keypair_file,
Keypair,
Signature,
Signer,
},
signers::Signers,
transaction::Transaction,
transport::TransportError,
};
use spl_token::state::Mint;
use std::{
convert::TryInto,
env,
io::{
Cursor,
Write,
},
time::{
Duration,
SystemTime,
},
time::SystemTime,
};
use token_bridge::{
accounts::*,
instruction,
instructions,
types::*,
Initialize,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
};
pub use helpers::*;
@ -99,11 +75,9 @@ mod helpers {
use bridge::{
accounts::{
FeeCollector,
PostedVAADerivationData,
},
types::ConsistencyLevel,
PostVAAData,
PostedVAAData,
};
use solana_program_test::processor;
use token_bridge::{
@ -115,7 +89,6 @@ mod helpers {
TransferWrappedData,
};
use std::ops::Add;
use token_bridge::messages::{
PayloadAssetMeta,
PayloadGovernanceRegisterChain,
@ -125,8 +98,6 @@ mod helpers {
/// Generate `count` secp256k1 private keys, along with their ethereum-styled public key
/// encoding: 0x0123456789ABCDEF01234
pub fn generate_keys(count: u8) -> (Vec<[u8; 20]>, Vec<SecretKey>) {
use rand::Rng;
use sha3::Digest;
let mut rng = rand::thread_rng();
@ -139,9 +110,9 @@ mod helpers {
secret_keys
.iter()
.map(|key| {
let public_key = PublicKey::from_secret_key(&key);
let public_key = PublicKey::from_secret_key(key);
let mut h = sha3::Keccak256::default();
h.write(&public_key.serialize()[1..]).unwrap();
h.write_all(&public_key.serialize()[1..]).unwrap();
let key: [u8; 32] = h.finalize().into();
let mut address = [0u8; 20];
address.copy_from_slice(&key[12..]);
@ -157,11 +128,11 @@ mod helpers {
pub async fn setup() -> (BanksClient, Keypair, Pubkey, Pubkey) {
let (program, token_program) = (
env::var("BRIDGE_PROGRAM")
.unwrap_or("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
.unwrap_or_else(|_| "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string())
.parse::<Pubkey>()
.unwrap(),
env::var("TOKEN_BRIDGE_PROGRAM")
.unwrap_or("B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE".to_string())
.unwrap_or_else(|_| "B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE".to_string())
.parse::<Pubkey>()
.unwrap(),
);
@ -188,6 +159,7 @@ mod helpers {
/// Wait for a single transaction to fully finalize, guaranteeing chain state has been
/// confirmed. Useful for consistently fetching data during state checks.
#[allow(dead_code)]
pub async fn sync(client: &mut BanksClient, payer: &Keypair) {
let payer_key = payer.pubkey();
execute(
@ -215,6 +187,7 @@ mod helpers {
}
/// Fetch account balance
#[allow(dead_code)]
pub async fn get_account_balance(client: &mut BanksClient, account: Pubkey) -> u64 {
client.get_account(account).await.unwrap().unwrap().lamports
}
@ -242,6 +215,7 @@ mod helpers {
.await
}
#[allow(dead_code)]
pub async fn transfer(
client: &mut BanksClient,
from: &Keypair,
@ -290,12 +264,6 @@ mod helpers {
mint: Pubkey,
nonce: u32,
) -> Result<(), TransportError> {
let account = client
.get_account_with_commitment(mint, CommitmentLevel::Finalized)
.await?
.expect("mint account not found");
let mint_data = Mint::unpack(&account.data).expect("Could not unpack Mint");
let instruction = instructions::attest(
program,
bridge,
@ -320,6 +288,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn transfer_native(
client: &mut BanksClient,
program: Pubkey,
@ -373,6 +342,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn transfer_wrapped(
client: &mut BanksClient,
program: Pubkey,
@ -604,6 +574,7 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn create_spl_metadata(
client: &mut BanksClient,
payer: &Keypair,
@ -705,7 +676,7 @@ mod helpers {
nonce: u32,
sequence: u64,
) -> (PostVAAData, [u8; 32], [u8; 32]) {
let mut vaa = PostVAAData {
let vaa = PostVAAData {
version: 0,
guardian_set_index: 0,
@ -728,10 +699,10 @@ mod helpers {
v.write_u32::<BigEndian>(vaa.timestamp).unwrap();
v.write_u32::<BigEndian>(vaa.nonce).unwrap();
v.write_u16::<BigEndian>(vaa.emitter_chain).unwrap();
v.write(&vaa.emitter_address).unwrap();
v.write_all(&vaa.emitter_address).unwrap();
v.write_u64::<BigEndian>(vaa.sequence).unwrap();
v.write_u8(vaa.consistency_level).unwrap();
v.write(&vaa.payload).unwrap();
v.write_all(&vaa.payload).unwrap();
v.into_inner()
};
@ -739,13 +710,13 @@ mod helpers {
// signature account, binding that set of signatures to this VAA.
let body: [u8; 32] = {
let mut h = sha3::Keccak256::default();
h.write(body.as_slice()).unwrap();
h.write_all(body.as_slice()).unwrap();
h.finalize().into()
};
let body_hash: [u8; 32] = {
let mut h = sha3::Keccak256::default();
h.write(&body).unwrap();
h.write_all(&body).unwrap();
h.finalize().into()
};
@ -815,6 +786,8 @@ mod helpers {
.await
}
#[allow(clippy::too_many_arguments)]
#[allow(dead_code)]
pub async fn post_message(
client: &mut BanksClient,
program: Pubkey,

View File

@ -1,101 +1,38 @@
#![allow(warnings)]
use borsh::BorshSerialize;
#![allow(dead_code)]
use bridge::{
accounts::{
Bridge,
FeeCollector,
GuardianSet,
GuardianSetDerivationData,
PostedVAA,
PostedVAADerivationData,
SignatureSet,
},
instruction,
types::{
GovernancePayloadGuardianSetChange,
GovernancePayloadSetMessageFee,
GovernancePayloadTransferFees,
},
BridgeConfig,
BridgeData,
GuardianSetData,
Initialize,
MessageData,
PostVAA,
PostVAAData,
PostedVAAData,
SequenceTracker,
SerializePayload,
Signature,
SignatureSet as SignatureSetData,
};
use byteorder::{
BigEndian,
WriteBytesExt,
};
use hex_literal::hex;
use libsecp256k1::{
Message as Secp256k1Message,
PublicKey,
SecretKey,
};
use libsecp256k1::SecretKey;
use primitive_types::U256;
use rand::Rng;
use sha3::Digest;
use solana_program::{
borsh::try_from_slice_unchecked,
hash,
instruction::{
AccountMeta,
Instruction,
},
program_pack::Pack,
pubkey::Pubkey,
system_instruction::{
self,
create_account,
},
system_program,
sysvar,
};
use solana_program::pubkey::Pubkey;
use solana_program_test::{
tokio,
BanksClient,
};
use solana_sdk::{
commitment_config::CommitmentLevel,
signature::{
read_keypair_file,
Keypair,
Signer,
},
transaction::Transaction,
transport::TransportError,
};
use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use spl_token::state::Mint;
use std::{
collections::HashMap,
convert::TryInto,
io::{
Cursor,
Write,
},
str::FromStr,
time::{
Duration,
SystemTime,
UNIX_EPOCH,
},
};
use token_bridge::{
accounts::{
ConfigAccount,
EmitterAccount,
WrappedDerivationData,
WrappedMint,
},
@ -104,10 +41,7 @@ use token_bridge::{
PayloadGovernanceRegisterChain,
PayloadTransfer,
},
types::{
Address,
Config,
},
types::Config,
};
mod common;
@ -190,7 +124,7 @@ async fn set_up() -> Result<Context, TransportError> {
mint_pubkey.as_ref(),
];
let (metadata_key, metadata_bump_seed) = Pubkey::find_program_address(
let (metadata_key, _metadata_bump_seed) = Pubkey::find_program_address(
metadata_seeds,
&Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap(),
);
@ -199,7 +133,7 @@ async fn set_up() -> Result<Context, TransportError> {
use token_bridge::accounts::WrappedTokenMeta;
let metadata_account = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key(
&token_bridge::accounts::WrappedMetaDerivationData {
mint_key: mint_pubkey.clone(),
mint_key: mint_pubkey,
},
&token_bridge,
);
@ -278,11 +212,11 @@ async fn create_wrapped(context: &mut Context) -> Pubkey {
ref mut client,
ref bridge,
ref token_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_account,
ref token_authority,
mint_authority: _,
mint: _,
mint_meta: _,
token_account: _,
token_authority: _,
..
} = context;
@ -305,11 +239,11 @@ async fn create_wrapped(context: &mut Context) -> Pubkey {
common::post_vaa(client, *bridge, payer, signature_set, vaa.clone())
.await
.unwrap();
let mut msg_derivation_data = &PostedVAADerivationData {
let msg_derivation_data = &PostedVAADerivationData {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, bridge);
common::create_wrapped(
client,
@ -328,7 +262,7 @@ async fn create_wrapped(context: &mut Context) -> Pubkey {
token_chain: 2,
token_address: [1u8; 32],
},
&token_bridge,
token_bridge,
)
}
@ -367,10 +301,10 @@ async fn attest() {
ref mut client,
bridge,
token_bridge,
ref mint_authority,
mint_authority: _,
ref mint,
ref mint_meta,
ref metadata_account,
mint_meta: _,
metadata_account: _,
..
} = set_up().await.unwrap();
@ -387,22 +321,6 @@ async fn attest() {
)
.await
.unwrap();
let emitter_key = EmitterAccount::key(None, &token_bridge);
let account = client
.get_account_with_commitment(mint.pubkey(), CommitmentLevel::Processed)
.await
.unwrap()
.unwrap();
let mint_data = Mint::unpack(&account.data).unwrap();
let payload = PayloadAssetMeta {
token_address: mint.pubkey().to_bytes(),
token_chain: 1,
decimals: mint_data.decimals,
symbol: "USD".to_string(),
name: "Bitcoin".to_string(),
};
let payload = payload.try_to_vec().unwrap();
}
#[tokio::test]
@ -412,9 +330,7 @@ async fn transfer_native() {
ref mut client,
bridge,
token_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_account,
ref token_authority,
..
@ -443,10 +359,6 @@ async fn register_chain(context: &mut Context) {
ref mut client,
ref bridge,
ref token_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_authority,
ref guardian_keys,
..
} = context;
@ -460,18 +372,18 @@ async fn register_chain(context: &mut Context) {
let message = payload.try_to_vec().unwrap();
let (vaa, body, _) = common::generate_vaa(emitter.pubkey().to_bytes(), 1, message, nonce, 0);
let signature_set = common::verify_signatures(client, &bridge, payer, body, guardian_keys, 0)
let signature_set = common::verify_signatures(client, bridge, payer, body, guardian_keys, 0)
.await
.unwrap();
common::post_vaa(client, *bridge, payer, signature_set, vaa.clone())
.await
.unwrap();
let mut msg_derivation_data = &PostedVAADerivationData {
let msg_derivation_data = &PostedVAADerivationData {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, bridge);
common::register_chain(
client,
@ -495,9 +407,7 @@ async fn transfer_native_in() {
ref mut client,
bridge,
token_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_account,
ref token_authority,
ref guardian_keys,
@ -544,7 +454,7 @@ async fn transfer_native_in() {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, &bridge);
common::complete_native(
client,
@ -569,10 +479,6 @@ async fn transfer_wrapped() {
ref mut client,
bridge,
token_bridge,
ref mint_authority,
ref mint,
ref mint_meta,
ref token_account,
ref token_authority,
ref guardian_keys,
..
@ -598,11 +504,11 @@ async fn transfer_wrapped() {
common::post_vaa(client, bridge, payer, signature_set, vaa.clone())
.await
.unwrap();
let mut msg_derivation_data = &PostedVAADerivationData {
let msg_derivation_data = &PostedVAADerivationData {
payload_hash: body.to_vec(),
};
let message_key =
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(msg_derivation_data, &bridge);
common::complete_transfer_wrapped(
client,

View File

@ -1,5 +1,5 @@
#![allow(warnings)]
// The solana_program::declare_id! macro generates spurious import statements.
#[allow(unused_imports)]
pub mod instruction;
pub mod state;
pub mod utils;

View File

@ -5,8 +5,6 @@ use borsh::{
};
use solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
program_error::ProgramError,
pubkey::Pubkey,
};

View File

@ -1,56 +1,12 @@
use crate::state::{
Data,
Key,
Metadata,
EDITION,
EDITION_MARKER_BIT_SIZE,
MAX_CREATOR_LIMIT,
MAX_EDITION_LEN,
MAX_EDITION_MARKER_SIZE,
MAX_MASTER_EDITION_LEN,
MAX_METADATA_LEN,
MAX_NAME_LENGTH,
MAX_SYMBOL_LENGTH,
MAX_URI_LENGTH,
PREFIX,
};
use borsh::{
BorshDeserialize,
BorshSerialize,
};
use solana_program::{
account_info::AccountInfo,
borsh::try_from_slice_unchecked,
entrypoint::ProgramResult,
msg,
program::{
invoke,
invoke_signed,
},
program_error::ProgramError,
program_option::COption,
program_pack::{
IsInitialized,
Pack,
},
pubkey::Pubkey,
system_instruction,
sysvar::{
rent::Rent,
Sysvar,
},
};
use spl_token::{
instruction::{
set_authority,
AuthorityType,
},
state::{
Account,
Mint,
},
};
use std::convert::TryInto;
pub fn try_from_slice_checked<T: BorshDeserialize>(
data: &[u8],

View File

@ -1,7 +1,7 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#![feature(const_generics_defaults)]
#![allow(warnings)]
//! Client-specific code
@ -106,7 +106,7 @@ where
match a {
Signer(pair) => Ok(vec![AccountMeta::new(pair.pubkey(), true)]),
SignerRO(pair) => Ok(vec![AccountMeta::new_readonly(pair.pubkey(), true)]),
other => Err(format!(
_other => Err(format!(
"{} must be passed as Signer or SignerRO",
std::any::type_name::<Self>()
)
@ -115,7 +115,7 @@ where
}
}
impl<'a, 'b: 'a, T, const Seed: &'static str> Wrap for Derive<T, Seed> {
impl<'a, 'b: 'a, T, const SEED: &'static str> Wrap for Derive<T, SEED> {
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
match a {
AccEntry::Derived(program_id) => {
@ -128,7 +128,7 @@ impl<'a, 'b: 'a, T, const Seed: &'static str> Wrap for Derive<T, Seed> {
Ok(vec![AccountMeta::new_readonly(k, false)])
}
other => Err(format!(
_other => Err(format!(
"{} must be passed as Derived or DerivedRO",
std::any::type_name::<Self>()
)
@ -137,14 +137,14 @@ impl<'a, 'b: 'a, T, const Seed: &'static str> Wrap for Derive<T, Seed> {
}
}
impl<'a, T, const IsInitialized: AccountState> Wrap for Data<'a, T, IsInitialized>
impl<'a, T, const IS_INITIALIZED: AccountState> Wrap for Data<'a, T, IS_INITIALIZED>
where
T: BorshSerialize + Owned + Default,
{
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
use AccEntry::*;
use AccountState::*;
match IsInitialized {
match IS_INITIALIZED {
Initialized => match a {
Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(*k, false)]),
@ -173,7 +173,7 @@ where
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
if let AccEntry::Sysvar(k) = a {
if Var::check_id(k) {
Ok(vec![AccountMeta::new_readonly(k.clone(), false)])
Ok(vec![AccountMeta::new_readonly(*k, false)])
} else {
Err(format!(
"{} does not point at sysvar {}",
@ -191,8 +191,8 @@ where
impl<'b> Wrap for Info<'b> {
fn wrap(a: &AccEntry) -> StdResult<Vec<AccountMeta>, ErrBox> {
match a {
AccEntry::UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(k.clone(), false)]),
AccEntry::Unprivileged(k) => Ok(vec![AccountMeta::new(k.clone(), false)]),
AccEntry::UnprivilegedRO(k) => Ok(vec![AccountMeta::new_readonly(*k, false)]),
AccEntry::Unprivileged(k) => Ok(vec![AccountMeta::new(*k, false)]),
_other => Err(format!(
"{} must be passed as Unprivileged or UnprivilegedRO",
std::any::type_name::<Self>()

View File

@ -64,10 +64,10 @@ impl From<std::io::Error> for SolitaireError {
}
}
impl Into<ProgramError> for SolitaireError {
fn into(self) -> ProgramError {
match self {
SolitaireError::ProgramError(e) => return e,
impl From<SolitaireError> for ProgramError {
fn from(err: SolitaireError) -> ProgramError {
match err {
SolitaireError::ProgramError(e) => e,
_ => ProgramError::Custom(0),
}
}

View File

@ -1,6 +1,6 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#![allow(warnings)]
pub use rocksalt::*;
@ -11,42 +11,12 @@ pub use rocksalt::*;
// We need a few Solana things in scope in order to properly abstract Solana.
use solana_program::{
account_info::{
next_account_info,
AccountInfo,
},
entrypoint,
entrypoint::ProgramResult,
instruction::{
AccountMeta,
Instruction,
},
program::invoke_signed,
program_error::ProgramError,
program_pack::Pack,
account_info::AccountInfo,
pubkey::Pubkey,
rent::Rent,
system_instruction,
system_program,
sysvar::{
self,
SysvarId,
},
};
use std::{
io::{
ErrorKind,
Write,
},
marker::PhantomData,
ops::{
Deref,
DerefMut,
},
slice::Iter,
string::FromUtf8Error,
};
use std::slice::Iter;
pub use borsh::{
BorshDeserialize,
@ -85,7 +55,7 @@ pub use crate::{
};
/// Library name and version to print in entrypoint. Must be evaluated in this crate in order to do the right thing
pub const PKG_NAME_VERSION: &'static str =
pub const PKG_NAME_VERSION: &str =
concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION"));
pub struct ExecutionContext<'a, 'b: 'a> {

View File

@ -1,8 +1,3 @@
use std::ops::{
Deref,
DerefMut,
};
/// A wrapper around Solana's `msg!` macro that is a no-op by default, allows for adding traces
/// through the application that can be toggled during tests.
#[macro_export]
@ -137,7 +132,7 @@ macro_rules! pack_type {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
let mut data = [0u8; <$embed as solana_program::program_pack::Pack>::LEN];
solana_program::program_pack::Pack::pack_into_slice(&self.0, &mut data);
writer.write(&data)?;
writer.write_all(&data)?;
Ok(())
}

View File

@ -1,7 +1,4 @@
use solana_program::{
pubkey::Pubkey,
sysvar::Sysvar as SolanaSysvar,
};
use solana_program::sysvar::Sysvar as SolanaSysvar;
use crate::{
processors::seeded::Owned,
@ -19,8 +16,8 @@ pub trait Keyed<'a, 'b: 'a> {
fn info(&'a self) -> &Info<'b>;
}
impl<'a, 'b: 'a, T: Owned + Default, const IsInitialized: AccountState> Keyed<'a, 'b>
for Data<'b, T, IsInitialized>
impl<'a, 'b: 'a, T: Owned + Default, const IS_INITIALIZED: AccountState> Keyed<'a, 'b>
for Data<'b, T, IS_INITIALIZED>
{
fn info(&'a self) -> &'a Info<'b> {
&self.0
@ -51,7 +48,7 @@ where
}
}
impl<'a, 'b: 'a, T, const Seed: &'static str> Keyed<'a, 'b> for Derive<T, Seed>
impl<'a, 'b: 'a, T, const SEED: &'static str> Keyed<'a, 'b> for Derive<T, SEED>
where
T: Keyed<'a, 'b>,
{

View File

@ -11,10 +11,8 @@ use solana_program::{
sysvar::{
self,
Sysvar as SolanaSysvar,
SysvarId,
},
};
use std::marker::PhantomData;
use crate::{
processors::seeded::{
@ -23,7 +21,6 @@ use crate::{
},
trace,
types::*,
AccountState::MaybeInitialized,
Context,
Result,
SolitaireError,
@ -75,15 +72,15 @@ 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>
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
let (derived, bump) = Pubkey::find_program_address(&[Seed.as_ref()], ctx.this);
let (derived, _bump) = Pubkey::find_program_address(&[SEED.as_ref()], ctx.this);
match derived == *ctx.info().key {
true => T::peel(ctx).map(|v| Derive(v)),
_ => Err(SolitaireError::InvalidDerive(*ctx.info().key, derived).into()),
_ => Err(SolitaireError::InvalidDerive(*ctx.info().key, derived)),
}
}
@ -103,7 +100,7 @@ impl<'a, 'b: 'a, 'c, T: Peel<'a, 'b, 'c>> Peel<'a, 'b, 'c> for Mut<T> {
match ctx.info().is_writable {
true => T::peel(ctx).map(|v| Mut(v)),
_ => Err(
SolitaireError::InvalidMutability(*ctx.info().key, ctx.info().is_writable).into(),
SolitaireError::InvalidMutability(*ctx.info().key, ctx.info().is_writable),
),
}
}
@ -137,7 +134,7 @@ 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 {
true => T::peel(ctx).map(|v| Signer(v)),
_ => Err(SolitaireError::InvalidSigner(*ctx.info().key).into()),
_ => Err(SolitaireError::InvalidSigner(*ctx.info().key)),
}
}
@ -179,7 +176,7 @@ where
ctx.info().clone(),
Var::from_account_info(ctx.info())?,
)),
_ => Err(SolitaireError::InvalidSysvar(*ctx.info().key).into()),
_ => Err(SolitaireError::InvalidSysvar(*ctx.info().key)),
}
}
@ -198,7 +195,7 @@ 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).into(),
SolitaireError::InvalidMutability(*ctx.info().key, ctx.info().is_writable),
);
}
@ -219,18 +216,18 @@ impl<
'b: 'a,
'c,
T: BorshDeserialize + BorshSerialize + Owned + Default,
const IsInitialized: AccountState,
> Peel<'a, 'b, 'c> for Data<'b, T, IsInitialized>
const IS_INITIALIZED: AccountState,
> Peel<'a, 'b, 'c> 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).into(),
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 IsInitialized {
let (initialized, data): (bool, T) = match IS_INITIALIZED {
AccountState::Uninitialized => {
if !ctx.info().data.borrow().is_empty() {
return Err(SolitaireError::AlreadyInitialized(*ctx.info().key));
@ -238,13 +235,13 @@ impl<
(false, T::default())
}
AccountState::Initialized => {
(true, T::try_from_slice(&mut *ctx.info().data.borrow_mut())?)
(true, T::try_from_slice(*ctx.info().data.borrow_mut())?)
}
AccountState::MaybeInitialized => {
if ctx.info().data.borrow().is_empty() {
(false, T::default())
} else {
(true, T::try_from_slice(&mut *ctx.info().data.borrow_mut())?)
(true, T::try_from_slice(*ctx.info().data.borrow_mut())?)
}
}
};
@ -269,7 +266,7 @@ impl<
}
fn deps() -> Vec<Pubkey> {
if IsInitialized == AccountState::Initialized {
if IS_INITIALIZED == AccountState::Initialized {
return vec![];
}

View File

@ -1,32 +1,21 @@
use super::keyed::Keyed;
use crate::{
create_account,
system_instruction,
AccountInfo,
AccountState,
CreationLamports,
Data,
Deref,
Derive,
ExecutionContext,
FromAccounts,
Info,
IsSigned::*,
Peel,
Result,
Signer,
SolitaireError,
System,
Sysvar,
};
use borsh::{
BorshSchema,
BorshSerialize,
};
use solana_program::{
entrypoint::ProgramResult,
instruction::Instruction,
msg,
program::invoke_signed,
pubkey::Pubkey,
};
@ -53,8 +42,8 @@ pub trait Owned {
}
}
impl<'a, T: Owned + Default, const IsInitialized: AccountState> Owned
for Data<'a, T, IsInitialized>
impl<'a, T: Owned + Default, const IS_INITIALIZED: AccountState> Owned
for Data<'a, T, IS_INITIALIZED>
{
fn owner(&self) -> AccountOwner {
self.1.owner()
@ -69,9 +58,9 @@ pub trait Seeded<I> {
}
fn key(accs: I, program_id: &Pubkey) -> Pubkey {
let mut seeds = Self::seeds(accs);
let mut s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let mut seed_slice = s.as_slice();
let seeds = Self::seeds(accs);
let s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let seed_slice = s.as_slice();
let (addr, _) = Pubkey::find_program_address(seed_slice, program_id);
addr
@ -79,8 +68,8 @@ pub trait Seeded<I> {
fn bumped_seeds(accs: I, program_id: &Pubkey) -> Vec<Vec<u8>> {
let mut seeds = Self::seeds(accs);
let mut s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let mut seed_slice = s.as_slice();
let s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let seed_slice = s.as_slice();
let (_, bump_seed) = Pubkey::find_program_address(seed_slice, program_id);
seeds.push(vec![bump_seed]);
@ -99,7 +88,7 @@ pub trait Seeded<I> {
let s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let seed_slice = s.as_slice();
let (derived, bump) = Pubkey::find_program_address(seed_slice, program_id);
let (derived, _bump) = Pubkey::find_program_address(seed_slice, program_id);
if &derived == self.info().key {
Ok(())
} else {
@ -118,8 +107,8 @@ pub trait Creatable<'a, I> {
) -> Result<()>;
}
impl<T: BorshSerialize + Owned + Default, const IsInitialized: AccountState> AccountSize
for Data<'_, T, IsInitialized>
impl<T: BorshSerialize + Owned + Default, const IS_INITIALIZED: AccountState> AccountSize
for Data<'_, T, IS_INITIALIZED>
{
fn size(&self) -> usize {
self.1.try_to_vec().unwrap().len()
@ -137,8 +126,8 @@ impl<'a, 'b: 'a, K, T: AccountSize + Seeded<K> + Keyed<'a, 'b> + Owned> Creatabl
let seeds = T::bumped_seeds(accs, ctx.program_id);
let size = self.size();
let mut s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let mut seed_slice = s.as_slice();
let s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect();
let seed_slice = s.as_slice();
create_account(
ctx,
@ -152,9 +141,9 @@ impl<'a, 'b: 'a, K, T: AccountSize + Seeded<K> + Keyed<'a, 'b> + Owned> Creatabl
}
}
impl<'a, const Seed: &'static str, T> Seeded<Option<()>> for Derive<T, Seed> {
fn seeds(accs: Option<()>) -> Vec<Vec<u8>> {
vec![Seed.as_bytes().to_vec()]
impl<'a, const SEED: &'static str, T> Seeded<Option<()>> for Derive<T, SEED> {
fn seeds(_accs: Option<()>) -> Vec<Vec<u8>> {
vec![SEED.as_bytes().to_vec()]
}
}

View File

@ -7,7 +7,6 @@
use borsh::BorshSerialize;
use solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
program::{
invoke,
invoke_signed,
@ -28,7 +27,6 @@ use crate::{
ExecutionContext,
Keyed,
Result,
SolitaireError,
};
/// A short alias for AccountInfo.
@ -85,13 +83,13 @@ use IsSigned::*;
///
/// Data<(), { AccountState::Uninitialized }>
#[rustfmt::skip]
pub struct Data<'r, T: Owned + Default, const IsInitialized: AccountState> (
pub struct Data<'r, T: Owned + Default, const IS_INITIALIZED: AccountState> (
pub Box<Info<'r>>,
pub T,
);
impl<'r, T: Owned + Default, const IsInitialized: AccountState> Deref
for Data<'r, T, IsInitialized>
impl<'r, T: Owned + Default, const IS_INITIALIZED: AccountState> Deref
for Data<'r, T, IS_INITIALIZED>
{
type Target = T;
fn deref(&self) -> &Self::Target {
@ -99,8 +97,8 @@ impl<'r, T: Owned + Default, const IsInitialized: AccountState> Deref
}
}
impl<'r, T: Owned + Default, const IsInitialized: AccountState> DerefMut
for Data<'r, T, IsInitialized>
impl<'r, T: Owned + Default, const IS_INITIALIZED: AccountState> DerefMut
for Data<'r, T, IS_INITIALIZED>
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.1
@ -123,7 +121,7 @@ impl<'b, Var: SolanaSysvar> Deref for Sysvar<'b, Var> {
}
}
impl<const Seed: &'static str> Derive<AccountInfo<'_>, Seed> {
impl<const SEED: &'static str> Derive<AccountInfo<'_>, SEED> {
pub fn create(
&self,
ctx: &ExecutionContext,
@ -132,7 +130,7 @@ impl<const Seed: &'static str> Derive<AccountInfo<'_>, Seed> {
space: usize,
owner: &Pubkey,
) -> Result<()> {
let (_, bump_seed) = Pubkey::find_program_address(&[Seed.as_bytes()][..], ctx.program_id);
let (_, bump_seed) = Pubkey::find_program_address(&[SEED.as_bytes()][..], ctx.program_id);
create_account(
ctx,
self.info(),
@ -140,13 +138,13 @@ impl<const Seed: &'static str> Derive<AccountInfo<'_>, Seed> {
lamports,
space,
owner,
SignedWithSeeds(&[&[Seed.as_bytes(), &[bump_seed]]]),
SignedWithSeeds(&[&[SEED.as_bytes(), &[bump_seed]]]),
)
}
}
impl<const Seed: &'static str, T: BorshSerialize + Owned + Default>
Derive<Data<'_, T, { AccountState::Uninitialized }>, Seed>
impl<const SEED: &'static str, T: BorshSerialize + Owned + Default>
Derive<Data<'_, T, { AccountState::Uninitialized }>, SEED>
{
pub fn create(
&self,
@ -156,7 +154,7 @@ impl<const Seed: &'static str, T: BorshSerialize + Owned + Default>
) -> Result<()> {
// Get serialized struct size
let size = self.0.try_to_vec().unwrap().len();
let (_, bump_seed) = Pubkey::find_program_address(&[Seed.as_bytes()][..], ctx.program_id);
let (_, bump_seed) = Pubkey::find_program_address(&[SEED.as_bytes()][..], ctx.program_id);
create_account(
ctx,
self.info(),
@ -164,7 +162,7 @@ impl<const Seed: &'static str, T: BorshSerialize + Owned + Default>
lamports,
size,
ctx.program_id,
SignedWithSeeds(&[&[Seed.as_bytes(), &[bump_seed]]]),
SignedWithSeeds(&[&[SEED.as_bytes(), &[bump_seed]]]),
)
}
}

View File

@ -6,23 +6,12 @@
//! the layer below, allowing for optimized recursion.
use std::{
io::{
ErrorKind,
Write,
},
marker::PhantomData,
ops::{
Deref,
DerefMut,
},
};
use crate::Info;
use borsh::{
BorshDeserialize,
BorshSerialize,
};
#[repr(transparent)]
pub struct Mut<Next>(pub Next);
@ -36,7 +25,7 @@ pub struct Signer<Next>(pub Next);
pub struct System<Next>(pub Next);
#[repr(transparent)]
pub struct Derive<Next, const Seed: &'static str>(pub Next);
pub struct Derive<Next, const SEED: &'static str>(pub Next);
// Several traits are required for types defined here, they cannot be defined in another file due
// to orphan instance limitations.
@ -93,14 +82,14 @@ impl<T> DerefMut for System<T> {
}
}
impl<T, const Seed: &'static str> Deref for Derive<T, Seed> {
impl<T, const SEED: &'static str> Deref for Derive<T, SEED> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { std::mem::transmute(&self.0) }
}
}
impl<T, const Seed: &'static str> DerefMut for Derive<T, Seed> {
impl<T, const SEED: &'static str> DerefMut for Derive<T, SEED> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::mem::transmute(&mut self.0) }
}

View File

@ -1,37 +1,18 @@
#![allow(warnings)]
mod to_instruction;
use to_instruction::*;
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
pubkey::Pubkey,
};
use proc_macro::TokenStream;
use proc_macro2::{
Span,
TokenStream as TokenStream2,
};
use quote::{
quote,
quote_spanned,
ToTokens,
};
use std::borrow::BorrowMut;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{
parse_macro_input,
parse_quote,
spanned::Spanned,
Data,
DeriveInput,
Fields,
GenericParam,
Generics,
Index,
};
#[proc_macro_derive(ToInstruction)]
@ -39,6 +20,45 @@ pub fn derive_to_instruction(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
// Type params of the instruction context account
let type_params: Vec<GenericParam> = input
.generics
.type_params()
.map(|v| GenericParam::Type(v.clone()))
.collect();
// Generics lifetimes of the peel type
let mut peel_g = input.generics.clone();
peel_g.params = parse_quote!('a, 'b: 'a, 'c);
// Params of the instruction context
let mut type_generics = input.generics.clone();
type_generics.params = parse_quote!('b);
for x in &type_params {
type_generics.params.push(x.clone());
}
// Combined lifetimes of peel and the instruction context
let mut combined_generics = Generics {
params: peel_g.params,
..Default::default()
};
for x in &type_params {
combined_generics.params.push(x.clone());
}
let (combined_impl_g, _, _) = combined_generics.split_for_impl();
let expanded = generate_to_instruction(&name, &combined_impl_g, &input.data);
TokenStream::from(expanded)
}
/// Generate a FromAccounts implementation for a product of accounts. Each field is constructed by
/// a call to the Verify::verify instance of its type.
#[proc_macro_derive(FromAccounts)]
pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
// Type params of the instruction context account
let type_params: Vec<GenericParam> = input
.generics
@ -60,55 +80,18 @@ pub fn derive_to_instruction(input: TokenStream) -> TokenStream {
let (type_impl_g, type_g, _) = type_generics.split_for_impl();
// Combined lifetimes of peel and the instruction context
let mut combined_generics = Generics::default();
combined_generics.params = peel_g.params.clone();
for x in &type_params {
combined_generics.params.push(x.clone());
}
let (combined_impl_g, _, _) = combined_generics.split_for_impl();
let expanded = generate_to_instruction(&name, &combined_impl_g, &input.data);
TokenStream::from(expanded)
}
/// Generate a FromAccounts implementation for a product of accounts. Each field is constructed by
/// a call to the Verify::verify instance of its type.
#[proc_macro_derive(FromAccounts)]
pub fn derive_from_accounts(input: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
// Type params of the instruction context account
let type_params: Vec<GenericParam> = input
.generics
.type_params()
.map(|v| GenericParam::Type(v.clone()))
.collect();
// Generics lifetimes of the peel type
let mut peel_g = input.generics.clone();
peel_g.params = parse_quote!('a, 'b: 'a, 'c);
let (_, peel_type_g, _) = peel_g.split_for_impl();
// Params of the instruction context
let mut type_generics = input.generics.clone();
type_generics.params = parse_quote!('b);
for x in &type_params {
type_generics.params.push(x.clone());
}
let (type_impl_g, type_g, _) = type_generics.split_for_impl();
// Combined lifetimes of peel and the instruction context
let mut combined_generics = Generics::default();
combined_generics.params = peel_g.params.clone();
let mut combined_generics = Generics {
params: peel_g.params.clone(),
..Default::default()
};
for x in &type_params {
combined_generics.params.push(x.clone());
}
let (combined_impl_g, _, _) = combined_generics.split_for_impl();
let from_method = generate_fields(&name, &input.data);
let persist_method = generate_persist(&name, &input.data);
let deps_method = generate_deps_fields(&name, &input.data);
let persist_method = generate_persist(&input.data);
let deps_method = generate_deps_fields(&input.data);
let expanded = quote! {
/// Macro generated implementation of FromAccounts by Solitaire.
impl #combined_impl_g solitaire::FromAccounts #peel_type_g for #name #type_g {
@ -201,7 +184,7 @@ fn generate_fields(name: &syn::Ident, data: &Data) -> TokenStream2 {
}
/// This function does the heavy lifting of generating the field parsers.
fn generate_deps_fields(name: &syn::Ident, data: &Data) -> TokenStream2 {
fn generate_deps_fields(data: &Data) -> TokenStream2 {
match *data {
// We only care about structures.
Data::Struct(ref data) => {
@ -240,7 +223,7 @@ fn generate_deps_fields(name: &syn::Ident, data: &Data) -> TokenStream2 {
}
/// This function does the heavy lifting of generating the field parsers.
fn generate_persist(name: &syn::Ident, data: &Data) -> TokenStream2 {
fn generate_persist(data: &Data) -> TokenStream2 {
match *data {
// We only care about structures.
Data::Struct(ref data) => {
@ -254,7 +237,6 @@ fn generate_persist(name: &syn::Ident, data: &Data) -> TokenStream2 {
let recurse = fields.named.iter().map(|f| {
// Field name, to assign to.
let name = &f.ident;
let ty = &f.ty;
quote! {
trace!(stringify!(#name));

View File

@ -1,25 +1,14 @@
//! Derive macro logic for ToInstruction
use proc_macro::TokenStream;
use proc_macro2::{
Span,
TokenStream as TokenStream2,
};
use quote::{
quote,
quote_spanned,
};
use quote::quote;
use syn::{
parse_macro_input,
parse_quote,
spanned::Spanned,
Data,
DataStruct,
DeriveInput,
Fields,
GenericParam,
Generics,
Index,
};
pub fn generate_to_instruction(
@ -45,9 +34,9 @@ pub fn generate_to_instruction(
}
});
let client_struct_name =
syn::Ident::new(&format!("{}Accounts", name.to_string()), Span::call_site());
syn::Ident::new(&format!("{}Accounts", name), Span::call_site());
let client_struct_decl = generate_clientside_struct(&name, &client_struct_name, &data);
let client_struct_decl = generate_clientside_struct(&client_struct_name, data);
quote! {
/// Solitaire-generated client-side #name representation
@ -90,7 +79,6 @@ pub fn generate_to_instruction(
}
pub fn generate_clientside_struct(
name: &syn::Ident,
client_struct_name: &syn::Ident,
data: &Data,
) -> TokenStream2 {