service/sol: Working SPL token deposits.

This commit is contained in:
parazyd
2021-09-29 15:01:51 +02:00
parent a45f9d3144
commit e3dffd044f
3 changed files with 42 additions and 69 deletions

1
Cargo.lock generated
View File

@@ -1225,6 +1225,7 @@ dependencies = [
"smol",
"solana-client",
"solana-sdk",
"spl-associated-token-account",
"spl-token",
"toml",
"tungstenite 0.15.0",

View File

@@ -65,6 +65,7 @@ rocksdb = {version = "0.16.0", default-features = false, features = ["lz4"]}
spl-token = {version = "3.2.0", optional = true}
solana-sdk = {version = "1.7.11", optional = true}
solana-client = {version = "1.7.11", optional = true}
spl-associated-token-account = {version = "1.0.3", optional = true}
## Cashier Bitcoin Dependencies
bitcoin = {version = "0.27.0", optional = true }
@@ -82,4 +83,4 @@ features = ["async-std-runtime", "all-transport"]
[features]
btc = ["bitcoin", "secp256k1", "electrum-client"]
sol = ["solana-sdk", "solana-client", "spl-token"]
sol = ["solana-sdk", "solana-client", "spl-token", "spl-associated-token-account"]

View File

@@ -11,7 +11,6 @@ use serde::Serialize;
use serde_json::{json, Value};
use solana_client::{blockhash_query::BlockhashQuery, rpc_client::RpcClient};
use solana_sdk::{
instruction::Instruction,
native_token::lamports_to_sol,
program_pack::Pack,
pubkey::Pubkey,
@@ -20,6 +19,7 @@ use solana_sdk::{
system_instruction,
transaction::Transaction,
};
use spl_associated_token_account::{create_associated_token_account, get_associated_token_address};
use tungstenite::Message;
use crate::rpc::{jsonrpc, jsonrpc::JsonResult, websockets};
@@ -51,6 +51,8 @@ impl SolClient {
let keypair: Keypair = deserialize(&keypair)?;
let notify_channel = async_channel::unbounded();
debug!("Main SOL wallet pubkey: {:?}", &keypair.pubkey());
let (rpc_server, wss_server) = match network {
"mainnet" => (
"https://api.mainnet-beta.solana.com",
@@ -89,7 +91,7 @@ impl SolClient {
// Derive token pubkey if mint was provided.
let pubkey = if mint.is_some() {
get_associated_token_account(&keypair.pubkey(), &mint.unwrap()).0
get_associated_token_address(&keypair.pubkey(), &mint.unwrap())
} else {
keypair.pubkey()
};
@@ -163,9 +165,10 @@ impl SolClient {
let params = n.params["result"]["value"].clone();
if mint.is_some() {
cur_balance = params["data"]["info"]["tokenAmount"]["amount"]
.as_u64()
.unwrap();
cur_balance = params["data"]["parsed"]["info"]["tokenAmount"]["amount"]
.as_str()
.unwrap()
.parse()?;
} else {
cur_balance = params["lamports"].as_u64().unwrap();
}
@@ -200,7 +203,7 @@ impl SolClient {
if mint.is_some() {
let amnt = cur_balance - prev_balance;
let ui_amnt = amnt * decimals;
let ui_amnt = amnt / u64::pow(10, decimals as u32);
debug!(target: "SOL BRIDGE", "Received {} {:?} tokens", ui_amnt, mint.unwrap());
let _ = self.send_tok_to_main_wallet(&rpc, &mint.unwrap(), amnt, decimals, &keypair)?;
} else {
@@ -221,81 +224,63 @@ impl SolClient {
decimals: u64,
keypair: &Keypair,
) -> Result<Signature> {
debug!(target: "SOL BRIDGE", "Sending {} {:?} tokens to main wallet", amount * decimals, mint);
debug!(target: "SOL BRIDGE", "Sending {} {:?} tokens to main wallet",
amount / u64::pow(10, decimals as u32), mint);
if !account_is_initialized_mint(rpc, mint) {
return Err(Error::ServicesError("Given mint is not valid"));
}
// The token account from our main wallet
let (main_tok_pk, _) = get_associated_token_account(&self.keypair.pubkey(), mint);
let main_tok_pk = get_associated_token_address(&self.keypair.pubkey(), mint);
// The token account from the deposit wallet
let (temp_tok_pk, _) = get_associated_token_account(&keypair.pubkey(), mint);
let temp_tok_pk = get_associated_token_address(&keypair.pubkey(), mint);
// Account initialize instruction
let init_ix: Option<Instruction>;
let mut instructions = vec![];
match rpc.get_account_data(&main_tok_pk) {
Ok(v) => {
match spl_token::state::Account::unpack_from_slice(&v) {
// It's valid token data, and we consider account initialized.
Ok(_) => init_ix = None,
Ok(_) => {}
// Some other unexpected data.
Err(_) => return Err(Error::ServicesError("Invalid data on derived account")),
}
}
Err(_) => {
// Create an initialize instruction.
init_ix = Some(
spl_token::instruction::initialize_account(
&spl_token::id(),
&main_tok_pk,
mint,
&self.keypair.pubkey(),
)
.unwrap(),
// Unitinialized, so we add a creation instruction
debug!("Main wallet token account is uninitialized. Adding init instruction.");
let init_ix = create_associated_token_account(
&self.keypair.pubkey(), // fee payer
&self.keypair.pubkey(), // wallet
mint,
);
instructions.push(init_ix);
}
}
// Transfer tokens from the deposit wallet to the main wallet
let tok_transfer_ix = spl_token::instruction::transfer(
let transfer_ix = spl_token::instruction::transfer_checked(
&spl_token::id(),
&temp_tok_pk,
mint,
&main_tok_pk,
&keypair.pubkey(),
&[&keypair.pubkey(), &self.keypair.pubkey()],
&[],
amount,
decimals as u8,
)
.unwrap();
// Transfer the remanining balance from the deposit account, resulting
// in account close.
/*
let rent_balance = rpc
.get_balance(&keypair.pubkey())
.map_err(|err| SolFailed::from(err))?;
instructions.push(transfer_ix);
let lmp_transfer_ix = solana_sdk::system_instruction::transfer(
&keypair.pubkey(),
&self.keypair.pubkey(),
rent_balance,
);
*/
let tx = if init_ix.is_some() {
Transaction::new_with_payer(
&[init_ix.unwrap(), tok_transfer_ix],
Some(&self.keypair.pubkey()),
)
} else {
Transaction::new_with_payer(&[tok_transfer_ix], Some(&self.keypair.pubkey()))
};
let signature = sign_and_send_transaction(&rpc, tx, vec![keypair, &self.keypair])?;
let tx = Transaction::new_with_payer(&instructions, Some(&self.keypair.pubkey()));
let signature = sign_and_send_transaction(&rpc, tx, vec![&self.keypair, keypair])?;
debug!(target: "SOL BRIDGE", "Sent tokens to main wallet: {}", signature);
Ok(signature)
// TODO: Close deposit account?
}
fn send_sol_to_main_wallet(
@@ -308,7 +293,7 @@ impl SolClient {
let ix = system_instruction::transfer(&keypair.pubkey(), &self.keypair.pubkey(), amount);
let tx = Transaction::new_with_payer(&[ix], Some(&self.keypair.pubkey()));
let signature = sign_and_send_transaction(&rpc, tx, vec![keypair, &self.keypair])?;
let signature = sign_and_send_transaction(&rpc, tx, vec![&self.keypair, keypair])?;
debug!(target: "SOL BRIDGE", "Sent SOL to main wallet: {}", signature);
Ok(signature)
@@ -325,7 +310,9 @@ impl NetworkClient for SolClient {
let self2 = self.clone();
// TODO: Option<Pubkey> for 2nd arg representing Token Mint account
smol::spawn(self2.handle_subscribe_request(keypair, None)).detach();
let mint = Pubkey::from_str("F4wkXLN5n1ckejfnJoahGpgW3ffRsrvS9GGVME6ckxS9").unwrap();
smol::spawn(self2.handle_subscribe_request(keypair, Some(mint))).detach();
//smol::spawn(self2.handle_subscribe_request(keypair, None)).detach();
Ok(TokenSubscribtion {
secret_key,
@@ -345,7 +332,9 @@ impl NetworkClient for SolClient {
let self2 = self.clone();
// TODO: Option<Pubkey> for 2nd arg representing Token Mint account
smol::spawn(self2.handle_subscribe_request(keypair, None)).detach();
let mint = Pubkey::from_str("F4wkXLN5n1ckejfnJoahGpgW3ffRsrvS9GGVME6ckxS9").unwrap();
smol::spawn(self2.handle_subscribe_request(keypair, Some(mint))).detach();
//smol::spawn(self2.handle_subscribe_request(keypair, None)).detach();
Ok(public_key)
}
@@ -374,21 +363,6 @@ impl NetworkClient for SolClient {
}
}
/// Derive an associated token address from given owner and mint
pub fn get_associated_token_account(owner: &Pubkey, mint: &Pubkey) -> (Pubkey, u8) {
let associated_token =
Pubkey::from_str("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").unwrap();
Pubkey::find_program_address(
&[
&owner.to_bytes(),
&spl_token::id().to_bytes(),
&mint.to_bytes(),
],
&associated_token,
)
}
/// Gets account token balance for given mint.
/// Returns: (amount, decimals)
pub fn get_account_token_balance(
@@ -406,10 +380,7 @@ pub fn get_account_token_balance(
/// Check if given account is a valid token mint
pub fn account_is_initialized_mint(rpc: &RpcClient, mint: &Pubkey) -> bool {
match rpc.get_token_supply(mint) {
Ok(_) => true,
Err(_) => false,
}
rpc.get_token_supply(mint).is_ok()
}
pub fn sign_and_send_transaction(