From ec8eb7816b80eb05b39642d3582c65c1ddba043b Mon Sep 17 00:00:00 2001 From: Satoshi Otomakan Date: Wed, 15 Nov 2023 12:54:02 +0100 Subject: [PATCH] [Cosmos]: Migrate Thorchain to Rust * TODO: move Thorchain specific implementation to Rust * TODO: Add Signing, Compiling tests --- registry.json | 1 + rust/Cargo.lock | 12 +++ rust/Cargo.toml | 1 + rust/chains/tw_thorchain/Cargo.toml | 14 +++ rust/chains/tw_thorchain/src/entry.rs | 94 +++++++++++++++++++ rust/chains/tw_thorchain/src/lib.rs | 7 ++ .../tests/tw_any_address_ffi_tests.rs | 35 ++++--- rust/tw_coin_registry/Cargo.toml | 1 + rust/tw_coin_registry/src/blockchain_type.rs | 4 +- rust/tw_coin_registry/src/dispatcher.rs | 4 + .../Cosmos/TransactionCompilerTests.cpp | 2 +- 11 files changed, 162 insertions(+), 13 deletions(-) create mode 100644 rust/chains/tw_thorchain/Cargo.toml create mode 100644 rust/chains/tw_thorchain/src/entry.rs create mode 100644 rust/chains/tw_thorchain/src/lib.rs diff --git a/registry.json b/registry.json index 0ef3117d215..65e637c59b4 100644 --- a/registry.json +++ b/registry.json @@ -3177,6 +3177,7 @@ "curve": "secp256k1", "publicKeyType": "secp256k1", "hrp": "thor", + "addressHasher": "sha256ripemd", "chainId": "thorchain-mainnet-v1", "explorer": { "url": "https://viewblock.io/thorchain", diff --git a/rust/Cargo.lock b/rust/Cargo.lock index d4bc750c6d2..68f040ad9a3 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1521,6 +1521,7 @@ dependencies = [ "tw_native_evmos", "tw_native_injective", "tw_ronin", + "tw_thorchain", ] [[package]] @@ -1745,6 +1746,17 @@ dependencies = [ "tw_proto", ] +[[package]] +name = "tw_thorchain" +version = "0.1.0" +dependencies = [ + "tw_coin_entry", + "tw_cosmos_sdk", + "tw_keypair", + "tw_memory", + "tw_proto", +] + [[package]] name = "tw_utxo" version = "0.1.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 9a6c299e1d6..0fd9852a899 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -3,6 +3,7 @@ members = [ "chains/tw_cosmos", "chains/tw_native_evmos", "chains/tw_native_injective", + "chains/tw_thorchain", "tw_any_coin", "tw_bech32_address", "tw_bitcoin", diff --git a/rust/chains/tw_thorchain/Cargo.toml b/rust/chains/tw_thorchain/Cargo.toml new file mode 100644 index 00000000000..a39bc4d7c80 --- /dev/null +++ b/rust/chains/tw_thorchain/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "tw_thorchain" +version = "0.1.0" +edition = "2021" + +[dependencies] +tw_coin_entry = { path = "../../tw_coin_entry" } +tw_cosmos_sdk = { path = "../../tw_cosmos_sdk" } +tw_keypair = { path = "../../tw_keypair" } +tw_memory = { path = "../../tw_memory" } +tw_proto = { path = "../../tw_proto" } + +[dev-dependencies] +tw_cosmos_sdk = { path = "../../tw_cosmos_sdk", features = ["test-utils"] } diff --git a/rust/chains/tw_thorchain/src/entry.rs b/rust/chains/tw_thorchain/src/entry.rs new file mode 100644 index 00000000000..b283fe8a237 --- /dev/null +++ b/rust/chains/tw_thorchain/src/entry.rs @@ -0,0 +1,94 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +use std::str::FromStr; +use tw_coin_entry::coin_context::CoinContext; +use tw_coin_entry::coin_entry::{CoinEntry, PublicKeyBytes, SignatureBytes}; +use tw_coin_entry::derivation::Derivation; +use tw_coin_entry::error::AddressResult; +use tw_coin_entry::modules::json_signer::NoJsonSigner; +use tw_coin_entry::modules::message_signer::NoMessageSigner; +use tw_coin_entry::modules::plan_builder::NoPlanBuilder; +use tw_cosmos_sdk::address::{Address, Bech32Prefix, CosmosAddress}; +use tw_cosmos_sdk::context::StandardCosmosContext; +use tw_cosmos_sdk::modules::compiler::tw_compiler::TWTransactionCompiler; +use tw_cosmos_sdk::modules::signer::tw_signer::TWSigner; +use tw_keypair::tw; +use tw_proto::Cosmos::Proto; +use tw_proto::TxCompiler::Proto as CompilerProto; + +pub struct ThorchainEntry; + +impl CoinEntry for ThorchainEntry { + type AddressPrefix = Bech32Prefix; + type Address = Address; + type SigningInput<'a> = Proto::SigningInput<'a>; + type SigningOutput = Proto::SigningOutput<'static>; + type PreSigningOutput = CompilerProto::PreSigningOutput<'static>; + type JsonSigner = NoJsonSigner; + type PlanBuilder = NoPlanBuilder; + type MessageSigner = NoMessageSigner; + + #[inline] + fn parse_address( + &self, + coin: &dyn CoinContext, + address: &str, + _prefix: Option, + ) -> AddressResult { + Address::from_str_with_coin(coin, address) + } + + #[inline] + fn parse_address_unchecked( + &self, + _coin: &dyn CoinContext, + address: &str, + ) -> AddressResult { + Address::from_str(address) + } + + #[inline] + fn derive_address( + &self, + coin: &dyn CoinContext, + public_key: tw::PublicKey, + _derivation: Derivation, + prefix: Option, + ) -> AddressResult { + Address::with_public_key_coin_context(coin, &public_key, prefix) + } + + #[inline] + fn sign(&self, coin: &dyn CoinContext, input: Self::SigningInput<'_>) -> Self::SigningOutput { + TWSigner::::sign(coin, input) + } + + #[inline] + fn preimage_hashes( + &self, + coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + ) -> Self::PreSigningOutput { + TWTransactionCompiler::::preimage_hashes(coin, input) + } + + #[inline] + fn compile( + &self, + coin: &dyn CoinContext, + input: Self::SigningInput<'_>, + signatures: Vec, + public_keys: Vec, + ) -> Self::SigningOutput { + TWTransactionCompiler::::compile( + coin, + input, + signatures, + public_keys, + ) + } +} diff --git a/rust/chains/tw_thorchain/src/lib.rs b/rust/chains/tw_thorchain/src/lib.rs new file mode 100644 index 00000000000..1afc00798db --- /dev/null +++ b/rust/chains/tw_thorchain/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright © 2017-2023 Trust Wallet. +// +// This file is part of Trust. The full Trust copyright notice, including +// terms governing use, modification, and redistribution, is contained in the +// file LICENSE at the root of the source code distribution tree. + +pub mod entry; diff --git a/rust/tw_any_coin/tests/tw_any_address_ffi_tests.rs b/rust/tw_any_coin/tests/tw_any_address_ffi_tests.rs index d6f5de08d72..4a16abc4101 100644 --- a/rust/tw_any_coin/tests/tw_any_address_ffi_tests.rs +++ b/rust/tw_any_coin/tests/tw_any_address_ffi_tests.rs @@ -46,12 +46,13 @@ fn test_any_address_derive() { // TODO fix this when `CoinType` is generated by a codegen tool. BlockchainType::Cosmos => continue, BlockchainType::Ethereum => "0xAc1ec44E4f0ca7D172B7803f6836De87Fb72b309", - BlockchainType::NativeEvmos => "evmos14s0vgnj0pjnazu4hsqlksdk7slah9vcfvt8ssm", - BlockchainType::NativeInjective => "inj14s0vgnj0pjnazu4hsqlksdk7slah9vcfyrp6ct", - BlockchainType::Ronin => "ronin:Ac1ec44E4f0ca7D172B7803f6836De87Fb72b309", BlockchainType::InternetComputer => { "290cc7c359f44c8516fc169c5ed4f0f3ae2e24bf5de0d4c51f5e7545b5474faa" }, + BlockchainType::NativeEvmos => "evmos14s0vgnj0pjnazu4hsqlksdk7slah9vcfvt8ssm", + BlockchainType::NativeInjective => "inj14s0vgnj0pjnazu4hsqlksdk7slah9vcfyrp6ct", + BlockchainType::Ronin => "ronin:Ac1ec44E4f0ca7D172B7803f6836De87Fb72b309", + BlockchainType::Thorchain => "thor1ten42eesehw0ktddcp0fws7d3ycsqez3er2y4e", BlockchainType::Unsupported => unreachable!(), }; @@ -88,6 +89,10 @@ fn test_any_address_normalize_eth() { "0xb16db98b365b1f89191996942612b14f1da4bd5f", "0xb16Db98B365B1f89191996942612B14F1Da4Bd5f", ), + BlockchainType::InternetComputer => ( + "290CC7C359F44C8516FC169C5ED4F0F3AE2E24BF5DE0D4C51F5E7545B5474FAA", + "290cc7c359f44c8516fc169c5ed4f0f3ae2e24bf5de0d4c51f5e7545b5474faa", + ), BlockchainType::NativeEvmos => ( "evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34", "evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34", @@ -100,9 +105,9 @@ fn test_any_address_normalize_eth() { "0xb16db98b365b1f89191996942612b14f1da4bd5f", "ronin:b16Db98B365B1f89191996942612B14F1Da4Bd5f", ), - BlockchainType::InternetComputer => ( - "290CC7C359F44C8516FC169C5ED4F0F3AE2E24BF5DE0D4C51F5E7545B5474FAA", - "290cc7c359f44c8516fc169c5ed4f0f3ae2e24bf5de0d4c51f5e7545b5474faa", + BlockchainType::Thorchain => ( + "thor1z53wwe7md6cewz9sqwqzn0aavpaun0gw0exn2r", + "thor1z53wwe7md6cewz9sqwqzn0aavpaun0gw0exn2r", ), BlockchainType::Unsupported => unreachable!(), }; @@ -143,6 +148,12 @@ fn test_any_address_is_valid_coin() { "0xb16db98b365b1f89191996942612b14f1da4bd5f", "0xb16Db98B365B1f89191996942612B14F1Da4Bd5f", ], + BlockchainType::InternetComputer => vec![ + "fb257577279ecac604d4780214af95aa6adc3a814f6f3d6d7ac844d1deca500a", + "e90c48d54847f4758f1d6b589a1db2500757a49a6722d4f775e050107b4b752d", + "a7c5baf393aed527ef6fb3869fbf84dd4e562edf9b04bd8f9bfbd6b8e6a22776", + "4cb2ca5cfcfa1d952f8cd7f0ec46c96e1023ab057b83a2c7ce236b9e71ccca0b", + ], BlockchainType::NativeEvmos => vec![ "evmos14py36sx57ud82t9yrks9z6hdsrpn5x6k0r05np", "evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34" @@ -157,11 +168,9 @@ fn test_any_address_is_valid_coin() { "ronin:b16db98b365b1f89191996942612b14f1da4bd5f", "ronin:b16Db98B365B1f89191996942612B14F1Da4Bd5f", ], - BlockchainType::InternetComputer => vec![ - "fb257577279ecac604d4780214af95aa6adc3a814f6f3d6d7ac844d1deca500a", - "e90c48d54847f4758f1d6b589a1db2500757a49a6722d4f775e050107b4b752d", - "a7c5baf393aed527ef6fb3869fbf84dd4e562edf9b04bd8f9bfbd6b8e6a22776", - "4cb2ca5cfcfa1d952f8cd7f0ec46c96e1023ab057b83a2c7ce236b9e71ccca0b", + BlockchainType::Thorchain => vec![ + "thor1z53wwe7md6cewz9sqwqzn0aavpaun0gw0exn2r", + "thor1c8jd7ad9pcw4k3wkuqlkz4auv95mldr2kyhc65", ], _ => unreachable!(), }; @@ -195,6 +204,10 @@ fn test_any_address_is_valid_coin_invalid() { ], BlockchainType::NativeEvmos => vec!["evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw"], BlockchainType::NativeInjective => vec!["ini13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a"], + BlockchainType::Thorchain => vec![ + "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02", + "thor1z53wwe7md6cewz9sqwqzn0aavpaun0gw0e", + ], BlockchainType::Unsupported => unreachable!(), }; diff --git a/rust/tw_coin_registry/Cargo.toml b/rust/tw_coin_registry/Cargo.toml index 29fe4958e1a..605888aab85 100644 --- a/rust/tw_coin_registry/Cargo.toml +++ b/rust/tw_coin_registry/Cargo.toml @@ -20,3 +20,4 @@ tw_misc = { path = "../tw_misc" } tw_native_evmos = { path = "../chains/tw_native_evmos" } tw_native_injective = { path = "../chains/tw_native_injective" } tw_ronin = { path = "../tw_ronin" } +tw_thorchain = { path = "../chains/tw_thorchain" } diff --git a/rust/tw_coin_registry/src/blockchain_type.rs b/rust/tw_coin_registry/src/blockchain_type.rs index ca8cf6805f4..bad948bdd45 100644 --- a/rust/tw_coin_registry/src/blockchain_type.rs +++ b/rust/tw_coin_registry/src/blockchain_type.rs @@ -20,6 +20,7 @@ pub enum BlockchainType { NativeEvmos, NativeInjective, Ronin, + Thorchain, Unsupported, } @@ -42,9 +43,10 @@ impl FromStr for BlockchainType { "Cosmos" => Ok(BlockchainType::Cosmos), "Ethereum" => Ok(BlockchainType::Ethereum), "InternetComputer" => Ok(BlockchainType::InternetComputer), - "Ronin" => Ok(BlockchainType::Ronin), "NativeEvmos" => Ok(BlockchainType::NativeEvmos), "NativeInjective" => Ok(BlockchainType::NativeInjective), + "Ronin" => Ok(BlockchainType::Ronin), + "Thorchain" => Ok(BlockchainType::Thorchain), _ => Ok(BlockchainType::Unsupported), } } diff --git a/rust/tw_coin_registry/src/dispatcher.rs b/rust/tw_coin_registry/src/dispatcher.rs index 12fe0d5f4be..0ad4de717d5 100644 --- a/rust/tw_coin_registry/src/dispatcher.rs +++ b/rust/tw_coin_registry/src/dispatcher.rs @@ -18,6 +18,7 @@ use tw_internet_computer::entry::InternetComputerEntry; use tw_native_evmos::entry::NativeEvmosEntry; use tw_native_injective::entry::NativeInjectiveEntry; use tw_ronin::entry::RoninEntry; +use tw_thorchain::entry::ThorchainEntry; pub type CoinEntryExtStaticRef = &'static dyn CoinEntryExt; pub type EvmEntryExtStaticRef = &'static dyn EvmEntryExt; @@ -29,6 +30,7 @@ const INTERNET_COMPUTER: InternetComputerEntry = InternetComputerEntry; const NATIVE_EVMOS: NativeEvmosEntry = NativeEvmosEntry; const NATIVE_INJECTIVE: NativeInjectiveEntry = NativeInjectiveEntry; const RONIN: RoninEntry = RoninEntry; +const THORCHAIN: ThorchainEntry = ThorchainEntry; pub fn blockchain_dispatcher(blockchain: BlockchainType) -> RegistryResult { match blockchain { @@ -39,6 +41,7 @@ pub fn blockchain_dispatcher(blockchain: BlockchainType) -> RegistryResult Ok(&NATIVE_EVMOS), BlockchainType::NativeInjective => Ok(&NATIVE_INJECTIVE), BlockchainType::Ronin => Ok(&RONIN), + BlockchainType::Thorchain => Ok(&THORCHAIN), BlockchainType::Unsupported => Err(RegistryError::Unsupported), } } @@ -62,6 +65,7 @@ pub fn evm_dispatcher(coin: CoinType) -> RegistryResult { BlockchainType::NativeEvmos => Err(RegistryError::Unsupported), BlockchainType::NativeInjective => Err(RegistryError::Unsupported), BlockchainType::Ronin => Ok(&RONIN), + BlockchainType::Thorchain => Err(RegistryError::Unsupported), BlockchainType::Unsupported => Err(RegistryError::Unsupported), } } diff --git a/tests/chains/Cosmos/TransactionCompilerTests.cpp b/tests/chains/Cosmos/TransactionCompilerTests.cpp index 4500533ab7a..64fa3617e99 100644 --- a/tests/chains/Cosmos/TransactionCompilerTests.cpp +++ b/tests/chains/Cosmos/TransactionCompilerTests.cpp @@ -139,7 +139,7 @@ TEST(CosmosCompiler, CompileWithSignatures) { Cosmos::Proto::SigningOutput output; ASSERT_TRUE(output.ParseFromArray(outputData.data(), (int)outputData.size())); EXPECT_EQ(output.serialized().size(), 0ul); - EXPECT_EQ(output.error(), Common::Proto::Error_invalid_params); + EXPECT_EQ(output.error(), Common::Proto::Error_signatures_count); } /// Step 3: Obtain json preimage hash