diff --git a/crates/gem_wallet_connect/src/actions.rs b/crates/gem_wallet_connect/src/actions.rs index ad1027ecf2..a803efd38a 100644 --- a/crates/gem_wallet_connect/src/actions.rs +++ b/crates/gem_wallet_connect/src/actions.rs @@ -13,6 +13,11 @@ pub enum WalletConnectAction { transaction_type: WalletConnectTransactionType, data: String, }, + SignAllTransactions { + chain: Chain, + transaction_type: WalletConnectTransactionType, + transactions: Vec, + }, SendTransaction { chain: Chain, transaction_type: WalletConnectTransactionType, diff --git a/crates/gem_wallet_connect/src/request_handler/mod.rs b/crates/gem_wallet_connect/src/request_handler/mod.rs index 9cd60267a7..377ad0ac9b 100644 --- a/crates/gem_wallet_connect/src/request_handler/mod.rs +++ b/crates/gem_wallet_connect/src/request_handler/mod.rs @@ -135,6 +135,7 @@ mod tests { use super::*; use crate::sign_type::SignDigestType; use gem_evm::testkit::eip712_mock::mock_eip712_json; + use primitives::TransferDataOutputType; #[test] fn test_unsupported_method() { @@ -217,6 +218,28 @@ mod tests { assert!(WalletConnectRequestHandler::parse_request(request).is_ok()); } + #[test] + fn test_solana_sign_all_transactions_roundtrip() { + let params = include_str!("../../testdata/solana_sign_all_transactions.json"); + let request = WalletConnectRequest::mock("solana_signAllTransactions", params, Some("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")); + let action = WalletConnectRequestHandler::parse_request(request).unwrap(); + match &action { + WalletConnectAction::SignAllTransactions { chain, transaction_type, transactions } => { + assert_eq!(*chain, Chain::Solana); + assert_eq!(transactions.len(), 1); + let decoded = WalletConnectRequestHandler::decode_send_transaction(transaction_type.clone(), transactions[0].clone()).unwrap(); + match decoded { + WalletConnectTransaction::Solana { data, output_type } => { + assert!(data.transaction.starts_with("AQAAAAAAAAA")); + assert_eq!(output_type, TransferDataOutputType::EncodedTransaction); + } + _ => panic!("Expected Solana transaction"), + } + } + _ => panic!("Expected SignAllTransactions action"), + } + } + #[test] fn test_parse_request_eth_sign_typed_data_v3_chain_mismatch() { let eip712_json = mock_eip712_json(56); diff --git a/crates/gem_wallet_connect/src/request_handler/solana.rs b/crates/gem_wallet_connect/src/request_handler/solana.rs index 3cd2eeeafc..8253aeca4a 100644 --- a/crates/gem_wallet_connect/src/request_handler/solana.rs +++ b/crates/gem_wallet_connect/src/request_handler/solana.rs @@ -41,14 +41,25 @@ impl SolanaRequestHandler { } pub fn parse_sign_all_transactions(params: Value) -> Result { - let transaction = params.get_value("transactions")?.at(0)?.string()?.to_string(); + let array = params.get_value("transactions")?.as_array().ok_or("Expected transactions array")?; + let transactions: Vec = array + .iter() + .map(|v| { + let transaction = v.string()?.to_string(); + Ok(serde_json::json!({"transaction": transaction}).to_string()) + }) + .collect::, String>>()?; - Ok(WalletConnectAction::SignTransaction { + if transactions.is_empty() { + return Err("Empty transactions array".to_string()); + } + + Ok(WalletConnectAction::SignAllTransactions { chain: Chain::Solana, transaction_type: WalletConnectTransactionType::Solana { output_type: TransferDataOutputType::EncodedTransaction, }, - data: transaction, + transactions, }) } } diff --git a/crates/gem_wallet_connect/src/response_handler.rs b/crates/gem_wallet_connect/src/response_handler.rs index 8985cf06f5..8a8d23bbaa 100644 --- a/crates/gem_wallet_connect/src/response_handler.rs +++ b/crates/gem_wallet_connect/src/response_handler.rs @@ -44,6 +44,12 @@ impl WalletConnectResponseHandler { } } + pub fn encode_sign_all_transactions(signed_transactions: Vec) -> WalletConnectResponseType { + WalletConnectResponseType::Object { + json: serde_json::json!({ "transactions": signed_transactions }).to_string(), + } + } + pub fn encode_send_transaction(chain_type: ChainType, transaction_id: String) -> WalletConnectResponseType { match chain_type { ChainType::Sui => WalletConnectResponseType::Object { @@ -113,4 +119,12 @@ mod tests { object(r#"{"result":true,"txid":"txid123"}"#) ); } + + #[test] + fn test_encode_sign_all_transactions() { + assert_eq!( + WalletConnectResponseHandler::encode_sign_all_transactions(vec!["signed_tx_1".to_string(), "signed_tx_2".to_string()]), + object(r#"{"transactions":["signed_tx_1","signed_tx_2"]}"#) + ); + } } diff --git a/crates/gem_wallet_connect/testdata/solana_sign_all_transactions.json b/crates/gem_wallet_connect/testdata/solana_sign_all_transactions.json new file mode 100644 index 0000000000..763c9185ba --- /dev/null +++ b/crates/gem_wallet_connect/testdata/solana_sign_all_transactions.json @@ -0,0 +1,5 @@ +{ + "transactions": [ + "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAEB4X7qT7inGBPqFijUWiMASkIQer7GcY6cKR108e8O++ff+KvGFsTU/tNNyl/GWd04onEeG60T3KS3sy+XeFY0Ki7nDUGiTeDXiXs77SALJIRnd7ysD54hjxwwqZWL45jVwMGRm/lIRcy/+ytunLDm+e8jOW7xfcSayxDmzpAAAAABSGfiZqB1P+E+1k9Lt+KkKwbOrNCWPffIz6lAwKxvS6uRHvTnhwX5MLyqWayYc3wikPwVLiIIofgiijQL5XRhtsX1PCpIazGy+0gPpCTePUXc/WDVmb3Qe5s/iGDPXfbOVNr91a1Z/vs5sRxA8hmPTdja26wmVOCqpF9Xf15KSAEAwAFAsPxAAADAAkDUMMAAAAAAAAEBgAHAQgJChHyI8aJUuHytv4gXacDAAAAAAQLAAcFBgEICQIICwomuBfuYWfF0z0gXacDAAAAAAEAAAAAAAAACKHsaQAAAAAAAAAAAAABe27qMoJyLSDj0LDOHu9s9YiqUZyCEDCEJV/DPetHbXIABQoLCQAB" + ] +} diff --git a/gemstone/src/wallet_connect/mod.rs b/gemstone/src/wallet_connect/mod.rs index e7dcb55124..4a31267317 100644 --- a/gemstone/src/wallet_connect/mod.rs +++ b/gemstone/src/wallet_connect/mod.rs @@ -67,6 +67,11 @@ pub enum WalletConnectAction { transaction_type: WalletConnectTransactionType, data: String, }, + SignAllTransactions { + chain: Chain, + transaction_type: WalletConnectTransactionType, + transactions: Vec, + }, SendTransaction { chain: Chain, transaction_type: WalletConnectTransactionType, @@ -232,6 +237,11 @@ impl From for WalletConnectAction { transaction_type: transaction_type.into(), data, }, + WcWalletConnectAction::SignAllTransactions { chain, transaction_type, transactions } => Self::SignAllTransactions { + chain, + transaction_type: transaction_type.into(), + transactions, + }, WcWalletConnectAction::SendTransaction { chain, transaction_type, data } => Self::SendTransaction { chain, transaction_type: transaction_type.into(), @@ -348,6 +358,10 @@ impl WalletConnect { WalletConnectResponseHandler::encode_sign_transaction(chain.chain_type(), transaction_id).into() } + pub fn encode_sign_all_transactions(&self, signed_transactions: Vec) -> WalletConnectResponseType { + WalletConnectResponseHandler::encode_sign_all_transactions(signed_transactions).into() + } + pub fn encode_send_transaction(&self, chain: Chain, transaction_id: String) -> WalletConnectResponseType { WalletConnectResponseHandler::encode_send_transaction(chain.chain_type(), transaction_id).into() }