use core::panic; use near_sdk::{env, near, Gas, NearToken, Promise, PromiseResult}; use crate::{ helpers::chainsig::{ self, derived_public_key_with_address, evm::Evm, get_mpc_contract_by_network, near::Near, svm::Svm, ChainEnvironment, ChainSig, ChainSigResponse, ChainSigSignRequest, Domain, NearNetwork, }, *, }; #[near(serializers=[json, borsh])] pub struct PublicKeyAddress { pub public_key: String, pub address: String, } pub fn chain_to_domain(chain: &ChainEnvironment) -> Domain { match chain { ChainEnvironment::SVM => Domain::ED25519, ChainEnvironment::EVM => Domain::SEC1, ChainEnvironment::NearWasm => Domain::ED25519, } } pub fn get_network_by_account_id(account_id: &AccountId) -> NearNetwork { if account_id.as_str().ends_with(".testnet") { return NearNetwork::Testnet; } NearNetwork::Mainnet } pub fn domain_to_domain_id(domain: &Domain) -> u8 { match domain { Domain::ED25519 => 1, Domain::SEC1 => 0, } } pub fn chain_to_domain_id(chain: &ChainEnvironment) -> u8 { let domain = chain_to_domain(chain); domain_to_domain_id(&domain) } #[near(serializers = [json, borsh])] impl Contract { #[private] pub fn after_sign(&self) -> Vec { let mut all_responses: Vec = vec![]; for i in 0..env::promise_results_count() { match env::promise_result(i) { PromiseResult::Failed => { panic!("Fail to collect all signature"); } PromiseResult::Successful(value) => { all_responses.push( serde_json::from_slice::(&value) .expect("Failed to deserialize result from sign"), ); } }; } all_responses } #[private] pub fn sign_near_nep413_message( &mut self, path: String, near_network: &NearNetwork, message: String, recipient: String, nonce: [u8; 32], callback_url: Option, ) -> Promise { let hashes = Near::prepare_nep413_message_for_signing(&message, &recipient, &nonce, &callback_url); let mut promises: Vec = vec![]; hashes.iter().for_each(|hash| { let mpc_contract = get_mpc_contract_by_network(near_network); promises.push( mpc_contract .with_attached_deposit(NearToken::from_yoctonear(1)) .with_static_gas(Gas::from_tgas(10)) .sign(ChainSigSignRequest { path: path.clone(), domain_id: 1, payload_v2: chainsig::ChainSigPayloadV2::Eddsa(hash.to_string()), }), ) }); return promises .into_iter() .reduce(|prev, cur| prev.and(cur)) .unwrap() .then(Self::ext(env::current_account_id()).after_sign()); } #[private] pub fn sign_transaction( &mut self, encoded_tx: String, chain: ChainEnvironment, near_network: &NearNetwork, path: String, ) -> Promise { let domain_id = chain_to_domain_id(&chain); let hashes = match chain { ChainEnvironment::SVM => Svm::prepare_transaction_for_signing(encoded_tx), ChainEnvironment::EVM => Evm::prepare_transaction_for_signing(encoded_tx), ChainEnvironment::NearWasm => Near::prepare_transaction_for_signing(encoded_tx), }; let mut promises: Vec = vec![]; hashes.iter().for_each(|hash| { let mpc_contract = get_mpc_contract_by_network(near_network); promises.push( mpc_contract .with_attached_deposit(NearToken::from_yoctonear(1)) .with_static_gas(Gas::from_tgas(10)) .sign(ChainSigSignRequest { path: path.clone(), domain_id, payload_v2: match chain { ChainEnvironment::EVM => { chainsig::ChainSigPayloadV2::Ecdsa(hash.to_string()) } ChainEnvironment::SVM | ChainEnvironment::NearWasm => { chainsig::ChainSigPayloadV2::Eddsa(hash.to_string()) } }, }), ) }); return promises .into_iter() .reduce(|prev, cur| prev.and(cur)) .unwrap() .then(Self::ext(env::current_account_id()).after_sign()); } pub fn derive_address_and_public_key( &self, path: &String, chain: &ChainEnvironment, near_network: &NearNetwork, ) -> PublicKeyAddress { derived_public_key_with_address(path, chain, near_network, &env::current_account_id()) } }