Working transfer in

This commit is contained in:
Hendrik Hofstadt 2020-08-17 17:06:09 +02:00
parent 2f526ff136
commit e040449197
9 changed files with 227 additions and 92 deletions

74
solana/Cargo.lock generated
View File

@ -386,7 +386,7 @@ dependencies = [
"solana-cli-config", "solana-cli-config",
"solana-client", "solana-client",
"solana-faucet", "solana-faucet",
"solana-logger", "solana-logger 1.3.3",
"solana-sdk", "solana-sdk",
"solana-transaction-status", "solana-transaction-status",
"spl-token 1.0.8 (git+https://github.com/solana-labs/solana-program-library)", "spl-token 1.0.8 (git+https://github.com/solana-labs/solana-program-library)",
@ -1937,9 +1937,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.18.0" version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac94b333ee2aac3284c5b8a1b7fb4dd11cba88c244e3fe33cdbd047af0eb693" checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81"
dependencies = [ dependencies = [
"base64 0.12.3", "base64 0.12.3",
"log", "log",
@ -2276,9 +2276,8 @@ dependencies = [
[[package]] [[package]]
name = "solana-crate-features" name = "solana-crate-features"
version = "1.3.3" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/jackcmay/solana?branch=cpi-create-account#d84010e4afe5f79c812ff7da349460dc690a8392"
checksum = "41045abbf3dd7ecb01db9851590cb2951df54d06f5f13667cfbc178497a9683b"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes 0.4.12", "bytes 0.4.12",
@ -2313,7 +2312,7 @@ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"solana-clap-utils", "solana-clap-utils",
"solana-logger", "solana-logger 1.3.3",
"solana-metrics", "solana-metrics",
"solana-sdk", "solana-sdk",
"solana-version", "solana-version",
@ -2332,6 +2331,16 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "solana-logger"
version = "1.4.0"
source = "git+https://github.com/jackcmay/solana?branch=cpi-create-account#d84010e4afe5f79c812ff7da349460dc690a8392"
dependencies = [
"env_logger",
"lazy_static",
"log",
]
[[package]] [[package]]
name = "solana-metrics" name = "solana-metrics"
version = "1.3.3" version = "1.3.3"
@ -2362,7 +2371,7 @@ dependencies = [
"serde_derive", "serde_derive",
"socket2", "socket2",
"solana-clap-utils", "solana-clap-utils",
"solana-logger", "solana-logger 1.3.3",
"solana-version", "solana-version",
"tokio 0.1.22", "tokio 0.1.22",
"tokio-codec", "tokio-codec",
@ -2391,9 +2400,8 @@ dependencies = [
[[package]] [[package]]
name = "solana-sdk" name = "solana-sdk"
version = "1.3.3" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/jackcmay/solana?branch=cpi-create-account#d84010e4afe5f79c812ff7da349460dc690a8392"
checksum = "d96fb797cf378f8c85ce4e37f45e2fdc75f3a27793e831b3cccd74b0c66e809d"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"bincode", "bincode",
@ -2422,17 +2430,16 @@ dependencies = [
"serde_json", "serde_json",
"sha2", "sha2",
"solana-crate-features", "solana-crate-features",
"solana-logger", "solana-logger 1.4.0",
"solana-sdk-macro", "solana-sdk-macro",
"solana-sdk-macro-frozen-abi", "solana-sdk-macro-frozen-abi 1.4.0",
"thiserror", "thiserror",
] ]
[[package]] [[package]]
name = "solana-sdk-macro" name = "solana-sdk-macro"
version = "1.3.3" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/jackcmay/solana?branch=cpi-create-account#d84010e4afe5f79c812ff7da349460dc690a8392"
checksum = "0aad003e717fc4f1831494de7c5307d667a5c5d2fa22b3dfbedd34a6e61ed4ea"
dependencies = [ dependencies = [
"bs58", "bs58",
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
@ -2454,6 +2461,18 @@ dependencies = [
"syn 1.0.38", "syn 1.0.38",
] ]
[[package]]
name = "solana-sdk-macro-frozen-abi"
version = "1.4.0"
source = "git+https://github.com/jackcmay/solana?branch=cpi-create-account#d84010e4afe5f79c812ff7da349460dc690a8392"
dependencies = [
"lazy_static",
"proc-macro2 1.0.19",
"quote 1.0.7",
"rustc_version",
"syn 1.0.38",
]
[[package]] [[package]]
name = "solana-stake-program" name = "solana-stake-program"
version = "1.3.3" version = "1.3.3"
@ -2470,7 +2489,7 @@ dependencies = [
"solana-config-program", "solana-config-program",
"solana-metrics", "solana-metrics",
"solana-sdk", "solana-sdk",
"solana-sdk-macro-frozen-abi", "solana-sdk-macro-frozen-abi 1.3.3",
"solana-vote-program", "solana-vote-program",
"thiserror", "thiserror",
] ]
@ -2507,9 +2526,9 @@ dependencies = [
"rustc_version", "rustc_version",
"serde", "serde",
"serde_derive", "serde_derive",
"solana-logger", "solana-logger 1.3.3",
"solana-sdk", "solana-sdk",
"solana-sdk-macro-frozen-abi", "solana-sdk-macro-frozen-abi 1.3.3",
] ]
[[package]] [[package]]
@ -2525,10 +2544,10 @@ dependencies = [
"rustc_version", "rustc_version",
"serde", "serde",
"serde_derive", "serde_derive",
"solana-logger", "solana-logger 1.3.3",
"solana-metrics", "solana-metrics",
"solana-sdk", "solana-sdk",
"solana-sdk-macro-frozen-abi", "solana-sdk-macro-frozen-abi 1.3.3",
"thiserror", "thiserror",
] ]
@ -2560,6 +2579,19 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "spl-token"
version = "1.0.8"
dependencies = [
"cbindgen",
"num-derive 0.3.1",
"num-traits",
"rand",
"remove_dir_all",
"solana-sdk",
"thiserror",
]
[[package]] [[package]]
name = "spl-token" name = "spl-token"
version = "1.0.8" version = "1.0.8"

View File

@ -1,2 +1,5 @@
[workspace] [workspace]
members = ["agent", "bridge", "cli"] members = ["agent", "bridge", "cli", "token"]
[patch.crates-io]
solana-sdk = { git="https://github.com/jackcmay/solana", branch="cpi-create-account" }

View File

@ -19,7 +19,7 @@ default = ["solana-sdk/default", "spl-token/default"]
num-derive = "0.2" num-derive = "0.2"
num-traits = "0.2" num-traits = "0.2"
remove_dir_all = "=0.5.0" remove_dir_all = "=0.5.0"
solana-sdk = { version = "=1.3.3", default-features = false, optional = true } solana-sdk = { version = "1.3.3", default-features = false, optional = true }
spl-token = { package = "spl-token", git = "https://github.com/solana-labs/solana-program-library", default-features = false, optional = true } spl-token = { package = "spl-token", git = "https://github.com/solana-labs/solana-program-library", default-features = false, optional = true }
thiserror = "1.0" thiserror = "1.0"
byteorder = "1.3.4" byteorder = "1.3.4"

View File

@ -97,6 +97,9 @@ pub enum Error {
/// VAA is longer than the maximum size /// VAA is longer than the maximum size
#[error("VAATooLong")] #[error("VAATooLong")]
VAATooLong, VAATooLong,
/// Cannot wrap a solana native asset
#[error("CannotWrapNative")]
CannotWrapNative,
} }
impl From<Error> for ProgramError { impl From<Error> for ProgramError {

View File

@ -37,6 +37,7 @@ impl PrintProgramError for Error {
Error::VAAProposalMismatch => info!("Error: VAAProposalMismatch"), Error::VAAProposalMismatch => info!("Error: VAAProposalMismatch"),
Error::SameChainTransfer => info!("Error: SameChainTransfer"), Error::SameChainTransfer => info!("Error: SameChainTransfer"),
Error::VAATooLong => info!("Error: VAATooLong"), Error::VAATooLong => info!("Error: VAATooLong"),
Error::CannotWrapNative => info!("Error: CannotWrapNative"),
} }
} }
} }

