From 0bfc117a1b5e911592b6824f1d39905ca40f4752 Mon Sep 17 00:00:00 2001 From: ryan Date: Tue, 17 Dec 2024 15:16:13 -0500 Subject: [PATCH] solana: add decimals support, revert commit w/ wrong None/None bindings --- crates/by-chain/icepick-solana/src/lib.rs | 64 +++++++++++++---------- e2e-tests/solana/offline.sh | 5 +- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/crates/by-chain/icepick-solana/src/lib.rs b/crates/by-chain/icepick-solana/src/lib.rs index 5bf70e7..a230cd9 100644 --- a/crates/by-chain/icepick-solana/src/lib.rs +++ b/crates/by-chain/icepick-solana/src/lib.rs @@ -50,8 +50,8 @@ //! //! # On an offline system //! blockhash=$(jq -r .blob sdcard/blockhash.json) -//! token_address=$(icepick sol get-token-address IPDBG) -//! token_address=$(jq -r .blob sdcard/ipdbg.json) +//! icepick sol get-token-info IPDBG > sdcard/ipdbg.json +//! token_address=$(jq -r .blob.token_address sdcard/ipdbg.json) //! icepick sol create-token-account $wallet_address $token_address | icepick sol sign $blockhash > sdcard/create-account.json //! //! # On an online system @@ -123,7 +123,7 @@ pub struct GetWalletAddress {} #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "kebab-case")] -pub struct GetTokenAddress { +pub struct GetTokenInfo { token: String, } @@ -155,6 +155,7 @@ pub struct TransferToken { to_address: String, from_account: Option, from_address: String, + decimals: String, fee: Option, fee_payer: Option, fee_payer_address: Option, @@ -192,7 +193,7 @@ pub enum Operation { GetBlockhash(GetBlockhash), GenerateWallet(GenerateWallet), GetWalletAddress(GetWalletAddress), - GetTokenAddress(GetTokenAddress), + GetTokenInfo(GetTokenInfo), Transfer(Transfer), CreateTokenAccount(CreateTokenAccount), TransferToken(TransferToken), @@ -276,7 +277,7 @@ impl Module for Solana { arguments: vec![], }, icepick_module::help::Operation { - name: "get-token-address".to_string(), + name: "get-token-info".to_string(), description: "Get the address for a given token.".to_string(), arguments: vec![Argument { name: "token".to_string(), @@ -370,6 +371,11 @@ impl Module for Solana { description: "The address to send the tokens from; will be used to verify the derivation account.".to_string(), r#type: ArgumentType::Required, }, + Argument { + name: "decimals".to_string(), + description: "The decimals of the token.".to_string(), + r#type: ArgumentType::Required, + }, fee.clone(), fee_payer.clone(), fee_payer_address.clone(), @@ -419,19 +425,26 @@ impl Module for Solana { "blob": pubkey.to_string(), })) } - Operation::GetTokenAddress(GetTokenAddress { token }) => { - let addr = match token.as_str() { + Operation::GetTokenInfo(GetTokenInfo { token }) => { + let values = match token.as_str() { // Only exists on devnet - "IPDBG" => Some("3V6hm5ifSLSWLZ86NpTxo5iVguGq9qCUtry6bn5PtT23"), + "IPDBG" => Some(("3V6hm5ifSLSWLZ86NpTxo5iVguGq9qCUtry6bn5PtT23", 9u8)), // Only exists on mainnet - "PYTH" => Some("HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3"), + "PYTH" => Some(("HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3", 6u8)), _ => None, }; - addr.map(|v| serde_json::Value::String(v.to_string())) - .unwrap_or(serde_json::Value::Null); - Ok(serde_json::json!({ - "blob": addr, - })) + + Ok(match values { + Some((address, decimals)) => serde_json::json!({ + "blob": { + "token_address": address, + "token_decimals": decimals, + } + }), + None => serde_json::json!({ + "blob": null, + }), + }) } Operation::Transfer(Transfer { amount, @@ -462,7 +475,7 @@ impl Module for Solana { Pubkey::from_str(address).unwrap(), )) } - (&None, &None) => { + (None, None) => { // Use the transaction account None } @@ -510,10 +523,8 @@ impl Module for Solana { &token_pubkey, &TOKEN_ID, ); - let message = solana_sdk::message::Message::new( - &[instruction], - Some(&funder_pubkey), - ); + let message = + solana_sdk::message::Message::new(&[instruction], Some(&funder_pubkey)); let transaction = solana_sdk::transaction::Transaction::new_unsigned(message); #[allow(clippy::identity_op)] Ok(serde_json::json!({ @@ -527,15 +538,16 @@ impl Module for Solana { to_address, from_account, from_address, + decimals, fee, fee_payer, fee_payer_address, }) => { // TODO: deduplicate code used in Transfer - // no transfer between types of currency, the only amount is the amount - // of the lowest denomination. no floats, like with SOL / lamports. - let amount = u64::from_str(&amount).expect("integer amount"); + let amount = f64::from_str(&amount).expect("float amount"); + let decimals = u8::from_str(&decimals).expect("decimals"); + let amount: u64 = (amount * 10u64.pow(decimals as u32) as f64) as u64; use solana_sdk::pubkey::Pubkey; use spl_associated_token_account::get_associated_token_address; @@ -568,7 +580,6 @@ impl Module for Solana { let from_token_address = get_associated_token_address(&from_pk, &token_pk); let to_token_address = get_associated_token_address(&to_pk, &token_pk); - let decimals = 9u8; let mut instruction = spl_token_2022::instruction::transfer_checked( &token_program_id, // token program id &from_token_address, // source, as token address @@ -577,10 +588,9 @@ impl Module for Solana { &from_pk, // authority, as source sol address // TODO: signers should be [] when not using multisig // but should contain all signers when multisig - &[], // signers - // TODO: make amount floatable - amount * 10u64.pow(decimals as u32), // amount - decimals, // decimals + &[], // signers + amount, // amount + decimals, // decimals ) .unwrap(); // TODO: check if this works with payer diff --git a/e2e-tests/solana/offline.sh b/e2e-tests/solana/offline.sh index a35eca7..e484c8c 100644 --- a/e2e-tests/solana/offline.sh +++ b/e2e-tests/solana/offline.sh @@ -14,7 +14,8 @@ to_address="$(jq -r .to_address /data/input.json)" token_name="$(jq -r .token_name /data/input.json)" token_amount="$(jq -r .token_amount /data/input.json)" blockhash="$(jq -r .blockhash /data/input.json)" -token_address="$(icepick sol get-token-address "$token_name" | jq -r .blob)" +token_address="$(icepick sol get-token-address "$token_name" | jq -r .blob.token_address)" +token_decimals="$(icepick sol get-token-address "$token_name" | jq -r .blob.token_decimals)" jq . /data/input.json echo "Do these values look correct? If not, press ctrl-c. Otherwise, press Enter." @@ -22,5 +23,5 @@ read _ echo "Creating and signing transaction" -icepick sol transfer-token "$token_amount" "$token_address" "$to_address" "$from_address" | icepick sol sign "$blockhash" > /data/output.json.tmp +icepick sol transfer-token "$token_amount" "$token_address" "$to_address" "$from_address" "$token_decimals" | icepick sol sign "$blockhash" > /data/output.json.tmp mv /data/output.json.tmp /data/output.json