| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631 |
- #![allow(warnings)]
- use borsh::BorshSerialize;
- use byteorder::{
- BigEndian,
- WriteBytesExt,
- };
- use hex_literal::hex;
- use rand::Rng;
- use secp256k1::{
- Message as Secp256k1Message,
- PublicKey,
- SecretKey,
- };
- use sha3::Digest;
- use solana_client::rpc_client::RpcClient;
- 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_sdk::{
- commitment_config::CommitmentConfig,
- signature::{
- read_keypair_file,
- Keypair,
- Signer,
- },
- transaction::Transaction,
- };
- use solitaire::{
- processors::seeded::Seeded,
- AccountState,
- };
- use spl_token::state::Mint;
- use std::{
- convert::TryInto,
- io::{
- Cursor,
- Write,
- },
- time::{
- Duration,
- SystemTime,
- },
- };
- use bridge::{
- accounts::{
- Bridge,
- FeeCollector,
- GuardianSet,
- GuardianSetDerivationData,
- PostedVAA,
- PostedVAADerivationData,
- SignatureSet,
- },
- instruction,
- types::{
- BridgeConfig,
- BridgeData,
- GovernancePayloadGuardianSetChange,
- GovernancePayloadSetMessageFee,
- GovernancePayloadTransferFees,
- GuardianSetData,
- MessageData,
- PostedVAAData,
- SequenceTracker,
- SignatureSet as SignatureSetData,
- },
- Initialize,
- PostVAA,
- PostVAAData,
- SerializePayload,
- Signature,
- };
- use primitive_types::U256;
- use std::{
- collections::HashMap,
- str::FromStr,
- time::UNIX_EPOCH,
- };
- use token_bridge::{
- accounts::{
- EmitterAccount,
- WrappedDerivationData,
- WrappedMint,
- },
- messages::{
- PayloadAssetMeta,
- PayloadGovernanceRegisterChain,
- PayloadTransfer,
- },
- types::Address,
- };
- mod common;
- const GOVERNANCE_KEY: [u8; 64] = [
- 240, 133, 120, 113, 30, 67, 38, 184, 197, 72, 234, 99, 241, 21, 58, 225, 41, 157, 171, 44, 196,
- 163, 134, 236, 92, 148, 110, 68, 127, 114, 177, 0, 173, 253, 199, 9, 242, 142, 201, 174, 108,
- 197, 18, 102, 115, 0, 31, 205, 127, 188, 191, 56, 171, 228, 20, 247, 149, 170, 141, 231, 147,
- 88, 97, 199,
- ];
- struct Context {
- /// Address of the core bridge contract.
- bridge: Pubkey,
- /// Shared RPC client for tests to make transactions with.
- client: RpcClient,
- /// Payer key with a ton of lamports to ease testing with.
- payer: Keypair,
- /// Track nonces throughout the tests.
- seq: Sequencer,
- /// Address of the token bridge itself that we wish to test.
- token_bridge: Pubkey,
- /// Keypairs for mint information, required in multiple tests.
- mint_authority: Keypair,
- mint: Keypair,
- mint_meta: Pubkey,
- /// Keypairs for test token accounts.
- token_authority: Keypair,
- token_account: Keypair,
- metadata_account: Pubkey,
- }
- /// Small helper to track and provide sequences during tests. This is in particular needed for
- /// guardian operations that require them for derivations.
- struct Sequencer {
- sequences: HashMap<[u8; 32], u64>,
- }
- impl Sequencer {
- fn next(&mut self, emitter: [u8; 32]) -> u64 {
- let entry = self.sequences.entry(emitter).or_insert(0);
- *entry += 1;
- *entry - 1
- }
- fn peek(&mut self, emitter: [u8; 32]) -> u64 {
- *self.sequences.entry(emitter).or_insert(0)
- }
- }
- #[test]
- fn run_integration_tests() {
- let (payer, client, bridge, token_bridge) = common::setup();
- // Setup a Bridge to test against.
- println!("Bridge: {}", bridge);
- common::initialize_bridge(&client, &bridge, &payer);
- // Context for test environment.
- let mint = Keypair::new();
- let mint_pubkey = mint.pubkey();
- let metadata_pubkey = Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap();
- // SPL Token Meta
- let metadata_seeds = &[
- "metadata".as_bytes(),
- metadata_pubkey.as_ref(),
- mint_pubkey.as_ref(),
- ];
- let (metadata_key, metadata_bump_seed) = Pubkey::find_program_address(
- metadata_seeds,
- &Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap(),
- );
- // Token Bridge Meta
- use token_bridge::accounts::WrappedTokenMeta;
- let metadata_account = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key(
- &token_bridge::accounts::WrappedMetaDerivationData {
- mint_key: mint_pubkey.clone(),
- },
- &token_bridge,
- );
- let mut context = Context {
- seq: Sequencer {
- sequences: HashMap::new(),
- },
- bridge,
- client,
- payer,
- token_bridge,
- mint_authority: Keypair::new(),
- mint,
- mint_meta: metadata_account,
- token_account: Keypair::new(),
- token_authority: Keypair::new(),
- metadata_account: metadata_key,
- };
- // Create a mint for use within tests.
- common::create_mint(
- &context.client,
- &context.payer,
- &context.mint_authority.pubkey(),
- &context.mint,
- )
- .unwrap();
- // Create Token accounts for use within tests.
- common::create_token_account(
- &context.client,
- &context.payer,
- &context.token_account,
- context.token_authority.pubkey(),
- context.mint.pubkey(),
- )
- .unwrap();
- // Mint tokens
- common::mint_tokens(
- &context.client,
- &context.payer,
- &context.mint_authority,
- &context.mint,
- &context.token_account.pubkey(),
- 1000,
- )
- .unwrap();
- // Initialize the bridge and verify the bridges state.
- test_initialize(&mut context);
- test_transfer_native(&mut context);
- test_attest(&mut context);
- test_register_chain(&mut context);
- test_transfer_native_in(&mut context);
- // Create an SPL Metadata account to test attestations for wrapped tokens.
- common::create_spl_metadata(
- &context.client,
- &context.payer,
- &context.metadata_account,
- &context.mint_authority,
- &context.mint,
- &context.payer.pubkey(),
- "BTC".to_string(),
- "Bitcoin".to_string(),
- )
- .unwrap();
- let wrapped = test_create_wrapped(&mut context);
- let wrapped_acc = Keypair::new();
- common::create_token_account(
- &context.client,
- &context.payer,
- &wrapped_acc,
- context.token_authority.pubkey(),
- wrapped,
- )
- .unwrap();
- test_transfer_wrapped_in(&mut context, wrapped_acc.pubkey());
- test_transfer_wrapped(&mut context, wrapped_acc.pubkey());
- }
- fn test_attest(context: &mut Context) -> () {
- println!("Attest");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref mint,
- ref mint_meta,
- ref metadata_account,
- ..
- } = context;
- let message = &Keypair::new();
- common::attest(
- client,
- token_bridge,
- bridge,
- payer,
- message,
- mint.pubkey(),
- 0,
- )
- .unwrap();
- let emitter_key = EmitterAccount::key(None, &token_bridge);
- let mint_data = Mint::unpack(
- &client
- .get_account_with_commitment(&mint.pubkey(), CommitmentConfig::processed())
- .unwrap()
- .value
- .unwrap()
- .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();
- }
- fn test_transfer_native(context: &mut Context) -> () {
- println!("Transfer Native");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref mint,
- ref mint_meta,
- ref token_account,
- ref token_authority,
- ..
- } = context;
- let message = &Keypair::new();
- common::transfer_native(
- client,
- token_bridge,
- bridge,
- payer,
- message,
- token_account,
- token_authority,
- mint.pubkey(),
- 100,
- )
- .unwrap();
- }
- fn test_transfer_wrapped(context: &mut Context, token_account: Pubkey) -> () {
- println!("TransferWrapped");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref token_authority,
- ..
- } = context;
- let message = &Keypair::new();
- common::transfer_wrapped(
- client,
- token_bridge,
- bridge,
- payer,
- message,
- token_account,
- token_authority,
- 2,
- [1u8; 32],
- 10000000,
- )
- .unwrap();
- }
- fn test_register_chain(context: &mut Context) -> () {
- println!("Register Chain");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref mint,
- ref mint_meta,
- ref token_account,
- ref token_authority,
- ..
- } = context;
- let nonce = rand::thread_rng().gen();
- let emitter = Keypair::from_bytes(&GOVERNANCE_KEY).unwrap();
- let payload = PayloadGovernanceRegisterChain {
- chain: 2,
- endpoint_address: [0u8; 32],
- };
- let message = payload.try_to_vec().unwrap();
- let (vaa, _, _) = common::generate_vaa(emitter.pubkey().to_bytes(), 1, message, nonce, 0);
- common::post_vaa(client, bridge, payer, vaa.clone()).unwrap();
- let mut msg_derivation_data = &PostedVAADerivationData {
- payload_hash: bridge::instructions::hash_vaa(&vaa).to_vec(),
- };
- let message_key =
- PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
- common::register_chain(
- client,
- token_bridge,
- bridge,
- &message_key,
- vaa,
- payload,
- payer,
- )
- .unwrap();
- }
- fn test_transfer_native_in(context: &mut Context) -> () {
- println!("TransferNativeIn");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref mint,
- ref mint_meta,
- ref token_account,
- ref token_authority,
- ..
- } = context;
- let nonce = rand::thread_rng().gen();
- let payload = PayloadTransfer {
- amount: U256::from(100),
- token_address: mint.pubkey().to_bytes(),
- token_chain: 1,
- to: token_account.pubkey().to_bytes(),
- to_chain: 1,
- fee: U256::from(0),
- };
- let message = payload.try_to_vec().unwrap();
- let (vaa, _, _) = common::generate_vaa([0u8; 32], 2, message, nonce, 1);
- common::post_vaa(client, bridge, payer, vaa.clone()).unwrap();
- let mut msg_derivation_data = &PostedVAADerivationData {
- payload_hash: bridge::instructions::hash_vaa(&vaa).to_vec(),
- };
- let message_key =
- PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
- common::complete_native(
- client,
- token_bridge,
- bridge,
- &message_key,
- vaa,
- payload,
- payer,
- )
- .unwrap();
- }
- fn test_transfer_wrapped_in(context: &mut Context, to: Pubkey) -> () {
- println!("TransferWrappedIn");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref mint,
- ref mint_meta,
- ref token_account,
- ref token_authority,
- ..
- } = context;
- let nonce = rand::thread_rng().gen();
- let payload = PayloadTransfer {
- amount: U256::from(100000000),
- token_address: [1u8; 32],
- token_chain: 2,
- to: to.to_bytes(),
- to_chain: 1,
- fee: U256::from(0),
- };
- let message = payload.try_to_vec().unwrap();
- let (vaa, _, _) = common::generate_vaa([0u8; 32], 2, message, nonce, rand::thread_rng().gen());
- common::post_vaa(client, bridge, payer, vaa.clone()).unwrap();
- let mut msg_derivation_data = &PostedVAADerivationData {
- payload_hash: bridge::instructions::hash_vaa(&vaa).to_vec(),
- };
- let message_key =
- PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
- common::complete_transfer_wrapped(
- client,
- token_bridge,
- bridge,
- &message_key,
- vaa,
- payload,
- payer,
- )
- .unwrap();
- }
- fn test_create_wrapped(context: &mut Context) -> (Pubkey) {
- println!("CreateWrapped");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ref mint_authority,
- ref mint,
- ref mint_meta,
- ref token_account,
- ref token_authority,
- ..
- } = context;
- let nonce = rand::thread_rng().gen();
- let payload = PayloadAssetMeta {
- token_address: [1u8; 32],
- token_chain: 2,
- decimals: 7,
- symbol: "".to_string(),
- name: "".to_string(),
- };
- let message = payload.try_to_vec().unwrap();
- let (vaa, _, _) = common::generate_vaa([0u8; 32], 2, message, nonce, 2);
- common::post_vaa(client, bridge, payer, vaa.clone()).unwrap();
- let mut msg_derivation_data = &PostedVAADerivationData {
- payload_hash: bridge::instructions::hash_vaa(&vaa).to_vec(),
- };
- let message_key =
- PostedVAA::<'_, { AccountState::MaybeInitialized }>::key(&msg_derivation_data, &bridge);
- common::create_wrapped(
- client,
- token_bridge,
- bridge,
- &message_key,
- vaa,
- payload,
- payer,
- )
- .unwrap();
- return WrappedMint::<'_, { AccountState::Initialized }>::key(
- &WrappedDerivationData {
- token_chain: 2,
- token_address: [1u8; 32],
- },
- token_bridge,
- );
- }
- fn test_initialize(context: &mut Context) {
- println!("Initialize");
- use token_bridge::{
- accounts::ConfigAccount,
- types::Config,
- };
- let Context {
- ref payer,
- ref client,
- ref bridge,
- ref token_bridge,
- ..
- } = context;
- common::initialize(client, token_bridge, payer, &bridge).unwrap();
- // Verify Token Bridge State
- let config_key = ConfigAccount::<'_, { AccountState::Uninitialized }>::key(None, &token_bridge);
- let config: Config = common::get_account_data(client, &config_key).unwrap();
- assert_eq!(config.wormhole_bridge, *bridge);
- }
|