diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt index 05d20a89744..0d0e8f18103 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/CoinAddressDerivationTests.kt @@ -153,5 +153,6 @@ class CoinAddressDerivationTests { INTERNETCOMPUTER -> assertEquals("b9a13d974ee9db036d5abc5b66ace23e513cb5676f3996626c7717c339a3ee87", address) TIA -> assertEquals("celestia142j9u5eaduzd7faumygud6ruhdwme98qpwmfv7", address) NATIVEZETACHAIN -> assertEquals("zeta13u6g7vqgw074mgmf2ze2cadzvkz9snlwywj304", address) + DYDX -> assertEquals("dydx142j9u5eaduzd7faumygud6ruhdwme98qeayaky", address) } } diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/dydx/TestDydxAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/dydx/TestDydxAddress.kt new file mode 100644 index 00000000000..408f8fb4ae3 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/dydx/TestDydxAddress.kt @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +package com.trustwallet.core.app.blockchains.dydx + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestDydxAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433".toHexByteArray()) + val pubKey = key.getPublicKeySecp256k1(true) + val address = AnyAddress(pubKey, CoinType.DYDX) + val expected = AnyAddress("dydx1mry47pkga5tdswtluy0m8teslpalkdq0hc72uz", CoinType.DYDX) + + assertEquals(address.description(), expected.description()) + } +} diff --git a/docs/registry.md b/docs/registry.md index 4fd54a26c0c..a2023da41f1 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -144,6 +144,7 @@ This list is generated from [./registry.json](../registry.json) | 20007000 | Zeta EVM | ZETA | | | | 20009001 | Native Evmos | EVMOS | | | | 21000118 | Celestia | TIA | | | +| 22000118 | dYdX | DYDX | | | | 30000118 | Juno | JUNO | | | | 30000714 | TBNB | BNB | | | | 40000118 | Stride | STRD | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index 289ff480a82..e65dc4878e7 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -180,6 +180,7 @@ enum TWCoinType { TWCoinTypeMantaPacific = 169, TWCoinTypeNativeZetaChain = 10007000, TWCoinTypeZetaEVM = 20007000, + TWCoinTypeDydx = 22000118, // end_of_tw_coin_type_marker_do_not_modify }; diff --git a/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt b/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt index 444e9ea9767..a586146c54d 100644 --- a/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt +++ b/kotlin/wallet-core-kotlin/src/commonTest/kotlin/com/trustwallet/core/test/CoinAddressDerivationTests.kt @@ -146,5 +146,6 @@ class CoinAddressDerivationTests { InternetComputer -> "b9a13d974ee9db036d5abc5b66ace23e513cb5676f3996626c7717c339a3ee87" Tia -> "celestia142j9u5eaduzd7faumygud6ruhdwme98qpwmfv7" NativeZetaChain -> "zeta13u6g7vqgw074mgmf2ze2cadzvkz9snlwywj304" + Dydx -> "dydx142j9u5eaduzd7faumygud6ruhdwme98qeayaky" } } diff --git a/registry.json b/registry.json index e034c34bede..ca3f9cf2660 100644 --- a/registry.json +++ b/registry.json @@ -4361,6 +4361,38 @@ "documentation": "https://docs.agoric.com" } }, + { + "id": "dydx", + "name": "Dydx", + "displayName": "dYdX", + "coinId": 22000118, + "symbol": "DYDX", + "decimals": 18, + "blockchain": "Cosmos", + "derivation": [ + { + "path": "m/44'/118'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1", + "hrp": "dydx", + "chainId": "dydx-mainnet-1", + "addressHasher": "sha256ripemd", + "explorer": { + "url": "https://www.mintscan.io/dydx", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "F236222E4F7C92FA84711FD6451ED22DD56CBDFA319BFDAFB99A21E4E9B9EC2F", + "sampleAccount": "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt" + }, + "info": { + "url": "https://dydx.exchange", + "source": "https://github.com/dydxprotocol", + "rpc": "https://dydx-dao-api.polkachu.com", + "documentation": "https://docs.dydx.exchange" + } + }, { "id": "nativeinjective", "name": "NativeInjective", diff --git a/rust/tw_any_coin/tests/chains/cosmos/cosmos_address.rs b/rust/tw_any_coin/tests/chains/cosmos/cosmos_address.rs index 51bf414bec3..a9acab72f63 100644 --- a/rust/tw_any_coin/tests/chains/cosmos/cosmos_address.rs +++ b/rust/tw_any_coin/tests/chains/cosmos/cosmos_address.rs @@ -73,9 +73,9 @@ fn test_any_address_is_valid_bech32() { fn test_any_address_create_bech32_with_public_key() { test_address_create_bech32_with_public_key(AddressCreateBech32WithPublicKey { coin: CoinType::Cosmos, - private_key: "afeefca74d9a325cf1d6b6911d61a65c32afa8e02bd5e78e2e4ac2910bab45f5", + private_key: "a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433", public_key_type: PublicKeyType::Secp256k1, - hrp: "juno", - expected: "juno1ten42eesehw0ktddcp0fws7d3ycsqez3fksy86", + hrp: "dydx", + expected: "dydx1mry47pkga5tdswtluy0m8teslpalkdq0hc72uz", }); } diff --git a/rust/tw_any_coin/tests/chains/dydx/dydx_address.rs b/rust/tw_any_coin/tests/chains/dydx/dydx_address.rs new file mode 100644 index 00000000000..8ba214f3e41 --- /dev/null +++ b/rust/tw_any_coin/tests/chains/dydx/dydx_address.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +use tw_any_coin::test_utils::address_utils::{ + test_address_bech32_is_valid, test_address_create_bech32_with_public_key, + test_address_get_data, test_address_invalid, test_address_normalization, test_address_valid, + AddressBech32IsValid, AddressCreateBech32WithPublicKey, +}; +use tw_coin_registry::coin_type::CoinType; +use tw_keypair::tw::PublicKeyType; + +#[test] +fn test_dydx_address_normalization() { + test_address_normalization( + CoinType::Dydx, + "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt", + "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt", + ); +} + +#[test] +fn test_dydx_address_is_valid() { + test_address_valid( + CoinType::Dydx, + "dydxvaloper1gf9yvztyvnc3aqrkjd8hfnaf8pk56sl7mzfage", + ); +} + +#[test] +fn test_dydx_address_invalid() { + test_address_invalid( + CoinType::Dydx, + "dydxvaloper1gf9yvztyvnc3aqrkjd8hfnaf8pk56sl7mz", + ); + // Cosmos has a different `hrp`. + test_address_invalid( + CoinType::Cosmos, + "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt", + ); +} + +#[test] +fn test_dydx_address_get_data() { + test_address_get_data( + CoinType::Dydx, + "dydxvaloper1gf9yvztyvnc3aqrkjd8hfnaf8pk56sl7mzfage", + "424a46096464f11e8076934f74cfa9386d4d43fe", + ); +} + +#[test] +fn test_dydx_is_valid_bech32() { + // Dydx address must be valid if its Base32 prefix passed. + test_address_bech32_is_valid(AddressBech32IsValid { + coin: CoinType::Dydx, + address: "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt", + hrp: "dydx", + }); + // Dydx address must be valid for the standard Cosmos hub if its Base32 prefix passed. + test_address_bech32_is_valid(AddressBech32IsValid { + coin: CoinType::Cosmos, + address: "dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt", + hrp: "dydx", + }); + // Cosmos address must be valid with "cosmos" hrp. + test_address_bech32_is_valid(AddressBech32IsValid { + coin: CoinType::Dydx, + address: "cosmos1hsk6jryyqjfhp5dhc55tc9jtckygx0eph6dd02", + hrp: "cosmos", + }); +} + +#[test] +fn test_any_address_create_bech32_with_public_key() { + test_address_create_bech32_with_public_key(AddressCreateBech32WithPublicKey { + coin: CoinType::Cosmos, + private_key: "a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433", + public_key_type: PublicKeyType::Secp256k1, + hrp: "dydx", + expected: "dydx1mry47pkga5tdswtluy0m8teslpalkdq0hc72uz", + }); +} diff --git a/rust/tw_any_coin/tests/chains/dydx/mod.rs b/rust/tw_any_coin/tests/chains/dydx/mod.rs new file mode 100644 index 00000000000..d559c269a8b --- /dev/null +++ b/rust/tw_any_coin/tests/chains/dydx/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +mod dydx_address; diff --git a/rust/tw_any_coin/tests/chains/mod.rs b/rust/tw_any_coin/tests/chains/mod.rs index 7a9f7285560..cefb0e37ae4 100644 --- a/rust/tw_any_coin/tests/chains/mod.rs +++ b/rust/tw_any_coin/tests/chains/mod.rs @@ -6,6 +6,7 @@ mod aptos; mod binance; mod bitcoin; mod cosmos; +mod dydx; mod ethereum; mod greenfield; mod internet_computer; diff --git a/rust/tw_any_coin/tests/coin_address_derivation_test.rs b/rust/tw_any_coin/tests/coin_address_derivation_test.rs index 12ce7f772fc..9cf10ad244a 100644 --- a/rust/tw_any_coin/tests/coin_address_derivation_test.rs +++ b/rust/tw_any_coin/tests/coin_address_derivation_test.rs @@ -147,6 +147,7 @@ fn test_coin_address_derivation() { CoinType::Binance => "bnb1ten42eesehw0ktddcp0fws7d3ycsqez3aqvnpg", CoinType::TBinance => "tbnb1ten42eesehw0ktddcp0fws7d3ycsqez3n49hpe", CoinType::NativeZetaChain => "zeta14s0vgnj0pjnazu4hsqlksdk7slah9vcfcwctsr", + CoinType::Dydx => "dydx1ten42eesehw0ktddcp0fws7d3ycsqez3kaamq3", // end_of_coin_address_derivation_tests_marker_do_not_modify _ => panic!("{:?} must be covered", coin), }; diff --git a/swift/Tests/Blockchains/DydxTests.swift b/swift/Tests/Blockchains/DydxTests.swift new file mode 100644 index 00000000000..a464c834c8a --- /dev/null +++ b/swift/Tests/Blockchains/DydxTests.swift @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +import WalletCore +import XCTest + +class DydxTests: XCTestCase { + func testAddress() { + let key = PrivateKey(data: Data(hexString: "a498a9ee41af9bab5ef2a8be63d5c970135c3c109e70efc8c56c534e6636b433")!)! + let pubkey = key.getPublicKeySecp256k1(compressed: true) + let address = AnyAddress(publicKey: pubkey, coin: .dydx) + let addressFromString = AnyAddress(string: "dydx1mry47pkga5tdswtluy0m8teslpalkdq0hc72uz", coin: .dydx)! + + XCTAssertEqual(address.description, addressFromString.description) + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index 4d18de7ae96..339b2ccde19 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -392,6 +392,9 @@ class CoinAddressDerivationTests: XCTestCase { case .nativeZetaChain: let expectedResult = "zeta13u6g7vqgw074mgmf2ze2cadzvkz9snlwywj304" assertCoinDerivation(coin, expectedResult, derivedAddress, address) + case .dydx: + let expectedResult = "dydx142j9u5eaduzd7faumygud6ruhdwme98qeayaky" + assertCoinDerivation(coin, expectedResult, derivedAddress, address) @unknown default: fatalError() } diff --git a/tests/chains/Dydx/TWCoinTypeTests.cpp b/tests/chains/Dydx/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..1dd49ee8eb4 --- /dev/null +++ b/tests/chains/Dydx/TWCoinTypeTests.cpp @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#include "TestUtilities.h" +#include +#include + +TEST(TWDydxCoinType, TWCoinType) { + const auto coin = TWCoinTypeDydx; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("F236222E4F7C92FA84711FD6451ED22DD56CBDFA319BFDAFB99A21E4E9B9EC2F")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "dydx"); + assertStringsEqual(name, "dYdX"); + assertStringsEqual(symbol, "DYDX"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 18); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainCosmos); + ASSERT_EQ(TWCoinTypeP2pkhPrefix(coin), 0); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0); + assertStringsEqual(txUrl, "https://www.mintscan.io/dydx/tx/F236222E4F7C92FA84711FD6451ED22DD56CBDFA319BFDAFB99A21E4E9B9EC2F"); + assertStringsEqual(accUrl, "https://www.mintscan.io/dydx/address/dydx1adl7usw7z2dnysyn7wvrghu0u0q6gr7jqs4gtt"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index f052b41322b..93411f2e8cf 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -388,6 +388,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeNativeZetaChain: EXPECT_EQ(address, "zeta1nk9x9ajk4rgkzhqjjn7hr6w0k0jg2kj027x9uy"); break; + case TWCoinTypeDydx: + EXPECT_EQ(address, "dydx1hkfq3zahaqkkzx5mjnamwjsfpq2jk7z0sz38vk"); + break; // end_of_coin_address_derivation_tests_marker_do_not_modify // no default branch here, intentionally, to better notice any missing coins }