View File

@ -241,6 +241,7 @@ pub fn create_wrapped(
Bridge::derive_wrapped_meta_id(program_id, &bridge_key, &wrapped_mint_key)?; Bridge::derive_wrapped_meta_id(program_id, &bridge_key, &wrapped_mint_key)?;
let accounts = vec![ let accounts = vec![
AccountMeta::new_readonly(*program_id, false),
AccountMeta::new_readonly(solana_sdk::system_program::id(), false), AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
AccountMeta::new_readonly(spl_token::id(), false), AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new(bridge_key, false), AccountMeta::new(bridge_key, false),
@ -279,6 +280,7 @@ pub fn transfer_out(
)?; )?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new_readonly(*program_id, false),
AccountMeta::new_readonly(solana_sdk::system_program::id(), false), AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
AccountMeta::new_readonly(spl_token::id(), false), AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new(*token_account, false), AccountMeta::new(*token_account, false),
@ -331,6 +333,7 @@ pub fn post_vaa(
let claim_key = Bridge::derive_claim_id(program_id, &bridge_key, &vaa.body_hash()?)?; let claim_key = Bridge::derive_claim_id(program_id, &bridge_key, &vaa.body_hash()?)?;
let mut accounts = vec![ let mut accounts = vec![
AccountMeta::new_readonly(*program_id, false),
AccountMeta::new_readonly(solana_sdk::system_program::id(), false), AccountMeta::new_readonly(solana_sdk::system_program::id(), false),
AccountMeta::new_readonly(solana_sdk::sysvar::clock::id(), false), AccountMeta::new_readonly(solana_sdk::sysvar::clock::id(), false),
AccountMeta::new(bridge_key, false), AccountMeta::new(bridge_key, false),

View File

@ -8,8 +8,6 @@ use num_traits::AsPrimitive;
use primitive_types::U256; use primitive_types::U256;
use solana_sdk::clock::Clock; use solana_sdk::clock::Clock;
use solana_sdk::hash::Hasher; use solana_sdk::hash::Hasher;
#[cfg(not(target_arch = "bpf"))]
use solana_sdk::instruction::Instruction;
#[cfg(target_arch = "bpf")] #[cfg(target_arch = "bpf")]
use solana_sdk::program::invoke_signed; use solana_sdk::program::invoke_signed;
use solana_sdk::rent::Rent; use solana_sdk::rent::Rent;
@ -17,7 +15,7 @@ use solana_sdk::system_instruction::{create_account, SystemInstruction};
use solana_sdk::sysvar::Sysvar; use solana_sdk::sysvar::Sysvar;
use solana_sdk::{ use solana_sdk::{
account_info::next_account_info, account_info::AccountInfo, entrypoint::ProgramResult, info, account_info::next_account_info, account_info::AccountInfo, entrypoint::ProgramResult, info,
program_error::ProgramError, pubkey::Pubkey, instruction::Instruction, program_error::ProgramError, pubkey::Pubkey,
}; };
use spl_token::state::Mint; use spl_token::state::Mint;
@ -87,11 +85,12 @@ impl Bridge {
// Create bridge account // Create bridge account
let bridge_seed = Bridge::derive_bridge_seeds(); let bridge_seed = Bridge::derive_bridge_seeds();
Bridge::check_and_create_account::<BridgeConfig>( Bridge::check_and_create_account::<Bridge>(
program_id, program_id,
accounts, accounts,
new_bridge_info.key, new_bridge_info.key,
payer_info.key, payer_info.key,
program_id,
&bridge_seed, &bridge_seed,
)?; )?;
@ -108,6 +107,7 @@ impl Bridge {
accounts, accounts,
new_guardian_info.key, new_guardian_info.key,
payer_info.key, payer_info.key,
program_id,
&guardian_seed, &guardian_seed,
)?; )?;
@ -139,6 +139,7 @@ impl Bridge {
) -> ProgramResult { ) -> ProgramResult {
info!("wrapped transfer out"); info!("wrapped transfer out");
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
next_account_info(account_info_iter)?; // Bridge program
next_account_info(account_info_iter)?; // System program next_account_info(account_info_iter)?; // System program
next_account_info(account_info_iter)?; // Token program next_account_info(account_info_iter)?; // Token program
let sender_account_info = next_account_info(account_info_iter)?; let sender_account_info = next_account_info(account_info_iter)?;
@ -182,6 +183,7 @@ impl Bridge {
accounts, accounts,
transfer_info.key, transfer_info.key,
payer_info.key, payer_info.key,
program_id,
&transfer_seed, &transfer_seed,
)?; )?;
@ -192,8 +194,10 @@ impl Bridge {
return Err(Error::AlreadyExists.into()); return Err(Error::AlreadyExists.into());
} }
info!("burning");
// Burn tokens // Burn tokens
Bridge::wrapped_burn( Bridge::wrapped_burn(
program_id,
accounts, accounts,
&bridge.config.token_program, &bridge.config.token_program,
authority_info.key, authority_info.key,
@ -221,6 +225,7 @@ impl Bridge {
) -> ProgramResult { ) -> ProgramResult {
info!("create wrapped"); info!("create wrapped");
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
next_account_info(account_info_iter)?; // Bridge program
next_account_info(account_info_iter)?; // System program next_account_info(account_info_iter)?; // System program
next_account_info(account_info_iter)?; // Token program next_account_info(account_info_iter)?; // Token program
let bridge_info = next_account_info(account_info_iter)?; let bridge_info = next_account_info(account_info_iter)?;
@ -230,6 +235,10 @@ impl Bridge {
let bridge = Bridge::bridge_deserialize(bridge_info)?; let bridge = Bridge::bridge_deserialize(bridge_info)?;
if a.chain == CHAIN_ID_SOLANA {
return Err(Error::CannotWrapNative.into());
}
// Create wrapped mint // Create wrapped mint
Self::create_wrapped_mint( Self::create_wrapped_mint(
program_id, program_id,
@ -248,6 +257,7 @@ impl Bridge {
accounts, accounts,
wrapped_meta_info.key, wrapped_meta_info.key,
payer_info.key, payer_info.key,
program_id,
&wrapped_meta_seeds, &wrapped_meta_seeds,
)?; )?;
@ -269,6 +279,7 @@ impl Bridge {
) -> ProgramResult { ) -> ProgramResult {
info!("native transfer out"); info!("native transfer out");
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
next_account_info(account_info_iter)?; // Bridge program
next_account_info(account_info_iter)?; // System program next_account_info(account_info_iter)?; // System program
next_account_info(account_info_iter)?; // Token program next_account_info(account_info_iter)?; // Token program
let sender_account_info = next_account_info(account_info_iter)?; let sender_account_info = next_account_info(account_info_iter)?;
@ -301,6 +312,7 @@ impl Bridge {
accounts, accounts,
transfer_info.key, transfer_info.key,
payer_info.key, payer_info.key,
program_id,
&transfer_seed, &transfer_seed,
)?; )?;
@ -320,6 +332,7 @@ impl Bridge {
// Create the account if it does not exist // Create the account if it does not exist
if custody_info.data_is_empty() { if custody_info.data_is_empty() {
info!("custody acc");
Bridge::create_custody_account( Bridge::create_custody_account(
program_id, program_id,
accounts, accounts,
@ -331,19 +344,23 @@ impl Bridge {
)?; )?;
} }
let bridge_authority = Self::derive_bridge_id(program_id)?;
// Check that the custody token account is owned by the derived key // Check that the custody token account is owned by the derived key
let custody = Self::token_account_deserialize(custody_info)?; let custody = Self::token_account_deserialize(custody_info)?;
if custody.owner != *bridge_info.key { if custody.owner != bridge_authority {
return Err(Error::WrongTokenAccountOwner.into()); return Err(Error::WrongTokenAccountOwner.into());
} }
info!("transferring");
// Transfer tokens to custody - This also checks that custody mint = mint // Transfer tokens to custody - This also checks that custody mint = mint
Bridge::token_transfer_caller( Bridge::token_transfer_caller(
program_id,
accounts, accounts,
&bridge.config.token_program, &bridge.config.token_program,
sender_account_info.key, sender_account_info.key,
custody_info.key, custody_info.key,
bridge_info.key, &bridge_authority,
t.amount, t.amount,
)?; )?;
@ -373,6 +390,7 @@ impl Bridge {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Load VAA processing default accounts // Load VAA processing default accounts
next_account_info(account_info_iter)?; // Bridge program
next_account_info(account_info_iter)?; // System program next_account_info(account_info_iter)?; // System program
let clock_info = next_account_info(account_info_iter)?; let clock_info = next_account_info(account_info_iter)?;
let bridge_info = next_account_info(account_info_iter)?; let bridge_info = next_account_info(account_info_iter)?;
@ -398,6 +416,7 @@ impl Bridge {
accounts, accounts,
claim_info.key, claim_info.key,
payer_info.key, payer_info.key,
program_id,
&claim_seeds, &claim_seeds,
)?; )?;
@ -507,6 +526,7 @@ impl Bridge {
accounts, accounts,
new_guardian_info.key, new_guardian_info.key,
payer_info.key, payer_info.key,
program_id,
&guardian_seed, &guardian_seed,
)?; )?;
@ -562,6 +582,7 @@ impl Bridge {
// Native Solana asset, transfer from custody // Native Solana asset, transfer from custody
Bridge::token_transfer_custody( Bridge::token_transfer_custody(
program_id,
accounts, accounts,
&bridge.config.token_program, &bridge.config.token_program,
bridge_info.key, bridge_info.key,
@ -584,6 +605,7 @@ impl Bridge {
// This automatically asserts that the mint was created by this account by using // This automatically asserts that the mint was created by this account by using
// derivated keys // derivated keys
Bridge::wrapped_mint_to( Bridge::wrapped_mint_to(
program_id,
accounts, accounts,
&bridge.config.token_program, &bridge.config.token_program,
mint_info.key, mint_info.key,
@ -681,6 +703,7 @@ pub fn invoke_signed<'a>(
impl Bridge { impl Bridge {
/// Burn a wrapped asset from account /// Burn a wrapped asset from account
pub fn wrapped_burn( pub fn wrapped_burn(
program_id: &Pubkey,
accounts: &[AccountInfo], accounts: &[AccountInfo],
token_program_id: &Pubkey, token_program_id: &Pubkey,
authority: &Pubkey, authority: &Pubkey,
@ -698,11 +721,12 @@ impl Bridge {
all_signers.as_slice(), all_signers.as_slice(),
amount.as_u64(), amount.as_u64(),
)?; )?;
invoke_signed(&ix, accounts, &[&["bridge".as_bytes()]]) Self::invoke_as_bridge(program_id, &ix, accounts)
} }
/// Mint a wrapped asset to account /// Mint a wrapped asset to account
pub fn wrapped_mint_to( pub fn wrapped_mint_to(
program_id: &Pubkey,
accounts: &[AccountInfo], accounts: &[AccountInfo],
token_program_id: &Pubkey, token_program_id: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
@ -718,11 +742,12 @@ impl Bridge {
&[], &[],
amount.as_u64(), amount.as_u64(),
)?; )?;
invoke_signed(&ix, accounts, &[&["bridge".as_bytes()]]) Self::invoke_as_bridge(program_id, &ix, accounts)
} }
/// Transfer tokens from a caller /// Transfer tokens from a caller
pub fn token_transfer_caller( pub fn token_transfer_caller(
program_id: &Pubkey,
accounts: &[AccountInfo], accounts: &[AccountInfo],
token_program_id: &Pubkey, token_program_id: &Pubkey,
source: &Pubkey, source: &Pubkey,
@ -738,11 +763,12 @@ impl Bridge {
&[], &[],
amount.as_u64(), amount.as_u64(),
)?; )?;
invoke_signed(&ix, accounts, &[&["bridge".as_bytes()]]) Self::invoke_as_bridge(program_id, &ix, accounts)
} }
/// Transfer tokens from a custody account /// Transfer tokens from a custody account
pub fn token_transfer_custody( pub fn token_transfer_custody(
program_id: &Pubkey,
accounts: &[AccountInfo], accounts: &[AccountInfo],
token_program_id: &Pubkey, token_program_id: &Pubkey,
bridge: &Pubkey, bridge: &Pubkey,
@ -758,7 +784,7 @@ impl Bridge {
&[], &[],
amount.as_u64(), amount.as_u64(),
)?; )?;
invoke_signed(&ix, accounts, &[&["bridge".as_bytes()]]) Self::invoke_as_bridge(program_id, &ix, accounts)
} }
/// Create a new account /// Create a new account
@ -771,15 +797,23 @@ impl Bridge {
mint: &Pubkey, mint: &Pubkey,
payer: &Pubkey, payer: &Pubkey,
) -> Result<(), ProgramError> { ) -> Result<(), ProgramError> {
Self::create_account::<Mint>( Self::check_and_create_account::<spl_token::state::Account>(
token_program, program_id,
accounts, accounts,
mint, account,
payer, payer,
token_program,
&Self::derive_custody_seeds(bridge, mint), &Self::derive_custody_seeds(bridge, mint),
)?; )?;
let ix = spl_token::instruction::initialize_account(token_program, account, mint, bridge)?; info!("bababu");
invoke_signed(&ix, accounts, &[&["bridge".as_bytes()]]) info!(token_program.to_string().as_str());
let ix = spl_token::instruction::initialize_account(
token_program,
account,
mint,
&Self::derive_bridge_id(program_id)?,
)?;
invoke_signed(&ix, accounts, &[])
} }
/// Create a mint for a wrapped asset /// Create a mint for a wrapped asset
@ -792,16 +826,43 @@ impl Bridge {
payer: &Pubkey, payer: &Pubkey,
asset: &AssetMeta, asset: &AssetMeta,
) -> Result<(), ProgramError> { ) -> Result<(), ProgramError> {
Self::create_account::<Mint>( Self::check_and_create_account::<Mint>(
token_program, program_id,
accounts, accounts,
mint, mint,
payer, payer,
token_program,
&Self::derive_wrapped_asset_seeds(bridge, asset.chain, asset.address), &Self::derive_wrapped_asset_seeds(bridge, asset.chain, asset.address),
)?; )?;
let ix = let ix = spl_token::instruction::initialize_mint(
spl_token::instruction::initialize_mint(token_program, mint, None, Some(bridge), 0, 8)?; token_program,
invoke_signed(&ix, accounts, &[&["bridge".as_bytes()]]) mint,
None,
Some(&Self::derive_bridge_id(program_id)?),
0,
8,
)?;
invoke_signed(&ix, accounts, &[])
}
pub fn invoke_as_bridge<'a>(
program_id: &Pubkey,
instruction: &Instruction,
account_infos: &[AccountInfo<'a>],
) -> ProgramResult {
let (_, seeds) =
Self::find_program_address(&vec!["bridge".as_bytes().to_vec()], program_id);
Self::invoke_vec_seed(program_id, instruction, account_infos, &seeds)
}
pub fn invoke_vec_seed<'a>(
program_id: &Pubkey,
instruction: &Instruction,
account_infos: &[AccountInfo<'a>],
seeds: &Vec<Vec<u8>>,
) -> ProgramResult {
let s: Vec<_> = seeds.iter().map(|item| item.as_slice()).collect();
invoke_signed(instruction, account_infos, &[s.as_slice()])
} }
/// Check that a key was derived correctly and create account /// Check that a key was derived correctly and create account
@ -810,22 +871,35 @@ impl Bridge {
accounts: &[AccountInfo], accounts: &[AccountInfo],
new_account: &Pubkey, new_account: &Pubkey,
payer: &Pubkey, payer: &Pubkey,
owner: &Pubkey,
seeds: &Vec<Vec<u8>>, seeds: &Vec<Vec<u8>>,
) -> Result<(), ProgramError> { ) -> Result<Vec<Vec<u8>>, ProgramError> {
let expected_key = Bridge::derive_key(program_id, seeds)?; info!("deriving key");
let (expected_key, full_seeds) = Bridge::derive_key(program_id, seeds)?;
if expected_key != *new_account { if expected_key != *new_account {
return Err(Error::InvalidDerivedAccount.into()); return Err(Error::InvalidDerivedAccount.into());
} }
Self::create_account::<T>(program_id, accounts, new_account, payer, seeds) info!("deploying contract");
Self::create_account_raw::<T>(
program_id,
accounts,
new_account,
payer,
owner,
&full_seeds,
)?;
Ok(full_seeds)
} }
/// Create a new account /// Create a new account
pub fn create_account<T: Sized>( fn create_account_raw<T: Sized>(
program_id: &Pubkey, program_id: &Pubkey,
accounts: &[AccountInfo], accounts: &[AccountInfo],
new_account: &Pubkey, new_account: &Pubkey,
payer: &Pubkey, payer: &Pubkey,
owner: &Pubkey,
seeds: &Vec<Vec<u8>>, seeds: &Vec<Vec<u8>>,
) -> Result<(), ProgramError> { ) -> Result<(), ProgramError> {
let size = size_of::<T>(); let size = size_of::<T>();
@ -834,7 +908,7 @@ impl Bridge {
new_account, new_account,
Rent::default().minimum_balance(size as usize), Rent::default().minimum_balance(size as usize),
size as u64, size as u64,
program_id, owner,
); );
let s: Vec<_> = seeds.iter().map(|item| item.as_slice()).collect(); let s: Vec<_> = seeds.iter().map(|item| item.as_slice()).collect();
invoke_signed(&ix, accounts, &[s.as_slice()]) invoke_signed(&ix, accounts, &[s.as_slice()])

View File

@ -3,6 +3,8 @@
use std::mem::size_of; use std::mem::size_of;
use primitive_types::U256; use primitive_types::U256;
use solana_sdk::hash::Hasher;
use solana_sdk::pubkey::{PubkeyError, MAX_SEED_LEN};
use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};
use zerocopy::AsBytes; use zerocopy::AsBytes;
@ -323,7 +325,7 @@ impl Bridge {
/// Calculates a derived address for this program /// Calculates a derived address for this program
pub fn derive_bridge_id(program_id: &Pubkey) -> Result<Pubkey, Error> { pub fn derive_bridge_id(program_id: &Pubkey) -> Result<Pubkey, Error> {
Self::derive_key(program_id, &Self::derive_bridge_seeds()) Ok(Self::derive_key(program_id, &Self::derive_bridge_seeds())?.0)
} }
/// Calculates a derived address for a custody account /// Calculates a derived address for a custody account
@ -332,7 +334,7 @@ impl Bridge {
bridge: &Pubkey, bridge: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Self::derive_key(program_id, &Self::derive_custody_seeds(bridge, mint)) Ok(Self::derive_key(program_id, &Self::derive_custody_seeds(bridge, mint))?.0)
} }
/// Calculates a derived address for a claim account /// Calculates a derived address for a claim account
@ -341,7 +343,7 @@ impl Bridge {
bridge: &Pubkey, bridge: &Pubkey,
hash: &[u8; 32], hash: &[u8; 32],
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Self::derive_key(program_id, &Self::derive_claim_seeds(bridge, hash)) Ok(Self::derive_key(program_id, &Self::derive_claim_seeds(bridge, hash))?.0)
} }
/// Calculates a derived address for a wrapped asset meta entry /// Calculates a derived address for a wrapped asset meta entry
@ -350,7 +352,7 @@ impl Bridge {
bridge: &Pubkey, bridge: &Pubkey,
mint: &Pubkey, mint: &Pubkey,
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Self::derive_key(program_id, &Self::derive_wrapped_meta_seeds(bridge, mint)) Ok(Self::derive_key(program_id, &Self::derive_wrapped_meta_seeds(bridge, mint))?.0)
} }
/// Calculates a derived address for this program /// Calculates a derived address for this program
@ -359,10 +361,11 @@ impl Bridge {
bridge_key: &Pubkey, bridge_key: &Pubkey,
guardian_set_index: u32, guardian_set_index: u32,
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Self::derive_key( Ok(Self::derive_key(
program_id, program_id,
&Self::derive_guardian_set_seeds(bridge_key, guardian_set_index), &Self::derive_guardian_set_seeds(bridge_key, guardian_set_index),
) )?
.0)
} }
/// Calculates a derived seeds for a wrapped asset /// Calculates a derived seeds for a wrapped asset
@ -372,10 +375,11 @@ impl Bridge {
asset_chain: u8, asset_chain: u8,
asset: ForeignAddress, asset: ForeignAddress,
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Self::derive_key( Ok(Self::derive_key(
program_id, program_id,
&Self::derive_wrapped_asset_seeds(bridge_key, asset_chain, asset), &Self::derive_wrapped_asset_seeds(bridge_key, asset_chain, asset),
) )?
.0)
} }
/// Calculates a derived address for a transfer out /// Calculates a derived address for a transfer out
@ -389,7 +393,7 @@ impl Bridge {
user: ForeignAddress, user: ForeignAddress,
slot: u32, slot: u32,
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Self::derive_key( Ok(Self::derive_key(
program_id, program_id,
&Self::derive_transfer_id_seeds( &Self::derive_transfer_id_seeds(
bridge_key, bridge_key,
@ -400,22 +404,32 @@ impl Bridge {
user, user,
slot, slot,
), ),
) )?
.0)
} }
pub fn derive_key(program_id: &Pubkey, seeds: &Vec<Vec<u8>>) -> Result<Pubkey, Error> { pub fn derive_key(
let s: Vec<_> = seeds.iter().map(|item| item.as_slice()).collect(); program_id: &Pubkey,
Ok(Self::find_program_address(s.as_slice(), program_id).0) seeds: &Vec<Vec<u8>>,
) -> Result<(Pubkey, Vec<Vec<u8>>), Error> {
Ok(Self::find_program_address(seeds, program_id))
} }
pub fn find_program_address(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) { pub fn find_program_address(
let mut nonce = [255]; seeds: &Vec<Vec<u8>>,
program_id: &Pubkey,
) -> (Pubkey, Vec<Vec<u8>>) {
let mut nonce = [255u8];
for _ in 0..std::u8::MAX { for _ in 0..std::u8::MAX {
{ {
let mut seeds_with_nonce = seeds.to_vec(); let mut seeds_with_nonce = seeds.to_vec();
seeds_with_nonce.push(&nonce); seeds_with_nonce.push(nonce.to_vec());
if let Ok(address) = Pubkey::create_program_address(&seeds_with_nonce, program_id) { let s: Vec<_> = seeds_with_nonce
return (address, nonce[0]); .iter()
.map(|item| item.as_slice())
.collect();
if let Ok(address) = Pubkey::create_program_address(&s, program_id) {
return (address, seeds_with_nonce);
} }
} }
nonce[0] -= 1; nonce[0] -= 1;

View File

@ -8,12 +8,14 @@ use clap::{
}; };
use hex; use hex;
use primitive_types::U256; use primitive_types::U256;
use solana_account_decoder::{parse_token::TokenAccountType, UiAccountData};
use solana_clap_utils::input_parsers::value_of; use solana_clap_utils::input_parsers::value_of;
use solana_clap_utils::input_validators::is_derivation; use solana_clap_utils::input_validators::is_derivation;
use solana_clap_utils::{ use solana_clap_utils::{
input_parsers::{keypair_of, pubkey_of}, input_parsers::{keypair_of, pubkey_of},
input_validators::{is_amount, is_keypair, is_pubkey_or_keypair, is_url}, input_validators::{is_amount, is_keypair, is_pubkey_or_keypair, is_url},
}; };
use solana_client::client_error::ClientError;
use solana_client::{rpc_client::RpcClient, rpc_request::TokenAccountsFilter}; use solana_client::{rpc_client::RpcClient, rpc_request::TokenAccountsFilter};
use solana_sdk::system_instruction::create_account; use solana_sdk::system_instruction::create_account;
use solana_sdk::{ use solana_sdk::{
@ -31,7 +33,6 @@ use spl_token::{
state::{Account, Mint}, state::{Account, Mint},
}; };
use solana_account_decoder::{parse_token::TokenAccountType, UiAccountData};
use spl_bridge::instruction::*; use spl_bridge::instruction::*;
use spl_bridge::state::*; use spl_bridge::state::*;
@ -94,9 +95,20 @@ fn command_lock_tokens(
// Check whether we can find wrapped asset meta for the given token // Check whether we can find wrapped asset meta for the given token
let wrapped_key = Bridge::derive_wrapped_meta_id(bridge, &bridge_key, &token)?; let wrapped_key = Bridge::derive_wrapped_meta_id(bridge, &bridge_key, &token)?;
let wrapped_info = config.rpc_client.get_account(&wrapped_key).or_else(Err)?; let asset_meta = match config.rpc_client.get_account(&wrapped_key) {
Ok(v) => {
let wrapped_meta: &WrappedAssetMeta = let wrapped_meta: &WrappedAssetMeta =
Bridge::unpack_unchecked_immutable(wrapped_info.data.as_slice())?; Bridge::unpack_unchecked_immutable(v.data.as_slice())?;
AssetMeta {
address: wrapped_meta.address,
chain: wrapped_meta.chain,
}
}
Err(_) => AssetMeta {
address: token.to_bytes(),
chain: CHAIN_ID_SOLANA,
},
};
let ix = transfer_out( let ix = transfer_out(
bridge, bridge,
@ -106,37 +118,30 @@ fn command_lock_tokens(
&TransferOutPayload { &TransferOutPayload {
amount: U256::from(amount), amount: U256::from(amount),
chain_id: to_chain, chain_id: to_chain,
asset: { asset: asset_meta,
if wrapped_meta.is_initialized() {
AssetMeta {
address: wrapped_meta.address,
chain: wrapped_meta.chain,
}
} else {
AssetMeta {
address: token.to_bytes(),
chain: CHAIN_ID_SOLANA,
}
}
},
target, target,
nonce, nonce,
}, },
)?; )?;
println!("custody: {}, ", ix.accounts[7].pubkey.to_string()); println!("custody: {}, ", ix.accounts[7].pubkey.to_string());
let mut instructions = vec![];
// Approve tokens // Approve tokens
if asset_meta.chain == CHAIN_ID_SOLANA {
let ix_a = approve( let ix_a = approve(
&spl_token::id(), &spl_token::id(),
&account, &account,
&ix.accounts[3].pubkey, &ix.accounts[4].pubkey,
&config.owner.pubkey(), &config.owner.pubkey(),
&[], &[],
amount, amount,
)?; )?;
instructions.push(ix_a);
}
instructions.push(ix);
let mut transaction = let mut transaction =
Transaction::new_with_payer(&[ix_a, ix], Some(&config.fee_payer.pubkey())); Transaction::new_with_payer(&instructions.as_slice(), Some(&config.fee_payer.pubkey()));
let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?; let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
check_fee_payer_balance( check_fee_payer_balance(