Skip to content

Commit

Permalink
[Cosmos]: Add NativeInjective blockchain, cover with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
satoshiotomakan committed Nov 13, 2023
1 parent eae1347 commit fffc406
Show file tree
Hide file tree
Showing 16 changed files with 256 additions and 12 deletions.
2 changes: 1 addition & 1 deletion registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -4335,7 +4335,7 @@
"coinId": 10000060,
"symbol": "INJ",
"decimals": 18,
"blockchain": "Cosmos",
"blockchain": "NativeInjective",
"derivation": [
{
"path": "m/44'/60'/0'/0/0"
Expand Down
12 changes: 12 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"chains/tw_cosmos",
"chains/tw_native_evmos",
"chains/tw_native_injective",
"tw_any_coin",
"tw_bech32_address",
"tw_bitcoin",
Expand Down
14 changes: 14 additions & 0 deletions rust/chains/tw_native_injective/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "tw_native_injective"
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"] }
20 changes: 20 additions & 0 deletions rust/chains/tw_native_injective/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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 crate::injective_public_key::InjectiveEthSecp256PublicKey;
use tw_cosmos_sdk::address::Address;
use tw_cosmos_sdk::context::CosmosContext;
use tw_cosmos_sdk::hasher::keccak256_hasher::Keccak256Hasher;
use tw_cosmos_sdk::private_key::secp256k1::Secp256PrivateKey;

pub struct NativeInjectiveContext;

impl CosmosContext for NativeInjectiveContext {
type Address = Address;
type TxHasher = Keccak256Hasher;
type PrivateKey = Secp256PrivateKey;
type PublicKey = InjectiveEthSecp256PublicKey;
}
74 changes: 74 additions & 0 deletions rust/chains/tw_native_injective/src/entry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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 crate::context::NativeInjectiveContext;
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_coin_entry::prefix::NoPrefix;
use tw_cosmos_sdk::address::{Address, CosmosAddress};
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 NativeInjectiveEntry;

impl CoinEntry for NativeInjectiveEntry {
type AddressPrefix = NoPrefix;
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;

fn parse_address(
&self,
coin: &dyn CoinContext,
address: &str,
_prefix: Option<Self::AddressPrefix>,
) -> AddressResult<Self::Address> {
Address::from_str_with_coin(coin, address)
}

fn derive_address(
&self,
coin: &dyn CoinContext,
public_key: tw::PublicKey,
_derivation: Derivation,
_prefix: Option<Self::AddressPrefix>,
) -> AddressResult<Self::Address> {
Address::with_public_key_coin_context(coin, &public_key)
}

fn sign(&self, coin: &dyn CoinContext, input: Self::SigningInput<'_>) -> Self::SigningOutput {
TWSigner::<NativeInjectiveContext>::sign(coin, input)
}

fn preimage_hashes(
&self,
_coin: &dyn CoinContext,
_input: Self::SigningInput<'_>,
) -> Self::PreSigningOutput {
todo!()
}

fn compile(
&self,
_coin: &dyn CoinContext,
_input: Self::SigningInput<'_>,
_signatures: Vec<SignatureBytes>,
_public_keys: Vec<PublicKeyBytes>,
) -> Self::SigningOutput {
todo!()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,15 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

// 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 crate::proto::injective;
use crate::public_key::secp256k1::prepare_secp256k1_public_key;
use crate::public_key::{CosmosPublicKey, JsonPublicKey, ProtobufPublicKey};
use tw_coin_entry::coin_context::CoinContext;
use tw_cosmos_sdk::proto::injective;
use tw_cosmos_sdk::public_key::secp256k1::prepare_secp256k1_public_key;
use tw_cosmos_sdk::public_key::{CosmosPublicKey, JsonPublicKey, ProtobufPublicKey};
use tw_keypair::tw::PrivateKey;
use tw_keypair::KeyPairResult;
use tw_memory::Data;
use tw_proto::{google, to_any};

// TODO move to tw_injective blockchain
pub struct InjectiveEthSecp256PublicKey {
public_key: Data,
}
Expand Down
9 changes: 9 additions & 0 deletions rust/chains/tw_native_injective/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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 context;
pub mod entry;
pub mod injective_public_key;
1 change: 1 addition & 0 deletions rust/tw_any_coin/tests/chains/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
// file LICENSE at the root of the source code distribution tree.

mod native_evmos;
mod native_injective;
7 changes: 7 additions & 0 deletions rust/tw_any_coin/tests/chains/native_injective/mod.rs
Original file line number Diff line number Diff line change
@@ -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 native_injective_sign;
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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::borrow::Cow;
use tw_any_coin::ffi::tw_any_signer::tw_any_signer_sign;
use tw_coin_entry::error::SigningErrorType;
use tw_cosmos_sdk::test_utils::proto_utils::{make_amount, make_fee, make_message};
use tw_encoding::hex::{DecodeHex, ToHex};
use tw_memory::test_utils::tw_data_helper::TWDataHelper;
use tw_proto::Cosmos::Proto;
use tw_proto::Cosmos::Proto::mod_Message::OneOfmessage_oneof as MessageEnum;
use tw_proto::{deserialize, serialize};

const NATIVE_INJECTIVE_COIN_TYPE: u32 = 10000060;

fn account_17396_private_key() -> Cow<'static, [u8]> {
"9ee18daf8e463877aaf497282abc216852420101430482a28e246c179e2c5ef1"
.decode_hex()
.unwrap()
.into()
}

fn send_tx_input() -> Proto::SigningInput<'static> {
let send_msg = Proto::mod_Message::Send {
from_address: "inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a".into(),
to_address: "inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd".into(),
amounts: vec![make_amount("inj", "10000000000")],
..Proto::mod_Message::Send::default()
};
Proto::SigningInput {
account_number: 17396,
chain_id: "injective-1".into(),
sequence: 1,
fee: Some(make_fee(110000, make_amount("inj", "100000000000000"))),
private_key: account_17396_private_key(),
messages: vec![make_message(MessageEnum::send_coins_message(send_msg))],
..Proto::SigningInput::default()
}
}

#[test]
fn test_sign_native_injective_tx_protobuf() {
let input = Proto::SigningInput {
signing_mode: Proto::SigningMode::Protobuf,
..send_tx_input()
};
let input_data = TWDataHelper::create(serialize(&input).unwrap());

let output = TWDataHelper::wrap(unsafe {
tw_any_signer_sign(input_data.ptr(), NATIVE_INJECTIVE_COIN_TYPE)
})
.to_vec()
.expect("!tw_any_signer_sign returned nullptr");

let output: Proto::SigningOutput = deserialize(&output).unwrap();
assert_eq!(output.error, SigningErrorType::OK);
assert!(output.error_message.is_empty());

// https://www.mintscan.io/injective/txs/135DD2C4A1910E4334A9C0F15125DA992E724EBF23FEB9638FCB71218BB064A5
assert_eq!(
output.serialized,
r#"{"mode":"BROADCAST_MODE_BLOCK","tx_bytes":"Co8BCowBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmwKKmluajEzdTZnN3ZxZ3cwNzRtZ21mMnplMmNhZHp2a3o5c25sd2NydHE4YRIqaW5qMXhtcGtteHI0YXMwMGVtMjN0YzJ6Z211eXkyZ3I0aDN3Z2NsNnZkGhIKA2luahILMTAwMDAwMDAwMDASngEKfgp0Ci0vaW5qZWN0aXZlLmNyeXB0by52MWJldGExLmV0aHNlY3AyNTZrMS5QdWJLZXkSQwpBBFoMa4O4vZgn5QcnDK20mbfjqQlSRvaiITKB94PYd8mLJWdCdBsGOfMXdo/k9MJ2JmDCESKDp2hdgVUH3uMikXMSBAoCCAEYARIcChYKA2luahIPMTAwMDAwMDAwMDAwMDAwELDbBhpAx2vkplmzeK7n3puCFGPWhLd0l/ZC/CYkGl+stH+3S3hiCvIe7uwwMpUlNaSwvT8HwF1kNUp+Sx2m0Uo1x5xcFw=="}"#
);
assert_eq!(output.signature.to_hex(), "c76be4a659b378aee7de9b821463d684b77497f642fc26241a5facb47fb74b78620af21eeeec3032952535a4b0bd3f07c05d64354a7e4b1da6d14a35c79c5c17");
}

#[test]
fn test_sign_native_injective_tx_json() {
let input = Proto::SigningInput {
signing_mode: Proto::SigningMode::JSON,
..send_tx_input()
};
let input_data = TWDataHelper::create(serialize(&input).unwrap());

let output = TWDataHelper::wrap(unsafe {
tw_any_signer_sign(input_data.ptr(), NATIVE_INJECTIVE_COIN_TYPE)
})
.to_vec()
.expect("!tw_any_signer_sign returned nullptr");

let output: Proto::SigningOutput = deserialize(&output).unwrap();
assert_eq!(output.error, SigningErrorType::OK);
assert!(output.error_message.is_empty());

// This transaction hasn't been broadcasted.
assert_eq!(
output.json,
r#"{"mode":"block","tx":{"fee":{"amount":[{"amount":"100000000000000","denom":"inj"}],"gas":"110000"},"memo":"","msg":[{"type":"cosmos-sdk/MsgSend","value":{"amount":[{"amount":"10000000000","denom":"inj"}],"from_address":"inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a","to_address":"inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd"}}],"signatures":[{"pub_key":{"type":"injective/PubKeyEthSecp256k1","value":"BFoMa4O4vZgn5QcnDK20mbfjqQlSRvaiITKB94PYd8mLJWdCdBsGOfMXdo/k9MJ2JmDCESKDp2hdgVUH3uMikXM="},"signature":"7wwedceebL95DwbClz5AzEp2Z74itHC7raiV976DcacfjrJ58oDfjbAO5UOZQAlihiYBP7PpyISFQ72FPRhdZA=="}]}}"#
);
assert_eq!(
output.signature_json,
r#"[{"pub_key":{"type":"injective/PubKeyEthSecp256k1","value":"BFoMa4O4vZgn5QcnDK20mbfjqQlSRvaiITKB94PYd8mLJWdCdBsGOfMXdo/k9MJ2JmDCESKDp2hdgVUH3uMikXM="},"signature":"7wwedceebL95DwbClz5AzEp2Z74itHC7raiV976DcacfjrJ58oDfjbAO5UOZQAlihiYBP7PpyISFQ72FPRhdZA=="}]"#
);
}
10 changes: 10 additions & 0 deletions rust/tw_any_coin/tests/tw_any_address_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fn test_any_address_derive() {
BlockchainType::Cosmos => continue,
BlockchainType::Ethereum => "0xAc1ec44E4f0ca7D172B7803f6836De87Fb72b309",
BlockchainType::NativeEvmos => "evmos14s0vgnj0pjnazu4hsqlksdk7slah9vcfvt8ssm",
BlockchainType::NativeInjective => "inj14s0vgnj0pjnazu4hsqlksdk7slah9vcfyrp6ct",
BlockchainType::Ronin => "ronin:Ac1ec44E4f0ca7D172B7803f6836De87Fb72b309",
BlockchainType::InternetComputer => {
"290cc7c359f44c8516fc169c5ed4f0f3ae2e24bf5de0d4c51f5e7545b5474faa"
Expand Down Expand Up @@ -88,6 +89,10 @@ fn test_any_address_normalize_eth() {
"evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34",
"evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34",
),
BlockchainType::NativeInjective => (
"inj14py36sx57ud82t9yrks9z6hdsrpn5x6k8tf7m3",
"inj14py36sx57ud82t9yrks9z6hdsrpn5x6k8tf7m3",
),
BlockchainType::Ronin => (
"0xb16db98b365b1f89191996942612b14f1da4bd5f",
"ronin:b16Db98B365B1f89191996942612B14F1Da4Bd5f",
Expand Down Expand Up @@ -139,6 +144,10 @@ fn test_any_address_is_valid_coin() {
"evmos14py36sx57ud82t9yrks9z6hdsrpn5x6k0r05np",
"evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw34"
],
BlockchainType::NativeInjective => vec![
"inj13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a",
"inj1xmpkmxr4as00em23tc2zgmuyy2gr4h3wgcl6vd"
],
BlockchainType::Ronin => vec![
"0xb16db98b365b1f89191996942612b14f1da4bd5f",
"0xb16Db98B365B1f89191996942612B14F1Da4Bd5f",
Expand Down Expand Up @@ -182,6 +191,7 @@ fn test_any_address_is_valid_coin_invalid() {
"553357cba483f268d044d4bbd4639f82c16028a76eebdf62c51bc11fc918d278",
],
BlockchainType::NativeEvmos => vec!["evmos17xpfvakm2amg962yls6f84z3kell8c5ljcjw"],
BlockchainType::NativeInjective => vec!["ini13u6g7vqgw074mgmf2ze2cadzvkz9snlwcrtq8a"],
BlockchainType::Unsupported => unreachable!(),
};

Expand Down
1 change: 1 addition & 0 deletions rust/tw_coin_registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ tw_keypair = { path = "../tw_keypair" }
tw_memory = { path = "../tw_memory" }
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" }
2 changes: 2 additions & 0 deletions rust/tw_coin_registry/src/blockchain_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub enum BlockchainType {
Ethereum,
InternetComputer,
NativeEvmos,
NativeInjective,
Ronin,
Unsupported,
}
Expand All @@ -43,6 +44,7 @@ impl FromStr for BlockchainType {
"InternetComputer" => Ok(BlockchainType::InternetComputer),
"Ronin" => Ok(BlockchainType::Ronin),
"NativeEvmos" => Ok(BlockchainType::NativeEvmos),
"NativeInjective" => Ok(BlockchainType::NativeInjective),
_ => Ok(BlockchainType::Unsupported),
}
}
Expand Down
4 changes: 4 additions & 0 deletions rust/tw_coin_registry/src/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use tw_ethereum::entry::EthereumEntry;
use tw_evm::evm_entry::EvmEntryExt;
use tw_internet_computer::entry::InternetComputerEntry;
use tw_native_evmos::entry::NativeEvmosEntry;
use tw_native_injective::entry::NativeInjectiveEntry;
use tw_ronin::entry::RoninEntry;

pub type CoinEntryExtStaticRef = &'static dyn CoinEntryExt;
Expand All @@ -26,6 +27,7 @@ const COSMOS: CosmosEntry = CosmosEntry;
const ETHEREUM: EthereumEntry = EthereumEntry;
const INTERNET_COMPUTER: InternetComputerEntry = InternetComputerEntry;
const NATIVE_EVMOS: NativeEvmosEntry = NativeEvmosEntry;
const NATIVE_INJECTIVE: NativeInjectiveEntry = NativeInjectiveEntry;
const RONIN: RoninEntry = RoninEntry;

pub fn blockchain_dispatcher(blockchain: BlockchainType) -> RegistryResult<CoinEntryExtStaticRef> {
Expand All @@ -35,6 +37,7 @@ pub fn blockchain_dispatcher(blockchain: BlockchainType) -> RegistryResult<CoinE
BlockchainType::Ethereum => Ok(&ETHEREUM),
BlockchainType::InternetComputer => Ok(&INTERNET_COMPUTER),
BlockchainType::NativeEvmos => Ok(&NATIVE_EVMOS),
BlockchainType::NativeInjective => Ok(&NATIVE_INJECTIVE),
BlockchainType::Ronin => Ok(&RONIN),
BlockchainType::Unsupported => Err(RegistryError::Unsupported),
}
Expand All @@ -57,6 +60,7 @@ pub fn evm_dispatcher(coin: CoinType) -> RegistryResult<EvmEntryExtStaticRef> {
BlockchainType::Ethereum => Ok(&ETHEREUM),
BlockchainType::InternetComputer => Err(RegistryError::Unsupported),
BlockchainType::NativeEvmos => Err(RegistryError::Unsupported),
BlockchainType::NativeInjective => Err(RegistryError::Unsupported),
BlockchainType::Ronin => Ok(&RONIN),
BlockchainType::Unsupported => Err(RegistryError::Unsupported),
}
Expand Down
Loading

0 comments on commit fffc406

Please sign in to comment.