From f034a12ddc7daf6ca34bb9efb654df52e52a7e09 Mon Sep 17 00:00:00 2001 From: Satoshi Otomakan Date: Thu, 29 Jun 2023 12:51:00 +0200 Subject: [PATCH 1/3] feat(Acala): Add Acala and Acala EVM chains --- .../blockchains/CoinAddressDerivationTests.kt | 4 +- .../app/blockchains/acala/TestAcalaAddress.kt | 28 ++++++++ .../app/blockchains/acala/TestAcalaSigner.kt | 65 +++++++++++++++++++ .../acalaevm/TestAcalaEVMAddress.kt | 29 +++++++++ .../polkadot/TestPolkadotSigner.kt | 44 ------------- docs/registry.md | 2 + include/TrustWalletCore/TWCoinType.h | 2 + registry.json | 61 +++++++++++++++++ src/Polkadot/Entry.cpp | 16 +++-- swift/Tests/Blockchains/AcalaEVMTests.swift | 19 ++++++ swift/Tests/Blockchains/AcalaTests.swift | 57 ++++++++++++++++ swift/Tests/CoinAddressDerivationTests.swift | 6 +- tests/chains/Acala/TWAnyAddressTests.cpp | 25 +++++-- tests/chains/Acala/TWCoinTypeTests.cpp | 35 ++++++++++ tests/chains/AcalaEVM/TWCoinTypeTests.cpp | 37 +++++++++++ tests/common/CoinAddressDerivationTests.cpp | 5 +- 16 files changed, 378 insertions(+), 57 deletions(-) create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt create mode 100644 swift/Tests/Blockchains/AcalaEVMTests.swift create mode 100644 swift/Tests/Blockchains/AcalaTests.swift create mode 100644 tests/chains/Acala/TWCoinTypeTests.cpp create mode 100644 tests/chains/AcalaEVM/TWCoinTypeTests.cpp 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 1085a809c22..ff871391a67 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 @@ -44,7 +44,8 @@ class CoinAddressDerivationTests { DIGIBYTE -> assertEquals("dgb1qtjgmerfqwdffyf8ghcrkgy52cghsqptynmyswu", address) ETHEREUM, SMARTCHAIN, POLYGON, OPTIMISM, ZKSYNC, ARBITRUM, ECOCHAIN, AVALANCHECCHAIN, XDAI, FANTOM, CELO, CRONOSCHAIN, SMARTBITCOINCASH, KUCOINCOMMUNITYCHAIN, BOBA, METIS, - AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN, POLYGONZKEVM, SCROLL, CONFLUXESPACE, -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) + AURORA, EVMOS, MOONRIVER, MOONBEAM, KAVAEVM, KLAYTN, METER, OKXCHAIN, POLYGONZKEVM, SCROLL, + CONFLUXESPACE, ACALAEVM -> assertEquals("0x8f348F300873Fd5DA36950B2aC75a26584584feE", address) RONIN -> assertEquals("ronin:8f348F300873Fd5DA36950B2aC75a26584584feE", address) ETHEREUMCLASSIC -> assertEquals("0x078bA3228F3E6C08bEEac9A005de0b7e7089aD1c", address) GOCHAIN -> assertEquals("0x5940ce4A14210d4Ccd0ac206CE92F21828016aC2", address) @@ -94,6 +95,7 @@ class CoinAddressDerivationTests { HARMONY -> assertEquals("one12fk20wmvgypdkn59n4hq8e3aa5899xfx4vsu09", address) SOLANA -> assertEquals("2bUBiBNZyD29gP1oV6de7nxowMLoDBtopMMTGgMvjG5m", address) ALGORAND -> assertEquals("JTJWO524JXIHVPGBDWFLJE7XUIA32ECOZOBLF2QP3V5TQBT3NKZSCG67BQ", address) + ACALA -> assertEquals("25GGezx3LWFQj6HZpYzoWoVzLsHojGtybef3vthC9nd19ms3", address) KUSAMA -> assertEquals("G9xV2EatmrjRC1FLPexc3ddqNRRzCsAdURU8RFiAAJX6ppY", address) POLKADOT -> assertEquals("13nN6BGAoJwd7Nw1XxeBCx5YcBXuYnL94Mh7i3xBprqVSsFk", address) PIVX -> assertEquals("D81AqC8zKma3Cht4TbVuh4jyVVyLkZULCm", address) diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt new file mode 100644 index 00000000000..b94158bace6 --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaAddress.kt @@ -0,0 +1,28 @@ +// 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. + +package com.trustwallet.core.app.blockchains.acala + +import com.trustwallet.core.app.utils.toHex +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAcalaAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("0x9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0".toHexByteArray()) + val pubkey = key.publicKeyEd25519 + val address = AnyAddress(pubkey, CoinType.ACALA) + assertEquals(address.description(), "269ZCS3WLGydTN8ynhyhZfzJrXkePUcdhwgLQs6TWFs5wVL5") + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt new file mode 100644 index 00000000000..a066009144d --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acala/TestAcalaSigner.kt @@ -0,0 +1,65 @@ +// 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. + +package com.trustwallet.core.app.blockchains.acala + +import com.trustwallet.core.app.utils.Numeric +import com.trustwallet.core.app.utils.toHexBytesInByteString +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.java.AnySigner +import wallet.core.jni.CoinType +import wallet.core.jni.proto.Polkadot + +class TestAcalaSigner { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun AcalaTransactionSigning() { + val transferCallIndices = Polkadot.CallIndices.newBuilder().apply { + custom = Polkadot.CustomCallIndices.newBuilder().apply { + moduleIndex = 0x0a + methodIndex = 0x00 + }.build() + } + + val call = Polkadot.Balance.Transfer.newBuilder().apply { + value = "0xe8d4a51000".toHexBytesInByteString() // 1 ACA + toAddress = "25Qqz3ARAvnZbahGZUzV3xpP1bB3eRrupEprK7f2FNbHbvsz" + callIndices = transferCallIndices.build() + } + + val acalaGenesisHashStr = "0xfc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c".toHexBytesInByteString() + + val input = Polkadot.SigningInput.newBuilder().apply { + genesisHash = acalaGenesisHashStr + blockHash = "0x707ffa05b7dc6cdb6356bd8bd51ff20b2757c3214a76277516080a10f1bc7537".toHexBytesInByteString() + nonce = 0 + specVersion = 2170 + network = CoinType.ACALA.ss58Prefix() + transactionVersion = 2 + privateKey = "9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0".toHexBytesInByteString() + era = Polkadot.Era.newBuilder().apply { + blockNumber = 3893613 + period = 64 + }.build() + balanceCall = Polkadot.Balance.newBuilder().apply { + transfer = call.build() + }.build() + multiAddress = true + } + + val output = AnySigner.sign(input.build(), CoinType.ACALA, Polkadot.SigningOutput.parser()) + val encoded = Numeric.toHexString(output.encoded.toByteArray()) + + // https://acala.subscan.io/extrinsic/3893620-3 + val expected = "0x41028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900dd54466dffd1e3c80b76013e9459fbdcd17805bd5fdbca0961a643bad1cbd2b7fe005c62c51c18b67f31eb9e61b187a911952fee172ef18402d07c703eec3100d50200000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8" + assertEquals(encoded, expected) + } +} diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt new file mode 100644 index 00000000000..81274311cdd --- /dev/null +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/acalaevm/TestAcalaEVMAddress.kt @@ -0,0 +1,29 @@ +// 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. + +package com.trustwallet.core.app.blockchains.acalaevm + +import com.trustwallet.core.app.utils.toHexByteArray +import org.junit.Assert.assertEquals +import org.junit.Test +import wallet.core.jni.* + +class TestAcalaEVMAddress { + + init { + System.loadLibrary("TrustWalletCore") + } + + @Test + fun testAddress() { + val key = PrivateKey("828c4c48c2cef521f0251920891ed79e871faa24f64f43cde83d07bc99f8dbf0".toHexByteArray()) + val pubkey = key.getPublicKeySecp256k1(false) + val address = AnyAddress(pubkey, CoinType.ACALAEVM) + val expected = AnyAddress("0xe32DC46bfBF78D1eada7b0a68C96903e01418D64", CoinType.ACALAEVM) + + assertEquals(address.description(), expected.description()) + } +} \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt index e9657c5f809..9da312ca3ea 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/polkadot/TestPolkadotSigner.kt @@ -115,48 +115,4 @@ class TestPolkadotSigner { val expected = "0xd10184008361bd08ddca5fda28b5e2aa84dc2621de566e23e089e555a42194c3eaf2da7900c891ba102db672e378945d74cf7f399226a76b43cab502436971599255451597fc2599902e4b62c7ce85ecc3f653c693fef3232be620984b5bb5bcecbbd7b209d50318001a02080706070207004d446617" assertEquals(encoded, expected) } - - @Test - fun PolkadotTransactionAcalaSigning() { - val transferCallIndices = Polkadot.CallIndices.newBuilder().apply { - custom = Polkadot.CustomCallIndices.newBuilder().apply { - moduleIndex = 0x0a - methodIndex = 0x00 - }.build() - } - - val call = Polkadot.Balance.Transfer.newBuilder().apply { - value = "0xe8d4a51000".toHexBytesInByteString() // 1 ACA - toAddress = "25Qqz3ARAvnZbahGZUzV3xpP1bB3eRrupEprK7f2FNbHbvsz" - callIndices = transferCallIndices.build() - } - - val acalaGenesisHashStr = "0xfc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c".toHexBytesInByteString() - val acalaNetworkSs58Prefix = 10 - - val input = Polkadot.SigningInput.newBuilder().apply { - genesisHash = acalaGenesisHashStr - blockHash = "0x707ffa05b7dc6cdb6356bd8bd51ff20b2757c3214a76277516080a10f1bc7537".toHexBytesInByteString() - nonce = 0 - specVersion = 2170 - network = acalaNetworkSs58Prefix - transactionVersion = 2 - privateKey = "9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0".toHexBytesInByteString() - era = Polkadot.Era.newBuilder().apply { - blockNumber = 3893613 - period = 64 - }.build() - balanceCall = Polkadot.Balance.newBuilder().apply { - transfer = call.build() - }.build() - multiAddress = true - } - - val output = AnySigner.sign(input.build(), POLKADOT, SigningOutput.parser()) - val encoded = Numeric.toHexString(output.encoded.toByteArray()) - - // https://acala.subscan.io/extrinsic/3893620-3 - val expected = "0x41028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900dd54466dffd1e3c80b76013e9459fbdcd17805bd5fdbca0961a643bad1cbd2b7fe005c62c51c18b67f31eb9e61b187a911952fee172ef18402d07c703eec3100d50200000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8" - assertEquals(encoded, expected) - } } diff --git a/docs/registry.md b/docs/registry.md index dfd7751a936..888ea526adb 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -65,6 +65,7 @@ This list is generated from [./registry.json](../registry.json) | 637 | Aptos | APT | | | | 714 | BNB Beacon Chain | BNB | | | | 784 | Sui | SUI | | | +| 787 | Acala | ACA | | | | 818 | VeChain | VET | | | | 820 | Callisto | CLO | | | | 888 | NEO | NEO | | | @@ -105,6 +106,7 @@ This list is generated from [./registry.json](../registry.json) | 10000324 | zkSync Era | ETH | | | | 10000330 | Terra | LUNA | | | | 10000553 | Huobi ECO Chain | HT | | | +| 10000787 | Acala EVM | ACA | | | | 10000990 | Coreum | CORE | | | | 10001088 | Metis | METIS | | | | 10001101 | Polygon zkEVM | ETH | | | diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h index af23f26ef92..9e54ea07f0e 100644 --- a/include/TrustWalletCore/TWCoinType.h +++ b/include/TrustWalletCore/TWCoinType.h @@ -166,6 +166,8 @@ enum TWCoinType { TWCoinTypeRootstock = 137, TWCoinTypeThetaFuel = 361, TWCoinTypeConfluxeSpace = 1030, + TWCoinTypeAcala = 787, + TWCoinTypeAcalaEVM = 10000787, }; /// Returns the blockchain for a coin type. diff --git a/registry.json b/registry.json index fc382a9d3a9..a0c585f264d 100644 --- a/registry.json +++ b/registry.json @@ -1924,6 +1924,67 @@ "documentation": "https://polkadot.js.org/api/substrate/rpc.html" } }, + { + "id": "acala", + "name": "Acala", + "coinId": 787, + "symbol": "ACA", + "decimals": 12, + "blockchain": "Polkadot", + "derivation": [ + { + "path": "m/44'/787'/0'/0'/0'" + } + ], + "curve": "ed25519", + "publicKeyType": "ed25519", + "addressHasher": "keccak256", + "ss58Prefix": 10, + "explorer": { + "url": "https://acala.subscan.io", + "txPath": "/extrinsic/", + "accountPath": "/account/", + "sampleTx": "0xf3d58aafb1208bc09d10ba74bbf1c7811dc55a9149c1505256b6fb5603f5047f", + "sampleAccount": "26JqMKx4HJJcmb1kXo24HYYobiK2jURGCq6zuEzFBK3hQ9Ti" + }, + "info": { + "url": "https://acala.network", + "source": "https://github.com/AcalaNetwork/Acala", + "rpc": "wss://acala-rpc.dwellir.com", + "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + } + }, + { + "id": "acalaevm", + "name": "Acala EVM", + "coinId": 10000787, + "slip44": 60, + "symbol": "ACA", + "decimals": 18, + "blockchain": "Ethereum", + "derivation": [ + { + "path": "m/44'/60'/0'/0/0" + } + ], + "curve": "secp256k1", + "publicKeyType": "secp256k1Extended", + "chainId": "787", + "addressHasher": "keccak256", + "explorer": { + "url": "https://blockscout.acala.network", + "txPath": "/tx/", + "accountPath": "/address/", + "sampleTx": "0x4b0b151dd71ed8ef3174da18565790bf14f0a903a13e4f3266c7848bc8841593", + "sampleAccount": "0x9d1d97aDFcd324Bbd603D3872BD78e04098510b1" + }, + "info": { + "url": "https://acala.network", + "source": "https://github.com/AcalaNetwork/Acala", + "rpc": "https://eth-rpc-acala.aca-api.network", + "documentation": "https://polkadot.js.org/api/substrate/rpc.html" + } + }, { "id": "aeternity", "name": "Aeternity", diff --git a/src/Polkadot/Entry.cpp b/src/Polkadot/Entry.cpp index b780059a240..14cf5f806ad 100644 --- a/src/Polkadot/Entry.cpp +++ b/src/Polkadot/Entry.cpp @@ -7,6 +7,7 @@ #include "Entry.h" #include "Address.h" +#include "Coin.h" #include "Signer.h" #include "../proto/TransactionCompiler.pb.h" @@ -14,22 +15,25 @@ namespace TW::Polkadot { // Note: avoid business logic from here, rather just call into classes like Address, Signer, etc. -bool Entry::validateAddress([[maybe_unused]] TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { +bool Entry::validateAddress(TWCoinType coin, const std::string& address, const PrefixVariant& addressPrefix) const { if (auto* prefix = std::get_if(&addressPrefix); prefix) { return Address::isValid(address, *prefix); } - return Address::isValid(address); + const auto ss58Prefix = TW::ss58Prefix(coin); + return Address::isValid(address, ss58Prefix); } -std::string Entry::deriveAddress([[maybe_unused]] TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { +std::string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, [[maybe_unused]] TWDerivation derivation, const PrefixVariant& addressPrefix) const { if (auto* ss58Prefix = std::get_if(&addressPrefix); ss58Prefix) { return Address(publicKey, *ss58Prefix).string(); } - return Address(publicKey).string(); + const auto ss58Prefix = TW::ss58Prefix(coin); + return Address(publicKey, ss58Prefix).string(); } -Data Entry::addressToData([[maybe_unused]] TWCoinType coin, const std::string& address) const { - const auto addr = Address(address); +Data Entry::addressToData(TWCoinType coin, const std::string& address) const { + const auto ss58Prefix = TW::ss58Prefix(coin); + const auto addr = Address(address, ss58Prefix); return {addr.bytes.begin() + 1, addr.bytes.end()}; } diff --git a/swift/Tests/Blockchains/AcalaEVMTests.swift b/swift/Tests/Blockchains/AcalaEVMTests.swift new file mode 100644 index 00000000000..bbf3bcab269 --- /dev/null +++ b/swift/Tests/Blockchains/AcalaEVMTests.swift @@ -0,0 +1,19 @@ +// 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. + +import WalletCore +import XCTest + +class AcalaEVMTests: XCTestCase { + func testAddress() { + let key = PrivateKey(data: Data(hexString: "828c4c48c2cef521f0251920891ed79e871faa24f64f43cde83d07bc99f8dbf0")!)! + let pubkey = key.getPublicKeySecp256k1(compressed: false) + let address = AnyAddress(publicKey: pubkey, coin: .acalaEVM) + let expected = AnyAddress(string: "0xe32DC46bfBF78D1eada7b0a68C96903e01418D64", coin: .acalaEVM)! + + XCTAssertEqual(address.description, expected.description) + } +} diff --git a/swift/Tests/Blockchains/AcalaTests.swift b/swift/Tests/Blockchains/AcalaTests.swift new file mode 100644 index 00000000000..c31d4fb3dbd --- /dev/null +++ b/swift/Tests/Blockchains/AcalaTests.swift @@ -0,0 +1,57 @@ +// 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. + +import WalletCore +import XCTest + +class AcalaTests: XCTestCase { + + let genesisHash = Data(hexString: "0xfc41b9bd8ef8fe53d58c7ea67c794c7ec9a73daf05e6d54b14ff6342c99ba64c")! + + func testAddress() { + let key = PrivateKey(data: Data(hexString: "0x9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0")!)! + let pubkey = key.getPublicKeyEd25519() + let address = AnyAddress(publicKey: pubkey, coin: .acala) + let addressFromString = AnyAddress(string: "269ZCS3WLGydTN8ynhyhZfzJrXkePUcdhwgLQs6TWFs5wVL5", coin: .acala)! + + XCTAssertEqual(address.description, addressFromString.description) + XCTAssertEqual(address.data, pubkey.data) + } + + func testSigning() { + // real key in 1p test + let key = PrivateKey(data: Data(hexString: "9066aa168c379a403becb235c15e7129c133c244e56a757ab07bc369288bcab0")!)! + + let input = PolkadotSigningInput.with { + $0.genesisHash = genesisHash + $0.blockHash = Data(hexString: "0x707ffa05b7dc6cdb6356bd8bd51ff20b2757c3214a76277516080a10f1bc7537")! + $0.era = PolkadotEra.with { + $0.blockNumber = 3893613 + $0.period = 64 + } + $0.nonce = 0 + $0.specVersion = 2170 + $0.network = CoinType.acala.ss58Prefix + $0.transactionVersion = 2 + $0.privateKey = key.data + $0.balanceCall.transfer = PolkadotBalance.Transfer.with { + $0.value = Data(hexString: "0xe8d4a51000")! // 1 ACA + $0.toAddress = "25Qqz3ARAvnZbahGZUzV3xpP1bB3eRrupEprK7f2FNbHbvsz" + $0.callIndices = PolkadotCallIndices.with { + $0.custom = PolkadotCustomCallIndices.with { + $0.moduleIndex = 0x0a + $0.methodIndex = 0x00 + } + } + } + $0.multiAddress = true + } + let output: PolkadotSigningOutput = AnySigner.sign(input: input, coin: .polkadot) + + // https://acala.subscan.io/extrinsic/3893620-3 + XCTAssertEqual("0x" + output.encoded.hexString, "0x41028400e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a900dd54466dffd1e3c80b76013e9459fbdcd17805bd5fdbca0961a643bad1cbd2b7fe005c62c51c18b67f31eb9e61b187a911952fee172ef18402d07c703eec3100d50200000a0000c8c602ded977c56076ae38d98026fa669ca10d6a2b5a0bfc4086ae7668ed1c60070010a5d4e8") + } +} diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift index f9b6eb6edc0..26c5b37d7b8 100644 --- a/swift/Tests/CoinAddressDerivationTests.swift +++ b/swift/Tests/CoinAddressDerivationTests.swift @@ -19,6 +19,9 @@ class CoinAddressDerivationTests: XCTestCase { let address = coin.address(string: derivedAddress) switch coin { + case .acala: + let expectedResult = "25GGezx3LWFQj6HZpYzoWoVzLsHojGtybef3vthC9nd19ms3" + assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .aeternity: let expectedResult = "ak_QDHJSfvHG9sDHBobaWt2TAGhuhipYjEqZEH34bWugpJfJc3GN" assertCoinDerivation(coin, expectedResult, derivedAddress, address) @@ -102,7 +105,8 @@ class CoinAddressDerivationTests: XCTestCase { .klaytn, .meter, .okxchain, - .confluxeSpace: + .confluxeSpace, + .acalaEVM: let expectedResult = "0x8f348F300873Fd5DA36950B2aC75a26584584feE" assertCoinDerivation(coin, expectedResult, derivedAddress, address) case .ronin: diff --git a/tests/chains/Acala/TWAnyAddressTests.cpp b/tests/chains/Acala/TWAnyAddressTests.cpp index ce409569c51..4cfd209e673 100644 --- a/tests/chains/Acala/TWAnyAddressTests.cpp +++ b/tests/chains/Acala/TWAnyAddressTests.cpp @@ -6,10 +6,8 @@ #include #include -#include "HexCoding.h" #include "Hash.h" #include "PublicKey.h" -#include "Bech32Address.h" #include "TestUtilities.h" #include @@ -20,12 +18,31 @@ inline constexpr uint32_t acalaPrefix{10}; TEST(TWAcalaAnyAddress, IsValid) { EXPECT_TRUE(TWAnyAddressIsValidSS58(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypePolkadot, acalaPrefix)); + EXPECT_TRUE(TWAnyAddressIsValid(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypeAcala)); EXPECT_FALSE(TWAnyAddressIsValid(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypePolkadot)); EXPECT_FALSE(TWAnyAddressIsValid(STRING("212ywJGVK2Nxnt5bjKXVHi4YY7FCFd4rVvhyt95CjpeHGZee").get(), TWCoinTypeBitcoin)); EXPECT_FALSE(TWAnyAddressIsValidSS58(STRING("15KRsCq9LLNmCxNFhGk55s5bEyazKefunDxUH24GFZwsTxyu").get(), TWCoinTypePolkadot, acalaPrefix)); } -TEST(TWAcalaAnyAddress, createFromPubKeyAcala) { +TEST(TWAcalaAnyAddress, createFromPubKey) { + const auto data = DATA("e9590e4d99264a14a85e21e69537e4a64f66a875d38cb8f76b305f41fabe24a9"); + const auto pubkey = WRAP(TWPublicKey, TWPublicKeyCreateWithData(data.get(), TWPublicKeyTypeED25519)); + const auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(pubkey.get(), TWCoinTypeAcala)); + const auto addrDescription = TWAnyAddressDescription(addr.get()); + EXPECT_EQ("269ZCS3WLGydTN8ynhyhZfzJrXkePUcdhwgLQs6TWFs5wVL5", *reinterpret_cast(addrDescription)); +} + +TEST(TWAcalaAnyAddress, createFromString) { + const auto acalaAddress = STRING("24CKv1LJ1T3U9ujCN63YzTPuQjcmURGA2xTjim98UKXxgNXT"); + const auto anyAddr = TWAnyAddressCreateWithString(acalaAddress.get(), TWCoinTypeAcala); + const auto addrDescription = TWAnyAddressDescription(anyAddr); + ASSERT_TRUE(TWAnyAddressIsValidSS58(addrDescription, TWCoinTypePolkadot, acalaPrefix)); + ASSERT_TRUE(TWAnyAddressIsValid(addrDescription, TWCoinTypeAcala)); + TWStringDelete(addrDescription); + TWAnyAddressDelete(anyAddr); +} + +TEST(TWAcalaAnyAddress, createFromPubKeyAcalaPrefix) { const auto data = DATA("92fd9c237030356e26cfcc4568dc71055d5ec92dfe0ff903767e00611971bad3"); const auto pubkey = TWPublicKeyCreateWithData(data.get(), TWPublicKeyTypeED25519); const auto twAddress = TWAnyAddressCreateSS58WithPublicKey(pubkey, TWCoinTypePolkadot, acalaPrefix); @@ -36,7 +53,7 @@ TEST(TWAcalaAnyAddress, createFromPubKeyAcala) { TWPublicKeyDelete(pubkey); } -TEST(TWAcalaAnyAddress, createFromStringAcala) { +TEST(TWAcalaAnyAddress, createFromStringAcalaPrefix) { const auto acalaAddress = STRING("24CKv1LJ1T3U9ujCN63YzTPuQjcmURGA2xTjim98UKXxgNXT"); const auto anyAddr = TWAnyAddressCreateSS58(acalaAddress.get(), TWCoinTypePolkadot, acalaPrefix); const auto addrDescription = TWAnyAddressDescription(anyAddr); diff --git a/tests/chains/Acala/TWCoinTypeTests.cpp b/tests/chains/Acala/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..3e8e742b209 --- /dev/null +++ b/tests/chains/Acala/TWCoinTypeTests.cpp @@ -0,0 +1,35 @@ +// 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. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWAcalaCoinType, TWCoinType) { + const auto coin = TWCoinTypeAcala; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0xf3d58aafb1208bc09d10ba74bbf1c7811dc55a9149c1505256b6fb5603f5047f")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("26JqMKx4HJJcmb1kXo24HYYobiK2jURGCq6zuEzFBK3hQ9Ti")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "acala"); + assertStringsEqual(name, "Acala"); + assertStringsEqual(symbol, "ACA"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 12); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainPolkadot); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(txUrl, "https://acala.subscan.io/extrinsic/0xf3d58aafb1208bc09d10ba74bbf1c7811dc55a9149c1505256b6fb5603f5047f"); + assertStringsEqual(accUrl, "https://acala.subscan.io/account/26JqMKx4HJJcmb1kXo24HYYobiK2jURGCq6zuEzFBK3hQ9Ti"); +} diff --git a/tests/chains/AcalaEVM/TWCoinTypeTests.cpp b/tests/chains/AcalaEVM/TWCoinTypeTests.cpp new file mode 100644 index 00000000000..3ea2f79b595 --- /dev/null +++ b/tests/chains/AcalaEVM/TWCoinTypeTests.cpp @@ -0,0 +1,37 @@ +// 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. +// +// This is a GENERATED FILE, changes made here MAY BE LOST. +// Generated one-time (codegen/bin/cointests) +// + +#include "TestUtilities.h" +#include +#include + + +TEST(TWAcalaEVMCoinType, TWCoinType) { + const auto coin = TWCoinTypeAcalaEVM; + const auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(coin)); + const auto id = WRAPS(TWCoinTypeConfigurationGetID(coin)); + const auto name = WRAPS(TWCoinTypeConfigurationGetName(coin)); + const auto chainId = WRAPS(TWCoinTypeChainId(coin)); + const auto txId = WRAPS(TWStringCreateWithUTF8Bytes("0x4b0b151dd71ed8ef3174da18565790bf14f0a903a13e4f3266c7848bc8841593")); + const auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(coin, txId.get())); + const auto accId = WRAPS(TWStringCreateWithUTF8Bytes("0x9d1d97aDFcd324Bbd603D3872BD78e04098510b1")); + const auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(coin, accId.get())); + + assertStringsEqual(id, "acalaevm"); + assertStringsEqual(name, "Acala EVM"); + assertStringsEqual(symbol, "ACA"); + ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(coin), 18); + ASSERT_EQ(TWCoinTypeBlockchain(coin), TWBlockchainEthereum); + ASSERT_EQ(TWCoinTypeP2shPrefix(coin), 0x0); + ASSERT_EQ(TWCoinTypeStaticPrefix(coin), 0x0); + assertStringsEqual(chainId, "787"); + assertStringsEqual(txUrl, "https://blockscout.acala.network/tx/0x4b0b151dd71ed8ef3174da18565790bf14f0a903a13e4f3266c7848bc8841593"); + assertStringsEqual(accUrl, "https://blockscout.acala.network/address/0x9d1d97aDFcd324Bbd603D3872BD78e04098510b1"); +} diff --git a/tests/common/CoinAddressDerivationTests.cpp b/tests/common/CoinAddressDerivationTests.cpp index ffd8f49fec2..00e2c854d16 100644 --- a/tests/common/CoinAddressDerivationTests.cpp +++ b/tests/common/CoinAddressDerivationTests.cpp @@ -37,6 +37,7 @@ TEST(Coin, DeriveAddress) { // Ethereum and ... case TWCoinTypeEthereum: // ... clones: + case TWCoinTypeAcalaEVM: case TWCoinTypeArbitrum: case TWCoinTypeAurora: case TWCoinTypeAvalancheCChain: @@ -101,7 +102,9 @@ TEST(Coin, DeriveAddress) { case TWCoinTypeKomodo: EXPECT_EQ(address, "RSZYjMDCP4q3t7NAFXPPnqEGrMZn971pdB"); break; - + case TWCoinTypeAcala: + EXPECT_EQ(address, "26GQqmwt3154cQbG2fyBsh3cGuCBoRFtrwuCD6WcVJdFReA4"); + break; case TWCoinTypeAeternity: EXPECT_EQ(address, "ak_2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5FeVfcw"); break; From 9868fd384aaa46d0873e9e804fb2e629d5e7740d Mon Sep 17 00:00:00 2001 From: Satoshi Otomakan Date: Thu, 29 Jun 2023 13:58:50 +0200 Subject: [PATCH 2/3] feat(Acala): Fix memory leak, freeze rust toolchain --- tests/chains/Acala/TWAnyAddressTests.cpp | 1 + tools/install-rust-dependencies | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/chains/Acala/TWAnyAddressTests.cpp b/tests/chains/Acala/TWAnyAddressTests.cpp index 4cfd209e673..f3ddc35b6cd 100644 --- a/tests/chains/Acala/TWAnyAddressTests.cpp +++ b/tests/chains/Acala/TWAnyAddressTests.cpp @@ -30,6 +30,7 @@ TEST(TWAcalaAnyAddress, createFromPubKey) { const auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithPublicKey(pubkey.get(), TWCoinTypeAcala)); const auto addrDescription = TWAnyAddressDescription(addr.get()); EXPECT_EQ("269ZCS3WLGydTN8ynhyhZfzJrXkePUcdhwgLQs6TWFs5wVL5", *reinterpret_cast(addrDescription)); + TWStringDelete(addrDescription); } TEST(TWAcalaAnyAddress, createFromString) { diff --git a/tools/install-rust-dependencies b/tools/install-rust-dependencies index 95f33653fcd..e946e143c83 100755 --- a/tools/install-rust-dependencies +++ b/tools/install-rust-dependencies @@ -2,14 +2,19 @@ set -e +TOOLCHAIN_STABLE="stable-2023-06-01" +TOOLCHAIN_NIGHTLY="nightly-2023-06-27" + if [[ `uname` == "Darwin" || "$1" == "dev" ]]; then - rustup update - rustup toolchain install nightly - rustup default nightly + rustup toolchain install $TOOLCHAIN_NIGHTLY + rustup default $TOOLCHAIN_NIGHTLY rustup toolchain install nightly-x86_64-apple-darwin --force-non-host rustup toolchain install nightly-aarch64-apple-darwin --force-non-host rustup component add rust-src --toolchain nightly-aarch64-apple-darwin rustup component add rust-src --toolchain nightly-x86_64-apple-darwin +else + rustup toolchain install $TOOLCHAIN_STABLE + rustup default $TOOLCHAIN_STABLE fi # Android From 08220d4bb1f1840cf7afc10895e8502d9147da27 Mon Sep 17 00:00:00 2001 From: Satoshi Otomakan Date: Thu, 29 Jun 2023 14:36:49 +0200 Subject: [PATCH 3/3] Fix `aarch64-apple-ios-macabi`, `x86_64-apple-ios-macabi` build --- tools/install-rust-dependencies | 20 ++++++++++---------- tools/rust-bindgen | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/install-rust-dependencies b/tools/install-rust-dependencies index e946e143c83..32fe675512d 100755 --- a/tools/install-rust-dependencies +++ b/tools/install-rust-dependencies @@ -2,19 +2,19 @@ set -e -TOOLCHAIN_STABLE="stable-2023-06-01" -TOOLCHAIN_NIGHTLY="nightly-2023-06-27" +STABLE="stable-2023-06-01" +NIGHTLY="nightly-2023-06-27" if [[ `uname` == "Darwin" || "$1" == "dev" ]]; then - rustup toolchain install $TOOLCHAIN_NIGHTLY - rustup default $TOOLCHAIN_NIGHTLY - rustup toolchain install nightly-x86_64-apple-darwin --force-non-host - rustup toolchain install nightly-aarch64-apple-darwin --force-non-host - rustup component add rust-src --toolchain nightly-aarch64-apple-darwin - rustup component add rust-src --toolchain nightly-x86_64-apple-darwin + rustup toolchain install $NIGHTLY + rustup default $NIGHTLY + rustup toolchain install $NIGHTLY-x86_64-apple-darwin --force-non-host + rustup toolchain install $NIGHTLY-aarch64-apple-darwin --force-non-host + rustup component add rust-src --toolchain $NIGHTLY-aarch64-apple-darwin + rustup component add rust-src --toolchain $NIGHTLY-x86_64-apple-darwin else - rustup toolchain install $TOOLCHAIN_STABLE - rustup default $TOOLCHAIN_STABLE + rustup toolchain install $STABLE + rustup default $STABLE fi # Android diff --git a/tools/rust-bindgen b/tools/rust-bindgen index 431df1a44e9..02546de6b1a 100755 --- a/tools/rust-bindgen +++ b/tools/rust-bindgen @@ -97,7 +97,7 @@ fi if [[ "$IOS" == "true" ]]; then echo "Generating iOS targets" cargo build --target aarch64-apple-ios --target aarch64-apple-ios-sim --target x86_64-apple-ios --target aarch64-apple-darwin --target x86_64-apple-darwin --release & - cargo +nightly build -Z build-std --target aarch64-apple-ios-macabi --target x86_64-apple-ios-macabi --release & + cargo build -Z build-std --target aarch64-apple-ios-macabi --target x86_64-apple-ios-macabi --release & wait lipo $BUILD_FOLDER/x86_64-apple-ios/release/$TARGET_NAME $BUILD_FOLDER/aarch64-apple-ios-sim/release/$TARGET_NAME -create -output $BUILD_FOLDER/$TARGET_NAME mkdir -p $BUILD_FOLDER/darwin_universal