From 72c8b9e6513474521506ce79e5844a368f42a04c Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Mon, 30 Mar 2020 19:19:04 +0800
Subject: [PATCH 01/81] Update FIO block explorer url (#903)
* :wrench: update FIO block explorer url
* update coins.md
---
coins.json | 18 ++++++++----------
docs/coins.md | 2 +-
samples/android/app/build.gradle | 2 +-
swift/Podfile.lock | 2 +-
tests/FIO/TWCoinTypeTests.cpp | 8 ++++----
5 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/coins.json b/coins.json
index 5fc87eb88cb..a5a3c759d8e 100644
--- a/coins.json
+++ b/coins.json
@@ -858,7 +858,6 @@
"curve": "ed25519Blake2bNano",
"publicKeyType": "ed25519Blake2b",
"url": "https://nano.org",
- "rpcNodeInfo": "https://github.com/nanocurrency/nano-node",
"explorer": {
"url": "https://nanocrawler.cc",
"txPath": "/explorer/block/",
@@ -1073,18 +1072,17 @@
"derivationPath": "m/44'/235'/0'/0/0",
"curve": "secp256k1",
"publicKeyType": "secp256k1",
- "url": "https://fio.foundation",
- "rpcNodeInfo": "https://fio.foundation",
+ "url": "https://fioprotocol.io/",
"explorer": {
- "url": "https://fio.foundation",
- "txPath": "/?",
- "accountPath": "/?"
+ "url": "https://explorer.fioprotocol.io",
+ "txPath": "/transaction/",
+ "accountPath": "/account/"
},
"info": {
- "url": "https://fio.foundation",
- "client": "https://fio.foundation",
- "clientPublic": "",
- "clientDocs": "https://fio.foundation"
+ "url": "https://fioprotocol.io",
+ "client": "https://github.com/fioprotocol/fio",
+ "clientPublic": "https://mainnet.fioprotocol.io",
+ "clientDocs": "https://developers.fioprotocol.io"
}
},
{
diff --git a/docs/coins.md b/docs/coins.md
index bd8b83ac4f5..2fae8caf2e8 100644
--- a/docs/coins.md
+++ b/docs/coins.md
@@ -27,7 +27,7 @@ This list is generated from [./coins.json](../coins.json)
| 178 | POA Network | POA | | |
| 194 | EOS | EOS | | |
| 195 | Tron | TRX | | |
-| 235 | FIO | FIO | | |
+| 235 | FIO | FIO | | |
| 242 | Nimiq | NIM | | |
| 283 | Algorand | ALGO | | |
| 304 | IoTeX | IOTX | | |
diff --git a/samples/android/app/build.gradle b/samples/android/app/build.gradle
index 53d7c729e47..6dcd7757e4a 100644
--- a/samples/android/app/build.gradle
+++ b/samples/android/app/build.gradle
@@ -24,7 +24,7 @@ android {
}
project.ext {
- walletcore_version = "2.0.3"
+ walletcore_version = "2.0.5"
}
dependencies {
diff --git a/swift/Podfile.lock b/swift/Podfile.lock
index 9250a5e40a0..46f957ed3b2 100644
--- a/swift/Podfile.lock
+++ b/swift/Podfile.lock
@@ -17,4 +17,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 9af33e2495c8b16bfcea0f7779a0fcfe29e3ab60
-COCOAPODS: 1.9.0
+COCOAPODS: 1.9.1
diff --git a/tests/FIO/TWCoinTypeTests.cpp b/tests/FIO/TWCoinTypeTests.cpp
index 60c5bf35440..b7bdaa4469a 100644
--- a/tests/FIO/TWCoinTypeTests.cpp
+++ b/tests/FIO/TWCoinTypeTests.cpp
@@ -15,9 +15,9 @@
TEST(TWFIOCoinType, TWCoinType) {
auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeFIO));
- auto txId = TWStringCreateWithUTF8Bytes("t123");
+ auto txId = TWStringCreateWithUTF8Bytes("930d1d3cf8988b39b5f64b64e9d61314a3e05a155d9e3505bdf863aab1adddf3");
auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeFIO, txId));
- auto accId = TWStringCreateWithUTF8Bytes("a12");
+ auto accId = TWStringCreateWithUTF8Bytes("f5axfpgffiqz");
auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeFIO, accId));
auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeFIO));
auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeFIO));
@@ -27,8 +27,8 @@ TEST(TWFIOCoinType, TWCoinType) {
ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeFIO));
ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeFIO));
assertStringsEqual(symbol, "FIO");
- assertStringsEqual(txUrl, "https://fio.foundation/?t123");
- assertStringsEqual(accUrl, "https://fio.foundation/?a12");
+ assertStringsEqual(txUrl, "https://explorer.fioprotocol.io/transaction/930d1d3cf8988b39b5f64b64e9d61314a3e05a155d9e3505bdf863aab1adddf3");
+ assertStringsEqual(accUrl, "https://explorer.fioprotocol.io/account/f5axfpgffiqz");
assertStringsEqual(id, "fio");
assertStringsEqual(name, "FIO");
}
From 72846ba7bc19f4f83cf88e764ae084fa76243146 Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Sat, 4 Apr 2020 14:56:31 +0800
Subject: [PATCH 02/81] Update zcash/xlm block explorer (#915)
* update zcash/xlm block explorer
* Fix tests
---
coins.json | 8 ++++----
tests/Stellar/TWCoinTypeTests.cpp | 8 ++++----
tests/Zcash/TWCoinTypeTests.cpp | 8 ++++----
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/coins.json b/coins.json
index a5a3c759d8e..18047f66535 100644
--- a/coins.json
+++ b/coins.json
@@ -571,9 +571,9 @@
"xpub": "xpub",
"xprv": "xprv",
"explorer": {
- "url": "https://sochain.com",
- "txPath": "/tx/ZEC/",
- "accountPath": "/address/ZEC/"
+ "url": "https://blockchair.com/zcash",
+ "txPath": "/transaction/",
+ "accountPath": "/address/"
},
"info": {
"url": "https://z.cash",
@@ -682,7 +682,7 @@
"curve": "ed25519",
"publicKeyType": "ed25519",
"explorer": {
- "url": "https://stellarscan.io",
+ "url": "https://blockchair.com/stellar",
"txPath": "/transaction/",
"accountPath": "/account/"
},
diff --git a/tests/Stellar/TWCoinTypeTests.cpp b/tests/Stellar/TWCoinTypeTests.cpp
index a93bbfdbefa..52397d75d8a 100644
--- a/tests/Stellar/TWCoinTypeTests.cpp
+++ b/tests/Stellar/TWCoinTypeTests.cpp
@@ -15,9 +15,9 @@
TEST(TWStellarCoinType, TWCoinType) {
auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeStellar));
- auto txId = TWStringCreateWithUTF8Bytes("t123");
+ auto txId = TWStringCreateWithUTF8Bytes("d9aeabfa9d24df8c5755125f8af243b74cd3ff878656cfa72c566a8824bf6e84");
auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeStellar, txId));
- auto accId = TWStringCreateWithUTF8Bytes("a12");
+ auto accId = TWStringCreateWithUTF8Bytes("GCILJZQ3CKBKBUJWW4TAM6Q37LJA5MQX6GMSFSQN75BPLWIZ33OPRG52");
auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeStellar, accId));
auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeStellar));
auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeStellar));
@@ -27,8 +27,8 @@ TEST(TWStellarCoinType, TWCoinType) {
ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeStellar));
ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeStellar));
assertStringsEqual(symbol, "XLM");
- assertStringsEqual(txUrl, "https://stellarscan.io/transaction/t123");
- assertStringsEqual(accUrl, "https://stellarscan.io/account/a12");
+ assertStringsEqual(txUrl, "https://blockchair.com/stellar/transaction/d9aeabfa9d24df8c5755125f8af243b74cd3ff878656cfa72c566a8824bf6e84");
+ assertStringsEqual(accUrl, "https://blockchair.com/stellar/account/GCILJZQ3CKBKBUJWW4TAM6Q37LJA5MQX6GMSFSQN75BPLWIZ33OPRG52");
assertStringsEqual(id, "stellar");
assertStringsEqual(name, "Stellar");
}
diff --git a/tests/Zcash/TWCoinTypeTests.cpp b/tests/Zcash/TWCoinTypeTests.cpp
index fc887dd9891..da6af47b0d6 100644
--- a/tests/Zcash/TWCoinTypeTests.cpp
+++ b/tests/Zcash/TWCoinTypeTests.cpp
@@ -15,9 +15,9 @@
TEST(TWZcashCoinType, TWCoinType) {
auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeZcash));
- auto txId = TWStringCreateWithUTF8Bytes("t123");
+ auto txId = TWStringCreateWithUTF8Bytes("f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35");
auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeZcash, txId));
- auto accId = TWStringCreateWithUTF8Bytes("a12");
+ auto accId = TWStringCreateWithUTF8Bytes("t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2");
auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeZcash, accId));
auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeZcash));
auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeZcash));
@@ -27,8 +27,8 @@ TEST(TWZcashCoinType, TWCoinType) {
ASSERT_EQ(0xbd, TWCoinTypeP2shPrefix(TWCoinTypeZcash));
ASSERT_EQ(0x1c, TWCoinTypeStaticPrefix(TWCoinTypeZcash));
assertStringsEqual(symbol, "ZEC");
- assertStringsEqual(txUrl, "https://sochain.com/tx/ZEC/t123");
- assertStringsEqual(accUrl, "https://sochain.com/address/ZEC/a12");
+ assertStringsEqual(txUrl, "https://blockchair.com/zcash/transaction/f2438a93039faf08d39bd3df1f7b5f19a2c29ffe8753127e2956ab4461adab35");
+ assertStringsEqual(accUrl, "https://blockchair.com/zcash/address/t1Yfrf1dssDLmaMBsq2LFKWPbS5vH3nGpa2");
assertStringsEqual(id, "zcash");
assertStringsEqual(name, "Zcash");
}
From d3e86ea4007c271d763d7832fa4181b222c75329 Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Mon, 6 Apr 2020 16:27:45 +0800
Subject: [PATCH 03/81] Change password type from string to data (#917)
---
.../core/app/utils/TestKeyStore.kt | 44 ++++++++++--
include/TrustWalletCore/TWStoredKey.h | 42 ++++++------
src/Keystore/EncryptionParameters.cpp | 8 +--
src/Keystore/EncryptionParameters.h | 4 +-
src/Keystore/StoredKey.cpp | 18 ++---
src/Keystore/StoredKey.h | 18 ++---
src/interface/TWStoredKey.cpp | 48 ++++++-------
swift/Sources/KeyStore.swift | 26 +++----
swift/Sources/Wallet.swift | 6 +-
swift/Tests/Keystore/AccountTests.swift | 9 +--
swift/Tests/Keystore/KeyStoreTests.swift | 12 ++--
swift/Tests/Keystore/KeystoreKeyTests.swift | 68 +++++++++++++++++--
swift/Tests/Keystore/WalletTests.swift | 2 +-
.../Data/ethereum-wallet-address-no-0x.json | 26 ++++++-
tests/Keystore/Data/myetherwallet.uu | 22 +++++-
tests/Keystore/Data/web3j.json | 21 ++++++
tests/Keystore/StoredKeyTests.cpp | 24 +++++--
tests/interface/TWStoredKeyTests.cpp | 60 ++++++++++------
18 files changed, 321 insertions(+), 137 deletions(-)
create mode 100644 tests/Keystore/Data/web3j.json
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt
index 3a19d9c2218..3832db95139 100644
--- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt
@@ -13,9 +13,9 @@ class TestKeyStore {
@Test
fun testDecryptMnemonic() {
- val keyStore = StoredKey("Test Wallet", "password")
- val result = keyStore.decryptMnemonic("wrong")
- val result2 = keyStore.decryptMnemonic("password")
+ val keyStore = StoredKey("Test Wallet", "password".toByteArray())
+ val result = keyStore.decryptMnemonic("wrong".toByteArray())
+ val result2 = keyStore.decryptMnemonic("password".toByteArray())
assertNull(result)
assertNotNull(result2)
@@ -23,7 +23,7 @@ class TestKeyStore {
@Test
fun testRemoveCoins() {
- val password = "password"
+ val password = "password".toByteArray()
val keyStore = StoredKey("Test Wallet", password)
val wallet = keyStore.wallet(password)
@@ -37,15 +37,47 @@ class TestKeyStore {
assertEquals(keyStore.account(0).coin(), CoinType.ETHEREUM)
}
+ @Test
+ fun testLongHexPassword() {
+ val json = """
+ {
+ "address": "34bae2218c254ed190c0f5b1dd4323aee8e7da09",
+ "id": "86066d8c-8dba-4d81-afd4-934e2a2b72a2",
+ "version": 3,
+ "crypto": {
+ "cipher": "aes-128-ctr",
+ "cipherparams": {
+ "iv": "a4976ad73057007ad788d1f792db851d"
+ },
+ "ciphertext": "5e4458d69964172c492616b751d6589b4ad7da4217dcfccecc3f4e515a934bb8",
+ "kdf": "scrypt",
+ "kdfparams": {
+ "dklen": 32,
+ "n": 4096,
+ "p": 6,
+ "r": 8,
+ "salt": "24c72d92bf88a4f7c7b3f5e3cb3620714d71fceabbb0bc6099f50c6d5d898e7c"
+ },
+ "mac": "c15e3035ddcaca766dfc56648978d33e94d3c57d4a5e13fcf8b5f8dbb0902900"
+ }
+ }
+ """.trimIndent()
+ val password = "2d6eefbfbd4622efbfbdefbfbd516718efbfbdefbfbdefbfbdefbfbd59efbfbd30efbfbdefbfbd3a4348efbfbd2aefbfbdefbfbd49efbfbd27efbfbd0638efbfbdefbfbdefbfbd4cefbfbd6befbfbdefbfbd6defbfbdefbfbd63efbfbd5aefbfbd61262b70efbfbdefbfbdefbfbdefbfbdefbfbdc7aa373163417cefbfbdefbfbdefbfbd44efbfbdefbfbd1d10efbfbdefbfbdefbfbd61dc9e5b124befbfbd11efbfbdefbfbd2fefbfbdefbfbd3d7c574868efbfbdefbfbdefbfbd37043b7b5c1a436471592f02efbfbd18efbfbdefbfbd2befbfbdefbfbd7218efbfbd6a68efbfbdcb8e5f3328773ec48174efbfbd67efbfbdefbfbdefbfbdefbfbdefbfbd2a31efbfbd7f60efbfbdd884efbfbd57efbfbd25efbfbd590459efbfbd37efbfbd2bdca20fefbfbdefbfbdefbfbdefbfbd39450113efbfbdefbfbdefbfbd454671efbfbdefbfbdd49fefbfbd47efbfbdefbfbdefbfbdefbfbd00efbfbdefbfbdefbfbdefbfbd05203f4c17712defbfbd7bd1bbdc967902efbfbdc98a77efbfbd707a36efbfbd12efbfbdefbfbd57c78cefbfbdefbfbdefbfbd10efbfbdefbfbdefbfbde1a1bb08efbfbdefbfbd26efbfbdefbfbd58efbfbdefbfbdc4b1efbfbd295fefbfbd0eefbfbdefbfbdefbfbd0e6eefbfbd"
+ val pass = password.toHexByteArray()
+ val keyStore = StoredKey.importJSON(json.toByteArray())
+ val privateKey = keyStore.decryptPrivateKey(pass)
+ assertEquals(privateKey.toHex(), "0x043c5429c7872502531708ec0d821c711691402caf37ef7ba78a8c506f10653b")
+ }
+
@Test
fun testExportJSON() {
- val password = "password"
+ val password = "password".toByteArray()
val keyStore = StoredKey("Test Wallet", password)
val json = keyStore.exportJSON()
assertNotNull(json)
val newKeyStore = StoredKey.importJSON(json)
- val privateKey = newKeyStore.decryptPrivateKey("")
+ val privateKey = newKeyStore.decryptPrivateKey("".toByteArray())
assertNull(privateKey)
}
}
diff --git a/include/TrustWalletCore/TWStoredKey.h b/include/TrustWalletCore/TWStoredKey.h
index 784339fd6e0..bb2048d236f 100644
--- a/include/TrustWalletCore/TWStoredKey.h
+++ b/include/TrustWalletCore/TWStoredKey.h
@@ -21,88 +21,88 @@ struct TWStoredKey;
/// Loads a key from a file.
TW_EXPORT_STATIC_METHOD
-struct TWStoredKey *_Nullable TWStoredKeyLoad(TWString *_Nonnull path);
+struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path);
/// Imports a private key.
TW_EXPORT_STATIC_METHOD
-struct TWStoredKey *_Nullable TWStoredKeyImportPrivateKey(TWData *_Nonnull privateKey, TWString *_Nonnull name, TWString *_Nonnull password, enum TWCoinType coin);
+struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin);
/// Imports an HD wallet.
TW_EXPORT_STATIC_METHOD
-struct TWStoredKey *_Nullable TWStoredKeyImportHDWallet(TWString *_Nonnull mnemonic, TWString *_Nonnull name, TWString *_Nonnull password, enum TWCoinType coin);
+struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin);
/// Imports a key from JSON.
TW_EXPORT_STATIC_METHOD
-struct TWStoredKey *_Nullable TWStoredKeyImportJSON(TWData *_Nonnull json);
+struct TWStoredKey* _Nullable TWStoredKeyImportJSON(TWData* _Nonnull json);
/// Creates a new key.
TW_EXPORT_STATIC_METHOD
-struct TWStoredKey *_Nonnull TWStoredKeyCreate(TWString *_Nonnull name, TWString *_Nonnull password);
+struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password);
TW_EXPORT_METHOD
-void TWStoredKeyDelete(struct TWStoredKey *_Nonnull key);
+void TWStoredKeyDelete(struct TWStoredKey* _Nonnull key);
/// Stored key uniqie identifier.
TW_EXPORT_PROPERTY
-TWString *_Nullable TWStoredKeyIdentifier(struct TWStoredKey *_Nonnull key);
+TWString* _Nullable TWStoredKeyIdentifier(struct TWStoredKey* _Nonnull key);
/// Stored key namer.
TW_EXPORT_PROPERTY
-TWString *_Nonnull TWStoredKeyName(struct TWStoredKey *_Nonnull key);
+TWString* _Nonnull TWStoredKeyName(struct TWStoredKey* _Nonnull key);
/// Whether this key is a mnemonic phrase for a HD wallet.
TW_EXPORT_PROPERTY
-bool TWStoredKeyIsMnemonic(struct TWStoredKey *_Nonnull key);
+bool TWStoredKeyIsMnemonic(struct TWStoredKey* _Nonnull key);
/// The number of accounts.
TW_EXPORT_PROPERTY
-size_t TWStoredKeyAccountCount(struct TWStoredKey *_Nonnull key);
+size_t TWStoredKeyAccountCount(struct TWStoredKey* _Nonnull key);
/// Returns the account at a given index.
TW_EXPORT_METHOD
-struct TWAccount *_Nullable TWStoredKeyAccount(struct TWStoredKey *_Nonnull key, size_t index);
+struct TWAccount* _Nullable TWStoredKeyAccount(struct TWStoredKey* _Nonnull key, size_t index);
/// Returns the account for a specific coin, creating it if necessary.
TW_EXPORT_METHOD
-struct TWAccount *_Nullable TWStoredKeyAccountForCoin(struct TWStoredKey *_Nonnull key, enum TWCoinType coin, struct TWHDWallet *_Nullable wallet);
+struct TWAccount* _Nullable TWStoredKeyAccountForCoin(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, struct TWHDWallet* _Nullable wallet);
/// Remove the account for a specific coin
TW_EXPORT_METHOD
-void TWStoredKeyRemoveAccountForCoin(struct TWStoredKey *_Nonnull key, enum TWCoinType coin);
+void TWStoredKeyRemoveAccountForCoin(struct TWStoredKey* _Nonnull key, enum TWCoinType coin);
/// Adds a new account.
TW_EXPORT_METHOD
-void TWStoredKeyAddAccount(struct TWStoredKey *_Nonnull key, TWString *_Nonnull address, TWString *_Nonnull derivationPath, TWString *_Nonnull extetndedPublicKey);
+void TWStoredKeyAddAccount(struct TWStoredKey* _Nonnull key, TWString* _Nonnull address, TWString* _Nonnull derivationPath, TWString* _Nonnull extetndedPublicKey);
/// Saves the key to a file.
TW_EXPORT_METHOD
-bool TWStoredKeyStore(struct TWStoredKey *_Nonnull key, TWString *_Nonnull path);
+bool TWStoredKeyStore(struct TWStoredKey* _Nonnull key, TWString* _Nonnull path);
/// Decrypts the private key.
TW_EXPORT_METHOD
-TWData *_Nullable TWStoredKeyDecryptPrivateKey(struct TWStoredKey *_Nonnull key, TWString *_Nonnull password);
+TWData* _Nullable TWStoredKeyDecryptPrivateKey(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password);
/// Decrypts the mnemonic phrase.
TW_EXPORT_METHOD
-TWString *_Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey *_Nonnull key, TWString *_Nonnull password);
+TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password);
/// Returns the private key for a specific coin.
TW_EXPORT_METHOD
-struct TWPrivateKey *_Nullable TWStoredKeyPrivateKey(struct TWStoredKey *_Nonnull key, enum TWCoinType coin, TWString *_Nonnull password);
+struct TWPrivateKey* _Nullable TWStoredKeyPrivateKey(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, TWData* _Nonnull password);
/// Dercrypts and returns the HD Wallet for mnemonic phrase keys.
TW_EXPORT_METHOD
-struct TWHDWallet *_Nullable TWStoredKeyWallet(struct TWStoredKey *_Nonnull key, TWString *_Nonnull password);
+struct TWHDWallet* _Nullable TWStoredKeyWallet(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password);
/// Exports the key as JSON
TW_EXPORT_METHOD
-TWData *_Nullable TWStoredKeyExportJSON(struct TWStoredKey *_Nonnull key);
+TWData* _Nullable TWStoredKeyExportJSON(struct TWStoredKey* _Nonnull key);
/// Fills in empty and invalid addresses.
///
/// This method needs the encryption password to re-derive addresses from private keys.
/// @returns `false` if the password is incorrect.
TW_EXPORT_METHOD
-bool TWStoredKeyFixAddresses(struct TWStoredKey *_Nonnull key, TWString *_Nonnull password);
+bool TWStoredKeyFixAddresses(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password);
TW_EXTERN_C_END
diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp
index 44f4af3f921..91540ad39f2 100644
--- a/src/Keystore/EncryptionParameters.cpp
+++ b/src/Keystore/EncryptionParameters.cpp
@@ -28,7 +28,7 @@ static Data computeMAC(Iter begin, Iter end, Data key) {
return Hash::keccak256(data);
}
-EncryptionParameters::EncryptionParameters(const std::string& password, Data data) : mac() {
+EncryptionParameters::EncryptionParameters(const Data& password, Data data) : mac() {
auto scryptParams = boost::get(kdfParams);
auto derivedKey = Data(scryptParams.desiredKeyLength);
scrypt(reinterpret_cast(password.data()), password.size(), scryptParams.salt.data(),
@@ -50,21 +50,21 @@ EncryptionParameters::~EncryptionParameters() {
std::fill(encrypted.begin(), encrypted.end(), 0);
}
-Data EncryptionParameters::decrypt(const std::string& password) const {
+Data EncryptionParameters::decrypt(const Data& password) const {
auto derivedKey = Data();
auto mac = Data();
if (kdfParams.which() == 0) {
auto scryptParams = boost::get(kdfParams);
derivedKey.resize(scryptParams.defaultDesiredKeyLength);
- scrypt(reinterpret_cast(password.data()), password.size(), scryptParams.salt.data(),
+ scrypt(password.data(), password.size(), scryptParams.salt.data(),
scryptParams.salt.size(), scryptParams.n, scryptParams.r, scryptParams.p, derivedKey.data(),
scryptParams.defaultDesiredKeyLength);
mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted);
} else if (kdfParams.which() == 1) {
auto pbkdf2Params = boost::get(kdfParams);
derivedKey.resize(pbkdf2Params.defaultDesiredKeyLength);
- pbkdf2_hmac_sha256(reinterpret_cast(password.data()), password.size(), pbkdf2Params.salt.data(),
+ pbkdf2_hmac_sha256(password.data(), password.size(), pbkdf2Params.salt.data(),
pbkdf2Params.salt.size(), pbkdf2Params.iterations, derivedKey.data(),
pbkdf2Params.defaultDesiredKeyLength);
mac = computeMAC(derivedKey.end() - 16, derivedKey.end(), encrypted);
diff --git a/src/Keystore/EncryptionParameters.h b/src/Keystore/EncryptionParameters.h
index db2e49cc1ba..eec3b44a9f3 100644
--- a/src/Keystore/EncryptionParameters.h
+++ b/src/Keystore/EncryptionParameters.h
@@ -54,13 +54,13 @@ struct EncryptionParameters {
/// Initializes `EncryptionParameters` by encrypting data with a password
/// using standard values.
- EncryptionParameters(const std::string& password, Data data);
+ EncryptionParameters(const Data& password, Data data);
/// Initializes `EncryptionParameters` with a JSON object.
EncryptionParameters(const nlohmann::json& json);
/// Decrypts the payload with the given password.
- Data decrypt(const std::string& password) const;
+ Data decrypt(const Data& password) const;
/// Saves `this` as a JSON object.
nlohmann::json json() const;
diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp
index 476fa336d7e..b59f6de733b 100644
--- a/src/Keystore/StoredKey.cpp
+++ b/src/Keystore/StoredKey.cpp
@@ -27,7 +27,7 @@
using namespace TW;
using namespace TW::Keystore;
-StoredKey StoredKey::createWithMnemonic(const std::string& name, const std::string& password, const std::string& mnemonic) {
+StoredKey StoredKey::createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic) {
if (!HDWallet::isValid(mnemonic)) {
throw std::invalid_argument("Invalid mnemonic");
}
@@ -37,7 +37,7 @@ StoredKey StoredKey::createWithMnemonic(const std::string& name, const std::stri
return key;
}
-StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const std::string& password) {
+StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const Data& password) {
const auto wallet = TW::HDWallet(128, "");
const auto& mnemonic = wallet.mnemonic;
assert(HDWallet::isValid(mnemonic));
@@ -46,7 +46,7 @@ StoredKey StoredKey::createWithMnemonicRandom(const std::string& name, const std
return key;
}
-StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name, const std::string& password, const std::string& mnemonic, TWCoinType coin) {
+StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin) {
StoredKey key = createWithMnemonic(name, password, mnemonic);
const auto wallet = HDWallet(mnemonic, "");
@@ -58,12 +58,12 @@ StoredKey StoredKey::createWithMnemonicAddDefaultAddress(const std::string& name
return key;
}
-StoredKey StoredKey::createWithPrivateKey(const std::string& name, const std::string& password, const Data& privateKeyData) {
+StoredKey StoredKey::createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData) {
StoredKey key = StoredKey(StoredKeyType::privateKey, name, password, privateKeyData);
return key;
}
-StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& name, const std::string& password, TWCoinType coin, const Data& privateKeyData) {
+StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData) {
const auto curve = TW::curve(coin);
if (!PrivateKey::isValid(privateKeyData, curve)) {
throw std::invalid_argument("Invalid private key data");
@@ -78,13 +78,13 @@ StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& na
return key;
}
-StoredKey::StoredKey(StoredKeyType type, std::string name, const std::string& password, Data data)
+StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, Data data)
: type(type), id(), name(std::move(name)), payload(password, data), accounts() {
boost::uuids::random_generator gen;
id = boost::lexical_cast(gen());
}
-const HDWallet StoredKey::wallet(const std::string& password) const {
+const HDWallet StoredKey::wallet(const Data& password) const {
if (type != StoredKeyType::mnemonicPhrase) {
throw std::invalid_argument("Invalid account requested.");
}
@@ -139,7 +139,7 @@ void StoredKey::removeAccount(TWCoinType coin) {
}
-const PrivateKey StoredKey::privateKey(TWCoinType coin, const std::string& password) {
+const PrivateKey StoredKey::privateKey(TWCoinType coin, const Data& password) {
switch (type) {
case StoredKeyType::mnemonicPhrase: {
const auto wallet = this->wallet(password);
@@ -151,7 +151,7 @@ const PrivateKey StoredKey::privateKey(TWCoinType coin, const std::string& passw
}
}
-void StoredKey::fixAddresses(const std::string& password) {
+void StoredKey::fixAddresses(const Data& password) {
switch (type) {
case StoredKeyType::mnemonicPhrase: {
const auto wallet = this->wallet(password);
diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h
index c742ba5423a..00e29ab969d 100644
--- a/src/Keystore/StoredKey.h
+++ b/src/Keystore/StoredKey.h
@@ -43,23 +43,23 @@ class StoredKey {
/// Create a new StoredKey, with the given name, mnemonic and password.
/// @throws std::invalid_argument if mnemonic is invalid
- static StoredKey createWithMnemonic(const std::string& name, const std::string& password, const std::string& mnemonic);
+ static StoredKey createWithMnemonic(const std::string& name, const Data& password, const std::string& mnemonic);
/// Create a new StoredKey, with the given name, mnemonic and password.
/// @throws std::invalid_argument if mnemonic is invalid
- static StoredKey createWithMnemonicRandom(const std::string& name, const std::string& password);
+ static StoredKey createWithMnemonicRandom(const std::string& name, const Data& password);
/// Create a new StoredKey, with the given name, mnemonic and password, and also add the default address for the given coin..
/// @throws std::invalid_argument if mnemonic is invalid
- static StoredKey createWithMnemonicAddDefaultAddress(const std::string& name, const std::string& password, const std::string& mnemonic, TWCoinType coin);
+ static StoredKey createWithMnemonicAddDefaultAddress(const std::string& name, const Data& password, const std::string& mnemonic, TWCoinType coin);
/// Create a new StoredKey, with the given name and private key.
/// @throws std::invalid_argument if privateKeyData is not a vald private key
- static StoredKey createWithPrivateKey(const std::string& name, const std::string& password, const Data& privateKeyData);
+ static StoredKey createWithPrivateKey(const std::string& name, const Data& password, const Data& privateKeyData);
/// Create a new StoredKey, with the given name and private key, and also add the default address for the given coin..
/// @throws std::invalid_argument if privateKeyData is not a vald private key
- static StoredKey createWithPrivateKeyAddDefaultAddress(const std::string& name, const std::string& password, TWCoinType coin, const Data& privateKeyData);
+ static StoredKey createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData);
/// Create a StoredKey from a JSON object.
static StoredKey createWithJson(const nlohmann::json& json);
@@ -67,7 +67,7 @@ class StoredKey {
/// Returns the HDWallet for this key.
///
/// @throws std::invalid_argument if this key is of a type other than `mnemonicPhrase`.
- const HDWallet wallet(const std::string& password) const;
+ const HDWallet wallet(const Data& password) const;
/// Returns the account for a specific coin, creating it if necessary and
/// the provided wallet is not `nullptr`.
@@ -86,7 +86,7 @@ class StoredKey {
///
/// @throws std::invalid_argument if this key is of a type other than
/// `mnemonicPhrase` and a coin other than the default is requested.
- const PrivateKey privateKey(TWCoinType coin, const std::string& password);
+ const PrivateKey privateKey(TWCoinType coin, const Data& password);
/// Loads and decrypts a stored key from a file.
///
@@ -110,7 +110,7 @@ class StoredKey {
///
/// Use to fix legacy wallets with invalid address data. This method needs
/// the encryption password to re-derive addresses from private keys.
- void fixAddresses(const std::string& password);
+ void fixAddresses(const Data& password);
private:
/// Default constructor, private
@@ -119,7 +119,7 @@ class StoredKey {
/// Initializes a `StoredKey` with a type, an encryption password, and unencrypted data.
/// This contstructor will encrypt the provided data with default encryption
/// parameters.
- StoredKey(StoredKeyType type, std::string name, const std::string& password, Data data);
+ StoredKey(StoredKeyType type, std::string name, const Data& password, Data data);
};
} // namespace TW::Keystore
diff --git a/src/interface/TWStoredKey.cpp b/src/interface/TWStoredKey.cpp
index 795cfa38ce9..28dd3d992c6 100644
--- a/src/interface/TWStoredKey.cpp
+++ b/src/interface/TWStoredKey.cpp
@@ -25,29 +25,29 @@ struct TWStoredKey* _Nullable TWStoredKeyLoad(TWString* _Nonnull path) {
}
}
-struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWString* _Nonnull password) {
+struct TWStoredKey* _Nonnull TWStoredKeyCreate(TWString* _Nonnull name, TWData* _Nonnull password) {
const auto& nameString = *reinterpret_cast(name);
- const auto& passwordString = *reinterpret_cast(password);
- return new TWStoredKey{ StoredKey::createWithMnemonicRandom(nameString, passwordString) };
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ return new TWStoredKey{ StoredKey::createWithMnemonicRandom(nameString, passwordData) };
}
-struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWString* _Nonnull password, enum TWCoinType coin) {
+struct TWStoredKey* _Nullable TWStoredKeyImportPrivateKey(TWData* _Nonnull privateKey, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin) {
try {
const auto& privateKeyData = *reinterpret_cast(privateKey);
const auto& nameString = *reinterpret_cast(name);
- const auto& passwordString = *reinterpret_cast(password);
- return new TWStoredKey{ StoredKey::createWithPrivateKeyAddDefaultAddress(nameString, passwordString, coin, privateKeyData) };
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ return new TWStoredKey{ StoredKey::createWithPrivateKeyAddDefaultAddress(nameString, passwordData, coin, privateKeyData) };
} catch (...) {
return nullptr;
}
}
-struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWString* _Nonnull password, enum TWCoinType coin) {
+struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin) {
try {
const auto& mnemonicString = *reinterpret_cast(mnemonic);
const auto& nameString = *reinterpret_cast(name);
- const auto& passwordString = *reinterpret_cast(password);
- return new TWStoredKey{ StoredKey::createWithMnemonicAddDefaultAddress(nameString, passwordString, mnemonicString, coin) };
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ return new TWStoredKey{ StoredKey::createWithMnemonicAddDefaultAddress(nameString, passwordData, mnemonicString, coin) };
} catch (...) {
return nullptr;
}
@@ -124,20 +124,20 @@ bool TWStoredKeyStore(struct TWStoredKey* _Nonnull key, TWString* _Nonnull path)
}
}
-TWData* _Nullable TWStoredKeyDecryptPrivateKey(struct TWStoredKey* _Nonnull key, TWString* _Nonnull password) {
+TWData* _Nullable TWStoredKeyDecryptPrivateKey(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password) {
try {
- const auto& passwordString = *reinterpret_cast(password);
- const auto data = key->impl.payload.decrypt(passwordString);
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ const auto data = key->impl.payload.decrypt(passwordData);
return TWDataCreateWithBytes(data.data(), data.size());
} catch (...) {
return nullptr;
}
}
-TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key, TWString* _Nonnull password) {
+TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password) {
try {
- const auto& passwordString = *reinterpret_cast(password);
- const auto data = key->impl.payload.decrypt(passwordString);
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ const auto data = key->impl.payload.decrypt(passwordData);
const auto string = std::string(data.begin(), data.end());
return TWStringCreateWithUTF8Bytes(string.c_str());
} catch (...) {
@@ -145,19 +145,19 @@ TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key,
}
}
-struct TWPrivateKey* _Nullable TWStoredKeyPrivateKey(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, TWString* _Nonnull password) {
+struct TWPrivateKey* _Nullable TWStoredKeyPrivateKey(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, TWData* _Nonnull password) {
try {
- const auto& passwordString = *reinterpret_cast(password);
- return new TWPrivateKey{ key->impl.privateKey(coin, passwordString) };
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ return new TWPrivateKey{ key->impl.privateKey(coin, passwordData) };
} catch (...) {
return nullptr;
}
}
-struct TWHDWallet* _Nullable TWStoredKeyWallet(struct TWStoredKey* _Nonnull key, TWString* _Nonnull password) {
+struct TWHDWallet* _Nullable TWStoredKeyWallet(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password) {
try {
- const auto& passwordString = *reinterpret_cast(password);
- return new TWHDWallet{ key->impl.wallet(passwordString) };
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ return new TWHDWallet{ key->impl.wallet(passwordData) };
} catch (...) {
return nullptr;
}
@@ -168,10 +168,10 @@ TWData* _Nullable TWStoredKeyExportJSON(struct TWStoredKey* _Nonnull key) {
return TWDataCreateWithBytes(reinterpret_cast(json.data()), json.size());
}
-bool TWStoredKeyFixAddresses(struct TWStoredKey* _Nonnull key, TWString* _Nonnull password) {
+bool TWStoredKeyFixAddresses(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password) {
try {
- const auto& passwordString = *reinterpret_cast(password);
- key->impl.fixAddresses(passwordString);
+ const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password));
+ key->impl.fixAddresses(passwordData);
return true;
} catch (...) {
return false;
diff --git a/swift/Sources/KeyStore.swift b/swift/Sources/KeyStore.swift
index 35e46d9ab0d..d86ce0014c2 100755
--- a/swift/Sources/KeyStore.swift
+++ b/swift/Sources/KeyStore.swift
@@ -75,7 +75,7 @@ public final class KeyStore {
/// Creates a new wallet. HD default by default
public func createWallet(name: String, password: String, coins: [CoinType]) throws -> Wallet {
- let key = StoredKey(name: name, password: password)
+ let key = StoredKey(name: name, password: Data(password.utf8))
return try saveCreatedWallet(for: key, password: password, coins: coins)
}
@@ -101,7 +101,7 @@ public final class KeyStore {
/// Remove accounts from a wallet.
public func removeAccounts(wallet: Wallet, coins: [CoinType], password: String) throws -> Wallet {
- guard wallet.key.decryptPrivateKey(password: password) != nil else {
+ guard wallet.key.decryptPrivateKey(password: Data(password.utf8)) != nil else {
throw Error.invalidPassword
}
@@ -130,7 +130,7 @@ public final class KeyStore {
guard let key = StoredKey.importJSON(json: json) else {
throw Error.invalidKey
}
- guard let data = key.decryptPrivateKey(password: password) else {
+ guard let data = key.decryptPrivateKey(password: Data(password.utf8)) else {
throw Error.invalidPassword
}
@@ -159,7 +159,7 @@ public final class KeyStore {
/// - coin: coin to use for this wallet
/// - Returns: new wallet
public func `import`(privateKey: PrivateKey, name: String, password: String, coin: CoinType) throws -> Wallet {
- guard let newKey = StoredKey.importPrivateKey(privateKey: privateKey.data, name: name, password: password, coin: coin) else {
+ guard let newKey = StoredKey.importPrivateKey(privateKey: privateKey.data, name: name, password: Data(password.utf8), coin: coin) else {
throw Error.invalidKey
}
let url = makeAccountURL()
@@ -180,7 +180,7 @@ public final class KeyStore {
/// - coins: coins to add
/// - Returns: new account
public func `import`(mnemonic: String, name: String, encryptPassword: String, coins: [CoinType]) throws -> Wallet {
- guard let key = StoredKey.importHDWallet(mnemonic: mnemonic, name: name, password: encryptPassword, coin: coins.first ?? .ethereum) else {
+ guard let key = StoredKey.importHDWallet(mnemonic: mnemonic, name: name, password: Data(encryptPassword.utf8), coin: coins.first ?? .ethereum) else {
throw Error.invalidMnemonic
}
let url = makeAccountURL()
@@ -211,12 +211,12 @@ public final class KeyStore {
throw Error.accountNotFound
}
- if let mnemonic = checkMnemonic(privateKeyData), let newKey = StoredKey.importHDWallet(mnemonic: mnemonic, name: "", password: newPassword, coin: coin) {
+ if let mnemonic = checkMnemonic(privateKeyData), let newKey = StoredKey.importHDWallet(mnemonic: mnemonic, name: "", password: Data(newPassword.utf8), coin: coin) {
guard let json = newKey.exportJSON() else {
throw Error.invalidKey
}
return json
- } else if let newKey = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "", password: newPassword, coin: coin) {
+ } else if let newKey = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "", password: Data(newPassword.utf8), coin: coin) {
guard let json = newKey.exportJSON() else {
throw Error.invalidKey
}
@@ -233,7 +233,7 @@ public final class KeyStore {
/// - password: account password
/// - Returns: private key data for encrypted keys or menmonic phrase for HD wallets
public func exportPrivateKey(wallet: Wallet, password: String) throws -> Data {
- guard let key = wallet.key.decryptPrivateKey(password: password) else {
+ guard let key = wallet.key.decryptPrivateKey(password: Data(password.utf8)) else {
throw Error.invalidPassword
}
return key
@@ -247,7 +247,7 @@ public final class KeyStore {
/// - Returns: mnemonic phrase
/// - Throws: `EncryptError.invalidMnemonic` if the account is not an HD wallet.
public func exportMnemonic(wallet: Wallet, password: String) throws -> String {
- guard let mnemonic = wallet.key.decryptMnemonic(password: password) else {
+ guard let mnemonic = wallet.key.decryptMnemonic(password: Data(password.utf8)) else {
throw Error.invalidPassword
}
return mnemonic
@@ -278,7 +278,7 @@ public final class KeyStore {
fatalError("Missing wallet")
}
- guard var privateKeyData = wallet.key.decryptPrivateKey(password: password) else {
+ guard var privateKeyData = wallet.key.decryptPrivateKey(password: Data(password.utf8)) else {
throw Error.invalidPassword
}
defer {
@@ -291,10 +291,10 @@ public final class KeyStore {
}
if let mnemonic = checkMnemonic(privateKeyData),
- let key = StoredKey.importHDWallet(mnemonic: mnemonic, name: newName, password: newPassword, coin: coins[0]) {
+ let key = StoredKey.importHDWallet(mnemonic: mnemonic, name: newName, password: Data(newPassword.utf8), coin: coins[0]) {
wallets[index].key = key
} else if let key = StoredKey.importPrivateKey(
- privateKey: privateKeyData, name: newName, password: newPassword, coin: coins[0]) {
+ privateKey: privateKeyData, name: newName, password: Data(newPassword.utf8), coin: coins[0]) {
wallets[index].key = key
} else {
throw Error.invalidKey
@@ -310,7 +310,7 @@ public final class KeyStore {
fatalError("Missing wallet")
}
- guard var privateKey = wallet.key.decryptPrivateKey(password: password) else {
+ guard var privateKey = wallet.key.decryptPrivateKey(password: Data(password.utf8)) else {
throw KeyStore.Error.invalidKey
}
defer {
diff --git a/swift/Sources/Wallet.swift b/swift/Sources/Wallet.swift
index e702ea105cf..036d2a22d7e 100755
--- a/swift/Sources/Wallet.swift
+++ b/swift/Sources/Wallet.swift
@@ -36,7 +36,7 @@ public final class Wallet: Hashable, Equatable {
/// - Returns: the account
/// - Throws: `KeyStore.Error.invalidPassword` if the password is incorrect.
public func getAccount(password: String, coin: CoinType) throws -> Account {
- let wallet = key.wallet(password: password)
+ let wallet = key.wallet(password: Data(password.utf8))
guard let account = key.accountForCoin(coin: coin, wallet: wallet) else {
throw KeyStore.Error.invalidPassword
}
@@ -51,7 +51,7 @@ public final class Wallet: Hashable, Equatable {
/// - Returns: the added accounts
/// - Throws: `KeyStore.Error.invalidPassword` if the password is incorrect.
public func getAccounts(password: String, coins: [CoinType]) throws -> [Account] {
- guard let wallet = key.wallet(password: password) else {
+ guard let wallet = key.wallet(password: Data(password.utf8)) else {
throw KeyStore.Error.invalidPassword
}
return coins.compactMap({ key.accountForCoin(coin: $0, wallet: wallet) })
@@ -65,7 +65,7 @@ public final class Wallet: Hashable, Equatable {
/// - Returns: the private key
/// - Throws: `KeyStore.Error.invalidPassword` if the password is incorrect.
public func privateKey(password: String, coin: CoinType) throws -> PrivateKey {
- guard let pk = key.privateKey(coin: coin, password: password) else {
+ guard let pk = key.privateKey(coin: coin, password: Data(password.utf8)) else {
throw KeyStore.Error.invalidPassword
}
return pk
diff --git a/swift/Tests/Keystore/AccountTests.swift b/swift/Tests/Keystore/AccountTests.swift
index 7d1d184173f..8fa934e9e11 100755
--- a/swift/Tests/Keystore/AccountTests.swift
+++ b/swift/Tests/Keystore/AccountTests.swift
@@ -9,7 +9,7 @@ import XCTest
class AccountTests: XCTestCase {
let words = "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn fatal"
- let password = "password"
+ let password = Data("password".utf8)
func testSignHash() throws {
let privateKeyData = Data(hexString: "D30519BCAE8D180DBFCC94FE0B8383DC310185B0BE97B4365083EBCECCD75759")!
@@ -42,9 +42,10 @@ class AccountTests: XCTestCase {
func testExtendedPubkey() throws {
let key = StoredKey.importHDWallet(mnemonic: words, name: "name", password: password, coin: .ethereum)!
let wallet = Wallet(keyURL: URL(fileURLWithPath: "/"), key: key)
- _ = try wallet.getAccount(password: password, coin: .bitcoin)
- _ = try wallet.getAccount(password: password, coin: .bitcoinCash)
- _ = try wallet.getAccount(password: password, coin: .ethereumClassic)
+ let stringPass = String(data: password, encoding: .utf8)!
+ _ = try wallet.getAccount(password: stringPass, coin: .bitcoin)
+ _ = try wallet.getAccount(password: stringPass, coin: .bitcoinCash)
+ _ = try wallet.getAccount(password: stringPass, coin: .ethereumClassic)
XCTAssertEqual(wallet.accounts[0].extendedPublicKey, "")
XCTAssertEqual(wallet.accounts[1].extendedPublicKey, "zpub6rNUNtxSa9Gxvm4Bdxf1MPMwrvkzwDx6vP96Hkzw3jiQKdg3fhXBStxjn12YixQB8h88B3RMSRscRstf9AEVaYr3MAqVBEWBDuEJU4PGaT9")
diff --git a/swift/Tests/Keystore/KeyStoreTests.swift b/swift/Tests/Keystore/KeyStoreTests.swift
index 928f5194345..f4e56822dd6 100755
--- a/swift/Tests/Keystore/KeyStoreTests.swift
+++ b/swift/Tests/Keystore/KeyStoreTests.swift
@@ -90,7 +90,7 @@ class KeyStoreTests: XCTestCase {
let savedKeyStore = try KeyStore(keyDirectory: keyDirectory)
let savedWallet = savedKeyStore.wallets.first(where: { $0 == wallet })!
- let data = savedWallet.key.decryptPrivateKey(password: "testpassword")
+ let data = savedWallet.key.decryptPrivateKey(password: Data("testpassword".utf8))
let mnemonic = String(data: data!, encoding: .ascii)
XCTAssertEqual(savedWallet.accounts.count, coins.count)
@@ -110,7 +110,7 @@ class KeyStoreTests: XCTestCase {
let savedKeyStore = try KeyStore(keyDirectory: keyDirectory)
let savedWallet = savedKeyStore.wallets.first(where: { $0 == wallet })!
- let data = savedWallet.key.decryptPrivateKey(password: "password")
+ let data = savedWallet.key.decryptPrivateKey(password: Data("password".utf8))
let mnemonic = String(data: data!, encoding: .ascii)
XCTAssertEqual(savedWallet.accounts.count, coins.count)
@@ -160,11 +160,11 @@ class KeyStoreTests: XCTestCase {
func testImportKey() throws {
let keyStore = try KeyStore(keyDirectory: keyDirectory)
let privateKeyData = Data(hexString: "9cdb5cab19aec3bd0fcd614c5f185e7a1d97634d4225730eba22497dc89a716c")!
- let key = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "name", password: "password", coin: .ethereum)!
+ let key = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "name", password: Data("password".utf8), coin: .ethereum)!
let json = key.exportJSON()!
let wallet = try keyStore.import(json: json, name: "name", password: "password", newPassword: "newPassword", coins: [.ethereum])
- let storedData = wallet.key.decryptPrivateKey(password: "newPassword")
+ let storedData = wallet.key.decryptPrivateKey(password: Data("newPassword".utf8))
XCTAssertNotNil(keyStore.keyWallet)
XCTAssertNotNil(storedData)
@@ -176,7 +176,7 @@ class KeyStoreTests: XCTestCase {
let privateKey = PrivateKey(data: Data(hexString: "9cdb5cab19aec3bd0fcd614c5f185e7a1d97634d4225730eba22497dc89a716c")!)!
let wallet = try keyStore.import(privateKey: privateKey, name: "name", password: "password", coin: .ethereum)
- let storedData = wallet.key.decryptPrivateKey(password: "password")
+ let storedData = wallet.key.decryptPrivateKey(password: Data("password".utf8))
XCTAssertNotNil(storedData)
XCTAssertNotNil(PrivateKey(data: storedData!))
@@ -189,7 +189,7 @@ class KeyStoreTests: XCTestCase {
func testImportWallet() throws {
let keyStore = try KeyStore(keyDirectory: keyDirectory)
let wallet = try keyStore.import(mnemonic: mnemonic, name: "name", encryptPassword: "newPassword", coins: [.ethereum])
- let storedData = wallet.key.decryptMnemonic(password: "newPassword")
+ let storedData = wallet.key.decryptMnemonic(password: Data("newPassword".utf8))
XCTAssertNotNil(storedData)
XCTAssertEqual(wallet.accounts.count, 1)
diff --git a/swift/Tests/Keystore/KeystoreKeyTests.swift b/swift/Tests/Keystore/KeystoreKeyTests.swift
index 580a1f8dae1..cad779e3105 100755
--- a/swift/Tests/Keystore/KeystoreKeyTests.swift
+++ b/swift/Tests/Keystore/KeystoreKeyTests.swift
@@ -25,21 +25,21 @@ class KeystoreKeyTests: XCTestCase {
let url = Bundle(for: type(of: self)).url(forResource: "key", withExtension: "json")!
let key = StoredKey.load(path: url.path)!
- XCTAssertNil(key.decryptPrivateKey(password: "password"))
+ XCTAssertNil(key.decryptPrivateKey(password: Data("password".utf8)))
}
func testDecrypt() {
let url = Bundle(for: type(of: self)).url(forResource: "key", withExtension: "json")!
let key = StoredKey.load(path: url.path)!
- let privateKey = key.decryptPrivateKey(password: "testpassword")!
+ let privateKey = key.decryptPrivateKey(password: Data("testpassword".utf8))!
XCTAssertEqual(privateKey.hexString, "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d")
}
func testCreateWallet() {
let privateKeyData = Data(hexString: "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266")!
- let key = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "name", password: "password", coin: .ethereum)!
- let decrypted = key.decryptPrivateKey(password: "password")!
+ let key = StoredKey.importPrivateKey(privateKey: privateKeyData, name: "name", password: Data("password".utf8), coin: .ethereum)!
+ let decrypted = key.decryptPrivateKey(password: Data("password".utf8))!
XCTAssertEqual(decrypted.hexString, privateKeyData.hexString)
}
@@ -59,4 +59,64 @@ class KeystoreKeyTests: XCTestCase {
XCTAssertEqual(account.address.description, "3PWazDi9n1Hfyq9gXFxDxzADNL8RNYyK2y")
}
+
+ func testLongHexPassword() {
+ let json = """
+ {
+ "address": "34bae2218c254ed190c0f5b1dd4323aee8e7da09",
+ "id": "86066d8c-8dba-4d81-afd4-934e2a2b72a2",
+ "version": 3,
+ "crypto": {
+ "cipher": "aes-128-ctr",
+ "cipherparams": {
+ "iv": "a4976ad73057007ad788d1f792db851d"
+ },
+ "ciphertext": "5e4458d69964172c492616b751d6589b4ad7da4217dcfccecc3f4e515a934bb8",
+ "kdf": "scrypt",
+ "kdfparams": {
+ "dklen": 32,
+ "n": 4096,
+ "p": 6,
+ "r": 8,
+ "salt": "24c72d92bf88a4f7c7b3f5e3cb3620714d71fceabbb0bc6099f50c6d5d898e7c"
+ },
+ "mac": "c15e3035ddcaca766dfc56648978d33e94d3c57d4a5e13fcf8b5f8dbb0902900"
+ }
+ }
+ """.data(using: .utf8)!
+ let keystore = StoredKey.importJSON(json: json)!
+ let password = Data(hexString: "2d6eefbfbd4622efbfbdefbfbd516718efbfbdefbfbdefbfbdefbfbd59efbfbd30efbfbdefbfbd3a4348efbfbd2aefbfbdefbfbd49efbfbd27efbfbd0638efbfbdefbfbdefbfbd4cefbfbd6befbfbdefbfbd6defbfbdefbfbd63efbfbd5aefbfbd61262b70efbfbdefbfbdefbfbdefbfbdefbfbdc7aa373163417cefbfbdefbfbdefbfbd44efbfbdefbfbd1d10efbfbdefbfbdefbfbd61dc9e5b124befbfbd11efbfbdefbfbd2fefbfbdefbfbd3d7c574868efbfbdefbfbdefbfbd37043b7b5c1a436471592f02efbfbd18efbfbdefbfbd2befbfbdefbfbd7218efbfbd6a68efbfbdcb8e5f3328773ec48174efbfbd67efbfbdefbfbdefbfbdefbfbdefbfbd2a31efbfbd7f60efbfbdd884efbfbd57efbfbd25efbfbd590459efbfbd37efbfbd2bdca20fefbfbdefbfbdefbfbdefbfbd39450113efbfbdefbfbdefbfbd454671efbfbdefbfbdd49fefbfbd47efbfbdefbfbdefbfbdefbfbd00efbfbdefbfbdefbfbdefbfbd05203f4c17712defbfbd7bd1bbdc967902efbfbdc98a77efbfbd707a36efbfbd12efbfbdefbfbd57c78cefbfbdefbfbdefbfbd10efbfbdefbfbdefbfbde1a1bb08efbfbdefbfbd26efbfbdefbfbd58efbfbdefbfbdc4b1efbfbd295fefbfbd0eefbfbdefbfbdefbfbd0e6eefbfbd")!
+ let data = keystore.decryptPrivateKey(password: password)
+ XCTAssertEqual(data?.hexString, "043c5429c7872502531708ec0d821c711691402caf37ef7ba78a8c506f10653b")
+ }
+
+ func testLongPassword() {
+ let json = """
+ {
+ "address": "b92bcd5b14d2d70651d483c8f03bae79223b88ec",
+ "id": "480fc670-e5e6-4b39-ba33-61f54ce792f9",
+ "version": 3,
+ "crypto": {
+ "cipher": "aes-128-ctr",
+ "cipherparams": {
+ "iv": "5d88369e4306bcc98e1fe70e7710f3a0"
+ },
+ "ciphertext": "de9bac5d1ca94cdd067a51275a56f0766ed3631de108609ee240c42a0994f97e",
+ "kdf": "scrypt",
+ "kdfparams": {
+ "dklen": 32,
+ "n": 4096,
+ "p": 6,
+ "r": 8,
+ "salt": "3849479dd4880793cfd92ebfeb30c60dccf04f3f76a2778fe89bead4237ddad4"
+ },
+ "mac": "361df97ff456009849ab1ffd4e71b61d7e66c9d2071c5a7563d1bbbdb0b2653b"
+ }
+ }
+ """.data(using: .utf8)!
+ let keystore = StoredKey.importJSON(json: json)!
+ let password = "2d6eefbfbd4622efbfbdefbfbd516718efbfbdefbfbdefbfbdefbfbd59efbfbd30efbfbdefbfbd3a4348efbfbd2aefbfbdefbfbd49efbfbd27efbfbd0638efbfbdefbfbdefbfbd4cefbfbd6befbfbdefbfbd6defbfbdefbfbd63efbfbd5aefbfbd61262b70efbfbdefbfbdefbfbdefbfbdefbfbdc7aa373163417cefbfbdefbfbdefbfbd44efbfbdefbfbd1d10efbfbdefbfbdefbfbd61dc9e5b124befbfbd11efbfbdefbfbd2fefbfbdefbfbd3d7c574868efbfbdefbfbdefbfbd37043b7b5c1a436471592f02efbfbd18efbfbdefbfbd2befbfbdefbfbd7218efbfbd6a68efbfbdcb8e5f3328773ec48174efbfbd67efbfbdefbfbdefbfbdefbfbdefbfbd2a31efbfbd7f60efbfbdd884efbfbd57efbfbd25efbfbd590459efbfbd37efbfbd2bdca20fefbfbdefbfbdefbfbdefbfbd39450113efbfbdefbfbdefbfbd454671efbfbdefbfbdd49fefbfbd47efbfbdefbfbdefbfbdefbfbd00efbfbdefbfbdefbfbdefbfbd05203f4c17712defbfbd7bd1bbdc967902efbfbdc98a77efbfbd707a36efbfbd12efbfbdefbfbd57c78cefbfbdefbfbdefbfbd10efbfbdefbfbdefbfbde1a1bb08efbfbdefbfbd26efbfbdefbfbd58efbfbdefbfbdc4b1efbfbd295fefbfbd0eefbfbdefbfbdefbfbd0e6eefbfbd".data(using: .utf8)!
+ let data = keystore.decryptPrivateKey(password: password)
+ XCTAssertEqual(data?.hexString, "4357b2f9a6150ba969bc52f01c98cce5313595fe49f2d08303759c73e5c7a46c")
+ }
}
diff --git a/swift/Tests/Keystore/WalletTests.swift b/swift/Tests/Keystore/WalletTests.swift
index 983797344cc..6b31424870e 100755
--- a/swift/Tests/Keystore/WalletTests.swift
+++ b/swift/Tests/Keystore/WalletTests.swift
@@ -21,7 +21,7 @@ class WalletTests: XCTestCase {
func testIdentifier() throws {
let url = URL(string: "UTC--2018-07-23T15-42-07.380692005-42000--6E199F01-FA96-4ADF-9A4B-36EE4B1E08C7")!
- let key = StoredKey(name: "name", password: "password")
+ let key = StoredKey(name: "name", password: Data("password".utf8))
let wallet = Wallet(keyURL: url, key: key)
XCTAssertEqual(wallet.identifier, "UTC--2018-07-23T15-42-07.380692005-42000--6E199F01-FA96-4ADF-9A4B-36EE4B1E08C7")
}
diff --git a/tests/Keystore/Data/ethereum-wallet-address-no-0x.json b/tests/Keystore/Data/ethereum-wallet-address-no-0x.json
index 87f0f870863..43cc9c51a9a 100644
--- a/tests/Keystore/Data/ethereum-wallet-address-no-0x.json
+++ b/tests/Keystore/Data/ethereum-wallet-address-no-0x.json
@@ -1 +1,25 @@
-{"activeAccounts":[{"address":"Ac1ec44E4f0ca7D172B7803f6836De87Fb72b309","derivationPath":"m/44'/60'/0'/0/0"}],"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"630d0a62bc8a6187c47fdb6c8b7bd38c"},"ciphertext":"4ec6d0157bde53900020d45c9db9235acdb366f727fe456b5a4536f20ea0848c","kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"4c3d38c0d114cb92b2cb4a44e92e27cf588f9ecd59840c8dea087e89d350d836"},"mac":"9748b96453a03bcdec2e714153d8d69f16cde7d398750932281f68844a6b2616"},"id":"48aa6b37-8276-44fe-aa4e-819145771183","type":"private-key","version":3}
\ No newline at end of file
+{
+ "activeAccounts": [{
+ "address": "Ac1ec44E4f0ca7D172B7803f6836De87Fb72b309",
+ "derivationPath": "m/44'/60'/0'/0/0"
+ }],
+ "crypto": {
+ "cipher": "aes-128-ctr",
+ "cipherparams": {
+ "iv": "630d0a62bc8a6187c47fdb6c8b7bd38c"
+ },
+ "ciphertext": "4ec6d0157bde53900020d45c9db9235acdb366f727fe456b5a4536f20ea0848c",
+ "kdf": "scrypt",
+ "kdfparams": {
+ "dklen": 32,
+ "n": 4096,
+ "p": 6,
+ "r": 8,
+ "salt": "4c3d38c0d114cb92b2cb4a44e92e27cf588f9ecd59840c8dea087e89d350d836"
+ },
+ "mac": "9748b96453a03bcdec2e714153d8d69f16cde7d398750932281f68844a6b2616"
+ },
+ "id": "48aa6b37-8276-44fe-aa4e-819145771183",
+ "type": "private-key",
+ "version": 3
+}
\ No newline at end of file
diff --git a/tests/Keystore/Data/myetherwallet.uu b/tests/Keystore/Data/myetherwallet.uu
index 10e2dab212d..751f16207e5 100755
--- a/tests/Keystore/Data/myetherwallet.uu
+++ b/tests/Keystore/Data/myetherwallet.uu
@@ -1 +1,21 @@
-{"version":3,"id":"beb60dc6-7553-4215-9aa7-4b26883da373","address":"8562fcccbae3019f5a716997609b301ac31fe04a","Crypto":{"ciphertext":"ed9de8b5568bac97c8199b82b197b61977440d360acec2ecf4f74f3da91308ab","cipherparams":{"iv":"cf6730826d91ce908aa15771952ab3e8"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"2904ecde7e2e5c6cb89291b2741bdd3dff3088f98a7013d63084c746efd7524f","n":1024,"r":8,"p":1},"mac":"cdb237916f98742d4e8f313638e16b04a4a780e69dd61c6407932be42d269c95"}}
\ No newline at end of file
+{
+ "version": 3,
+ "id": "beb60dc6-7553-4215-9aa7-4b26883da373",
+ "address": "8562fcccbae3019f5a716997609b301ac31fe04a",
+ "Crypto": {
+ "ciphertext": "ed9de8b5568bac97c8199b82b197b61977440d360acec2ecf4f74f3da91308ab",
+ "cipherparams": {
+ "iv": "cf6730826d91ce908aa15771952ab3e8"
+ },
+ "cipher": "aes-128-ctr",
+ "kdf": "scrypt",
+ "kdfparams": {
+ "dklen": 32,
+ "salt": "2904ecde7e2e5c6cb89291b2741bdd3dff3088f98a7013d63084c746efd7524f",
+ "n": 1024,
+ "r": 8,
+ "p": 1
+ },
+ "mac": "cdb237916f98742d4e8f313638e16b04a4a780e69dd61c6407932be42d269c95"
+ }
+}
\ No newline at end of file
diff --git a/tests/Keystore/Data/web3j.json b/tests/Keystore/Data/web3j.json
new file mode 100644
index 00000000000..b47dc6a2d51
--- /dev/null
+++ b/tests/Keystore/Data/web3j.json
@@ -0,0 +1,21 @@
+{
+ "address": "34bae2218c254ed190c0f5b1dd4323aee8e7da09",
+ "id": "86066d8c-8dba-4d81-afd4-934e2a2b72a2",
+ "version": 3,
+ "crypto": {
+ "cipher": "aes-128-ctr",
+ "cipherparams": {
+ "iv": "a4976ad73057007ad788d1f792db851d"
+ },
+ "ciphertext": "5e4458d69964172c492616b751d6589b4ad7da4217dcfccecc3f4e515a934bb8",
+ "kdf": "scrypt",
+ "kdfparams": {
+ "dklen": 32,
+ "n": 4096,
+ "p": 6,
+ "r": 8,
+ "salt": "24c72d92bf88a4f7c7b3f5e3cb3620714d71fceabbb0bc6099f50c6d5d898e7c"
+ },
+ "mac": "c15e3035ddcaca766dfc56648978d33e94d3c57d4a5e13fcf8b5f8dbb0902900"
+ }
+}
\ No newline at end of file
diff --git a/tests/Keystore/StoredKeyTests.cpp b/tests/Keystore/StoredKeyTests.cpp
index d5648c661e8..5e385323ac0 100644
--- a/tests/Keystore/StoredKeyTests.cpp
+++ b/tests/Keystore/StoredKeyTests.cpp
@@ -8,6 +8,7 @@
#include "Coin.h"
#include "HexCoding.h"
+#include "Data.h"
#include "PrivateKey.h"
#include
@@ -19,7 +20,8 @@ namespace TW::Keystore {
using namespace std;
-const auto password = "password";
+const auto passwordString = "password";
+const auto password = TW::data(string(passwordString));
const auto mnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle";
const TWCoinType coinTypeBc = TWCoinTypeBitcoin;
@@ -176,14 +178,14 @@ TEST(StoredKey, LoadLegacyPrivateKey) {
const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/legacy-private-key.json");
EXPECT_EQ(key.id, "3051ca7d-3d36-4a4a-acc2-09e9083732b0");
EXPECT_EQ(key.accounts[0].coin(), TWCoinTypeEthereum);
- EXPECT_EQ(hex(key.payload.decrypt("testpassword")), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d");
+ EXPECT_EQ(hex(key.payload.decrypt(TW::data("testpassword"))), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d");
}
TEST(StoredKey, LoadLivepeerKey) {
const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/livepeer.json");
EXPECT_EQ(key.id, "70ea3601-ee21-4e94-a7e4-66255a987d22");
EXPECT_EQ(key.accounts[0].coin(), TWCoinTypeEthereum);
- EXPECT_EQ(hex(key.payload.decrypt("Radchenko")), "09b4379d9a41a71d94ee36357bccb4d77b45e7fd9307e2c0f673dd54c0558c73");
+ EXPECT_EQ(hex(key.payload.decrypt(TW::data("Radchenko"))), "09b4379d9a41a71d94ee36357bccb4d77b45e7fd9307e2c0f673dd54c0558c73");
}
TEST(StoredKey, LoadPBKDF2Key) {
@@ -196,7 +198,7 @@ TEST(StoredKey, LoadPBKDF2Key) {
EXPECT_EQ(boost::get(payload.kdfParams).iterations, 262144);
EXPECT_EQ(hex(boost::get(payload.kdfParams).salt), "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd");
- EXPECT_EQ(hex(payload.decrypt("testpassword")), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d");
+ EXPECT_EQ(hex(payload.decrypt(TW::data("testpassword"))), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d");
}
TEST(StoredKey, LoadLegacyMnemonic) {
@@ -216,6 +218,14 @@ TEST(StoredKey, LoadLegacyMnemonic) {
EXPECT_EQ(key.accounts[1].extendedPublicKey, "zpub6r97AegwVxVbJeuDAWP5KQgX5y4Q6KyFUrsFQRn8yzSXrnmpwg1ZKHSWwECR1Kiqgr4h93WN5kdS48KC6hVFniuZHqVFXjULZZkCwurqyPn");
}
+TEST(StoredKey, LoadFromWeb3j) {
+ const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/web3j.json");
+ EXPECT_EQ(key.id, "86066d8c-8dba-4d81-afd4-934e2a2b72a2");
+ const auto password = parse_hex("2d6eefbfbd4622efbfbdefbfbd516718efbfbdefbfbdefbfbdefbfbd59efbfbd30efbfbdefbfbd3a4348efbfbd2aefbfbdefbfbd49efbfbd27efbfbd0638efbfbdefbfbdefbfbd4cefbfbd6befbfbdefbfbd6defbfbdefbfbd63efbfbd5aefbfbd61262b70efbfbdefbfbdefbfbdefbfbdefbfbdc7aa373163417cefbfbdefbfbdefbfbd44efbfbdefbfbd1d10efbfbdefbfbdefbfbd61dc9e5b124befbfbd11efbfbdefbfbd2fefbfbdefbfbd3d7c574868efbfbdefbfbdefbfbd37043b7b5c1a436471592f02efbfbd18efbfbdefbfbd2befbfbdefbfbd7218efbfbd6a68efbfbdcb8e5f3328773ec48174efbfbd67efbfbdefbfbdefbfbdefbfbdefbfbd2a31efbfbd7f60efbfbdd884efbfbd57efbfbd25efbfbd590459efbfbd37efbfbd2bdca20fefbfbdefbfbdefbfbdefbfbd39450113efbfbdefbfbdefbfbd454671efbfbdefbfbdd49fefbfbd47efbfbdefbfbdefbfbdefbfbd00efbfbdefbfbdefbfbdefbfbd05203f4c17712defbfbd7bd1bbdc967902efbfbdc98a77efbfbd707a36efbfbd12efbfbdefbfbd57c78cefbfbdefbfbdefbfbd10efbfbdefbfbdefbfbde1a1bb08efbfbdefbfbd26efbfbdefbfbd58efbfbdefbfbdc4b1efbfbd295fefbfbd0eefbfbdefbfbdefbfbd0e6eefbfbd");
+ const auto data = key.payload.decrypt(password);
+ EXPECT_EQ(hex(data), "043c5429c7872502531708ec0d821c711691402caf37ef7ba78a8c506f10653b");
+}
+
TEST(StoredKey, ReadWallet) {
const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json");
@@ -250,12 +260,12 @@ TEST(StoredKey, InvalidPassword) {
TEST(StoredKey, EmptyAccounts) {
const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/empty-accounts.json");
- ASSERT_NO_THROW(key.payload.decrypt("testpassword"));
+ ASSERT_NO_THROW(key.payload.decrypt(TW::data("testpassword")));
}
TEST(StoredKey, Decrypt) {
const auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/key.json");
- const auto privateKey = key.payload.decrypt("testpassword");
+ const auto privateKey = key.payload.decrypt(TW::data("testpassword"));
EXPECT_EQ(hex(privateKey), "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d");
}
@@ -310,7 +320,7 @@ TEST(StoredKey, MissingAddress) {
TEST(StoredKey, EtherWalletAddressNo0x) {
auto key = StoredKey::load(TESTS_ROOT + "/Keystore/Data/ethereum-wallet-address-no-0x.json");
- key.fixAddresses("15748c4e3dca6ae2110535576ab0c398cb79d985707c68ee6c9f9df9d421dd53");
+ key.fixAddresses(TW::data("15748c4e3dca6ae2110535576ab0c398cb79d985707c68ee6c9f9df9d421dd53"));
EXPECT_EQ(key.account(TWCoinTypeEthereum, nullptr)->address, "0xAc1ec44E4f0ca7D172B7803f6836De87Fb72b309");
}
diff --git a/tests/interface/TWStoredKeyTests.cpp b/tests/interface/TWStoredKeyTests.cpp
index b769752db9b..66704ee4c6f 100644
--- a/tests/interface/TWStoredKeyTests.cpp
+++ b/tests/interface/TWStoredKeyTests.cpp
@@ -10,7 +10,7 @@
#include
#include
#include
-
+#include
#include "../src/HexCoding.h"
#include
@@ -24,17 +24,19 @@ using namespace std;
/// Return a StoredKey instance that can be used for further tests. Needs to be deleted at the end.
-struct TWStoredKey *_Nonnull createAStoredKey(TWCoinType coin, const string& password) {
+struct TWStoredKey *_Nonnull createAStoredKey(TWCoinType coin, TWData* password) {
const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("team engine square letter hero song dizzy scrub tornado fabric divert saddle"));
const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name"));
- const auto password2 = WRAPS(TWStringCreateWithUTF8Bytes(password.c_str()));
- const auto key = TWStoredKeyImportHDWallet(mnemonic.get(), name.get(), password2.get(), coin);
+ const auto key = TWStoredKeyImportHDWallet(mnemonic.get(), name.get(), password, coin);
return key;
}
/// Return a StoredKey instance that can be used for further tests. Needs to be deleted at the end.
struct TWStoredKey *_Nonnull createDefaultStoredKey() {
- return createAStoredKey(TWCoinTypeBitcoin, "password");
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
+
+ return createAStoredKey(TWCoinTypeBitcoin, password.get());
}
TEST(TWStoredKey, loadPBKDF2Key) {
@@ -52,7 +54,8 @@ TEST(TWStoredKey, loadNonexistent) {
TEST(TWStoredKey, createWallet) {
const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name"));
- const auto password = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
const auto key = TWStoredKeyCreate(name.get(), password.get());
const auto name2 = WRAPS(TWStoredKeyName(key));
EXPECT_EQ(string(TWStringUTF8Bytes(name2.get())), "name");
@@ -66,7 +69,8 @@ TEST(TWStoredKey, importPrivateKey) {
const auto privateKeyHex = "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266";
const auto privateKey = WRAPD(TWDataCreateWithHexString(TWStringCreateWithUTF8Bytes(privateKeyHex)));
const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name"));
- const auto password = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
const auto coin = TWCoinTypeBitcoin;
const auto key = TWStoredKeyImportPrivateKey(privateKey.get(), name.get(), password.get(), coin);
const auto privateKey2 = WRAPD(TWStoredKeyDecryptPrivateKey(key, password.get()));
@@ -83,7 +87,8 @@ TEST(TWStoredKey, importPrivateKey) {
TEST(TWStoredKey, importHDWallet) {
const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("team engine square letter hero song dizzy scrub tornado fabric divert saddle"));
const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name"));
- const auto password = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
const auto coin = TWCoinTypeBitcoin;
const auto key = TWStoredKeyImportHDWallet(mnemonic.get(), name.get(), password.get(), coin);
EXPECT_TRUE(TWStoredKeyIsMnemonic(key));
@@ -96,11 +101,13 @@ TEST(TWStoredKey, importHDWallet) {
}
TEST(TWStoredKey, addressAddRemove) {
- const auto password = "password";
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
+
const auto coin = TWCoinTypeBitcoin;
- const auto key = createAStoredKey(coin, password);
+ const auto key = createAStoredKey(coin, password.get());
- const auto wallet = TWStoredKeyWallet(key, WRAPS(TWStringCreateWithUTF8Bytes(password)).get());
+ const auto wallet = TWStoredKeyWallet(key, password.get());
const auto accountCoin = TWStoredKeyAccountForCoin(key, coin, wallet);
const auto accountAddress = WRAPS(TWAccountAddress(accountCoin));
EXPECT_EQ(string(TWStringUTF8Bytes(accountAddress.get())), "bc1qturc268v0f2srjh4r2zu4t6zk4gdutqd5a6zny");
@@ -171,9 +178,11 @@ TEST(TWStoredKey, importJsonInvalid) {
}
TEST(TWStoredKey, fixAddresses) {
- const auto password = "password";
- const auto key = createAStoredKey(TWCoinTypeBitcoin, password);
- EXPECT_TRUE(TWStoredKeyFixAddresses(key, WRAPS(TWStringCreateWithUTF8Bytes(password)).get()));
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
+
+ const auto key = createAStoredKey(TWCoinTypeBitcoin, password.get());
+ EXPECT_TRUE(TWStoredKeyFixAddresses(key, password.get()));
TWStoredKeyDelete(key);
}
@@ -181,10 +190,11 @@ TEST(TWStoredKey, importInvalidKey) {
auto bytes = TW::parse_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
auto data = WRAPD(TWDataCreateWithBytes(bytes.data(), bytes.size()));
auto name = WRAPS(TWStringCreateWithUTF8Bytes("test"));
+ auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(name.get())), TWStringSize(name.get())));
- auto eth = TWStoredKeyImportPrivateKey(data.get(), name.get(), name.get(), TWCoinTypeEthereum);
- auto ont = TWStoredKeyImportPrivateKey(data.get(), name.get(), name.get(), TWCoinTypeOntology);
- auto tezos = TWStoredKeyImportPrivateKey(data.get(), name.get(), name.get(), TWCoinTypeTezos);
+ auto eth = TWStoredKeyImportPrivateKey(data.get(), name.get(), password.get(), TWCoinTypeEthereum);
+ auto ont = TWStoredKeyImportPrivateKey(data.get(), name.get(), password.get(), TWCoinTypeOntology);
+ auto tezos = TWStoredKeyImportPrivateKey(data.get(), name.get(), password.get(), TWCoinTypeTezos);
ASSERT_EQ(eth, nullptr);
ASSERT_EQ(ont, nullptr);
@@ -192,9 +202,11 @@ TEST(TWStoredKey, importInvalidKey) {
}
TEST(TWStoredKey, removeAccountForCoin) {
- auto password = "password";
- auto key = TWStoredKeyCreate("Test KeyStore", password);
- auto wallet = TWStoredKeyWallet(key, password);
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
+
+ auto key = TWStoredKeyCreate("Test KeyStore", password.get());
+ auto wallet = TWStoredKeyWallet(key, password.get());
ASSERT_NE(TWStoredKeyAccountForCoin(key, TWCoinTypeEthereum, wallet), nullptr);
ASSERT_NE(TWStoredKeyAccountForCoin(key, TWCoinTypeBitcoin, wallet), nullptr);
@@ -211,8 +223,12 @@ TEST(TWStoredKey, removeAccountForCoin) {
TEST(TWStoredKey, getWalletPasswordInvalid) {
const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name"));
- const auto password = WRAPS(TWStringCreateWithUTF8Bytes("password"));
- const auto passwordInvalid = WRAPS(TWStringCreateWithUTF8Bytes("_THIS_IS_INVALID_PASSWORD_"));
+ const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password"));
+ const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get())));
+
+ const auto invalidString = WRAPS(TWStringCreateWithUTF8Bytes("_THIS_IS_INVALID_PASSWORD_"));
+ const auto passwordInvalid = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(invalidString.get())), TWStringSize(invalidString.get())));
+
auto key = TWStoredKeyCreate (name.get(), password.get());
ASSERT_NE(TWStoredKeyWallet(key, password.get()), nullptr);
ASSERT_EQ(TWStoredKeyWallet(key, passwordInvalid.get()), nullptr);
From 8f8a3962fa867d5c6ce63f4e32851712b968ecb9 Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Thu, 9 Apr 2020 17:28:26 +0800
Subject: [PATCH 04/81] enable Filecoin json protobuf signing (#919)
---
src/Filecoin/Entry.cpp | 4 ++++
src/Filecoin/Entry.h | 2 ++
src/Filecoin/Signer.cpp | 10 ++++++++++
src/Filecoin/Signer.h | 3 +++
tests/Filecoin/TWAnySignerTests.cpp | 13 +++++++++++++
5 files changed, 32 insertions(+)
diff --git a/src/Filecoin/Entry.cpp b/src/Filecoin/Entry.cpp
index 8980a773fd8..ef98fcbdb87 100644
--- a/src/Filecoin/Entry.cpp
+++ b/src/Filecoin/Entry.cpp
@@ -25,3 +25,7 @@ string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byt
void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const {
signTemplate(dataIn, dataOut);
}
+
+string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const {
+ return Signer::signJSON(json, key);
+}
diff --git a/src/Filecoin/Entry.h b/src/Filecoin/Entry.h
index cb370ba5e3e..8259953005e 100644
--- a/src/Filecoin/Entry.h
+++ b/src/Filecoin/Entry.h
@@ -18,6 +18,8 @@ class Entry: public CoinEntry {
virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const;
virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const;
virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const;
+ virtual bool supportsJSONSigning() const { return true; }
+ virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const;
};
} // namespace TW::Filecoin
diff --git a/src/Filecoin/Signer.cpp b/src/Filecoin/Signer.cpp
index adadc8b9c29..ed5363ba63e 100644
--- a/src/Filecoin/Signer.cpp
+++ b/src/Filecoin/Signer.cpp
@@ -5,6 +5,8 @@
// file LICENSE at the root of the source code distribution tree.
#include "Signer.h"
+#include "HexCoding.h"
+#include
using namespace TW;
using namespace TW::Filecoin;
@@ -38,3 +40,11 @@ Data Signer::sign(const PrivateKey& privateKey, Transaction& transaction) noexce
auto signature = privateKey.sign(toSign, TWCurveSECP256k1);
return Data(signature.begin(), signature.end());
}
+
+std::string Signer::signJSON(const std::string& json, const Data& key) {
+ auto input = Proto::SigningInput();
+ google::protobuf::util::JsonStringToMessage(json, &input);
+ input.set_private_key(key.data(), key.size());
+ auto output = Signer::sign(input);
+ return hex(output.encoded());
+}
diff --git a/src/Filecoin/Signer.h b/src/Filecoin/Signer.h
index 4509374f882..3d20617bcb4 100644
--- a/src/Filecoin/Signer.h
+++ b/src/Filecoin/Signer.h
@@ -23,6 +23,9 @@ class Signer {
/// Signs a Proto::SigningInput transaction.
static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept;
+ /// Signs a json Proto::SigningInput with private key
+ static std::string signJSON(const std::string& json, const Data& key);
+
/// Signs the given transaction.
static Data sign(const PrivateKey& privateKey, Transaction& transaction) noexcept;
};
diff --git a/tests/Filecoin/TWAnySignerTests.cpp b/tests/Filecoin/TWAnySignerTests.cpp
index 6df308c8c47..e1dd177277e 100644
--- a/tests/Filecoin/TWAnySignerTests.cpp
+++ b/tests/Filecoin/TWAnySignerTests.cpp
@@ -59,3 +59,16 @@ TEST(TWAnySignerFilecoin, Sign) {
TWDataDelete(inputData);
TWDataDelete(outputData);
}
+
+TEST(TWAnySignerFilecoin, SignJSON) {
+ auto json = STRING(R"({"toAddress":"f3um6uo3qt5of54xjbx3hsxbw5mbsc6auxzrvfxekn5bv3duewqyn2tg5rhrlx73qahzzpkhuj7a34iq7oifsq","nonce":"2","value":"IIasNRBSYAAA","gasPrice":"Ag==","gasLimit":"1000"})");
+ auto key = DATA("1d969865e189957b9824bd34f26d5cbf357fda1a6d844cbf0c9ab1ed93fa7dbe");
+ auto result = WRAPS(TWAnySignerSignJSON(json.get(), key.get(), TWCoinTypeFilecoin));
+
+ ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeFilecoin));
+ assertStringsEqual(result,
+ "8288583103a33d476e13eb8bde5d21becf2b86dd60642f0297cc6a5b914de86bb1d096861ba99bb13c57"
+ "7fee003e72f51e89f837c45501cf01bf485f61435e6770b52615bf455e043a2361024a002086ac351052"
+ "600000420002430003e800405842014e896d4fa72a1f39c37a4415629dfbb7ea301b7f001fff60befa48"
+ "5903f51d824659ba19c5bc969d7206de7afabfc4a0eec2dd34f15e58a064adf4ee9f72e64f01");
+}
From 0d91994784f386f7373c66427131e107025ff791 Mon Sep 17 00:00:00 2001
From: lzxm160
Date: Fri, 10 Apr 2020 12:45:55 +0800
Subject: [PATCH 05/81] [IoTeX ] support IoTeX native staking (#912)
* support IoTeX native staking
---
.../app/blockchains/iotex/TestIotexSigning.kt | 227 +++++++++
src/IoTeX/Protobuf/.gitignore | 2 -
src/IoTeX/Protobuf/action.proto | 40 --
src/IoTeX/Signer.cpp | 42 +-
src/IoTeX/Signer.h | 3 +-
src/IoTeX/Staking.cpp | 114 +++--
src/IoTeX/Staking.h | 33 +-
src/proto/IoTeX.proto | 138 ++++--
swift/Tests/Blockchains/IoTeXTests.swift | 202 ++++++--
tests/IoTeX/StakingTests.cpp | 447 ++++++++++++------
tests/IoTeX/TWIoTeXStakingTests.cpp | 156 ------
tools/generate-files | 1 -
12 files changed, 885 insertions(+), 520 deletions(-)
create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/iotex/TestIotexSigning.kt
delete mode 100644 src/IoTeX/Protobuf/.gitignore
delete mode 100644 src/IoTeX/Protobuf/action.proto
delete mode 100644 tests/IoTeX/TWIoTeXStakingTests.cpp
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/iotex/TestIotexSigning.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/iotex/TestIotexSigning.kt
new file mode 100644
index 00000000000..1871c6c0d76
--- /dev/null
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/iotex/TestIotexSigning.kt
@@ -0,0 +1,227 @@
+package com.trustwallet.core.app.blockchains.IoTeX
+
+import com.google.protobuf.ByteString
+import com.trustwallet.core.app.utils.toHex
+import com.trustwallet.core.app.utils.Numeric
+import com.trustwallet.core.app.utils.toHexBytes
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import wallet.core.java.AnySigner
+import wallet.core.jni.CoinType.IOTEX
+import wallet.core.jni.proto.IoTeX
+import wallet.core.jni.proto.IoTeX.SigningOutput
+
+class TestIotexSigning {
+
+ init {
+ System.loadLibrary("TrustWalletCore")
+ }
+
+ @Test
+ fun testIotexSigningCreate() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign Create
+ val create = IoTeX.Staking.Create.newBuilder().apply {
+ candidateName = "io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj"
+ stakedAmount = "100"
+ stakedDuration = 10000
+ autoStake = true
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeCreate = create
+ }
+
+ val sign = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytes = sign.encoded
+ assertEquals(signBytes.toByteArray().toHex(), "0x0a4b080118c0843d22023130c2023e0a29696f313964307033616834673877773964376b63786671383779786537666e7238727074683573686a120331303018904e20012a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a412e8bac421bab88dcd99c26ac8ffbf27f11ee57a41e7d2537891bfed5aed8e2e026d46e55d1b856787bc1cd7c1216a6e2534c5b5d1097c3afe8e657aa27cbbb0801")
+ }
+ fun testIotexSigningAddDeposit() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign AddDeposit
+ val adddeposit = IoTeX.Staking.AddDeposit.newBuilder().apply {
+ bucketIndex = 10
+ amount = "10"
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeAddDeposit = adddeposit
+ }
+
+ var signAddDeposit = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ var signBytesAddDeposit = signAddDeposit.encoded
+ assertEquals(signBytesAddDeposit.toByteArray().toHex(), "0x0a1c080118c0843d22023130da020f080a120231301a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41a48ab1feba8181d760de946aefed7d815a89fd9b1ab503d2392bb55e1bb75eec42dddc8bd642f89accc3a37b3cf15a103a95d66695fdf0647b202869fdd66bcb01")
+ }
+ fun testIotexSigningUnstake() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign Unstake
+ val unstake = IoTeX.Staking.Reclaim.newBuilder().apply {
+ bucketIndex = 10
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeUnstake = unstake
+ }
+
+ val signUnstake = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesUnstake = signUnstake.encoded
+ assertEquals(signBytesUnstake.toByteArray().toHex(), "0x0a18080118c0843d22023130ca020b080a12077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a4100adee39b48e1d3dbbd65298a57c7889709fc4df39987130da306f6997374a184b7e7c232a42f21e89b06e6e7ceab81303c6b7483152d08d19ac829b22eb81e601")
+ }
+ fun testIotexSigningWithdraw() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign Withdraw
+ val withdraw = IoTeX.Staking.Reclaim.newBuilder().apply {
+ bucketIndex = 10
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeWithdraw = withdraw
+ }
+
+ val signWithdraw = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesWithdraw = signWithdraw.encoded
+ assertEquals(signBytesWithdraw.toByteArray().toHex(), "0x0a18080118c0843d22023130d2020b080a12077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a4152644d102186be6640d46b517331f3402e24424b0d85129595421d28503d75340b2922f5a0d4f667bbd6f576d9816770286b2ce032ba22eaec3952e24da4756b00")
+ }
+ fun testIotexSigningRestake() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign Restake
+ val restake = IoTeX.Staking.Restake.newBuilder().apply {
+ bucketIndex = 10
+ stakedDuration = 1000
+ autoStake = true
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeRestake = restake
+ }
+
+ val signRestake = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesRestake = signRestake.encoded
+ assertEquals(signBytesRestake.toByteArray().toHex(), "0x0a1d080118c0843d22023130e20210080a10e807180122077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41e2e763aed5b1fd1a8601de0f0ae34eb05162e34b0389ae3418eedbf762f64959634a968313a6516dba3a97b34efba4753bbed3a33d409ecbd45ac75007cd8e9101")
+ }
+ fun testIotexSigningChangeCandidate() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign ChangeCandidate
+ val changecandidate = IoTeX.Staking.ChangeCandidate.newBuilder().apply {
+ bucketIndex = 10
+ candidateName = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza"
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeChangeCandidate = changecandidate
+ }
+
+ val signChangeCandidate = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesChangeCandidate = signChangeCandidate.encoded
+ assertEquals(signBytesChangeCandidate.toByteArray().toHex(), "0x0a43080118c0843d22023130ea0236080a1229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41d519eb3747163b945b862989b7e82a7f8468001e9683757cb88d5ddd95f81895047429e858bd48f7d59a88bfec92de231d216293aeba1e4fbe11461d9c9fc99801")
+ }
+ fun testIotexSigningTransferOwnership() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign TransferOwnership
+ val transfer = IoTeX.Staking.TransferOwnership.newBuilder().apply {
+ bucketIndex = 10
+ voterAddress = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza"
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+
+ input.apply {
+ stakeTransferOwnership = transfer
+ }
+
+ val signTransferOwnership = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesTransferOwnership = signTransferOwnership.encoded
+ assertEquals(signBytesTransferOwnership.toByteArray().toHex(), "0x0a43080118c0843d22023130f20236080a1229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41fa26db427ab87a56a129196c1604f2e22c4dd2a1f99b2217bc916260757d00093d9e6dccdf53e3b0b64e41a69d71c238fbf9281625164694a74dfbeba075d0ce01")
+ }
+ fun testIotexSigningCandidateBasicInfo() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("10")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign CandidateBasicInfo
+ val cbi = IoTeX.Staking.CandidateBasicInfo.newBuilder().apply {
+ name = "test"
+ operatorAddress = "io1cl6rl2ev5dfa988qmgzg2x4hfazmp9vn2g66ng"
+ rewardAddress = "io1juvx5g063eu4ts832nukp4vgcwk2gnc5cu9ayd"
+ }.build()
+
+ input.apply {
+ candidateUpdate = cbi
+ }
+
+ val signCandidateBasicInfo = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesCandidateBasicInfo = signCandidateBasicInfo.encoded
+ assertEquals(signBytesCandidateBasicInfo.toByteArray().toHex(), "0x0a69080118c0843d2202313082035c0a04746573741229696f31636c36726c32657635646661393838716d677a673278346866617a6d7039766e326736366e671a29696f316a757678356730363365753474733833326e756b7034766763776b32676e6335637539617964124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a4101885c9c6684a4a8f2f5bf11f8326f27be48658f292e8f55ec8a11a604bb0c563a11ebf12d995ca1c152e00f8e0f0edf288db711aa10dbdfd5b7d73b4a28e1f701")
+ }
+ fun testIotexSigningCandidateRegister() {
+ val input = IoTeX.SigningInput.newBuilder()
+ .setVersion(1)
+ .setNonce(0)
+ .setGasLimit(1000000)
+ .setGasPrice("1000")
+ .setPrivateKey(ByteString.copyFrom(Numeric.hexStringToByteArray("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")))
+ // test sign CandidateBasicInfo
+ val cbi = IoTeX.Staking.CandidateBasicInfo.newBuilder().apply {
+ name = "test"
+ operatorAddress = "io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he"
+ rewardAddress = "io13sj9mzpewn25ymheukte4v39hvjdtrfp00mlyv"
+ }.build()
+ val cr = IoTeX.Staking.CandidateRegister.newBuilder().apply {
+ candidate = cbi
+ stakedAmount = "100"
+ stakedDuration = 10000
+ autoStake = false
+ ownerAddress ="io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj"
+ payload = ByteString.copyFrom("payload".toByteArray())
+ }.build()
+ input.apply {
+ candidateRegister = cr
+ }
+
+ val signCandidateRegister = AnySigner.sign(input.build(), IOTEX, SigningOutput.parser())
+ val signBytesCandidateRegister = signCandidateRegister.encoded
+ assertEquals(signBytesCandidateRegister.toByteArray().toHex(), "0x0aaa01080118c0843d220431303030fa029a010a5c0a04746573741229696f3130613239387a6d7a7672743467757137396139663478377165646a35397937657279383468651a29696f3133736a396d7a7065776e3235796d6865756b74653476333968766a647472667030306d6c7976120331303018904e2a29696f313964307033616834673877773964376b63786671383779786537666e7238727074683573686a32077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a417819b5bcb635e3577acc8ca757f2c3d6afa451c2b6ff8a9179b141ac68e2c50305679e5d09d288da6f0fb52876a86c74deab6a5247edc6d371de5c2f121e159400")
+ }
+}
diff --git a/src/IoTeX/Protobuf/.gitignore b/src/IoTeX/Protobuf/.gitignore
deleted file mode 100644
index 687ffbb426e..00000000000
--- a/src/IoTeX/Protobuf/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.cc
-*.h
diff --git a/src/IoTeX/Protobuf/action.proto b/src/IoTeX/Protobuf/action.proto
deleted file mode 100644
index 921d8c38807..00000000000
--- a/src/IoTeX/Protobuf/action.proto
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2018 IoTeX
-// This is an alpha (internal) release and is not suitable for production. This
-// source code is provided 'as is' and no warranties are given as to title or
-// non-infringement, merchantability or fitness for purpose and, to the extent
-// permitted by law, all liability for your use of the code is disclaimed. This
-// source code is governed by Apache License 2.0 that can be found in the
-// LICENSE file.
-
-syntax = "proto3";
-package iotextypes;
-
-message Transfer {
- // used by state-based model
- string amount = 1;
- string recipient = 2;
- bytes payload = 3;
-}
-
-message Execution {
- string amount = 1;
- string contract = 2;
- bytes data = 3;
-}
-
-message ActionCore {
- uint32 version = 1;
- uint64 nonce = 2;
- uint64 gasLimit = 3;
- string gasPrice = 4;
- oneof action {
- Transfer transfer = 10;
- Execution execution = 12;
- }
-}
-
-message Action {
- ActionCore core = 1;
- bytes senderPubKey = 2;
- bytes signature = 3;
-}
diff --git a/src/IoTeX/Signer.cpp b/src/IoTeX/Signer.cpp
index e7fb547d025..6b0e6d6ec1a 100644
--- a/src/IoTeX/Signer.cpp
+++ b/src/IoTeX/Signer.cpp
@@ -24,7 +24,7 @@ Data Signer::sign() const {
}
Proto::SigningOutput Signer::build() const {
- auto signedAction = iotextypes::Action();
+ auto signedAction = Proto::Action();
signedAction.mutable_core()->MergeFrom(action);
auto key = PrivateKey(input.privatekey());
auto pk = key.getPublicKey(TWPublicKeyTypeSECP256k1Extended).bytes;
@@ -32,7 +32,7 @@ Proto::SigningOutput Signer::build() const {
auto sig = key.sign(hash(), TWCurveSECP256k1);
signedAction.set_signature(sig.data(), sig.size());
- auto output = IoTeX::Proto::SigningOutput();
+ auto output = Proto::SigningOutput();
auto serialized = signedAction.SerializeAsString();
output.set_encoded(serialized);
auto h = Hash::keccak256(serialized);
@@ -44,41 +44,7 @@ Data Signer::hash() const {
return Hash::keccak256(action.SerializeAsString());
}
-static Data encodeStaking(const Proto::Staking& staking) {
- Data encoded;
- if (staking.has_stake()) {
- auto& stake = staking.stake();
- stakingStake(TW::data(stake.candidate()), stake.duration(), stake.nondecay(), TW::data(stake.data()), encoded);
- } else if (staking.has_unstake()) {
- auto& unstake = staking.unstake();
- stakingUnstake(unstake.piggy_index(), TW::data(unstake.data()), encoded);
- } else if (staking.has_withdraw()) {
- auto& withdraw = staking.withdraw();
- stakingWithdraw(withdraw.piggy_index(), TW::data(withdraw.data()), encoded);
- } else if (staking.has_movestake()) {
- auto& move = staking.movestake();
- stakingMoveStake(move.piggy_index(), TW::data(move.candidate()), TW::data(move.data()), encoded);
- } else if (staking.has_addstake()) {
- auto& add = staking.addstake();
- stakingAddStake(add.piggy_index(), TW::data(add.data()), encoded);
- }
- return encoded;
-}
void Signer::toActionCore() {
- if (input.has_staking()) {
- action.set_version(input.version());
- action.set_nonce(input.nonce());
- action.set_gaslimit(input.gaslimit());
- action.set_gasprice(input.gasprice());
- auto& staking = input.staking();
- auto encoded = encodeStaking(staking);
- auto& execution = *action.mutable_execution();
- execution.set_amount(staking.amount());
- execution.set_contract(staking.contract());
- execution.set_data(encoded.data(), encoded.size());
- } else {
- // ActionCore is almost same as SigningInput, missing field privateKey = 5;
- action.ParseFromString(input.SerializeAsString());
- action.DiscardUnknownFields();
- }
+ action.ParseFromString(input.SerializeAsString());
+ action.DiscardUnknownFields();
}
diff --git a/src/IoTeX/Signer.h b/src/IoTeX/Signer.h
index d1e5d8caf33..31fc2c8a15f 100644
--- a/src/IoTeX/Signer.h
+++ b/src/IoTeX/Signer.h
@@ -9,7 +9,6 @@
#include "Data.h"
#include "proto/IoTeX.pb.h"
-#include "Protobuf/action.pb.h"
namespace TW::IoTeX {
@@ -20,7 +19,7 @@ class Signer {
static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept;
public:
Proto::SigningInput input;
- iotextypes::ActionCore action;
+ Proto::ActionCore action;
/// Initializes a transaction signer
Signer(const Proto::SigningInput& input) : input(input) { toActionCore(); }
diff --git a/src/IoTeX/Staking.cpp b/src/IoTeX/Staking.cpp
index 938be61ed9d..493b3a86013 100644
--- a/src/IoTeX/Staking.cpp
+++ b/src/IoTeX/Staking.cpp
@@ -5,56 +5,106 @@
// file LICENSE at the root of the source code distribution tree.
#include "Staking.h"
-
-#include "Ethereum/ABI/Function.h"
#include "Data.h"
-#include "uint256.h"
+#include "HexCoding.h"
+using namespace TW;
namespace TW::IoTeX {
-using namespace TW::Ethereum::ABI;
+const char* FromData(const Data& data) {
+ auto s = new std::string(data.begin(), data.end());
+ s->append(data.size(), '\0');
+ auto ss = reinterpret_cast(s);
+ return ss->data();
+}
-void stakingStake(const Data& candidate, uint64_t stakeDuration, bool nonDecay, const Data& dataIn, Data& dataOut) {
- Function func("createPygg");
- func.addInParam(std::make_shared(12, candidate));
- func.addInParam(std::make_shared(uint256_t(stakeDuration)));
- func.addInParam(std::make_shared(nonDecay));
- func.addInParam(std::make_shared(dataIn));
+Data dataFromString(const std::string& d) {
+ Data data;
+ std::copy(d.c_str(), d.c_str() + d.length(), back_inserter(data));
+ return data;
+}
- func.encode(dataOut);
+Data stakingCreate(const Data& candidate, const Data& amount, uint32_t duration, bool autoStake,
+ const Data& payload) {
+ auto action = IoTeX::Proto::Staking_Create();
+ action.set_candidatename(FromData(candidate));
+ action.set_stakedamount(FromData(amount));
+ action.set_stakedduration(duration);
+ action.set_autostake(autoStake);
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
}
-void stakingUnstake(uint64_t pyggIndex, const Data& dataIn, Data& dataOut) {
- Function func("unstake");
- func.addInParam(std::make_shared(uint256_t(pyggIndex)));
- func.addInParam(std::make_shared(dataIn));
+Data stakingAddDeposit(uint64_t index, const Data& amount, const Data& payload) {
+ auto action = IoTeX::Proto::Staking_AddDeposit();
+ action.set_bucketindex(index);
+ action.set_amount(FromData(amount));
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
+}
- func.encode(dataOut);
+Data stakingUnstake(uint64_t index, const Data& payload) {
+ auto action = IoTeX::Proto::Staking_Reclaim();
+ action.set_bucketindex(index);
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
}
-void stakingWithdraw(uint64_t pyggIndex, const Data& dataIn, Data& dataOut) {
- Function func("withdraw");
- func.addInParam(std::make_shared(uint256_t(pyggIndex)));
- func.addInParam(std::make_shared(dataIn));
+Data stakingWithdraw(uint64_t index, const Data& payload) {
+ auto action = IoTeX::Proto::Staking_Reclaim();
+ action.set_bucketindex(index);
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
+}
- func.encode(dataOut);
+Data stakingRestake(uint64_t index, uint32_t duration, bool autoStake, const Data& payload) {
+ auto action = IoTeX::Proto::Staking_Restake();
+ action.set_bucketindex(index);
+ action.set_stakedduration(duration);
+ action.set_autostake(autoStake);
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
}
-void stakingAddStake(uint64_t pyggIndex, const Data& dataIn, Data& dataOut) {
- Function func("storeToPygg");
- func.addInParam(std::make_shared(uint256_t(pyggIndex)));
- func.addInParam(std::make_shared(dataIn));
+Data stakingChangeCandidate(uint64_t index, const Data& candidate, const Data& payload) {
+ auto action = IoTeX::Proto::Staking_ChangeCandidate();
+ action.set_bucketindex(index);
+ action.set_candidatename(FromData(candidate));
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
+}
- func.encode(dataOut);
+Data stakingTransfer(uint64_t index, const Data& voterAddress, const Data& payload) {
+ auto action = IoTeX::Proto::Staking_TransferOwnership();
+ action.set_bucketindex(index);
+ action.set_voteraddress(FromData(voterAddress));
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
}
-void stakingMoveStake(uint64_t pyggIndex, const Data& candidate, const Data& dataIn, Data& dataOut) {
- Function func("revote");
- func.addInParam(std::make_shared(uint256_t(pyggIndex)));
- func.addInParam(std::make_shared(12, candidate));
- func.addInParam(std::make_shared(dataIn));
+Data candidateRegister(const Data& name, const Data& operatorAddress, const Data& rewardAddress,
+ const Data& amount, uint32_t duration, bool autoStake,
+ const Data& ownerAddress, const Data& payload) {
+ auto cbi = new IoTeX::Proto::Staking_CandidateBasicInfo();
+ cbi->set_name(FromData(name));
+ cbi->set_operatoraddress(FromData(operatorAddress));
+ cbi->set_rewardaddress(FromData(rewardAddress));
- func.encode(dataOut);
+ auto action = IoTeX::Proto::Staking_CandidateRegister();
+ action.set_allocated_candidate(cbi);
+ action.set_stakedamount(FromData(amount));
+ action.set_stakedduration(duration);
+ action.set_autostake(autoStake);
+ action.set_owneraddress(FromData(ownerAddress));
+ action.set_payload(FromData(payload));
+ return dataFromString(action.SerializeAsString());
}
+Data candidateUpdate(const Data& name, const Data& operatorAddress, const Data& rewardAddress) {
+ auto action = IoTeX::Proto::Staking_CandidateBasicInfo();
+ action.set_name(FromData(name));
+ action.set_operatoraddress(FromData(operatorAddress));
+ action.set_rewardaddress(FromData(rewardAddress));
+ return dataFromString(action.SerializeAsString());
+}
} // namespace TW::IoTeX
diff --git a/src/IoTeX/Staking.h b/src/IoTeX/Staking.h
index 9d5a6846be1..73a5e737473 100644
--- a/src/IoTeX/Staking.h
+++ b/src/IoTeX/Staking.h
@@ -7,22 +7,37 @@
#pragma once
#include "Data.h"
-
+#include "proto/IoTeX.pb.h"
namespace TW::IoTeX {
-/// Function to generate Stake message
-void stakingStake(const Data& candidate, uint64_t stakeDuration, bool nonDecay, const Data& dataIn, Data& dataOut);
+/// Function to generate Create message
+Data stakingCreate(const Data& candidate, const Data& amount, uint32_t duration, bool autoStake,
+ const Data& payload);
+
+/// Function to generate AddDeposit message
+Data stakingAddDeposit(uint64_t index, const Data& amount, const Data& payload);
/// Function to generate Unstake message
-void stakingUnstake(uint64_t pyggIndex, const Data& dataIn, Data& dataOut);
+Data stakingUnstake(uint64_t index, const Data& payload);
/// Function to generate Withdraw message
-void stakingWithdraw(uint64_t pyggIndex, const Data& dataIn, Data& dataOut);
+Data stakingWithdraw(uint64_t index, const Data& payload);
+
+/// Function to generate Restake message
+Data stakingRestake(uint64_t index, uint32_t duration, bool autoStake, const Data& payload);
+
+/// Function to generate ChangeCandidate message
+Data stakingChangeCandidate(uint64_t index, const Data& candidate, const Data& payload);
+
+/// Function to generate Transfer message
+Data stakingTransfer(uint64_t index, const Data& voterAddress, const Data& payload);
-/// Function to generate AddStake message
-void stakingAddStake(uint64_t pyggIndex, const Data& dataIn, Data& dataOut);
+/// Function to generate candidate register message
+Data candidateRegister(const Data& name, const Data& operatorAddress, const Data& rewardAddress,
+ const Data& amount, uint32_t duration, bool autoStake,
+ const Data& ownerAddress, const Data& payload);
-/// Function to generate MoveStake message
-void stakingMoveStake(uint64_t pyggIndex, const Data& candidate, const Data& dataIn, Data& dataOut);
+/// Function to generate candidate update message
+Data candidateUpdate(const Data& name, const Data& operatorAddress, const Data& rewardAddress);
} // namespace TW::IoTeX
diff --git a/src/proto/IoTeX.proto b/src/proto/IoTeX.proto
index 669b049ecb3..1df337cf627 100644
--- a/src/proto/IoTeX.proto
+++ b/src/proto/IoTeX.proto
@@ -10,43 +10,73 @@ message Transfer {
}
message Staking {
- message Stake {
- string candidate = 1;
- uint64 duration = 2;
- bool nonDecay= 3;
- bytes data = 4;
- }
-
- message Unstake {
- uint64 piggy_index = 1;
- bytes data = 2;
- }
-
- message Withdraw {
- uint64 piggy_index = 1;
- bytes data = 2;
- }
-
- message AddStake {
- uint64 piggy_index = 1;
- bytes data = 2;
- }
-
- message MoveStake {
- uint64 piggy_index = 1;
- string candidate = 2;
- bytes data = 3;
- }
+ // create stake
+ message Create {
+ string candidateName = 1;
+ string stakedAmount = 2;
+ uint32 stakedDuration = 3;
+ bool autoStake = 4;
+ bytes payload = 5;
+ }
- string amount = 1;
- string contract = 2;
+ // unstake or withdraw
+ message Reclaim {
+ uint64 bucketIndex = 1;
+ bytes payload = 2;
+ }
+
+ // add the amount of bucket
+ message AddDeposit {
+ uint64 bucketIndex = 1;
+ string amount = 2;
+ bytes payload = 3;
+ }
+
+ // restake the duration and autoStake flag of bucket
+ message Restake {
+ uint64 bucketIndex = 1;
+ uint32 stakedDuration = 2;
+ bool autoStake = 3;
+ bytes payload = 4;
+ }
+
+ // move the bucket to vote for another candidate or transfer the ownership of bucket to another voters
+ message ChangeCandidate {
+ uint64 bucketIndex = 1;
+ string candidateName = 2;
+ bytes payload = 3;
+ }
- oneof message {
- Stake stake = 3;
- Unstake unstake = 4;
- Withdraw withdraw = 5;
- AddStake addStake = 6;
- MoveStake moveStake = 7;
+ message TransferOwnership {
+ uint64 bucketIndex = 1;
+ string voterAddress = 2;
+ bytes payload = 3;
+ }
+
+ message CandidateBasicInfo {
+ string name = 1;
+ string operatorAddress = 2;
+ string rewardAddress = 3;
+ }
+
+ message CandidateRegister {
+ CandidateBasicInfo candidate = 1;
+ string stakedAmount = 2;
+ uint32 stakedDuration = 3;
+ bool autoStake = 4;
+ string ownerAddress = 5; // if ownerAddress is absent, owner of candidate is the sender
+ bytes payload = 6;
+ }
+ oneof message {
+ Create stakeCreate = 1;
+ Reclaim stakeUnstake = 2;
+ Reclaim stakeWithdraw = 3;
+ AddDeposit stakeAddDeposit = 4;
+ Restake stakeRestake = 5;
+ ChangeCandidate stakeChangeCandidate = 6;
+ TransferOwnership stakeTransferOwnership = 7;
+ CandidateRegister candidateRegister = 8;
+ CandidateBasicInfo candidateUpdate = 9;
}
}
@@ -65,8 +95,17 @@ message SigningInput {
bytes privateKey = 5;
oneof action {
Transfer transfer = 10;
- Staking staking = 11;
ContractCall call = 12;
+ // Native staking
+ Staking.Create stakeCreate = 40;
+ Staking.Reclaim stakeUnstake = 41;
+ Staking.Reclaim stakeWithdraw = 42;
+ Staking.AddDeposit stakeAddDeposit = 43;
+ Staking.Restake stakeRestake = 44;
+ Staking.ChangeCandidate stakeChangeCandidate = 45;
+ Staking.TransferOwnership stakeTransferOwnership = 46;
+ Staking.CandidateRegister candidateRegister = 47;
+ Staking.CandidateBasicInfo candidateUpdate = 48;
}
}
@@ -78,3 +117,30 @@ message SigningOutput {
// Signed Action hash
bytes hash = 2;
}
+
+message ActionCore {
+ uint32 version = 1;
+ uint64 nonce = 2;
+ uint64 gasLimit = 3;
+ string gasPrice = 4;
+ oneof action {
+ Transfer transfer = 10;
+ ContractCall execution = 12;
+ // Native staking
+ Staking.Create stakeCreate = 40;
+ Staking.Reclaim stakeUnstake = 41;
+ Staking.Reclaim stakeWithdraw = 42;
+ Staking.AddDeposit stakeAddDeposit = 43;
+ Staking.Restake stakeRestake = 44;
+ Staking.ChangeCandidate stakeChangeCandidate = 45;
+ Staking.TransferOwnership stakeTransferOwnership = 46;
+ Staking.CandidateRegister candidateRegister = 47;
+ Staking.CandidateBasicInfo candidateUpdate = 48;
+ }
+}
+
+message Action {
+ ActionCore core = 1;
+ bytes senderPubKey = 2;
+ bytes signature = 3;
+}
\ No newline at end of file
diff --git a/swift/Tests/Blockchains/IoTeXTests.swift b/swift/Tests/Blockchains/IoTeXTests.swift
index 1209db8d4e1..0e68e5ab83f 100644
--- a/swift/Tests/Blockchains/IoTeXTests.swift
+++ b/swift/Tests/Blockchains/IoTeXTests.swift
@@ -8,7 +8,6 @@ import XCTest
import TrustWalletCore
class IoTeXTests: XCTestCase {
-
func testSign() {
let privateKey = PrivateKey(data: Data(hexString: "0x68ffa8ec149ce50da647166036555f73d57f662eb420e154621e5f24f6cf9748")!)!
@@ -29,81 +28,182 @@ class IoTeXTests: XCTestCase {
XCTAssertEqual(output.encoded.hexString, "0a39080110011801220131522e0a01311229696f3165326e7173797437666b707a733578377a6632756b306a6a3732746575356e36616b75337472124104fb30b196ce3e976593ecc2da220dca9cdea8c84d2373770042a930b892ac0f5cf762f20459c9100eb9d4d7597f5817bf21e10b53a0120b9ec1ba5cddfdcb669b1a41ec9757ae6c9009315830faaab250b6db0e9535b00843277f596ae0b2b9efc0bd4e14138c056fc4cdfa285d13dd618052b3d1cb7a3f554722005a2941bfede96601")
}
- func stakingInput() -> IoTeXSigningInput {
- let input = IoTeXSigningInput.with {
+ func testSignStakingCreate() {
+ var input = IoTeXSigningInput.with {
$0.version = 1
- $0.nonce = 123
- $0.gasLimit = 888
- $0.gasPrice = "999"
- $0.staking = IoTeXStaking.with {
- $0.amount = "456"
- $0.contract = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza"
- }
- $0.privateKey = Data(hexString: "0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f")!
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
}
- return input
+ input.stakeCreate = IoTeXStaking.Create.with {
+ $0.candidateName = "io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj"
+ $0.stakedAmount = "100"
+ $0.stakedDuration = 10000
+ $0.autoStake = true
+ $0.payload = "payload".data(using: .utf8)!
+ }
+ let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
+
+ XCTAssertEqual(output.encoded.hexString, "0a4b080118c0843d22023130c2023e0a29696f313964307033616834673877773964376b63786671383779786537666e7238727074683573686a120331303018904e20012a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a412e8bac421bab88dcd99c26ac8ffbf27f11ee57a41e7d2537891bfed5aed8e2e026d46e55d1b856787bc1cd7c1216a6e2534c5b5d1097c3afe8e657aa27cbbb0801")
+ XCTAssertEqual(output.hash.hexString, "f1785e47b4200c752bb6518bd18097a41e075438b8c18c9cb00e1ae2f38ce767")
}
- func testStake() {
- // candidate name is a string
- let candidate = "\u{01}\u{02}\u{03}\u{04}\u{05}\u{06}\u{07}\u{08}\t\n\u{0B}\u{0C}"
- var input = stakingInput()
- input.staking.stake = IoTeXStaking.Stake.with {
- $0.candidate = candidate
- $0.duration = 1001
- $0.nonDecay = true
- $0.data = "this is a test".data(using: .utf8)!
+ func testSignStakingAddDeposit() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.stakeAddDeposit = IoTeXStaking.AddDeposit.with {
+ $0.bucketIndex = 10
+ $0.amount = "10"
+ $0.payload = "payload".data(using: .utf8)!
}
let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
- XCTAssertEqual(output.encoded.hexString, "0a86020801107b18f806220339393962f7010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611ac40107c35fc00102030405060708090a0b0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e74686973206973206120746573740000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41a558bc9a4bfba920242ccd4d5c5da363ec534d4dd5eb67f88e9db7aaad5c50ad62dfe298c0e54e311ebba045f48cea1136e42a123a8e6b03d3e6ed82d4ec2b9401")
- XCTAssertEqual(output.hash.hexString, "41b1f8be5f6b884c06556fba2611716e8e514b507f5a653fc02ac50ba13fbd6c")
+ XCTAssertEqual(output.encoded.hexString, "0a1c080118c0843d22023130da020f080a120231301a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41a48ab1feba8181d760de946aefed7d815a89fd9b1ab503d2392bb55e1bb75eec42dddc8bd642f89accc3a37b3cf15a103a95d66695fdf0647b202869fdd66bcb01")
+ XCTAssertEqual(output.hash.hexString, "ca8937d6f224a4e4bf93cb5605581de2d26fb0481e1dfc1eef384ee7ccf94b73")
}
+
+ func testSignStakingUnstake() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.stakeUnstake = IoTeXStaking.Reclaim.with {
+ $0.bucketIndex = 10
+ $0.payload = "payload".data(using: .utf8)!
+ }
+ let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
- func testUnstake() {
- var input = stakingInput()
- input.staking.unstake = IoTeXStaking.Unstake.with {
- $0.piggyIndex = 1001
+ XCTAssertEqual(output.encoded.hexString, "0a18080118c0843d22023130ca020b080a12077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a4100adee39b48e1d3dbbd65298a57c7889709fc4df39987130da306f6997374a184b7e7c232a42f21e89b06e6e7ceab81303c6b7483152d08d19ac829b22eb81e601")
+ XCTAssertEqual(output.hash.hexString, "bed58b64a6c4e959eca60a86f0b2149ce0e1dd527ac5fd26aef725ebf7c22a7d")
+ }
+
+ func testSignStakingWithdraw() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.stakeWithdraw = IoTeXStaking.Reclaim.with {
+ $0.bucketIndex = 10
+ $0.payload = "payload".data(using: .utf8)!
}
let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
- XCTAssertEqual(output.encoded.hexString, "0aa5010801107b18f80622033939396296010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a64c8fd6ed000000000000000000000000000000000000000000000000000000000000003e9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41eeb7cb3fa7ec22a61156753d569b3f4da3c74c3c7e2f148b1a43e11d220cac5d164663ff6c785439679b088de9d7f2437545f007ca9cda4b2f5327d2c6eda5aa01")
- XCTAssertEqual(output.hash.hexString, "b93a2874a72ce4eb8a41a20c209cf3fd188671ed8be8239a57960cbed887e962")
+ XCTAssertEqual(output.encoded.hexString, "0a18080118c0843d22023130d2020b080a12077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a4152644d102186be6640d46b517331f3402e24424b0d85129595421d28503d75340b2922f5a0d4f667bbd6f576d9816770286b2ce032ba22eaec3952e24da4756b00")
+ XCTAssertEqual(output.hash.hexString, "28049348cf34f1aa927caa250e7a1b08778c44efaf73b565b6fa9abe843871b4")
}
- func testWithdraw() {
- var input = stakingInput()
- input.staking.withdraw = IoTeXStaking.Withdraw.with {
- $0.piggyIndex = 1001
+ func testSignStakingRestake() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.stakeRestake = IoTeXStaking.Restake.with {
+ $0.bucketIndex = 10
+ $0.stakedDuration = 1000
+ $0.autoStake = true
+ $0.payload = "payload".data(using: .utf8)!
}
let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
- XCTAssertEqual(output.encoded.hexString, "0aa5010801107b18f80622033939396296010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a64030ba25d00000000000000000000000000000000000000000000000000000000000003e9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41903c79d042f6b1c05446ececb3d760ca154c539b5787e66135cd3db77638294d18dbbbbcb0de8b9a393cc7c0448cf246898e4343a2a51666e21e738ee6d8a6f700")
- XCTAssertEqual(output.hash.hexString, "2b2657247a72cb262de214b4e793c7a01fa2139fd5d12a46d43c24f87f9e2396")
+ XCTAssertEqual(output.encoded.hexString, "0a1d080118c0843d22023130e20210080a10e807180122077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41e2e763aed5b1fd1a8601de0f0ae34eb05162e34b0389ae3418eedbf762f64959634a968313a6516dba3a97b34efba4753bbed3a33d409ecbd45ac75007cd8e9101")
+ XCTAssertEqual(output.hash.hexString, "8816e8f784a1fce40b54d1cd172bb6976fd9552f1570c73d1d9fcdc5635424a9")
}
- func testAddStake() {
- var input = stakingInput()
- input.staking.addStake = IoTeXStaking.AddStake.with {
- $0.piggyIndex = 1001
+ func testSignStakingChangeCandidate() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.stakeChangeCandidate = IoTeXStaking.ChangeCandidate.with {
+ $0.bucketIndex = 10
+ $0.candidateName = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza"
+ $0.payload = "payload".data(using: .utf8)!
+ }
+ let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
+
+ XCTAssertEqual(output.encoded.hexString, "0a43080118c0843d22023130ea0236080a1229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41d519eb3747163b945b862989b7e82a7f8468001e9683757cb88d5ddd95f81895047429e858bd48f7d59a88bfec92de231d216293aeba1e4fbe11461d9c9fc99801")
+ XCTAssertEqual(output.hash.hexString, "186526b5b9fe74e25beb52c83c41780a69108160bef2ddaf3bffb9f1f1e5e73a")
+ }
+
+ func testSignStakingTransfer() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.stakeTransferOwnership = IoTeXStaking.TransferOwnership.with {
+ $0.bucketIndex = 10
+ $0.voterAddress = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza"
+ $0.payload = "payload".data(using: .utf8)!
+ }
+ let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
+
+ XCTAssertEqual(output.encoded.hexString, "0a43080118c0843d22023130f20236080a1229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a41fa26db427ab87a56a129196c1604f2e22c4dd2a1f99b2217bc916260757d00093d9e6dccdf53e3b0b64e41a69d71c238fbf9281625164694a74dfbeba075d0ce01")
+ XCTAssertEqual(output.hash.hexString, "74b2e1d6a09ba5d1298fa422d5850991ae516865077282196295a38f93c78b85")
+ }
+
+ func testSignCandidateRegister() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "1000"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.candidateRegister = IoTeXStaking.CandidateRegister.with {
+ $0.candidate = IoTeXStaking.CandidateBasicInfo.with {
+ $0.name = "test"
+ $0.operatorAddress = "io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he"
+ $0.rewardAddress = "io13sj9mzpewn25ymheukte4v39hvjdtrfp00mlyv"
+ }
+ $0.stakedAmount = "100"
+ $0.stakedDuration = 10000
+ $0.autoStake = false
+ $0.ownerAddress = "io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj"
+ $0.payload = "payload".data(using: .utf8)!
}
let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
- XCTAssertEqual(output.encoded.hexString, "0aa5010801107b18f80622033939396296010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a646e7b301700000000000000000000000000000000000000000000000000000000000003e9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a410f0832bb7a48c9e468c0bcb2c4a35a202f9519a63c4d6474b48087ab9dc33aea18127940d5cda43710cd874cbdf7a7b26efc9c04236e14dfb4d9b6f7095b0b6c01")
- XCTAssertEqual(output.hash.hexString, "c71058812a5febe5cdcdaf9499ba0b2c895f88d1acd3203e5097b307c2a5f1d1")
+ XCTAssertEqual(output.encoded.hexString, "0aaa01080118c0843d220431303030fa029a010a5c0a04746573741229696f3130613239387a6d7a7672743467757137396139663478377165646a35397937657279383468651a29696f3133736a396d7a7065776e3235796d6865756b74653476333968766a647472667030306d6c7976120331303018904e2a29696f313964307033616834673877773964376b63786671383779786537666e7238727074683573686a32077061796c6f6164124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a417819b5bcb635e3577acc8ca757f2c3d6afa451c2b6ff8a9179b141ac68e2c50305679e5d09d288da6f0fb52876a86c74deab6a5247edc6d371de5c2f121e159400")
+ XCTAssertEqual(output.hash.hexString, "35f53a536e014b32b85df50483ef04849b80ad60635b3b1979c5ba1096b65237")
}
- func testMoveStake() {
- // candidate name is a string
- let candidate = "\u{01}\u{02}\u{03}\u{04}\u{05}\u{06}\u{07}\u{08}\t\n\u{0B}\u{0C}"
- var input = stakingInput()
- input.staking.moveStake = IoTeXStaking.MoveStake.with {
- $0.piggyIndex = 1001
- $0.candidate = candidate
+ func testSignCandidateUpdate() {
+ var input = IoTeXSigningInput.with {
+ $0.version = 1
+ $0.nonce = 0
+ $0.gasLimit = 1000000
+ $0.gasPrice = "10"
+ $0.privateKey = Data(hexString: "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1")!
+ }
+ input.candidateUpdate = IoTeXStaking.CandidateBasicInfo.with {
+ $0.name = "test"
+ $0.operatorAddress = "io1cl6rl2ev5dfa988qmgzg2x4hfazmp9vn2g66ng"
+ $0.rewardAddress = "io1juvx5g063eu4ts832nukp4vgcwk2gnc5cu9ayd"
}
let output: IoTeXSigningOutput = AnySigner.sign(input: input, coin: .ioTeX)
- XCTAssertEqual(output.encoded.hexString, "0ac6010801107b18f806220339393962b7010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611a8401d3e41fd200000000000000000000000000000000000000000000000000000000000003e90102030405060708090a0b0c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a4118b71944993d1cd5362379ff64e892024a75ce697b2755cc9bbfcac24482a19b1ec2951bec7461ef9eb0723f803987cb87e3c3afb340006cd5b413c1fac10d7c01")
- XCTAssertEqual(output.hash.hexString, "33290ded342efaebf795855be73d34cbac149a2415ff9558de10303e6126f30d")
+ XCTAssertEqual(output.encoded.hexString, "0a69080118c0843d2202313082035c0a04746573741229696f31636c36726c32657635646661393838716d677a673278346866617a6d7039766e326736366e671a29696f316a757678356730363365753474733833326e756b7034766763776b32676e6335637539617964124104755ce6d8903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a1038ed9da8daf331a4101885c9c6684a4a8f2f5bf11f8326f27be48658f292e8f55ec8a11a604bb0c563a11ebf12d995ca1c152e00f8e0f0edf288db711aa10dbdfd5b7d73b4a28e1f701")
+ XCTAssertEqual(output.hash.hexString, "ca1a28f0e9a58ffc67037cc75066dbdd8e024aa2b2e416e4d6ce16c3d86282e5")
}
-}
+}
\ No newline at end of file
diff --git a/tests/IoTeX/StakingTests.cpp b/tests/IoTeX/StakingTests.cpp
index 96a79d3734f..0668a4a927d 100644
--- a/tests/IoTeX/StakingTests.cpp
+++ b/tests/IoTeX/StakingTests.cpp
@@ -4,193 +4,334 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
-#include "IoTeX/Staking.h"
-#include "IoTeX/Signer.h"
#include "Data.h"
#include "HexCoding.h"
+#include "IoTeX/Signer.h"
+#include "IoTeX/Staking.h"
+#include "PrivateKey.h"
#include "proto/IoTeX.pb.h"
#include "../interface/TWTestUtilities.h"
-
+#include
#include
using namespace TW;
using namespace TW::IoTeX;
-static const uint64_t pyggyIndex01 = 1001;
-static std::string IOTEX_STAKING_CONTRACT = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza";
-static const Data IOTEX_STAKING_TEST = TW::data(std::string("this is a test"));
-static const Data candidate12 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+TEST(TWIoTeXStaking, Create) {
+ std::string IOTEX_STAKING_CANDIDATE = "io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj";
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ std::string IOTEX_STAKING_AMOUNT = "100";
+ Data candidate(IOTEX_STAKING_CANDIDATE.begin(), IOTEX_STAKING_CANDIDATE.end());
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+ Data amount(IOTEX_STAKING_AMOUNT.begin(), IOTEX_STAKING_AMOUNT.end());
-TEST(IoTeXStaking, Stake) {
- Data result;
- stakingStake(candidate12, pyggyIndex01, true, IOTEX_STAKING_TEST, result);
- ASSERT_EQ(hex(result), "07c35fc00102030405060708090a0b0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e7468697320697320612074657374000000000000000000000000000000000000");
+ auto stake = stakingCreate(candidate, amount, 10000, true, payload);
+ ASSERT_EQ(hex(stake), "0a29696f313964307033616834673877773964376b63786671383779786537666e723872"
+ "7074683573686a120331303018904e20012a077061796c6f6164");
}
-TEST(IoTeXStaking, Unstake) {
- Data result;
- stakingUnstake(pyggyIndex01, IOTEX_STAKING_TEST, result);
- ASSERT_EQ(hex(result), "c8fd6ed000000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e7468697320697320612074657374000000000000000000000000000000000000");
+TEST(TWIoTeXStaking, AddDeposit) {
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ std::string IOTEX_STAKING_AMOUNT = "10";
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+ Data amount(IOTEX_STAKING_AMOUNT.begin(), IOTEX_STAKING_AMOUNT.end());
+
+ auto stake = stakingAddDeposit(10, amount, payload);
+
+ ASSERT_EQ(hex(stake), "080a120231301a077061796c6f6164");
}
-TEST(IoTeXStaking, Withdraw) {
- Data result;
- stakingWithdraw(pyggyIndex01, IOTEX_STAKING_TEST, result);
- ASSERT_EQ(hex(result), "030ba25d00000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e7468697320697320612074657374000000000000000000000000000000000000");
+TEST(TWIoTeXStaking, Unstake) {
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+
+ auto stake = stakingUnstake(10, payload);
+
+ ASSERT_EQ(hex(stake), "080a12077061796c6f6164");
}
-TEST(IoTeXStaking, AddStake) {
- Data result;
- stakingAddStake(pyggyIndex01, IOTEX_STAKING_TEST, result);
- ASSERT_EQ(hex(result), "6e7b301700000000000000000000000000000000000000000000000000000000000003e90000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e7468697320697320612074657374000000000000000000000000000000000000");
+TEST(TWIoTeXStaking, Withdraw) {
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+
+ auto stake = stakingWithdraw(10, payload);
+
+ ASSERT_EQ(hex(stake), "080a12077061796c6f6164");
}
-TEST(IoTeXStaking, MoveStake) {
- Data result;
- stakingMoveStake(pyggyIndex01, candidate12, IOTEX_STAKING_TEST, result);
- ASSERT_EQ(hex(result), "d3e41fd200000000000000000000000000000000000000000000000000000000000003e90102030405060708090a0b0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000e7468697320697320612074657374000000000000000000000000000000000000");
+TEST(TWIoTeXStaking, Restake) {
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+
+ auto stake = stakingRestake(10, 1000, true, payload);
+
+ ASSERT_EQ(hex(stake), "080a10e807180122077061796c6f6164");
}
-TEST(IoTeXStaking, SignStake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
+TEST(TWIoTeXStaking, ChangeCandidate) {
+ std::string IOTEX_STAKING_CANDIDATE = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza";
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ Data candidate(IOTEX_STAKING_CANDIDATE.begin(), IOTEX_STAKING_CANDIDATE.end());
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+
+ auto stake = stakingChangeCandidate(10, candidate, payload);
- // staking is implemented using the Execution message
- auto staking = input.mutable_call();
- staking->set_amount("456");
- staking->set_contract(IOTEX_STAKING_CONTRACT);
-
- // call staking API to generate calldata
- // data = "this is a test" here, it could be null (user leaves data empty when signing the tx)
- Data stake;
- stakingStake(candidate12, pyggyIndex01, true, IOTEX_STAKING_TEST, stake);
- staking->set_data(stake.data(), stake.size());
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "cc3c8f7a0129455d70457c4be42a8b31d8e1df59594c99041b6b6d091b295b32");
- // build() signs the tx
- auto output = signer.build();
- // signed action's serialized bytes
- auto encoded = output.encoded();
- ASSERT_EQ(hex(encoded.begin(), encoded.end()), "0a86020801107b18f806220339393962f7010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611ac40107c35fc00102030405060708090a0b0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e74686973206973206120746573740000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41a558bc9a4bfba920242ccd4d5c5da363ec534d4dd5eb67f88e9db7aaad5c50ad62dfe298c0e54e311ebba045f48cea1136e42a123a8e6b03d3e6ed82d4ec2b9401");
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "41b1f8be5f6b884c06556fba2611716e8e514b507f5a653fc02ac50ba13fbd6c");
+ ASSERT_EQ(hex(stake), "080a1229696f3178707136326177383575717a72636367397935686e727976386c"
+ "64326e6b7079636333677a611a077061796c6f6164");
}
-TEST(IoTeXStaking, SignUnstake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
+TEST(TWIoTeXStaking, Transfer) {
+ std::string IOTEX_STAKING_CANDIDATE = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza";
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ Data candidate(IOTEX_STAKING_CANDIDATE.begin(), IOTEX_STAKING_CANDIDATE.end());
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+
+ auto stake = stakingTransfer(10, candidate, payload);
- // staking is implemented using the Execution message
- auto staking = input.mutable_call();
- staking->set_amount("456");
- staking->set_contract(IOTEX_STAKING_CONTRACT);
-
- // call staking API to generate calldata
- Data unstake;
- stakingUnstake(pyggyIndex01, Data{}, unstake);
- staking->set_data(unstake.data(), unstake.size());
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "784f3d71246dfe897c1cb02da94e8ef1ac2381ac7f25ecfee80eaa78237db95b");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "b93a2874a72ce4eb8a41a20c209cf3fd188671ed8be8239a57960cbed887e962");
+ ASSERT_EQ(hex(stake), "080a1229696f3178707136326177383575717a72636367397935686e727976386c6432"
+ "6e6b7079636333677a611a077061796c6f6164");
}
-TEST(IoTeXStaking, SignWithdraw) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
+TEST(TWIoTeXStaking, CandidateRegister) {
+ std::string IOTEX_STAKING_NAME = "test";
+ std::string IOTEX_STAKING_OPERATOR = "io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he";
+ std::string IOTEX_STAKING_REWARD = "io13sj9mzpewn25ymheukte4v39hvjdtrfp00mlyv";
+ std::string IOTEX_STAKING_OWNER = "io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj";
+ std::string IOTEX_STAKING_AMOUNT = "100";
+ std::string IOTEX_STAKING_PAYLOAD = "payload";
+ Data name(IOTEX_STAKING_NAME.begin(), IOTEX_STAKING_NAME.end());
+ Data operatorAddress(IOTEX_STAKING_OPERATOR.begin(), IOTEX_STAKING_OPERATOR.end());
+ Data reward(IOTEX_STAKING_REWARD.begin(), IOTEX_STAKING_REWARD.end());
+ Data amount(IOTEX_STAKING_AMOUNT.begin(), IOTEX_STAKING_AMOUNT.end());
+ Data owner(IOTEX_STAKING_OWNER.begin(), IOTEX_STAKING_OWNER.end());
+ Data payload(IOTEX_STAKING_PAYLOAD.begin(), IOTEX_STAKING_PAYLOAD.end());
+
+ auto stake =
+ candidateRegister(name, operatorAddress, reward, amount, 10000, false, owner, payload);
- // staking is implemented using the Execution message
- auto staking = input.mutable_call();
- staking->set_amount("456");
- staking->set_contract(IOTEX_STAKING_CONTRACT);
-
- // call staking API to generate calldata
- Data withdraw;
- stakingWithdraw(pyggyIndex01, Data{}, withdraw);
- staking->set_data(withdraw.data(), withdraw.size());
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "ff55882624b2a1d6ae2d9fdec5f8a0f13b2f23c8b28c8ba91773b63f49b97fcc");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "2b2657247a72cb262de214b4e793c7a01fa2139fd5d12a46d43c24f87f9e2396");
+ ASSERT_EQ(hex(stake),
+ "0a5c0a04746573741229696f3130613239387a6d7a7672743467757137396139663478377165646a3539"
+ "7937657279383468651a29696f3133736a396d7a7065776e3235796d6865756b74653476333968766a64"
+ "7472667030306d6c7976120331303018904e2a29696f313964307033616834673877773964376b637866"
+ "71383779786537666e7238727074683573686a32077061796c6f6164");
}
-TEST(IoTeXStaking, SignAddStake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
+TEST(TWIoTeXStaking, CandidateUpdate) {
+ std::string IOTEX_STAKING_NAME = "test";
+ std::string IOTEX_STAKING_OPERATOR = "io1cl6rl2ev5dfa988qmgzg2x4hfazmp9vn2g66ng";
+ std::string IOTEX_STAKING_REWARD = "io1juvx5g063eu4ts832nukp4vgcwk2gnc5cu9ayd";
+ Data name(IOTEX_STAKING_NAME.begin(), IOTEX_STAKING_NAME.end());
+ Data operatorAddress(IOTEX_STAKING_OPERATOR.begin(), IOTEX_STAKING_OPERATOR.end());
+ Data reward(IOTEX_STAKING_REWARD.begin(), IOTEX_STAKING_REWARD.end());
+
+ auto stake = candidateUpdate(name, operatorAddress, reward);
- // staking is implemented using the Execution message
- auto staking = input.mutable_call();
- staking->set_amount("456");
- staking->set_contract(IOTEX_STAKING_CONTRACT);
-
- // call staking API to generate calldata
- Data addStake;
- stakingAddStake(pyggyIndex01, Data{}, addStake);
- staking->set_data(addStake.data(), addStake.size());
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "7581e7f779429aa502879581fdc29f87917acfe638069255b6f033c45d7f24fe");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "c71058812a5febe5cdcdaf9499ba0b2c895f88d1acd3203e5097b307c2a5f1d1");
+ ASSERT_EQ(hex(stake), "0a04746573741229696f31636c36726c32657635646661393838716d677a6732783468"
+ "66617a6d7039766e326736366e671a29696f316a757678356730363365753474733833"
+ "326e756b7034766763776b32676e6335637539617964");
}
-TEST(IoTeXStaking, SignMoveStake) {
+TEST(TWIoTeXStaking, SignAll) {
auto input = Proto::SigningInput();
input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
+ input.set_nonce(0);
+ input.set_gaslimit(1000000);
+ input.set_gasprice("10");
+ auto keyhex = parse_hex("cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1");
input.set_privatekey(keyhex.data(), keyhex.size());
+ Proto::SigningOutput output;
+
+ { // sign stakecreate
+ auto action = input.mutable_stakecreate();
+ action->set_candidatename("io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj");
+ action->set_stakedamount("100");
+ action->set_stakedduration(10000);
+ action->set_autostake(true);
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(hex(output.encoded()),
+ "0a4b080118c0843d22023130c2023e0a29696f313964307033616834673877773964376b63786671"
+ "3837797865"
+ "37666e7238727074683573686a120331303018904e20012a077061796c6f6164124104755ce6d890"
+ "3f6b3793bd"
+ "db4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c"
+ "0bc76ef30d"
+ "d6a1038ed9da8daf331a412e8bac421bab88dcd99c26ac8ffbf27f11ee57a41e7d2537891bfed5ae"
+ "d8e2e026d4"
+ "6e55d1b856787bc1cd7c1216a6e2534c5b5d1097c3afe8e657aa27cbbb0801");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "f1785e47b4200c752bb6518bd18097a41e075438b8c18c9cb00e1ae2f38ce767");
+ input.release_stakecreate();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign stakeadddeposit
+ auto action = input.mutable_stakeadddeposit();
+ action->set_bucketindex(10);
+ action->set_amount("10");
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a1c080118c0843d22023130da020f080a120231301a077061796c6f6164124104755ce6d8903f6b3793"
+ "bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0b"
+ "c76ef30dd6a1038ed9da8daf331a41a48ab1feba8181d760de946aefed7d815a89fd9b1ab503d2392bb5"
+ "5e1bb75eec42dddc8bd642f89accc3a37b3cf15a103a95d66695fdf0647b202869fdd66bcb01");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "ca8937d6f224a4e4bf93cb5605581de2d26fb0481e1dfc1eef384ee7ccf94b73");
+ input.release_stakeadddeposit();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign stakeunstake
+ auto action = input.mutable_stakeunstake();
+ action->set_bucketindex(10);
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a18080118c0843d22023130ca020b080a12077061796c6f6164124104755ce6d8903f6b3793bddb4ea5"
+ "d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30d"
+ "d6a1038ed9da8daf331a4100adee39b48e1d3dbbd65298a57c7889709fc4df39987130da306f6997374a"
+ "184b7e7c232a42f21e89b06e6e7ceab81303c6b7483152d08d19ac829b22eb81e601");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "bed58b64a6c4e959eca60a86f0b2149ce0e1dd527ac5fd26aef725ebf7c22a7d");
+ input.release_stakeunstake();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign stakewithdraw
+ auto action = input.mutable_stakewithdraw();
+ action->set_bucketindex(10);
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a18080118c0843d22023130d2020b080a12077061796c6f6164124104755ce6d8903f6b3793bddb4ea5"
+ "d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30d"
+ "d6a1038ed9da8daf331a4152644d102186be6640d46b517331f3402e24424b0d85129595421d28503d75"
+ "340b2922f5a0d4f667bbd6f576d9816770286b2ce032ba22eaec3952e24da4756b00");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "28049348cf34f1aa927caa250e7a1b08778c44efaf73b565b6fa9abe843871b4");
+ input.release_stakewithdraw();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign stakerestake
+ auto action = input.mutable_stakerestake();
+ action->set_bucketindex(10);
+ action->set_stakedduration(1000);
+ action->set_autostake(true);
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a1d080118c0843d22023130e20210080a10e807180122077061796c6f6164124104755ce6d8903f6b37"
+ "93bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c"
+ "0bc76ef30dd6a1038ed9da8daf331a41e2e763aed5b1fd1a8601de0f0ae34eb05162e34b0389ae3418ee"
+ "dbf762f64959634a968313a6516dba3a97b34efba4753bbed3a33d409ecbd45ac75007cd8e9101");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "8816e8f784a1fce40b54d1cd172bb6976fd9552f1570c73d1d9fcdc5635424a9");
+ input.release_stakerestake();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign stakechangecandidate
+ auto action = input.mutable_stakechangecandidate();
+ action->set_bucketindex(10);
+ action->set_candidatename("io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza");
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a43080118c0843d22023130ea0236080a1229696f3178707136326177383575717a7263636739793568"
+ "6e727976386c64326e6b7079636333677a611a077061796c6f6164124104755ce6d8903f6b3793bddb4e"
+ "a5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef3"
+ "0dd6a1038ed9da8daf331a41d519eb3747163b945b862989b7e82a7f8468001e9683757cb88d5ddd95f8"
+ "1895047429e858bd48f7d59a88bfec92de231d216293aeba1e4fbe11461d9c9fc99801");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "186526b5b9fe74e25beb52c83c41780a69108160bef2ddaf3bffb9f1f1e5e73a");
+ input.release_stakechangecandidate();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign staketransfer
+ auto action = input.mutable_staketransferownership();
+ action->set_bucketindex(10);
+ action->set_voteraddress("io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza");
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a43080118c0843d22023130f20236080a1229696f3178707136326177383575717a7263636739793568"
+ "6e727976386c64326e6b7079636333677a611a077061796c6f6164124104755ce6d8903f6b3793bddb4e"
+ "a5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef3"
+ "0dd6a1038ed9da8daf331a41fa26db427ab87a56a129196c1604f2e22c4dd2a1f99b2217bc916260757d"
+ "00093d9e6dccdf53e3b0b64e41a69d71c238fbf9281625164694a74dfbeba075d0ce01");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "74b2e1d6a09ba5d1298fa422d5850991ae516865077282196295a38f93c78b85");
+ input.release_staketransferownership();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign candidateupdate
+ auto action = input.mutable_candidateupdate();
+ action->set_name("test");
+ action->set_operatoraddress("io1cl6rl2ev5dfa988qmgzg2x4hfazmp9vn2g66ng");
+ action->set_rewardaddress("io1juvx5g063eu4ts832nukp4vgcwk2gnc5cu9ayd");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(
+ hex(output.encoded()),
+ "0a69080118c0843d2202313082035c0a04746573741229696f31636c36726c3265763564666139383871"
+ "6d677a673278346866617a6d7039766e326736366e671a29696f316a7576783567303633657534747338"
+ "33326e756b7034766763776b32676e6335637539617964124104755ce6d8903f6b3793bddb4ea5d3589d"
+ "637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99a5c1335b583c0bc76ef30dd6a103"
+ "8ed9da8daf331a4101885c9c6684a4a8f2f5bf11f8326f27be48658f292e8f55ec8a11a604bb0c563a11"
+ "ebf12d995ca1c152e00f8e0f0edf288db711aa10dbdfd5b7d73b4a28e1f701");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "ca1a28f0e9a58ffc67037cc75066dbdd8e024aa2b2e416e4d6ce16c3d86282e5");
+ input.release_candidateupdate();
+ output.release_encoded();
+ output.release_hash();
+ }
+ { // sign candidateregister
+ input.set_gasprice("1000");
+ auto cbi = input.mutable_candidateregister()->mutable_candidate();
+ cbi->set_name("test");
+ cbi->set_operatoraddress("io10a298zmzvrt4guq79a9f4x7qedj59y7ery84he");
+ cbi->set_rewardaddress("io13sj9mzpewn25ymheukte4v39hvjdtrfp00mlyv");
- // staking is implemented using the Execution message
- auto staking = input.mutable_call();
- staking->set_amount("456");
- staking->set_contract(IOTEX_STAKING_CONTRACT);
-
- // call staking API to generate calldata
- Data moveStake;
- stakingMoveStake(pyggyIndex01, candidate12, Data{}, moveStake);
- staking->set_data(moveStake.data(), moveStake.size());
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "818637b9708ec9e075c7a17f23757cb6895eae6dd3331f7e44129efae6ca9a21");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "33290ded342efaebf795855be73d34cbac149a2415ff9558de10303e6126f30d");
+ auto action = input.mutable_candidateregister();
+ action->set_stakedamount("100");
+ action->set_stakedduration(10000);
+ action->set_autostake(false);
+ action->set_owneraddress("io19d0p3ah4g8ww9d7kcxfq87yxe7fnr8rpth5shj");
+ action->set_payload("payload");
+ ANY_SIGN(input, TWCoinTypeIoTeX);
+ ASSERT_EQ(hex(output.encoded()),
+ "0aaa01080118c0843d220431303030fa029a010a5c0a04746573741229696f3130613239387a6d7a"
+ "7672743467"
+ "757137396139663478377165646a35397937657279383468651a29696f3133736a396d7a7065776e"
+ "3235796d68"
+ "65756b74653476333968766a647472667030306d6c7976120331303018904e2a29696f3139643070"
+ "3361683467"
+ "3877773964376b63786671383779786537666e7238727074683573686a32077061796c6f61641241"
+ "04755ce6d8"
+ "903f6b3793bddb4ea5d3589d637de2d209ae0ea930815c82db564ee8cc448886f639e8a0c7e94e99"
+ "a5c1335b58"
+ "3c0bc76ef30dd6a1038ed9da8daf331a417819b5bcb635e3577acc8ca757f2c3d6afa451c2b6ff8a"
+ "9179b141ac"
+ "68e2c50305679e5d09d288da6f0fb52876a86c74deab6a5247edc6d371de5c2f121e159400");
+ // signed action's hash
+ ASSERT_EQ(hex(output.hash()),
+ "35f53a536e014b32b85df50483ef04849b80ad60635b3b1979c5ba1096b65237");
+ }
}
diff --git a/tests/IoTeX/TWIoTeXStakingTests.cpp b/tests/IoTeX/TWIoTeXStakingTests.cpp
deleted file mode 100644
index 502e5dc62f9..00000000000
--- a/tests/IoTeX/TWIoTeXStakingTests.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright © 2017-2020 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.
-
-#include "Data.h"
-#include "HexCoding.h"
-#include "PrivateKey.h"
-#include "IoTeX/Signer.h"
-#include "proto/IoTeX.pb.h"
-#include "../interface/TWTestUtilities.h"
-
-#include
-
-using namespace TW;
-using namespace TW::IoTeX;
-
-static const char *_Nonnull IOTEX_STAKING_CONTRACT = "io1xpq62aw85uqzrccg9y5hnryv8ld2nkpycc3gza";
-static const char * IOTEX_STAKING_TEST = "this is a test";
-
-TEST(TWIoTeXStaking, SignStake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
-
- auto& staking = *input.mutable_staking();
- staking.set_amount("456");
- staking.set_contract(IOTEX_STAKING_CONTRACT);
-
- auto name = Data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- auto candidate = std::string(name.begin(), name.end());
- auto& stake = *staking.mutable_stake();
- stake.set_candidate(candidate);
- stake.set_duration(1001);
- stake.set_nondecay(true);
- stake.set_data(IOTEX_STAKING_TEST);
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "cc3c8f7a0129455d70457c4be42a8b31d8e1df59594c99041b6b6d091b295b32");
- // build() signs the tx
- auto output = signer.build();
- // signed action's serialized bytes
- auto encoded = output.encoded();
- ASSERT_EQ(hex(encoded.begin(), encoded.end()), "0a86020801107b18f806220339393962f7010a033435361229696f3178707136326177383575717a72636367397935686e727976386c64326e6b7079636333677a611ac40107c35fc00102030405060708090a0b0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e74686973206973206120746573740000000000000000000000000000000000001241044e18306ae9ef4ec9d07bf6e705442d4d1a75e6cdf750330ca2d880f2cc54607c9c33deb9eae9c06e06e04fe9ce3d43962cc67d5aa34fbeb71270d4bad3d648d91a41a558bc9a4bfba920242ccd4d5c5da363ec534d4dd5eb67f88e9db7aaad5c50ad62dfe298c0e54e311ebba045f48cea1136e42a123a8e6b03d3e6ed82d4ec2b9401");
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "41b1f8be5f6b884c06556fba2611716e8e514b507f5a653fc02ac50ba13fbd6c");
-}
-
-TEST(TWIoTeXStaking, SignUnstake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
-
- auto& staking = *input.mutable_staking();
- staking.set_amount("456");
- staking.set_contract(IOTEX_STAKING_CONTRACT);
-
- auto& unstake = *staking.mutable_unstake();
- unstake.set_piggy_index(1001);
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "784f3d71246dfe897c1cb02da94e8ef1ac2381ac7f25ecfee80eaa78237db95b");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "b93a2874a72ce4eb8a41a20c209cf3fd188671ed8be8239a57960cbed887e962");
-}
-
-TEST(TWIoTeXStaking, SignWithdraw) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
-
- auto& staking = *input.mutable_staking();
- staking.set_amount("456");
- staking.set_contract(IOTEX_STAKING_CONTRACT);
-
- auto& withdraw = *staking.mutable_withdraw();
- withdraw.set_piggy_index(1001);
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "ff55882624b2a1d6ae2d9fdec5f8a0f13b2f23c8b28c8ba91773b63f49b97fcc");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "2b2657247a72cb262de214b4e793c7a01fa2139fd5d12a46d43c24f87f9e2396");
-}
-
-TEST(TWIoTeXStaking, SignAddStake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
-
- auto& staking = *input.mutable_staking();
- staking.set_amount("456");
- staking.set_contract(IOTEX_STAKING_CONTRACT);
-
- auto& add = *staking.mutable_addstake();
- add.set_piggy_index(1001);
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "7581e7f779429aa502879581fdc29f87917acfe638069255b6f033c45d7f24fe");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "c71058812a5febe5cdcdaf9499ba0b2c895f88d1acd3203e5097b307c2a5f1d1");
-}
-
-TEST(TWIoTeXStaking, SignMoveStake) {
- auto input = Proto::SigningInput();
- input.set_version(1);
- input.set_nonce(123);
- input.set_gaslimit(888);
- input.set_gasprice("999");
- auto keyhex = parse_hex("0806c458b262edd333a191e92f561aff338211ee3e18ab315a074a2d82aa343f");
- input.set_privatekey(keyhex.data(), keyhex.size());
-
- auto& staking = *input.mutable_staking();
- staking.set_amount("456");
- staking.set_contract(IOTEX_STAKING_CONTRACT);
-
- auto name = Data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- auto candidate = std::string(name.begin(), name.end());
- auto& move = *staking.mutable_movestake();
- move.set_candidate(candidate);
- move.set_piggy_index(1001);
-
- auto signer = IoTeX::Signer(std::move(input));
- // raw action's hash
- ASSERT_EQ(hex(signer.hash()), "818637b9708ec9e075c7a17f23757cb6895eae6dd3331f7e44129efae6ca9a21");
- // build() signs the tx
- auto output = signer.build();
- // signed action's hash
- ASSERT_EQ(hex(output.hash()), "33290ded342efaebf795855be73d34cbac149a2415ff9558de10303e6126f30d");
-}
diff --git a/tools/generate-files b/tools/generate-files
index 20079f3c417..523835e157c 100755
--- a/tools/generate-files
+++ b/tools/generate-files
@@ -59,7 +59,6 @@ fi
# Generate internal message protocol Protobuf files -- not every time
"$PROTOC" -I=$PREFIX/include -I=src/Tron/Protobuf --cpp_out=src/Tron/Protobuf src/Tron/Protobuf/*.proto
"$PROTOC" -I=$PREFIX/include -I=src/Zilliqa/Protobuf --cpp_out=src/Zilliqa/Protobuf src/Zilliqa/Protobuf/*.proto
-"$PROTOC" -I=$PREFIX/include -I=src/IoTeX/Protobuf --cpp_out=src/IoTeX/Protobuf src/IoTeX/Protobuf/*.proto
# Generate Proto interface file
"$PROTOC" -I=$PREFIX/include -I=src/proto --plugin=$PREFIX/bin/protoc-gen-c-typedef --c-typedef_out include/TrustWalletCore src/proto/*.proto
From 4fd327aa3346265c2b88bbb4d7b89860505c421d Mon Sep 17 00:00:00 2001
From: Andrea
Date: Tue, 14 Apr 2020 11:43:51 +0000
Subject: [PATCH 06/81] Fix possible memory leak in walletconsole/Util.cpp
(#921)
Add missing call to `delete` in function `fileR`.
---
walletconsole/lib/Util.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/walletconsole/lib/Util.cpp b/walletconsole/lib/Util.cpp
index 5a54509998e..01bcba85e9f 100644
--- a/walletconsole/lib/Util.cpp
+++ b/walletconsole/lib/Util.cpp
@@ -79,6 +79,7 @@ bool Util::fileR(const string& fileName, string& res) {
char* buffer = new char[length];
if (!infile.read(buffer, length)) {
_out << "Could not read file '" << fileName << "'" << endl;
+ delete[] buffer;
return false;
}
int red = infile.gcount();
From e8ff9c710673e327229b2cc0d91d3e054fe72fcf Mon Sep 17 00:00:00 2001
From: Adam R <13562139+catenocrypt@users.noreply.github.com>
Date: Wed, 15 Apr 2020 04:11:26 +0200
Subject: [PATCH 07/81] Build sample apps in CI (#909)
* Script for building sample app (C++).
* Include go sample app in build script.
* Add echo's.
* Sample build: include OSX and Android build.
* Minor FIo test extension.
* Samples build: split in 3, by 3 build platforms.
* Revert "Samples build: split in 3, by 3 build platforms."
This reverts commit a262043b626b096b2be2cf32b57208ee0391ebac.
* Options for different platforms.
* Sample-build: Rearranged with functions per sample app
Co-authored-by: Catenocrypt
---
samples/go/main.go | 4 +--
tests/FIO/AddressTests.cpp | 7 ++--
tools/samples-build | 73 ++++++++++++++++++++++++++++++++++++++
3 files changed, 78 insertions(+), 6 deletions(-)
create mode 100755 tools/samples-build
diff --git a/samples/go/main.go b/samples/go/main.go
index 3f56b5241a9..38507a3a341 100644
--- a/samples/go/main.go
+++ b/samples/go/main.go
@@ -1,7 +1,7 @@
package main
-// #cgo CFLAGS: -I/wallet-core/include
-// #cgo LDFLAGS: -L/wallet-core/build -L/wallet-core/build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lc++ -lm
+// #cgo CFLAGS: -I../../include
+// #cgo LDFLAGS: -L../../build -L../../build/trezor-crypto -lTrustWalletCore -lprotobuf -lTrezorCrypto -lc++ -lm
// #include
// #include
// #include
diff --git a/tests/FIO/AddressTests.cpp b/tests/FIO/AddressTests.cpp
index 62d117e99d9..f78e3ae25f2 100644
--- a/tests/FIO/AddressTests.cpp
+++ b/tests/FIO/AddressTests.cpp
@@ -35,10 +35,9 @@ TEST(FIOAddress, ValidateData) {
}
TEST(FIOAddress, FromString) {
- ASSERT_EQ(
- Address("FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o").string(),
- "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o"
- );
+ Address addr("FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o");
+ ASSERT_EQ(addr.string(), "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o");
+ ASSERT_EQ(hex(addr.bytes), "0271195c66ec2799e436757a70cd8431d4b17733a097b18a5f7f1b6b085978ff0f343fc54e");
}
TEST(FIOAddress, FromStringInvalid) {
diff --git a/tools/samples-build b/tools/samples-build
new file mode 100755
index 00000000000..c956e7bc4c8
--- /dev/null
+++ b/tools/samples-build
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# This script builds the sample applications.
+
+set -e
+
+if [ -z $1 ]
+then
+ echo "No platform argument given, use all|linux|ios|android"
+ set $1 'linux'
+fi
+
+if [ ! "$1" = "linux" ] && [ ! "$1" = "ios" ] && [ ! "$1" = "android" ] && [ ! "$1" = "all" ]
+then
+ echo "Wrong platform argument given, use all|linux|ios|android"
+ set $1 'linux'
+fi
+
+echo "Platform argument: "$1
+
+build_cpp() {
+ pushd samples/cpp
+ echo "Building CPP sample app:"`pwd`
+ cmake . -DWALLET_CORE=../../
+ make
+ echo "Building CPP sample app: done"
+ popd
+}
+
+build_ios() {
+ pushd samples/osx/cocoapods
+ echo "Building OSX sample app:"`pwd`
+ pod repo update
+ pod install
+ echo "Building OSX sample app: done"
+ popd
+}
+
+build_android() {
+ pushd samples/android
+ echo "Building Android sample app:"`pwd`
+ ./gradlew assembleDebug
+ echo "Building Android sample app: done"
+ popd
+}
+
+build_go() {
+ pushd samples/go
+ echo "Building GO sample app:"`pwd`
+ go build -o main
+ echo "Building GO sample app: done"
+ popd
+}
+
+if [ "$1" = "linux" ]; then
+ build_cpp
+ build_go
+fi
+
+if [ "$1" = "ios" ]; then
+ build_ios
+fi
+
+if [ "$1" = "android" ]; then
+ build_android
+fi
+
+if [ "$1" = "all" ]; then
+ build_cpp
+ build_go
+ build_ios
+ build_android
+fi
From 87c4f1fd8dbf5a8d2d46b389ef98369c4060b8c6 Mon Sep 17 00:00:00 2001
From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com>
Date: Wed, 22 Apr 2020 21:14:03 -0700
Subject: [PATCH 08/81] Create auto_assign.yml (#928)
---
.github/auto_assign.yml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 .github/auto_assign.yml
diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml
new file mode 100644
index 00000000000..8dbdbff7c77
--- /dev/null
+++ b/.github/auto_assign.yml
@@ -0,0 +1,18 @@
+# Set to true to add reviewers to pull requests
+addReviewers: true
+
+# Set to true to add assignees to pull requests
+addAssignees: false
+
+# A list of reviewers to be added to pull requests (GitHub user name)
+reviewers:
+ - hewigovens
+ - catenocrypt
+
+# A list of keywords to be skipped the process that add reviewers if pull requests include it
+skipKeywords:
+ - wip
+
+# A number of reviewers added to the pull request
+# Set 0 to add all the reviewers (default: 0)
+numberOfReviewers: 0
From 15fb8f3d31778a6786896de33d9dd088f4200731 Mon Sep 17 00:00:00 2001
From: Viktor Radchenko <1641795+vikmeup@users.noreply.github.com>
Date: Thu, 23 Apr 2020 16:28:53 -0700
Subject: [PATCH 09/81] Add CODEOWNERS (#930)
* Create CODEOWNERS
---
.github/CODEOWNERS | 6 ++++++
.github/auto_assign.yml | 18 ------------------
2 files changed, 6 insertions(+), 18 deletions(-)
create mode 100644 .github/CODEOWNERS
delete mode 100644 .github/auto_assign.yml
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000000..33536958aad
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,6 @@
+# These owners will be the default owners for everything in
+# the repo. Unless a later match takes precedence,
+# @global-owner1 and @global-owner2 will be requested for
+# review when someone opens a pull request.
+
+* @hewigovens @catenocrypt
diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml
deleted file mode 100644
index 8dbdbff7c77..00000000000
--- a/.github/auto_assign.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-# Set to true to add reviewers to pull requests
-addReviewers: true
-
-# Set to true to add assignees to pull requests
-addAssignees: false
-
-# A list of reviewers to be added to pull requests (GitHub user name)
-reviewers:
- - hewigovens
- - catenocrypt
-
-# A list of keywords to be skipped the process that add reviewers if pull requests include it
-skipKeywords:
- - wip
-
-# A number of reviewers added to the pull request
-# Set 0 to add all the reviewers (default: 0)
-numberOfReviewers: 0
From e0e21bc2c201b81d2d742d012cce9e1c530672cf Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Tue, 28 Apr 2020 03:05:40 +0800
Subject: [PATCH 10/81] Migrate CI to GitHub Actions (#937)
* Create android-ci.yml
* Add ios-ci.yml
* Add linux-ci.yml
* Add sudo
* try set boost version
* install libc++
* Fix linux coverage
* move internal src to local/src
* Fix protobuf symbolic link
---
.github/workflows/android-ci.yml | 37 ++++++++++++++++++++++++
.github/workflows/ios-ci.yml | 32 +++++++++++++++++++++
.github/workflows/linux-ci.yml | 43 ++++++++++++++++++++++++++++
README.md | 6 ++--
TrustWalletCore.podspec | 2 +-
android/build.gradle | 2 +-
android/trustwalletcore/build.gradle | 2 +-
cmake/Protobuf.cmake | 4 +--
samples/android/build.gradle | 2 +-
swift/cpp.xcconfig.in | 2 +-
swift/protobuf | 2 +-
tests/CMakeLists.txt | 2 +-
tests/interface/TWTestUtilities.cpp | 1 -
tools/coverage | 18 +++++++++++-
tools/install-dependencies | 12 ++++----
tools/ios-test | 2 +-
16 files changed, 148 insertions(+), 21 deletions(-)
create mode 100644 .github/workflows/android-ci.yml
create mode 100644 .github/workflows/ios-ci.yml
create mode 100644 .github/workflows/linux-ci.yml
diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml
new file mode 100644
index 00000000000..c38c0dfdf7f
--- /dev/null
+++ b/.github/workflows/android-ci.yml
@@ -0,0 +1,37 @@
+name: Android CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: [macos-10.15]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install system dependencies
+ run: brew install boost ninja
+ - name: Install Android Dependencies
+ run: |
+ $ANDROID_HOME/tools/bin/sdkmanager --verbose "cmake;3.10.2.4988404" "ndk-bundle"
+ $ANDROID_HOME/tools/bin/sdkmanager "system-images;android-26;google_apis;x86"
+ - name: Accept Licenses
+ run: echo -e "y\ny\ny\ny\ny\n" | $ANDROID_HOME/tools/bin/sdkmanager --licenses
+ - name: Cache internal dependencies
+ id: internal_cache
+ uses: actions/cache@v1.1.2
+ with:
+ path: build/local
+ key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }}
+ - name: Install internal dependencies
+ run: |
+ tools/install-dependencies
+ if: steps.internal_cache.outputs.cache-hit != 'true'
+ - name: Run test
+ run: |
+ tools/generate-files
+ tools/android-test
diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml
new file mode 100644
index 00000000000..e3ad8eb88a2
--- /dev/null
+++ b/.github/workflows/ios-ci.yml
@@ -0,0 +1,32 @@
+name: iOS CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+ runs-on: [macos-10.15]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install system dependencies
+ run: |
+ brew install boost ninja xcodegen
+ - name: Cache internal dependencies
+ id: internal_cache
+ uses: actions/cache@v1.1.2
+ with:
+ path: build/local
+ key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }}
+ - name: Install internal dependencies
+ run: |
+ tools/install-dependencies
+ if: steps.internal_cache.outputs.cache-hit != 'true'
+ - name: Run codegen tests
+ run: tools/codegen-test
+ - name: Run iOS tests
+ run: |
+ tools/generate-files
+ tools/ios-test
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
new file mode 100644
index 00000000000..666c0343f1c
--- /dev/null
+++ b/.github/workflows/linux-ci.yml
@@ -0,0 +1,43 @@
+name: Linux CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+ runs-on: [ubuntu-18.04]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Install system dependencies
+ run: |
+ # build-essential libboost-all-dev clang-9 ruby-full cmake
+ sudo apt-get install libc++-dev libc++abi-dev ninja-build lcov llvm
+ - name: Cache internal dependencies
+ id: internal_cache
+ uses: actions/cache@v1.1.2
+ with:
+ path: build/local
+ key: ${{ runner.os }}-internal-${{ hashFiles('tools/install-dependencies') }}
+ - name: Install internal dependencies
+ run: |
+ tools/install-dependencies
+ env:
+ CC: /usr/bin/clang
+ CXX: /usr/bin/clang++
+ if: steps.internal_cache.outputs.cache-hit != 'true'
+ - name: Build and test
+ run: |
+ tools/generate-files
+ cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DBOOST_ROOT=${BOOST_ROOT_1_72_0}
+ make -Cbuild
+ build/tests/tests tests --gtest_output=xml
+ env:
+ CC: /usr/bin/clang
+ CXX: /usr/bin/clang++
+ - name: Gather code coverage
+ run: |
+ sudo rm -rf coverage.info
+ tools/coverage
diff --git a/README.md b/README.md
index a42187be546..827eca33c04 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,9 @@
Trust Wallet Core is a cross-platform library that implements low-level cryptographic wallet functionality for all supported blockchains. Most of the code is C++ with a set of strict exported C interfaces. The library provides idiomatic interfaces for all supported languages (currently Swift for iOS and Java for Android).
-[![iOS status](https://dev.azure.com/TrustWallet/Trust%20Wallet%20Core/_apis/build/status/Wallet%20Core%20iOS)](https://dev.azure.com/TrustWallet/Trust%20Wallet%20Core/_build/latest?definitionId=13)
-[![Android status](https://dev.azure.com/TrustWallet/Trust%20Wallet%20Core/_apis/build/status/Wallet%20Core%20Android)](https://dev.azure.com/TrustWallet/Trust%20Wallet%20Core/_build/latest?definitionId=11)
-[![Linux status](https://dev.azure.com/TrustWallet/Trust%20Wallet%20Core/_apis/build/status/Wallet%20Core%20Linux)](https://dev.azure.com/TrustWallet/Trust%20Wallet%20Core/_build/latest?definitionId=24)
+![iOS CI](https://github.com/trustwallet/wallet-core/workflows/iOS%20CI/badge.svg)
+![Android CI](https://github.com/trustwallet/wallet-core/workflows/Android%20CI/badge.svg)
+![Linux CI](https://github.com/trustwallet/wallet-core/workflows/Linux%20CI/badge.svg)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/82e76f6ea4ba4f0d9029e8846c04c093)](https://www.codacy.com/app/hewigovens/wallet-core?utm_source=github.com&utm_medium=referral&utm_content=TrustWallet/wallet-core&utm_campaign=Badge_Grade)
![Codecov](https://codecov.io/gh/TrustWallet/wallet-core/branch/master/graph/badge.svg)
diff --git a/TrustWalletCore.podspec b/TrustWalletCore.podspec
index 028cb115716..3182e93d445 100644
--- a/TrustWalletCore.podspec
+++ b/TrustWalletCore.podspec
@@ -28,7 +28,7 @@ Pod::Spec.new do |s|
end
s.subspec 'Core' do |ss|
- protobuf_source_dir = 'build/protobuf/staging/protobuf-3.9.0'
+ protobuf_source_dir = 'build/local/src/protobuf/protobuf-3.9.0'
include_dir = 'build/local/include'
ss.source_files =
'src/**/*.{c,cc,cpp,h}',
diff --git a/android/build.gradle b/android/build.gradle
index c3b350a38ce..a710c7f55ed 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.1'
+ classpath 'com.android.tools.build:gradle:3.6.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
diff --git a/android/trustwalletcore/build.gradle b/android/trustwalletcore/build.gradle
index 83bc1d15148..145624ca9a6 100644
--- a/android/trustwalletcore/build.gradle
+++ b/android/trustwalletcore/build.gradle
@@ -4,7 +4,7 @@ group='com.github.trustwallet'
android {
compileSdkVersion 28
-
+ ndkVersion '21.1.6352462'
defaultConfig {
minSdkVersion 23
targetSdkVersion 28
diff --git a/cmake/Protobuf.cmake b/cmake/Protobuf.cmake
index 72f271d70d8..7f27286911e 100644
--- a/cmake/Protobuf.cmake
+++ b/cmake/Protobuf.cmake
@@ -1,5 +1,5 @@
-set(protobuf_SOURCE_DIR ${CMAKE_SOURCE_DIR}/build/protobuf/staging/protobuf-3.9.0)
-set(protobuf_source_dir ${CMAKE_SOURCE_DIR}/build/protobuf/staging/protobuf-3.9.0)
+set(protobuf_SOURCE_DIR ${CMAKE_SOURCE_DIR}/build/local/src/protobuf/protobuf-3.9.0)
+set(protobuf_source_dir ${CMAKE_SOURCE_DIR}/build/local/src/protobuf/protobuf-3.9.0)
# Updated from https://github.com/protocolbuffers/protobuf/blob/master/cmake/libprotopuf.cmake
diff --git a/samples/android/build.gradle b/samples/android/build.gradle
index a706027ba80..b908ed10fd6 100644
--- a/samples/android/build.gradle
+++ b/samples/android/build.gradle
@@ -8,7 +8,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.1'
+ classpath 'com.android.tools.build:gradle:3.6.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/swift/cpp.xcconfig.in b/swift/cpp.xcconfig.in
index 9d351112b5b..9e2fd5ef152 100644
--- a/swift/cpp.xcconfig.in
+++ b/swift/cpp.xcconfig.in
@@ -5,4 +5,4 @@
// file LICENSE at the root of the source code distribution tree.
HEADER_SEARCH_PATHS = $(SRCROOT)/../src @Boost_INCLUDE_DIRS@
-SYSTEM_HEADER_SEARCH_PATHS = $(SRCROOT)/../src/build/local/include $(SRCROOT)/../build/protobuf/staging/protobuf-3.9.0/src
+SYSTEM_HEADER_SEARCH_PATHS = $(SRCROOT)/../src/build/local/include $(SRCROOT)/../build/local/src/protobuf/protobuf-3.9.0/src
diff --git a/swift/protobuf b/swift/protobuf
index 42dacc8e080..b0c567bc5a1 120000
--- a/swift/protobuf
+++ b/swift/protobuf
@@ -1 +1 @@
-../build/protobuf/staging/protobuf-3.9.0/src
\ No newline at end of file
+../build/local/src/protobuf/protobuf-3.9.0/src
\ No newline at end of file
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index be1569b89cd..f6acfc476be 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -6,7 +6,7 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
-add_subdirectory(${CMAKE_SOURCE_DIR}/build/gtest/staging/googletest-release-1.8.1
+add_subdirectory(${CMAKE_SOURCE_DIR}/build/local/src/gtest/googletest-release-1.8.1
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
diff --git a/tests/interface/TWTestUtilities.cpp b/tests/interface/TWTestUtilities.cpp
index 14d256a89bc..2c7412330c8 100644
--- a/tests/interface/TWTestUtilities.cpp
+++ b/tests/interface/TWTestUtilities.cpp
@@ -7,7 +7,6 @@
#include "TWTestUtilities.h"
#include
-#include
using namespace std;
diff --git a/tools/coverage b/tools/coverage
index aea89ceac39..a60dd5266d7 100755
--- a/tools/coverage
+++ b/tools/coverage
@@ -4,7 +4,23 @@
set -e
-lcov --capture --directory . --output-file coverage.info
+function install_llvm_gcov() {
+ cat << EOF > /tmp/llvm-gcov.sh
+#!/bin/bash
+exec /usr/bin/llvm-cov gcov "\$@"
+EOF
+ sudo chmod 755 /tmp/llvm-gcov.sh
+}
+
+if [[ `uname` == "Darwin" ]]; then
+ echo "gcov is llvm-cov on macOS"
+ lcov --capture --directory . --output-file coverage.info
+else
+ echo "call llvm-cov on Linux"
+ install_llvm_gcov
+ lcov --gcov-tool /tmp/llvm-gcov.sh --capture --directory . --output-file coverage.info
+fi
+
lcov --remove coverage.info '/usr/*' --output-file coverage.info
lcov --remove coverage.info '/Applications/*' --output-file coverage.info
lcov --remove coverage.info '*/build/*' --output-file coverage.info
diff --git a/tools/install-dependencies b/tools/install-dependencies
index 53536a5afd5..80919b45cdd 100755
--- a/tools/install-dependencies
+++ b/tools/install-dependencies
@@ -16,7 +16,7 @@ export LD_RUN_PATH="$PREFIX/lib"
# Download Google Test
export GTEST_VERSION=1.8.1
-GTEST_DIR="$ROOT/build/gtest/staging"
+GTEST_DIR="$ROOT/build/local/src/gtest"
mkdir -p "$GTEST_DIR"
cd "$GTEST_DIR"
if [ ! -f release-$GTEST_VERSION.tar.gz ]; then
@@ -32,7 +32,7 @@ make install
# Download Check
export CHECK_VERSION=0.12.0
-CHECK_DIR="$ROOT/build/check/staging"
+CHECK_DIR="$ROOT/build/local/src/check"
mkdir -p "$CHECK_DIR"
cd "$CHECK_DIR"
if [ ! -f check-$CHECK_VERSION.tar.gz ]; then
@@ -48,7 +48,7 @@ make install
# Download Nlohmann JSON
export JSON_VERSION=3.5.0
-JSON_DIR="$ROOT/build/json/staging"
+JSON_DIR="$ROOT/build/local/json"
mkdir -p "$JSON_DIR"
cd "$JSON_DIR"
if [ ! -f include.zip ]; then
@@ -58,7 +58,7 @@ unzip -d "$PREFIX" -o include.zip
# Download Protobuf sources
export PROTOBUF_VERSION=3.9.0
-PROTOBUF_DIR="$ROOT/build/protobuf/staging"
+PROTOBUF_DIR="$ROOT/build/local/src/protobuf"
mkdir -p "$PROTOBUF_DIR"
cd "$PROTOBUF_DIR"
if [ ! -f protobuf-java-$PROTOBUF_VERSION.tar.gz ]; then
@@ -75,10 +75,10 @@ make install
make clean
"$PREFIX/bin/protoc" --version
-if [ -x "$(command -v swift)" ]; then
+if [[ -x "$(command -v swift)" && `uname` == "Darwin" ]]; then
# Download Swift Protobuf sources
export SWIFT_PROTOBUF_VERSION=1.7.0
- SWIFT_PROTOBUF_DIR="$ROOT/build/swift-protobuf/staging"
+ SWIFT_PROTOBUF_DIR="$ROOT/build/local/src/swift-protobuf"
mkdir -p "$SWIFT_PROTOBUF_DIR"
cd "$SWIFT_PROTOBUF_DIR"
if [ ! -f $SWIFT_PROTOBUF_VERSION.tar.gz ]; then
diff --git a/tools/ios-test b/tools/ios-test
index 1206d3c57a5..8c68a4b70f9 100755
--- a/tools/ios-test
+++ b/tools/ios-test
@@ -7,5 +7,5 @@ set -e
pushd swift
xcodegen
pod install
-xcrun xcodebuild -workspace TrustWalletCore.xcworkspace -scheme TrustWalletCore -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11,OS=13.0' test
+xcrun xcodebuild -workspace TrustWalletCore.xcworkspace -scheme TrustWalletCore -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11' test
popd
From 7dde1a51d0ce2b2a459af3d9dfe2ea4f7cc422f2 Mon Sep 17 00:00:00 2001
From: Adam R <13562139+catenocrypt@users.noreply.github.com>
Date: Mon, 27 Apr 2020 21:45:11 +0200
Subject: [PATCH 11/81] Bitcoin Script minor fixes and new tests. (#933)
* Bitcoin Script minor fixes and new tests.
* Extra tests for the missing 3 lines.
* Fix isPayToWitnessScriptHash (was typo), new isPayToWitnessPublicKeyHash().
* A rename (Pubkey -> PublicKey).
* Extra test for TWBitcoinScript coverage.
---
include/TrustWalletCore/TWBitcoinScript.h | 4 +
src/Bitcoin/Script.cpp | 44 ++-
src/Bitcoin/Script.h | 24 +-
src/Bitcoin/TransactionSigner.cpp | 4 +-
src/Decred/Signer.cpp | 4 +-
src/interface/TWBitcoinScript.cpp | 10 +-
tests/Bitcoin/BitcoinScriptTests.cpp | 285 ++++++++++++++++++
tests/Bitcoin/TWBitcoinScriptTests.cpp | 131 +++++++-
tests/Bitcoin/TWBitcoinSigningTests.cpp | 2 +-
.../Groestlcoin/TWGroestlcoinSigningTests.cpp | 2 +-
10 files changed, 465 insertions(+), 45 deletions(-)
create mode 100644 tests/Bitcoin/BitcoinScriptTests.cpp
diff --git a/include/TrustWalletCore/TWBitcoinScript.h b/include/TrustWalletCore/TWBitcoinScript.h
index a50499fa4db..a382328c45d 100644
--- a/include/TrustWalletCore/TWBitcoinScript.h
+++ b/include/TrustWalletCore/TWBitcoinScript.h
@@ -49,6 +49,10 @@ bool TWBitcoinScriptIsPayToScriptHash(const struct TWBitcoinScript *_Nonnull scr
TW_EXPORT_PROPERTY
bool TWBitcoinScriptIsPayToWitnessScriptHash(const struct TWBitcoinScript *_Nonnull script);
+/// Determines whether this is a pay-to-witness-public-key-hash (P2WPKH) script.
+TW_EXPORT_PROPERTY
+bool TWBitcoinScriptIsPayToWitnessPublicKeyHash(const struct TWBitcoinScript *_Nonnull script);
+
/// Determines whether this is a witness programm script.
TW_EXPORT_PROPERTY
bool TWBitcoinScriptIsWitnessProgram(const struct TWBitcoinScript *_Nonnull script);
diff --git a/src/Bitcoin/Script.cpp b/src/Bitcoin/Script.cpp
index bf1ce32aad7..358e030b3e6 100644
--- a/src/Bitcoin/Script.cpp
+++ b/src/Bitcoin/Script.cpp
@@ -42,6 +42,11 @@ bool Script::isPayToScriptHash() const {
bool Script::isPayToWitnessScriptHash() const {
// Extra-fast test for pay-to-witness-script-hash
+ return bytes.size() == 34 && bytes[0] == OP_0 && bytes[1] == 0x20;
+}
+
+bool Script::isPayToWitnessPublicKeyHash() const {
+ // Extra-fast test for pay-to-witness-public-key-hash
return bytes.size() == 22 && bytes[0] == OP_0 && bytes[1] == 0x14;
}
@@ -55,7 +60,7 @@ bool Script::isWitnessProgram() const {
return bytes[1] + 2 == bytes.size();
}
-bool Script::matchPayToPubkey(Data& result) const {
+bool Script::matchPayToPublicKey(Data& result) const {
if (bytes.size() == PublicKey::secp256k1ExtendedSize + 2 &&
bytes[0] == PublicKey::secp256k1ExtendedSize && bytes.back() == OP_CHECKSIG) {
result.clear();
@@ -73,7 +78,7 @@ bool Script::matchPayToPubkey(Data& result) const {
return false;
}
-bool Script::matchPayToPubkeyHash(Data& result) const {
+bool Script::matchPayToPublicKeyHash(Data& result) const {
if (bytes.size() == 25 && bytes[0] == OP_DUP && bytes[1] == OP_HASH160 && bytes[2] == 20 &&
bytes[23] == OP_EQUALVERIFY && bytes[24] == OP_CHECKSIG) {
result.clear();
@@ -93,30 +98,21 @@ bool Script::matchPayToScriptHash(Data& result) const {
}
bool Script::matchPayToWitnessPublicKeyHash(Data& result) const {
- if (bytes.size() == 22 && bytes[0] == OP_0 && bytes[1] == 0x14) {
- result.clear();
- std::copy(std::begin(bytes) + 2, std::end(bytes), std::back_inserter(result));
- return true;
+ if (!isPayToWitnessPublicKeyHash()) {
+ return false;
}
- return false;
+ result.clear();
+ std::copy(std::begin(bytes) + 2, std::end(bytes), std::back_inserter(result));
+ return true;
}
bool Script::matchPayToWitnessScriptHash(Data& result) const {
- if (bytes.size() == 34 && bytes[0] == OP_0 && bytes[1] == 0x20) {
- result.clear();
- std::copy(std::begin(bytes) + 2, std::end(bytes), std::back_inserter(result));
- return true;
- }
- return false;
-}
-
-/// Decodes a small integer
-static inline int decodeNumber(uint8_t opcode) {
- if (opcode == OP_0) {
- return 0;
+ if (!isPayToWitnessScriptHash()) {
+ return false;
}
- assert(opcode >= OP_1 && opcode <= OP_16);
- return static_cast(opcode) - static_cast(OP_1 - 1);
+ result.clear();
+ std::copy(std::begin(bytes) + 2, std::end(bytes), std::back_inserter(result));
+ return true;
}
bool Script::matchMultisig(std::vector& keys, int& required) const {
@@ -185,7 +181,7 @@ bool Script::getScriptOp(size_t& index, uint8_t& opcode, Data& operand) const {
if (bytes.size() - index < 1) {
return false;
}
- size = index;
+ size = bytes[index];
index += 1;
} else if (opcode == OP_PUSHDATA2) {
if (bytes.size() - index < 2) {
@@ -240,11 +236,13 @@ Script Script::buildPayToWitnessProgram(const Data& program) {
return script;
}
-Script Script::buildPayToWitnessPubkeyHash(const Data& hash) {
+Script Script::buildPayToWitnessPublicKeyHash(const Data& hash) {
+ assert(hash.size() == 20);
return Script::buildPayToWitnessProgram(hash);
}
Script Script::buildPayToWitnessScriptHash(const Data& scriptHash) {
+ assert(scriptHash.size() == 32);
return Script::buildPayToWitnessProgram(scriptHash);
}
diff --git a/src/Bitcoin/Script.h b/src/Bitcoin/Script.h
index f6b5de13427..08dfe6bfe28 100644
--- a/src/Bitcoin/Script.h
+++ b/src/Bitcoin/Script.h
@@ -43,14 +43,17 @@ class Script {
/// Determines whether this is a pay-to-witness-script-hash (P2WSH) script.
bool isPayToWitnessScriptHash() const;
+ /// Determines whether this is a pay-to-witness-public-key-hash (P2WPKH) script.
+ bool isPayToWitnessPublicKeyHash() const;
+
/// Determines whether this is a witness programm script.
bool isWitnessProgram() const;
/// Matches the script to a pay-to-public-key (P2PK) script.
- bool matchPayToPubkey(Data& publicKey) const;
+ bool matchPayToPublicKey(Data& publicKey) const;
/// Matches the script to a pay-to-public-key-hash (P2PKH).
- bool matchPayToPubkeyHash(Data& keyHash) const;
+ bool matchPayToPublicKeyHash(Data& keyHash) const;
/// Matches the script to a pay-to-script-hash (P2SH).
bool matchPayToScriptHash(Data& scriptHash) const;
@@ -58,7 +61,7 @@ class Script {
/// Matches the script to a pay-to-witness-public-key-hash (P2WPKH).
bool matchPayToWitnessPublicKeyHash(Data& keyHash) const;
- /// Matches the script to a pay-to-witness-script-hash (P2WSH).
+ /// Matches the script to a pay-to-witness-script-hash (P2WSH). Returns the script hash, a SHA256 of the witness script.
bool matchPayToWitnessScriptHash(Data& scriptHash) const;
/// Matches the script to a multisig script.
@@ -75,7 +78,7 @@ class Script {
/// Builds a pay-to-witness-public-key-hash (P2WPKH) script from a public
/// key hash.
- static Script buildPayToWitnessPubkeyHash(const Data& hash);
+ static Script buildPayToWitnessPublicKeyHash(const Data& hash);
/// Builds a pay-to-witness-script-hash (P2WSH) script from a script hash.
static Script buildPayToWitnessScriptHash(const Data& scriptHash);
@@ -88,7 +91,7 @@ class Script {
void encode(Data& data) const;
/// Encodes a small integer
- static uint8_t encodeNumber(int n) {
+ static inline uint8_t encodeNumber(int n) {
assert(n >= 0 && n <= 16);
if (n == 0) {
return OP_0;
@@ -96,8 +99,17 @@ class Script {
return OP_1 + uint8_t(n - 1);
}
- private:
+ /// Decodes a small integer
+ static inline int decodeNumber(uint8_t opcode) {
+ if (opcode == OP_0) {
+ return 0;
+ }
+ assert(opcode >= OP_1 && opcode <= OP_16);
+ return static_cast(opcode) - static_cast(OP_1 - 1);
+ }
+
/// Extracts a single opcode at the given index including its operand.
+ /// Public for testability.
///
/// \param index [in/out] index where the operation starts, on return the
/// index of the next operation. \param opcode [out] the opcode. \param
diff --git a/src/Bitcoin/TransactionSigner.cpp b/src/Bitcoin/TransactionSigner.cpp
index 6260242854d..acf191cf11d 100644
--- a/src/Bitcoin/TransactionSigner.cpp
+++ b/src/Bitcoin/TransactionSigner.cpp
@@ -169,7 +169,7 @@ Result> TransactionSigner::si
}
results.resize(required + 1);
return Result>::success(std::move(results));
- } else if (script.matchPayToPubkey(data)) {
+ } else if (script.matchPayToPublicKey(data)) {
auto keyHash = TW::Hash::ripemd(TW::Hash::sha256(data));
auto key = keyForPublicKeyHash(keyHash);
if (key.empty()) {
@@ -183,7 +183,7 @@ Result> TransactionSigner::si
return Result>::failure("Failed to sign.");
}
return Result>::success({signature});
- } else if (script.matchPayToPubkeyHash(data)) {
+ } else if (script.matchPayToPublicKeyHash(data)) {
auto key = keyForPublicKeyHash(data);
if (key.empty()) {
// Error: Missing keyxs
diff --git a/src/Decred/Signer.cpp b/src/Decred/Signer.cpp
index 2a7b99ca0a3..09ddf587313 100644
--- a/src/Decred/Signer.cpp
+++ b/src/Decred/Signer.cpp
@@ -108,7 +108,7 @@ Result> Signer::signStep(Bitcoin::Script script, size_t index)
std::vector keys;
int required;
- if (script.matchPayToPubkey(data)) {
+ if (script.matchPayToPublicKey(data)) {
auto keyHash = TW::Hash::ripemd(TW::Hash::blake256(data));
auto key = keyForPublicKeyHash(keyHash);
if (key.empty()) {
@@ -121,7 +121,7 @@ Result> Signer::signStep(Bitcoin::Script script, size_t index)
return Result>::failure("Failed to sign.");
}
return Result>::success({signature});
- } else if (script.matchPayToPubkeyHash(data)) {
+ } else if (script.matchPayToPublicKeyHash(data)) {
auto key = keyForPublicKeyHash(data);
if (key.empty()) {
// Error: Missing keyxs
diff --git a/src/interface/TWBitcoinScript.cpp b/src/interface/TWBitcoinScript.cpp
index 1fa6575c560..b316b1d0fe6 100644
--- a/src/interface/TWBitcoinScript.cpp
+++ b/src/interface/TWBitcoinScript.cpp
@@ -59,6 +59,10 @@ bool TWBitcoinScriptIsPayToWitnessScriptHash(const struct TWBitcoinScript *scrip
return script->impl.isPayToWitnessScriptHash();
}
+bool TWBitcoinScriptIsPayToWitnessPublicKeyHash(const struct TWBitcoinScript *script) {
+ return script->impl.isPayToWitnessPublicKeyHash();
+}
+
bool TWBitcoinScriptIsWitnessProgram(const struct TWBitcoinScript *script) {
return script->impl.isWitnessProgram();
}
@@ -69,7 +73,7 @@ bool TWBitcoinScriptEqual(const struct TWBitcoinScript *_Nonnull lhs, const stru
TWData *TWBitcoinScriptMatchPayToPubkey(const struct TWBitcoinScript *script) {
std::vector data;
- if (script->impl.matchPayToPubkey(data)) {
+ if (script->impl.matchPayToPublicKey(data)) {
return TWDataCreateWithBytes(data.data(), data.size());
}
return nullptr;
@@ -77,7 +81,7 @@ TWData *TWBitcoinScriptMatchPayToPubkey(const struct TWBitcoinScript *script) {
TWData *TWBitcoinScriptMatchPayToPubkeyHash(const struct TWBitcoinScript *script) {
std::vector data;
- if (script->impl.matchPayToPubkeyHash(data)) {
+ if (script->impl.matchPayToPublicKeyHash(data)) {
return TWDataCreateWithBytes(data.data(), data.size());
}
return nullptr;
@@ -127,7 +131,7 @@ struct TWBitcoinScript *TWBitcoinScriptBuildPayToScriptHash(TWData *scriptHash)
struct TWBitcoinScript *TWBitcoinScriptBuildPayToWitnessPubkeyHash(TWData *hash) {
auto v = reinterpret_cast*>(hash);
- auto script = Script::buildPayToWitnessPubkeyHash(*v);
+ auto script = Script::buildPayToWitnessPublicKeyHash(*v);
return new TWBitcoinScript{ .impl = script };
}
diff --git a/tests/Bitcoin/BitcoinScriptTests.cpp b/tests/Bitcoin/BitcoinScriptTests.cpp
new file mode 100644
index 00000000000..c54505e9894
--- /dev/null
+++ b/tests/Bitcoin/BitcoinScriptTests.cpp
@@ -0,0 +1,285 @@
+// Copyright © 2017-2020 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.
+
+#include "Bitcoin/Script.h"
+#include "../interface/TWTestUtilities.h"
+#include "HexCoding.h"
+
+#include
+
+using namespace TW;
+using namespace TW::Bitcoin;
+
+const Script PayToScriptHash(parse_hex("a914" "4733f37cf4db86fbc2efed2500b4f4e49f312023" "87"));
+const Script PayToWitnessScriptHash(parse_hex("0020" "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db"));
+const Script PayToWitnessPublicKeyHash(parse_hex("0014" "79091972186c449eb1ded22b78e40d009bdf0089"));
+const Script PayToPublicKeySecp256k1(parse_hex("21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ac"));
+const Script PayToPublicKeySecp256k1Extended(parse_hex("41" "0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1" "66b489a4b7c491e7688e6ebea3a71fc3a1a48d60f98d5ce84c93b65e423fde91ac"));
+const Script PayToPublicKeyHash(parse_hex("76a914" "79091972186c449eb1ded22b78e40d009bdf0089" "88ac"));
+
+TEST(BitcoinScript, PayToPublicKey) {
+ Data res;
+ EXPECT_EQ(PayToPublicKeySecp256k1.matchPayToPublicKey(res), true);
+ EXPECT_EQ(hex(res), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.matchPayToPublicKey(res), true);
+ EXPECT_EQ(hex(res), "0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1");
+
+ EXPECT_EQ(PayToScriptHash.matchPayToPublicKey(res), false);
+ EXPECT_EQ(PayToWitnessScriptHash.matchPayToPublicKey(res), false);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.matchPayToPublicKey(res), false);
+ EXPECT_EQ(PayToPublicKeyHash.matchPayToPublicKey(res), false);
+}
+
+TEST(BitcoinScript, PayToPublicKeyHash) {
+ Data res;
+ EXPECT_EQ(PayToPublicKeyHash.matchPayToPublicKeyHash(res), true);
+ EXPECT_EQ(hex(res), "79091972186c449eb1ded22b78e40d009bdf0089");
+ EXPECT_EQ(PayToPublicKeySecp256k1.matchPayToPublicKey(res), true);
+ EXPECT_EQ(hex(res), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.matchPayToPublicKey(res), true);
+ EXPECT_EQ(hex(res), "0499c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1");
+
+ EXPECT_EQ(PayToScriptHash.matchPayToPublicKeyHash(res), false);
+ EXPECT_EQ(PayToWitnessScriptHash.matchPayToPublicKeyHash(res), false);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.matchPayToPublicKeyHash(res), false);
+}
+
+TEST(BitcoinScript, PayToScriptHash) {
+ EXPECT_EQ(PayToScriptHash.isPayToScriptHash(), true);
+ EXPECT_EQ(PayToScriptHash.bytes.size(), 23);
+
+ EXPECT_EQ(PayToWitnessScriptHash.isPayToScriptHash(), false);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.isPayToScriptHash(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.isPayToScriptHash(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.isPayToScriptHash(), false);
+ EXPECT_EQ(PayToPublicKeyHash.isPayToScriptHash(), false);
+
+ Data res;
+ EXPECT_EQ(PayToScriptHash.matchPayToScriptHash(res), true);
+ EXPECT_EQ(hex(res), "4733f37cf4db86fbc2efed2500b4f4e49f312023");
+
+ EXPECT_EQ(PayToWitnessScriptHash.matchPayToScriptHash(res), false);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.matchPayToScriptHash(res), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.matchPayToScriptHash(res), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.matchPayToScriptHash(res), false);
+ EXPECT_EQ(PayToPublicKeyHash.matchPayToScriptHash(res), false);
+}
+
+TEST(BitcoinScript, PayToWitnessScriptHash) {
+ EXPECT_EQ(PayToWitnessScriptHash.isPayToWitnessScriptHash(), true);
+ EXPECT_EQ(PayToWitnessScriptHash.bytes.size(), 34);
+
+ EXPECT_EQ(PayToScriptHash.isPayToWitnessScriptHash(), false);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.isPayToWitnessScriptHash(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.isPayToWitnessScriptHash(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.isPayToWitnessScriptHash(), false);
+ EXPECT_EQ(PayToPublicKeyHash.isPayToWitnessScriptHash(), false);
+
+ Data res;
+ EXPECT_EQ(PayToWitnessScriptHash.matchPayToWitnessScriptHash(res), true);
+ EXPECT_EQ(hex(res), "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db");
+
+ EXPECT_EQ(PayToScriptHash.matchPayToWitnessScriptHash(res), false);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.matchPayToWitnessScriptHash(res), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.matchPayToWitnessScriptHash(res), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.matchPayToWitnessScriptHash(res), false);
+ EXPECT_EQ(PayToPublicKeyHash.matchPayToWitnessScriptHash(res), false);
+}
+
+TEST(BitcoinScript, PayToWitnessPublicKeyHash) {
+ EXPECT_EQ(PayToWitnessPublicKeyHash.isPayToWitnessPublicKeyHash(), true);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.bytes.size(), 22);
+
+ EXPECT_EQ(PayToScriptHash.isPayToWitnessPublicKeyHash(), false);
+ EXPECT_EQ(PayToWitnessScriptHash.isPayToWitnessPublicKeyHash(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.isPayToWitnessPublicKeyHash(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.isPayToWitnessPublicKeyHash(), false);
+ EXPECT_EQ(PayToPublicKeyHash.isPayToWitnessPublicKeyHash(), false);
+
+ Data res;
+ EXPECT_EQ(PayToWitnessPublicKeyHash.matchPayToWitnessPublicKeyHash(res), true);
+ EXPECT_EQ(hex(res), "79091972186c449eb1ded22b78e40d009bdf0089");
+
+ EXPECT_EQ(PayToScriptHash.matchPayToWitnessPublicKeyHash(res), false);
+ EXPECT_EQ(PayToWitnessScriptHash.matchPayToWitnessPublicKeyHash(res), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.matchPayToWitnessPublicKeyHash(res), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.matchPayToWitnessPublicKeyHash(res), false);
+ EXPECT_EQ(PayToPublicKeyHash.matchPayToWitnessPublicKeyHash(res), false);
+}
+
+TEST(BitcoinScript, WitnessProgram) {
+ EXPECT_EQ(PayToWitnessScriptHash.isWitnessProgram(), true);
+ EXPECT_EQ(PayToWitnessPublicKeyHash.isWitnessProgram(), true);
+
+ EXPECT_EQ(PayToScriptHash.isWitnessProgram(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1.isWitnessProgram(), false);
+ EXPECT_EQ(PayToPublicKeySecp256k1Extended.isWitnessProgram(), false);
+ EXPECT_EQ(PayToPublicKeyHash.isWitnessProgram(), false);
+}
+
+TEST(BitcoinScript, EncodeNumber) {
+ EXPECT_EQ(Script::encodeNumber(0), OP_0);
+ EXPECT_EQ(Script::encodeNumber(1), OP_1);
+ EXPECT_EQ(Script::encodeNumber(3), OP_3);
+ EXPECT_EQ(Script::encodeNumber(9), OP_9);
+}
+
+TEST(BitcoinScript, DecodeNumber) {
+ EXPECT_EQ(Script::decodeNumber(OP_0), 0);
+ EXPECT_EQ(Script::decodeNumber(OP_1), 1);
+ EXPECT_EQ(Script::decodeNumber(OP_3), 3);
+ EXPECT_EQ(Script::decodeNumber(OP_9), 9);
+}
+
+TEST(BitcoinScript, GetScriptOp) {
+ {
+ size_t index = 5; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("")).getScriptOp(index, opcode, operand), false);
+ }
+ {
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4f")).getScriptOp(index, opcode, operand), true);
+ EXPECT_EQ(index, 1);
+ EXPECT_EQ(opcode, 0x4f);
+ EXPECT_EQ(hex(operand), "");
+ }
+ {
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("05" "0102030405")).getScriptOp(index, opcode, operand), true);
+ EXPECT_EQ(index, 6);
+ EXPECT_EQ(opcode, 0x05);
+ EXPECT_EQ(hex(operand), "0102030405");
+ }
+ { // OP_PUSHDATA1
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4c" "05" "0102030405")).getScriptOp(index, opcode, operand), true);
+ EXPECT_EQ(index, 7);
+ EXPECT_EQ(opcode, 0x4c);
+ EXPECT_EQ(hex(operand), "0102030405");
+ }
+ { // OP_PUSHDATA1 too short
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4c")).getScriptOp(index, opcode, operand), false);
+ }
+ { // OP_PUSHDATA1 too short
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4c" "05" "010203")).getScriptOp(index, opcode, operand), false);
+ }
+ { // OP_PUSHDATA2
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4d" "0500" "0102030405")).getScriptOp(index, opcode, operand), true);
+ EXPECT_EQ(index, 8);
+ EXPECT_EQ(opcode, 0x4d);
+ EXPECT_EQ(hex(operand), "0102030405");
+ }
+ { // OP_PUSHDATA2 too short
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4d" "05")).getScriptOp(index, opcode, operand), false);
+ }
+ { // OP_PUSHDATA2 too short
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4d" "0500" "010203")).getScriptOp(index, opcode, operand), false);
+ }
+ { // OP_PUSHDATA4
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4e" "05000000" "0102030405")).getScriptOp(index, opcode, operand), true);
+ EXPECT_EQ(index, 10);
+ EXPECT_EQ(opcode, 0x4e);
+ EXPECT_EQ(hex(operand), "0102030405");
+ }
+ { // OP_PUSHDATA4 too short
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4e" "0500")).getScriptOp(index, opcode, operand), false);
+ }
+ { // OP_PUSHDATA4 too short
+ size_t index = 0; uint8_t opcode; Data operand;
+ EXPECT_EQ(Script(parse_hex("4e" "05000000" "010203")).getScriptOp(index, opcode, operand), false);
+ }
+}
+
+TEST(BitcoinScript, MatchMultiSig) {
+ std::vector keys;
+ int required;
+ EXPECT_EQ(Script(parse_hex("")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("20")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("00ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("4fae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("20ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514cae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514c05ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("51ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("51" "05" "0102030405" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "00ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "52ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51aeae")).matchMultisig(keys, required), false);
+
+ // valid one key
+ EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true);
+ EXPECT_EQ(required, 1);
+ ASSERT_EQ(keys.size(), 1);
+ EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+
+ EXPECT_EQ(Script(parse_hex("51" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "21" "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1" "51" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("52" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "21" "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1" "51" "ae")).matchMultisig(keys, required), false);
+
+ // valid two keys
+ EXPECT_EQ(Script(parse_hex("52" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "21" "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1" "52" "ae")).matchMultisig(keys, required), true);
+ EXPECT_EQ(required, 2);
+ ASSERT_EQ(keys.size(), 2);
+ EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+ EXPECT_EQ(hex(keys[1]), "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1");
+
+ // OP_PUSHDATA1
+ EXPECT_EQ(Script(parse_hex("514cae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514c" "05" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514c" "05" "0102030405" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514c" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ae")).matchMultisig(keys, required), false);
+
+ // valid one key, OP_PUSHDATA1
+ EXPECT_EQ(Script(parse_hex("514c" "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true);
+ EXPECT_EQ(required, 1);
+ ASSERT_EQ(keys.size(), 1);
+ EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+
+ // OP_PUSHDATA2
+ EXPECT_EQ(Script(parse_hex("514dae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514d" "0500" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514d" "0500" "0102030405" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514d" "2100" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ae")).matchMultisig(keys, required), false);
+
+ // valid one key, OP_PUSHDATA2
+ EXPECT_EQ(Script(parse_hex("514d" "2100" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true);
+ EXPECT_EQ(required, 1);
+ ASSERT_EQ(keys.size(), 1);
+ EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+
+ // OP_PUSHDATA4
+ EXPECT_EQ(Script(parse_hex("514eae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514e" "0500" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514e" "05000000" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514e" "05000000" "0102030405" "ae")).matchMultisig(keys, required), false);
+ EXPECT_EQ(Script(parse_hex("514e" "21000000" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ae")).matchMultisig(keys, required), false);
+
+ // valid one key, OP_PUSHDATA2
+ EXPECT_EQ(Script(parse_hex("514e" "21000000" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "51" "ae")).matchMultisig(keys, required), true);
+ EXPECT_EQ(required, 1);
+ ASSERT_EQ(keys.size(), 1);
+ EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+
+ // valid three keys, mixed
+ EXPECT_EQ(Script(parse_hex("53"
+ "21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"
+ "4d" "2100" "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1"
+ "4e" "21000000" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432"
+ "53" "ae")).matchMultisig(keys, required), true);
+ EXPECT_EQ(required, 3);
+ ASSERT_EQ(keys.size(), 3);
+ EXPECT_EQ(hex(keys[0]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+ EXPECT_EQ(hex(keys[1]), "0399c6f51ad6f98c9c583f8e92bb7758ab2ca9a04110c0a1126ec43e5453d196c1");
+ EXPECT_EQ(hex(keys[2]), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+}
diff --git a/tests/Bitcoin/TWBitcoinScriptTests.cpp b/tests/Bitcoin/TWBitcoinScriptTests.cpp
index 6e5c716fcc5..5337008e9a7 100644
--- a/tests/Bitcoin/TWBitcoinScriptTests.cpp
+++ b/tests/Bitcoin/TWBitcoinScriptTests.cpp
@@ -11,7 +11,124 @@
#include
-TEST(BitcoinScript, ScriptHash) {
+const auto PayToScriptHash = TWBitcoinScriptCreateWithData(DATA("a914" "4733f37cf4db86fbc2efed2500b4f4e49f312023" "87").get());
+const auto PayToWitnessScriptHash = TWBitcoinScriptCreateWithData(DATA("0020" "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db").get());
+const auto PayToWitnessPublicKeyHash = TWBitcoinScriptCreateWithData(DATA("0014" "79091972186c449eb1ded22b78e40d009bdf0089").get());
+const auto PayToPublicKeySecp256k1 = TWBitcoinScriptCreateWithData(DATA("21" "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432" "ac").get());
+const auto PayToPublicKeyHash = TWBitcoinScriptCreateWithData(DATA("76a914" "79091972186c449eb1ded22b78e40d009bdf0089" "88ac").get());
+
+TEST(TWBitcoinScript, Create) {
+ auto data = DATA("a9144733f37cf4db86fbc2efed2500b4f4e49f31202387");
+ {
+ auto script = TWBitcoinScriptCreateWithData(data.get());
+ ASSERT_TRUE(script != nullptr);
+ ASSERT_EQ(TWBitcoinScriptSize(script), 23);
+ }
+ {
+ auto script = TWBitcoinScriptCreateWithBytes(TWDataBytes(data.get()), TWDataSize(data.get()));
+ ASSERT_TRUE(script != nullptr);
+ ASSERT_EQ(TWBitcoinScriptSize(script), 23);
+
+ auto scriptCopy = TWBitcoinScriptCreateCopy(script);
+ ASSERT_TRUE(scriptCopy != nullptr);
+ ASSERT_EQ(TWBitcoinScriptSize(scriptCopy), 23);
+ }
+}
+
+TEST(TWBitcoinScript, Equals) {
+ auto data = DATA("a9144733f37cf4db86fbc2efed2500b4f4e49f31202387");
+ auto script = TWBitcoinScriptCreateWithBytes(TWDataBytes(data.get()), TWDataSize(data.get()));
+ auto scriptCopy = TWBitcoinScriptCreateCopy(script);
+ ASSERT_TRUE(TWBitcoinScriptEqual(script, scriptCopy));
+}
+
+TEST(TWBitcoinScript, IsPayToScriptHash) {
+ ASSERT_TRUE(TWBitcoinScriptIsPayToScriptHash(PayToScriptHash));
+}
+
+TEST(TWBitcoinScript, IsPayToWitnessScriptHash) {
+ ASSERT_TRUE(TWBitcoinScriptIsPayToWitnessScriptHash(PayToWitnessScriptHash));
+}
+
+TEST(TWBitcoinScript, IsPayToWitnessPublicKeyHash) {
+ ASSERT_TRUE(TWBitcoinScriptIsPayToWitnessPublicKeyHash(PayToWitnessPublicKeyHash));
+}
+
+TEST(TWBitcoinScript, IsWitnessProgram) {
+ ASSERT_TRUE(TWBitcoinScriptIsWitnessProgram(PayToWitnessScriptHash));
+ ASSERT_TRUE(TWBitcoinScriptIsWitnessProgram(PayToWitnessPublicKeyHash));
+ ASSERT_FALSE(TWBitcoinScriptIsWitnessProgram(PayToScriptHash));
+}
+
+TEST(TWBitcoinScript, MatchPayToPubkey) {
+ const auto res = WRAPD(TWBitcoinScriptMatchPayToPubkey(PayToPublicKeySecp256k1));
+ ASSERT_TRUE(res.get() != nullptr);
+ const auto hexRes = WRAPS(TWStringCreateWithHexData(res.get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hexRes.get()), "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432");
+
+ ASSERT_EQ(TWBitcoinScriptMatchPayToPubkey(PayToScriptHash), nullptr);
+}
+
+TEST(TWBitcoinScript, TWBitcoinScriptMatchPayToPubkeyHash) {
+ const auto res = WRAPD(TWBitcoinScriptMatchPayToPubkeyHash(PayToPublicKeyHash));
+ ASSERT_TRUE(res.get() != nullptr);
+ const auto hexRes = WRAPS(TWStringCreateWithHexData(res.get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hexRes.get()), "79091972186c449eb1ded22b78e40d009bdf0089");
+
+ ASSERT_EQ(TWBitcoinScriptMatchPayToPubkeyHash(PayToScriptHash), nullptr);
+}
+
+TEST(TWBitcoinScript, MatchPayToScriptHash) {
+ const auto res = WRAPD(TWBitcoinScriptMatchPayToScriptHash(PayToScriptHash));
+ ASSERT_TRUE(res.get() != nullptr);
+ const auto hexRes = WRAPS(TWStringCreateWithHexData(res.get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hexRes.get()), "4733f37cf4db86fbc2efed2500b4f4e49f312023");
+
+ ASSERT_EQ(TWBitcoinScriptMatchPayToScriptHash(PayToPublicKeySecp256k1), nullptr);
+}
+
+TEST(TWBitcoinScript, MatchPayToWitnessPublicKeyHash) {
+ const auto res = WRAPD(TWBitcoinScriptMatchPayToWitnessPublicKeyHash(PayToWitnessPublicKeyHash));
+ ASSERT_TRUE(res.get() != nullptr);
+ const auto hexRes = WRAPS(TWStringCreateWithHexData(res.get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hexRes.get()), "79091972186c449eb1ded22b78e40d009bdf0089");
+
+ ASSERT_EQ(TWBitcoinScriptMatchPayToWitnessPublicKeyHash(PayToPublicKeySecp256k1), nullptr);
+}
+
+TEST(TWBitcoinScript, MatchPayToWitnessScriptHash) {
+ const auto res = WRAPD(TWBitcoinScriptMatchPayToWitnessScriptHash(PayToWitnessScriptHash));
+ ASSERT_TRUE(res.get() != nullptr);
+ const auto hexRes = WRAPS(TWStringCreateWithHexData(res.get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hexRes.get()), "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db");
+
+ ASSERT_EQ(TWBitcoinScriptMatchPayToWitnessScriptHash(PayToPublicKeySecp256k1), nullptr);
+}
+
+TEST(TWBitcoinScript, Encode) {
+ const auto res = WRAPD(TWBitcoinScriptEncode(PayToScriptHash));
+ ASSERT_TRUE(res.get() != nullptr);
+ const auto hexRes = WRAPS(TWStringCreateWithHexData(res.get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hexRes.get()), "17a9144733f37cf4db86fbc2efed2500b4f4e49f31202387");
+}
+
+TEST(TWBitcoinScript, BuildPayToWitnessPubkeyHash) {
+ const auto hash = DATA("79091972186c449eb1ded22b78e40d009bdf0089");
+ const auto script = TWBitcoinScriptBuildPayToWitnessPubkeyHash(hash.get());
+ ASSERT_TRUE(script != nullptr);
+ const auto hex = WRAPS(TWStringCreateWithHexData(WRAPD(TWBitcoinScriptData(script)).get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "0014" "79091972186c449eb1ded22b78e40d009bdf0089");
+}
+
+TEST(TWBitcoinScript, BuildPayToWitnessScriptHash) {
+ const auto hash = DATA("ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db");
+ const auto script = TWBitcoinScriptBuildPayToWitnessScriptHash(hash.get());
+ ASSERT_TRUE(script != nullptr);
+ const auto hex = WRAPS(TWStringCreateWithHexData(WRAPD(TWBitcoinScriptData(script)).get()));
+ ASSERT_STREQ(TWStringUTF8Bytes(hex.get()), "0020" "ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db");
+}
+
+TEST(TWBitcoinScript, ScriptHash) {
auto pkData = DATA("cf5007e19af3641199f21f3fa54dff2fa2627471");
auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildPayToPublicKeyHash(pkData.get()));
@@ -26,7 +143,7 @@ TEST(BitcoinScript, ScriptHash) {
ASSERT_STREQ(TWStringUTF8Bytes(hexData.get()), "c470d22e69a2a967f2cec0cd5a5aebb955cdd395");
}
-TEST(BitcoinScript, RedeemScript) {
+TEST(TWBitcoinScript, RedeemScript) {
auto pkData = DATA("cf5007e19af3641199f21f3fa54dff2fa2627471");
auto embeddedScript = WRAP(TWBitcoinScript, TWBitcoinScriptBuildPayToPublicKeyHash(pkData.get()));
@@ -40,7 +157,7 @@ TEST(BitcoinScript, RedeemScript) {
ASSERT_STREQ(TWStringUTF8Bytes(hexData.get()), "a914c470d22e69a2a967f2cec0cd5a5aebb955cdd39587");
}
-TEST(BitcoinScript, LockScriptForP2PKHAddress) {
+TEST(TWBitcoinScript, LockScriptForP2PKHAddress) {
auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildForAddress(STRING("1Cu32FVupVCgHkMMRJdYJugxwo2Aprgk7H").get(), TWCoinTypeBitcoin));
auto scriptData = WRAPD(TWBitcoinScriptData(script.get()));
assertHexEqual(scriptData, "76a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac");
@@ -50,7 +167,7 @@ TEST(BitcoinScript, LockScriptForP2PKHAddress) {
assertHexEqual(scriptPub2Data, "76a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac");
}
-TEST(BitcoinScript, LockScriptForP2SHAddress) {
+TEST(TWBitcoinScript, LockScriptForP2SHAddress) {
auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildForAddress(STRING("37rHiL4DN2wkt8pgCAUfYJRxhir98ZGN1y").get(), TWCoinTypeBitcoin));
auto scriptData = WRAPD(TWBitcoinScriptData(script.get()));
assertHexEqual(scriptData, "a9144391adbec172cad6a9fc3eebca36aeec6640abda87");
@@ -60,7 +177,7 @@ TEST(BitcoinScript, LockScriptForP2SHAddress) {
assertHexEqual(scriptPub2Data, "a914ad40768af6419a20bdb94d83c06b6c8c94721dc087");
}
-TEST(BitcoinScript, LockScriptForP2WPKHAddress) {
+TEST(TWBitcoinScript, LockScriptForP2WPKHAddress) {
auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildForAddress(STRING("bc1q6hppaw7uld68amnnu5vpp5dd5u7k92c2vtdtkq").get(), TWCoinTypeBitcoin));
auto scriptData = WRAPD(TWBitcoinScriptData(script.get()));
assertHexEqual(scriptData, "0014d5c21ebbdcfb747eee73e51810d1ada73d62ab0a");
@@ -70,13 +187,13 @@ TEST(BitcoinScript, LockScriptForP2WPKHAddress) {
assertHexEqual(scriptPub2Data, "0014039f2ffd2b28703f0e9c73ccf3ce564adebbb5e8");
}
-TEST(BitcoinScript, LockScriptForP2WSHAddress) {
+TEST(TWBitcoinScript, LockScriptForP2WSHAddress) {
auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildForAddress(STRING("bc1qcuqamesrt803xld4l2j2vxx8rxmrx7aq82mkw7xwxh643wzqjlnqutkcv2").get(), TWCoinTypeBitcoin));
auto scriptData = WRAPD(TWBitcoinScriptData(script.get()));
assertHexEqual(scriptData, "0020c701dde60359df137db5faa4a618c719b6337ba03ab76778ce35f558b84097e6");
}
-TEST(BitcoinScript, LockScriptForCashAddress) {
+TEST(TWBitcoinScript, LockScriptForCashAddress) {
auto script = WRAP(TWBitcoinScript, TWBitcoinScriptBuildForAddress(STRING("bitcoincash:pzclklsyx9f068hd00a0vene45akeyrg7vv0053uqf").get(), TWCoinTypeBitcoin));
auto scriptData = WRAPD(TWBitcoinScriptData(script.get()));
assertHexEqual(scriptData, "a914b1fb7e043152fd1eed7bfaf66679ad3b6c9068f387");
diff --git a/tests/Bitcoin/TWBitcoinSigningTests.cpp b/tests/Bitcoin/TWBitcoinSigningTests.cpp
index 931e8dfe46f..45137ad48ef 100644
--- a/tests/Bitcoin/TWBitcoinSigningTests.cpp
+++ b/tests/Bitcoin/TWBitcoinSigningTests.cpp
@@ -249,7 +249,7 @@ TEST(BitcoinSigning, SignP2SH_P2WPKH) {
ASSERT_EQ(hex(utxoPubkeyHash.begin(), utxoPubkeyHash.end()), "79091972186c449eb1ded22b78e40d009bdf0089");
input.add_private_key(utxoKey0.bytes.data(), utxoKey0.bytes.size());
- auto redeemScript = Script::buildPayToWitnessPubkeyHash(utxoPubkeyHash);
+ auto redeemScript = Script::buildPayToWitnessPublicKeyHash(utxoPubkeyHash);
auto scriptHash = Hash::ripemd(Hash::sha256(redeemScript.bytes));
ASSERT_EQ(hex(scriptHash.begin(), scriptHash.end()), "4733f37cf4db86fbc2efed2500b4f4e49f312023");
auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end());
diff --git a/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp b/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp
index 28d75b48d4c..c8a098a7aff 100644
--- a/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp
+++ b/tests/Groestlcoin/TWGroestlcoinSigningTests.cpp
@@ -91,7 +91,7 @@ TEST(GroestlcoinSigning, SignP2SH_P2WPKH) {
EXPECT_EQ(hex(utxoPubkeyHash.begin(), utxoPubkeyHash.end()), "2fc7d70acef142d1f7b5ef2f20b1a9b759797674");
input.add_private_key(utxoKey0.bytes.data(), utxoKey0.bytes.size());
- auto redeemScript = Script::buildPayToWitnessPubkeyHash(utxoPubkeyHash);
+ auto redeemScript = Script::buildPayToWitnessPublicKeyHash(utxoPubkeyHash);
auto scriptHash = Hash::ripemd(Hash::sha256(redeemScript.bytes));
ASSERT_EQ(hex(scriptHash.begin(), scriptHash.end()), "0055b0c94df477ee6b9f75185dfc9aa8ce2e52e4");
auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end());
From 4dfeeeb1e85132cf04cda9b5f23f5879d9cf5bb7 Mon Sep 17 00:00:00 2001
From: Adam R <13562139+catenocrypt@users.noreply.github.com>
Date: Wed, 29 Apr 2020 09:03:15 +0200
Subject: [PATCH 12/81] Some low-impact cppcheck finding fixes. (#938)
* Some low-impact cppcheck finding fixes.
* Some reverts to address diff coverage metric.
* Add scripts for cppcheck to tools.
* Some minor reference type style linting.
Co-authored-by: Catenocrypt
---
src/Aeternity/Address.cpp | 8 ++++----
src/Aeternity/Address.h | 8 ++++----
src/Aeternity/Signer.cpp | 8 ++++----
src/Aeternity/Signer.h | 8 ++++----
src/Aeternity/Transaction.cpp | 4 ++--
src/Aeternity/Transaction.h | 8 ++++----
src/Aion/Transaction.h | 2 +-
src/Algorand/BinaryCoding.h | 6 +++---
src/Algorand/Transaction.cpp | 2 +-
src/Algorand/Transaction.h | 4 ++--
src/Bech32Address.h | 2 +-
src/Binance/Address.h | 4 ++--
src/Cardano/AddressV3.h | 2 +-
src/Cbor.cpp | 26 +++++++++++++-------------
src/Cbor.h | 2 +-
src/Coin.cpp | 2 +-
src/Cosmos/Address.h | 2 +-
src/DerivationPath.cpp | 2 +-
src/DerivationPath.h | 4 ++--
src/EOS/Asset.cpp | 8 ++++----
src/EOS/Transaction.cpp | 2 +-
src/EOS/Transaction.h | 4 ++--
src/Ethereum/ABI/Bytes.h | 2 +-
src/Ethereum/ABI/Function.h | 2 +-
src/Ethereum/Signer.cpp | 4 ++--
src/Ethereum/Signer.h | 4 ++--
src/Ethereum/Transaction.h | 2 +-
src/FIO/Action.h | 2 +-
src/HDWallet.cpp | 4 ++--
src/HDWallet.h | 4 ++--
src/Harmony/Address.h | 4 ++--
src/Harmony/Signer.cpp | 8 ++++----
src/Harmony/Signer.h | 8 ++++----
src/Harmony/Transaction.h | 2 +-
src/IoTeX/Address.h | 4 ++--
src/Keystore/EncryptionParameters.cpp | 4 ++--
src/Keystore/EncryptionParameters.h | 4 ++--
src/Keystore/PBKDF2Parameters.h | 2 +-
src/Keystore/ScryptParameters.h | 2 +-
src/Keystore/StoredKey.cpp | 2 +-
src/Keystore/StoredKey.h | 2 +-
src/NEAR/Serialization.cpp | 2 +-
src/NEO/Address.h | 8 ++++----
src/NEO/CoinReference.h | 2 +-
src/NEO/ISerializable.h | 2 +-
src/NEO/MinerTransaction.h | 2 +-
src/NEO/ReadData.cpp | 10 +++++-----
src/NEO/ReadData.h | 12 ++++++------
src/NEO/Script.cpp | 4 ++--
src/NEO/Script.h | 4 ++--
src/NEO/Serializable.h | 7 ++-----
src/NEO/Transaction.cpp | 4 ++--
src/NEO/Transaction.h | 6 +++---
src/NEO/TransactionAttribute.h | 2 +-
src/NEO/TransactionOutput.h | 2 +-
src/NEO/Witness.h | 2 +-
src/Nebulas/Address.cpp | 6 +++---
src/Solana/Address.cpp | 4 ++--
src/Solana/Address.h | 6 +++---
src/Solana/Transaction.h | 2 +-
src/TON/Cell.cpp | 2 +-
src/Tezos/Signer.cpp | 2 +-
src/Tezos/Signer.h | 2 +-
src/Theta/Transaction.h | 2 +-
src/VeChain/Clause.h | 2 +-
src/Waves/Address.cpp | 8 ++++----
src/Waves/Address.h | 15 ++++-----------
src/Waves/Transaction.cpp | 14 +++++++-------
src/Waves/Transaction.h | 2 +-
src/XXHash64.h | 1 +
src/Zilliqa/Address.h | 4 ++--
src/interface/TWAnyAddress.cpp | 4 ++--
src/interface/TWBase58.cpp | 2 +-
src/interface/TWBitcoinAddress.cpp | 2 +-
src/interface/TWData.cpp | 3 +--
src/interface/TWPrivateKey.cpp | 4 ++--
src/interface/TWPublicKey.cpp | 8 ++++----
tools/lint-cppcheck-all | 7 +++++++
tools/lint-cppcheck-diff | 15 +++++++++++++++
79 files changed, 191 insertions(+), 179 deletions(-)
create mode 100755 tools/lint-cppcheck-all
create mode 100755 tools/lint-cppcheck-diff
diff --git a/src/Aeternity/Address.cpp b/src/Aeternity/Address.cpp
index ff256597044..101ba527854 100644
--- a/src/Aeternity/Address.cpp
+++ b/src/Aeternity/Address.cpp
@@ -13,7 +13,7 @@
using namespace TW::Aeternity;
/// Determines whether a string makes a valid address.
-bool Address::isValid(const std::string &string) {
+bool Address::isValid(const std::string& string) {
if (string.empty()) {
return false;
}
@@ -34,7 +34,7 @@ Address::Address(const PublicKey &publicKey) {
}
/// Initializes an address from a string representation.
-Address::Address(const std::string &string) {
+Address::Address(const std::string& string) {
if (!isValid(string)) {
throw std::invalid_argument("Invalid address");
}
@@ -48,11 +48,11 @@ std::string Address::string() const {
return Identifiers::prefixAccountPubkey + Base58::bitcoin.encodeCheck(bytes);
}
-bool Address::checkType(const std::string &type) {
+bool Address::checkType(const std::string& type) {
return type == Identifiers::prefixAccountPubkey;
}
-bool Address::checkPayload(const std::string &payload) {
+bool Address::checkPayload(const std::string& payload) {
unsigned long base58 = Base58::bitcoin.decodeCheck(payload).size();
return base58 == size;
}
diff --git a/src/Aeternity/Address.h b/src/Aeternity/Address.h
index 0f8b4e24724..07e9b732939 100644
--- a/src/Aeternity/Address.h
+++ b/src/Aeternity/Address.h
@@ -15,10 +15,10 @@ class Address {
Data bytes;
/// Determines whether a string makes a valid address.
- static bool isValid(const std::string &string);
+ static bool isValid(const std::string& string);
/// Initializes an address from a string representation.
- explicit Address(const std::string &string);
+ explicit Address(const std::string& string);
/// Initializes an address from a public key.
explicit Address(const PublicKey &publicKey);
@@ -28,8 +28,8 @@ class Address {
private:
- static bool checkType(const std::string &type);
- static bool checkPayload(const std::string &payload);
+ static bool checkType(const std::string& type);
+ static bool checkPayload(const std::string& payload);
};
inline bool operator==(const Address& lhs, const Address& rhs) {
diff --git a/src/Aeternity/Signer.cpp b/src/Aeternity/Signer.cpp
index 02a6c0412a2..7c9adf1fafa 100644
--- a/src/Aeternity/Signer.cpp
+++ b/src/Aeternity/Signer.cpp
@@ -48,7 +48,7 @@ Proto::SigningOutput Signer::sign(const TW::PrivateKey &privateKey, Transaction
return createProtoOutput(signature, signedEncodedTx);
}
-Data Signer::buildRlpTxRaw(Data &txRaw, Data &sigRaw) {
+Data Signer::buildRlpTxRaw(Data& txRaw, Data& sigRaw) {
auto rlpTxRaw = Data();
auto signaturesList = Data();
append(signaturesList, Ethereum::RLP::encode(sigRaw));
@@ -61,7 +61,7 @@ Data Signer::buildRlpTxRaw(Data &txRaw, Data &sigRaw) {
return Ethereum::RLP::encodeList(rlpTxRaw);
}
-Data Signer::buildMessageToSign(Data &txRaw) {
+Data Signer::buildMessageToSign(Data& txRaw) {
auto data = Data();
Data bytes(Identifiers::networkId.begin(), Identifiers::networkId.end());
append(data, bytes);
@@ -69,7 +69,7 @@ Data Signer::buildMessageToSign(Data &txRaw) {
return data;
}
-Proto::SigningOutput Signer::createProtoOutput(std::string &signature, const std::string &signedTx) {
+Proto::SigningOutput Signer::createProtoOutput(std::string& signature, const std::string& signedTx) {
auto output = Proto::SigningOutput();
output.set_signature(signature);
@@ -77,7 +77,7 @@ Proto::SigningOutput Signer::createProtoOutput(std::string &signature, const std
return output;
}
-std::string Signer::encodeBase64WithChecksum(const std::string &prefix, const TW::Data &rawTx) {
+std::string Signer::encodeBase64WithChecksum(const std::string& prefix, const TW::Data& rawTx) {
auto checksum = Hash::sha256(Hash::sha256(rawTx));
std::vector checksumPart(checksum.begin(), checksum.begin() + checkSumSize);
diff --git a/src/Aeternity/Signer.h b/src/Aeternity/Signer.h
index eae11aa4bc4..dd289e5487d 100644
--- a/src/Aeternity/Signer.h
+++ b/src/Aeternity/Signer.h
@@ -21,14 +21,14 @@ class Signer {
private:
static const uint8_t checkSumSize = 4;
- static Data buildRlpTxRaw(Data &txRaw, Data &sigRaw);
+ static Data buildRlpTxRaw(Data& txRaw, Data& sigRaw);
- static Data buildMessageToSign(Data &txRaw);
+ static Data buildMessageToSign(Data& txRaw);
- static Proto::SigningOutput createProtoOutput(std::string &signature, const std::string &signedTx);
+ static Proto::SigningOutput createProtoOutput(std::string& signature, const std::string& signedTx);
/// Encode a byte array into base64 with prefix and a checksum
- static std::string encodeBase64WithChecksum(const std::string &prefix, const TW::Data &rawTx);
+ static std::string encodeBase64WithChecksum(const std::string& prefix, const TW::Data& rawTx);
};
} // namespace TW::Aeternity
diff --git a/src/Aeternity/Transaction.cpp b/src/Aeternity/Transaction.cpp
index 198df6c3af0..416531544b5 100644
--- a/src/Aeternity/Transaction.cpp
+++ b/src/Aeternity/Transaction.cpp
@@ -26,11 +26,11 @@ Data Transaction::encode() {
append(encoded, encodeSafeZero(nonce));
append(encoded, Ethereum::RLP::encode(payload));
- const Data &raw = Ethereum::RLP::encodeList(encoded);
+ const Data& raw = Ethereum::RLP::encodeList(encoded);
return raw;
}
-TW::Data Transaction::buildTag(const std::string &address) {
+TW::Data Transaction::buildTag(const std::string& address) {
auto payload = address.substr(Identifiers::prefixTransaction.size(), address.size());
auto data = Data();
diff --git a/src/Aeternity/Transaction.h b/src/Aeternity/Transaction.h
index 979d9b8312d..6bace4629b8 100644
--- a/src/Aeternity/Transaction.h
+++ b/src/Aeternity/Transaction.h
@@ -31,11 +31,11 @@ class Transaction {
uint64_t nonce;
Transaction(
- std::string &sender_id,
- std::string &recipientId,
+ std::string& sender_id,
+ std::string& recipientId,
uint256_t amount,
uint256_t fee,
- std::string &payload,
+ std::string& payload,
uint64_t ttl,
uint64_t nonce
)
@@ -51,7 +51,7 @@ class Transaction {
//// buildIDTag assemble an id() object
//// see https://github.com/aeternity/protocol/blob/epoch-v0.22.0/serializations.md#the-id-type
- static Data buildTag(const std::string &address);
+ static Data buildTag(const std::string& address);
/// Awternity network does not accept zero int values as rlp param,
/// instead empty byte array should be encoded
diff --git a/src/Aion/Transaction.h b/src/Aion/Transaction.h
index e1c8013e5bf..c87e5bc0256 100644
--- a/src/Aion/Transaction.h
+++ b/src/Aion/Transaction.h
@@ -28,7 +28,7 @@ class Transaction {
std::vector signature;
Transaction(uint128_t nonce, uint128_t gasPrice, uint128_t gasLimit, Address to,
- uint128_t amount, Data payload)
+ uint128_t amount, const Data& payload)
: nonce(std::move(nonce))
, gasPrice(std::move(gasPrice))
, gasLimit(std::move(gasLimit))
diff --git a/src/Algorand/BinaryCoding.h b/src/Algorand/BinaryCoding.h
index 87895a97daa..3a169cf3e00 100644
--- a/src/Algorand/BinaryCoding.h
+++ b/src/Algorand/BinaryCoding.h
@@ -11,7 +11,7 @@
namespace TW::Algorand {
-static inline void encodeString(std::string string, Data &data) {
+static inline void encodeString(std::string string, Data& data) {
// encode string header
auto bytes = Data(string.begin(), string.end());
if (bytes.size() < 0x20) {
@@ -36,7 +36,7 @@ static inline void encodeString(std::string string, Data &data) {
append(data, bytes);
}
-static inline void encodeNumber(uint64_t number, Data &data) {
+static inline void encodeNumber(uint64_t number, Data& data) {
if (number < 0x80) {
// positive fixint
data.push_back(static_cast(number));
@@ -59,7 +59,7 @@ static inline void encodeNumber(uint64_t number, Data &data) {
}
}
-static inline void encodeBytes(const Data &bytes, Data &data) {
+static inline void encodeBytes(const Data& bytes, Data& data) {
auto size = bytes.size();
if (size < 0x100) {
// bin 8
diff --git a/src/Algorand/Transaction.cpp b/src/Algorand/Transaction.cpp
index a2f6cdd7820..ac608af5b3e 100644
--- a/src/Algorand/Transaction.cpp
+++ b/src/Algorand/Transaction.cpp
@@ -71,7 +71,7 @@ Data Transaction::serialize() const {
return data;
}
-Data Transaction::serialize(Data &signature) const {
+Data Transaction::serialize(Data& signature) const {
/* Algorand transaction and signature are encoded with msgpack:
{
"sig":
diff --git a/src/Algorand/Transaction.h b/src/Algorand/Transaction.h
index a545d65d48f..f7b9c3dd694 100644
--- a/src/Algorand/Transaction.h
+++ b/src/Algorand/Transaction.h
@@ -27,7 +27,7 @@ class Transaction {
Data genesisHash;
Transaction(Address &from, Address &to, uint64_t fee, uint64_t amount, uint64_t firstRound,
- uint64_t lastRound, Data ¬e, std::string type, std::string &genesisIdg, Data &genesisHash)
+ uint64_t lastRound, Data& note, std::string type, std::string& genesisIdg, Data& genesisHash)
: from(from) , to(to)
, fee(fee), amount(amount)
, firstRound(firstRound), lastRound(lastRound)
@@ -36,7 +36,7 @@ class Transaction {
public:
Data serialize() const;
- Data serialize(Data &signature) const;
+ Data serialize(Data& signature) const;
};
} // namespace TW::Algorand
diff --git a/src/Bech32Address.h b/src/Bech32Address.h
index a5aea665805..23b4c06a640 100644
--- a/src/Bech32Address.h
+++ b/src/Bech32Address.h
@@ -48,7 +48,7 @@ class Bech32Address {
Bech32Address(const std::string& hrp, HasherType hasher, const PublicKey& publicKey);
void setHrp(const std::string& hrp_in) { hrp = std::move(hrp_in); }
- void setKey(Data keyHash_in) { keyHash = std::move(keyHash_in); }
+ void setKey(const Data& keyHash_in) { keyHash = std::move(keyHash_in); }
inline const std::string& getHrp() const { return hrp; }
diff --git a/src/Binance/Address.h b/src/Binance/Address.h
index 412fac043c0..198540e0962 100644
--- a/src/Binance/Address.h
+++ b/src/Binance/Address.h
@@ -17,12 +17,12 @@ class Address: public Bech32Address {
public:
static const std::string hrp; // HRP_BINANCE
- static bool isValid(const std::string addr) { return Bech32Address::isValid(addr, hrp); }
+ static bool isValid(const std::string& addr) { return Bech32Address::isValid(addr, hrp); }
Address() : Bech32Address(hrp) {}
/// Initializes an address with a key hash.
- Address(Data keyHash) : Bech32Address(hrp, keyHash) {}
+ Address(const Data& keyHash) : Bech32Address(hrp, keyHash) {}
/// Initializes an address with a public key.
Address(const PublicKey& publicKey) : Bech32Address(hrp, HASHER_SHA2_RIPEMD, publicKey) {}
diff --git a/src/Cardano/AddressV3.h b/src/Cardano/AddressV3.h
index 2c9655041be..960750ccee3 100644
--- a/src/Cardano/AddressV3.h
+++ b/src/Cardano/AddressV3.h
@@ -86,7 +86,7 @@ class AddressV3 {
Data data() const;
private:
- AddressV3() : legacyAddressV2(nullptr) {}
+ AddressV3() : legacyAddressV2(nullptr), discrimination(Discrim_Production), kind(Kind_Single) {}
};
inline bool operator==(const AddressV3& lhs, const AddressV3& rhs) {
diff --git a/src/Cbor.cpp b/src/Cbor.cpp
index ae2fccf1ab8..51304779b21 100644
--- a/src/Cbor.cpp
+++ b/src/Cbor.cpp
@@ -162,8 +162,8 @@ Decode Decode::skipClone(uint32_t offset) const {
Decode::TypeDesc Decode::getTypeDesc() const {
TypeDesc typeDesc;
typeDesc.isIndefiniteValue = false;
- typeDesc.majorType = (MajorType)(byte(0) >> 5);
- auto minorType = (TW::byte)((uint8_t)byte(0) & 0x1F);
+ typeDesc.majorType = (MajorType)(getByte(0) >> 5);
+ auto minorType = (TW::byte)((uint8_t)getByte(0) & 0x1F);
if (minorType < 24) {
// direct value
typeDesc.byteCount = 1;
@@ -172,31 +172,31 @@ Decode::TypeDesc Decode::getTypeDesc() const {
}
if (minorType == 24) {
typeDesc.byteCount = 1 + 1;
- typeDesc.value = byte(1);
+ typeDesc.value = getByte(1);
return typeDesc;
}
if (minorType == 25) {
typeDesc.byteCount = 1 + 2;
- typeDesc.value = (uint16_t)(((uint16_t)byte(1) << 8) + (uint16_t)byte(2));
+ typeDesc.value = (uint16_t)(((uint16_t)getByte(1) << 8) + (uint16_t)getByte(2));
return typeDesc;
}
if (minorType == 26) {
typeDesc.byteCount = 1 + 4;
- typeDesc.value = (uint32_t)(((uint32_t)byte(1) << 24) + ((uint32_t)byte(2) << 16) + ((uint32_t)byte(3) << 8) + (uint32_t)byte(4));
+ typeDesc.value = (uint32_t)(((uint32_t)getByte(1) << 24) + ((uint32_t)getByte(2) << 16) + ((uint32_t)getByte(3) << 8) + (uint32_t)getByte(4));
return typeDesc;
}
if (minorType == 27) {
typeDesc.byteCount = 1 + 8;
typeDesc.value =
(uint64_t)(
- ((uint64_t)byte(1) << 56) +
- ((uint64_t)byte(2) << 48) +
- ((uint64_t)byte(3) << 40) +
- ((uint64_t)byte(4) << 32) +
- ((uint64_t)byte(5) << 24) +
- ((uint64_t)byte(6) << 16) +
- ((uint64_t)byte(7) << 8) +
- ((uint64_t)byte(8)));
+ ((uint64_t)getByte(1) << 56) +
+ ((uint64_t)getByte(2) << 48) +
+ ((uint64_t)getByte(3) << 40) +
+ ((uint64_t)getByte(4) << 32) +
+ ((uint64_t)getByte(5) << 24) +
+ ((uint64_t)getByte(6) << 16) +
+ ((uint64_t)getByte(7) << 8) +
+ ((uint64_t)getByte(8)));
return typeDesc;
}
if (minorType >= 28 && minorType <= 30) {
diff --git a/src/Cbor.h b/src/Cbor.h
index 653bd23bfb9..71de1adb2e0 100644
--- a/src/Cbor.h
+++ b/src/Cbor.h
@@ -118,7 +118,7 @@ class Decode {
/// Skip ahead: form other Decode data with offset
Decode skipClone(uint32_t offset) const;
/// Get the Nth byte
- inline TW::byte byte(uint32_t idx) const {
+ inline TW::byte getByte(uint32_t idx) const {
if (subStart + idx >= data->origData.size()) { throw std::invalid_argument("CBOR data too short"); }
return data->origData[subStart + idx];
}
diff --git a/src/Coin.cpp b/src/Coin.cpp
index c6135ddbec0..8f96291d962 100644
--- a/src/Coin.cpp
+++ b/src/Coin.cpp
@@ -147,7 +147,7 @@ bool TW::validateAddress(TWCoinType coin, const std::string& string) {
return dispatcher->validateAddress(coin, string, p2pkh, p2sh, hrp);
}
-std::string TW::normalizeAddress(TWCoinType coin, const std::string &address) {
+std::string TW::normalizeAddress(TWCoinType coin, const std::string& address) {
if (!TW::validateAddress(coin, address)) {
// invalid address, not normalizing
return "";
diff --git a/src/Cosmos/Address.h b/src/Cosmos/Address.h
index 67d91040c07..49bf640d5cb 100644
--- a/src/Cosmos/Address.h
+++ b/src/Cosmos/Address.h
@@ -20,7 +20,7 @@ class Address: public Bech32Address {
Address() : Bech32Address("") {}
/// Initializes an address with a key hash.
- Address(const std::string& hrp, Data keyHash) : Bech32Address(hrp, keyHash) {}
+ Address(const std::string& hrp, const Data& keyHash) : Bech32Address(hrp, keyHash) {}
/// Initializes an address with a public key.
Address(const std::string& hrp, const PublicKey& publicKey) : Bech32Address(hrp, HASHER_SHA2_RIPEMD, publicKey) {}
diff --git a/src/DerivationPath.cpp b/src/DerivationPath.cpp
index 269a6a5c06a..e0f97ed8c71 100644
--- a/src/DerivationPath.cpp
+++ b/src/DerivationPath.cpp
@@ -24,7 +24,7 @@ DerivationPath::DerivationPath(const std::string& string) {
while (it != end) {
uint32_t value;
- if (std::sscanf(it, "%d", &value) != 1) {
+ if (std::sscanf(it, "%ud", &value) != 1) {
throw std::invalid_argument("Invalid component");
}
while (it != end && isdigit(*it)) {
diff --git a/src/DerivationPath.h b/src/DerivationPath.h
index 9a254da1d0e..0955d24cc37 100644
--- a/src/DerivationPath.h
+++ b/src/DerivationPath.h
@@ -101,8 +101,8 @@ struct DerivationPath {
/// Creates a `DerivationPath` by BIP44 components.
DerivationPath(TWPurpose purpose, TWCoinType coin, uint32_t account, uint32_t change,
- uint32_t address) {
- indices = std::vector(5);
+ uint32_t address)
+ : indices(std::vector(5)) {
setPurpose(purpose);
setCoin(coin);
setAccount(account);
diff --git a/src/EOS/Asset.cpp b/src/EOS/Asset.cpp
index 80d7e159665..17d03be7976 100644
--- a/src/EOS/Asset.cpp
+++ b/src/EOS/Asset.cpp
@@ -12,11 +12,11 @@
using namespace TW::EOS;
-static const int64_t precision = 1000;
-static const uint8_t maxDecimals = 18;
+static const int64_t Precision = 1000;
+static const uint8_t MaxDecimals = 18;
Asset::Asset(int64_t amount, uint8_t decimals, const std::string& symbol) {
- if (decimals > maxDecimals) {
+ if (decimals > MaxDecimals) {
throw std::invalid_argument("Too many decimals!");
}
this->symbol |= decimals;
@@ -112,7 +112,7 @@ std::string Asset::string() const {
int charsWritten = snprintf(buffer, maxBufferSize, "%.*f %s",
decimals,
- static_cast(amount) / precision,
+ static_cast(amount) / Precision,
getSymbol().c_str());
if (charsWritten < 0 || charsWritten > maxBufferSize) {
diff --git a/src/EOS/Transaction.cpp b/src/EOS/Transaction.cpp
index 57138378b2d..e7ae58700aa 100644
--- a/src/EOS/Transaction.cpp
+++ b/src/EOS/Transaction.cpp
@@ -18,7 +18,7 @@ using namespace TW;
using namespace TW::EOS;
using json = nlohmann::json;
-Signature::Signature(Data sig, Type type) : data(sig), type(type) {
+Signature::Signature(const Data& sig, Type type) : data(sig), type(type) {
if (sig.size() != DataSize) {
throw std::invalid_argument("Invalid signature size!");
}
diff --git a/src/EOS/Transaction.h b/src/EOS/Transaction.h
index d2413e8aee1..5d6660c462a 100644
--- a/src/EOS/Transaction.h
+++ b/src/EOS/Transaction.h
@@ -25,7 +25,7 @@ class Signature {
static const size_t DataSize = 65;
static const size_t ChecksumSize = 4;
- Signature(Data sig, Type type);
+ Signature(const Data& sig, Type type);
virtual ~Signature() { }
void serialize(Data& os) const noexcept;
std::string string() const noexcept;
@@ -36,7 +36,7 @@ class Extension {
uint16_t type;
Data buffer;
- Extension(uint16_t type, Data buffer) : type(type), buffer(buffer) { }
+ Extension(uint16_t type, const Data& buffer) : type(type), buffer(buffer) { }
virtual ~Extension() { }
void serialize(Data& os) const noexcept;
nlohmann::json serialize() const noexcept;
diff --git a/src/Ethereum/ABI/Bytes.h b/src/Ethereum/ABI/Bytes.h
index c2b85e2e5b1..69eb5aaede8 100644
--- a/src/Ethereum/ABI/Bytes.h
+++ b/src/Ethereum/ABI/Bytes.h
@@ -64,7 +64,7 @@ class ParamString: public ParamCollection
public:
ParamString() = default;
ParamString(std::string val): ParamCollection() { setVal(val); }
- void setVal(std::string& val) { _str = val; }
+ void setVal(const std::string& val) { _str = val; }
const std::string& getVal() const { return _str; }
virtual std::string getType() const { return "string"; };
virtual size_t getSize() const { return 32 + ValueEncoder::paddedTo32(_str.size()); }
diff --git a/src/Ethereum/ABI/Function.h b/src/Ethereum/ABI/Function.h
index cf3585096bd..11d020c8ab7 100644
--- a/src/Ethereum/ABI/Function.h
+++ b/src/Ethereum/ABI/Function.h
@@ -26,7 +26,7 @@ class Function {
ParamSet _outParams;
Function(std::string name) : name(std::move(name)) {}
- Function(std::string name, std::vector> inParams)
+ Function(std::string name, const std::vector>& inParams)
: name(std::move(name)), _inParams(ParamSet(inParams)) {}
virtual ~Function() {}
/// Add an input parameter. Returns the index of the parameter.
diff --git a/src/Ethereum/Signer.cpp b/src/Ethereum/Signer.cpp
index 2dd09f11b15..bbeeb7c8157 100644
--- a/src/Ethereum/Signer.cpp
+++ b/src/Ethereum/Signer.cpp
@@ -44,7 +44,7 @@ std::string Signer::signJSON(const std::string& json, const Data& key) {
}
std::tuple Signer::values(const uint256_t &chainID,
- const Data &signature) noexcept {
+ const Data& signature) noexcept {
boost::multiprecision::uint256_t r, s, v;
import_bits(r, signature.begin(), signature.begin() + 32);
import_bits(s, signature.begin() + 32, signature.begin() + 64);
@@ -62,7 +62,7 @@ std::tuple Signer::values(const uint256_t &chai
}
std::tuple
-Signer::sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data &hash) noexcept {
+Signer::sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept {
auto signature = privateKey.sign(hash, TWCurveSECP256k1);
return values(chainID, signature);
}
diff --git a/src/Ethereum/Signer.h b/src/Ethereum/Signer.h
index 50b279f5f9c..b041b64417f 100644
--- a/src/Ethereum/Signer.h
+++ b/src/Ethereum/Signer.h
@@ -46,13 +46,13 @@ class Signer {
///
/// @returns the r, s, and v values of the transaction signature
static std::tuple
- sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data &hash) noexcept;
+ sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept;
/// R, S, and V values for the given chain identifier and signature.
///
/// @returns the r, s, and v values of the transaction signature
static std::tuple values(const uint256_t &chainID,
- const Data &signature) noexcept;
+ const Data& signature) noexcept;
protected:
/// Computes the transaction hash.
diff --git a/src/Ethereum/Transaction.h b/src/Ethereum/Transaction.h
index e16d5d8f17c..d5af92b3ed8 100644
--- a/src/Ethereum/Transaction.h
+++ b/src/Ethereum/Transaction.h
@@ -26,7 +26,7 @@ class Transaction {
uint256_t r = uint256_t();
uint256_t s = uint256_t();
- Transaction(uint256_t nonce, uint256_t gasPrice, uint256_t gasLimit, Data to, uint256_t amount,
+ Transaction(uint256_t nonce, uint256_t gasPrice, uint256_t gasLimit, const Data& to, uint256_t amount,
Data payload)
: nonce(std::move(nonce))
, gasPrice(std::move(gasPrice))
diff --git a/src/FIO/Action.h b/src/FIO/Action.h
index b88931a71f6..c79ef65a500 100644
--- a/src/FIO/Action.h
+++ b/src/FIO/Action.h
@@ -92,7 +92,7 @@ class AddPubAddressData {
std::string tpid;
std::string actor;
- AddPubAddressData(const std::string& fioAddress, std::vector addresses,
+ AddPubAddressData(const std::string& fioAddress, const std::vector& addresses,
uint64_t fee, const std::string& tpid, const std::string& actor) :
fioAddress(fioAddress), addresses(addresses),
fee(fee), tpid(tpid), actor(actor) {}
diff --git a/src/HDWallet.cpp b/src/HDWallet.cpp
index 9d13c0af0d6..52d2deab333 100644
--- a/src/HDWallet.cpp
+++ b/src/HDWallet.cpp
@@ -139,7 +139,7 @@ std::string HDWallet::getExtendedPublicKey(TWPurpose purpose, TWCoinType coin, T
return serialize(&node, fingerprintValue, version, true, base58Hasher(coin));
}
-std::optional HDWallet::getPublicKeyFromExtended(const std::string &extended, const DerivationPath& path) {
+std::optional HDWallet::getPublicKeyFromExtended(const std::string& extended, const DerivationPath& path) {
const auto coin = path.coin();
const auto curve = TW::curve(coin);
const auto hasher = TW::base58Hasher(coin);
@@ -173,7 +173,7 @@ std::optional HDWallet::getPublicKeyFromExtended(const std::string &e
}
}
-std::optional HDWallet::getPrivateKeyFromExtended(const std::string &extended, const DerivationPath& path) {
+std::optional HDWallet::getPrivateKeyFromExtended(const std::string& extended, const DerivationPath& path) {
const auto coin = path.coin();
const auto curve = TW::curve(coin);
const auto hasher = TW::base58Hasher(coin);
diff --git a/src/HDWallet.h b/src/HDWallet.h
index fb2dd62e4ee..784dcbd0c34 100644
--- a/src/HDWallet.h
+++ b/src/HDWallet.h
@@ -83,10 +83,10 @@ class HDWallet {
std::string getExtendedPublicKey(TWPurpose purpose, TWCoinType coin, TWHDVersion version) const;
/// Computes the public key from an exteded public key representation.
- static std::optional getPublicKeyFromExtended(const std::string &extended, const DerivationPath& path);
+ static std::optional getPublicKeyFromExtended(const std::string& extended, const DerivationPath& path);
/// Computes the private key from an exteded private key representation.
- static std::optional getPrivateKeyFromExtended(const std::string &extended, const DerivationPath& path);
+ static std::optional getPrivateKeyFromExtended(const std::string& extended, const DerivationPath& path);
public:
// Private key type (later could be moved out of HDWallet)
diff --git a/src/Harmony/Address.h b/src/Harmony/Address.h
index 2c65defc17e..a36d8507ec1 100644
--- a/src/Harmony/Address.h
+++ b/src/Harmony/Address.h
@@ -18,12 +18,12 @@ class Address: public Bech32Address {
static const std::string hrp; // HRP_HARMONY
- static bool isValid(const std::string addr) { return Bech32Address::isValid(addr, hrp); }
+ static bool isValid(const std::string& addr) { return Bech32Address::isValid(addr, hrp); }
Address() : Bech32Address(hrp) {}
/// Initializes an address with a key hash.
- Address(Data keyHash) : Bech32Address(hrp, keyHash) {
+ Address(const Data& keyHash) : Bech32Address(hrp, keyHash) {
if (getKeyHash().size() != Address::size) {
throw std::invalid_argument("invalid address data");
}
diff --git a/src/Harmony/Signer.cpp b/src/Harmony/Signer.cpp
index a75d8110f75..0543facad72 100644
--- a/src/Harmony/Signer.cpp
+++ b/src/Harmony/Signer.cpp
@@ -13,7 +13,7 @@ using namespace TW;
using namespace TW::Harmony;
std::tuple Signer::values(const uint256_t &chainID,
- const Data &signature) noexcept {
+ const Data& signature) noexcept {
auto r = load(Data(signature.begin(), signature.begin() + 32));
auto s = load(Data(signature.begin() + 32, signature.begin() + 64));
auto v = load(Data(signature.begin() + 64, signature.begin() + 65));
@@ -22,13 +22,13 @@ std::tuple Signer::values(const uint256_t &chai
}
std::tuple
-Signer::sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data &hash) noexcept {
+Signer::sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept {
auto signature = privateKey.sign(hash, TWCurveSECP256k1);
return values(chainID, signature);
}
template
-Proto::SigningOutput Signer::prepareOutput(const Data &encoded, const T &transaction) noexcept {
+Proto::SigningOutput Signer::prepareOutput(const Data& encoded, const T &transaction) noexcept {
auto protoOutput = Proto::SigningOutput();
auto v = store(transaction.v);
@@ -322,7 +322,7 @@ Proto::SigningOutput Signer::signCollectRewards(const Proto::SigningInput &input
}
template
-void Signer::sign(const PrivateKey &privateKey, const Data &hash, T &transaction) const noexcept {
+void Signer::sign(const PrivateKey &privateKey, const Data& hash, T &transaction) const noexcept {
auto tuple = sign(chainID, privateKey, hash);
transaction.r = std::get<0>(tuple);
transaction.s = std::get<1>(tuple);
diff --git a/src/Harmony/Signer.h b/src/Harmony/Signer.h
index a7aa10d5cbc..70d048838b9 100644
--- a/src/Harmony/Signer.h
+++ b/src/Harmony/Signer.h
@@ -52,23 +52,23 @@ class Signer {
explicit Signer(uint256_t chainID) : chainID(std::move(chainID)) {}
template
- static Proto::SigningOutput prepareOutput(const Data &encoded, const T &transaction) noexcept;
+ static Proto::SigningOutput prepareOutput(const Data& encoded, const T &transaction) noexcept;
/// Signs the given transaction.
template
- void sign(const PrivateKey &privateKey, const Data &hash, T &transaction) const noexcept;
+ void sign(const PrivateKey &privateKey, const Data& hash, T &transaction) const noexcept;
/// Signs a hash with the given private key for the given chain identifier.
///
/// @returns the r, s, and v values of the transaction signature
static std::tuple
- sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data &hash) noexcept;
+ sign(const uint256_t &chainID, const PrivateKey &privateKey, const Data& hash) noexcept;
/// R, S, and V values for the given chain identifier and signature.
///
/// @returns the r, s, and v values of the transaction signature
static std::tuple values(const uint256_t &chainID,
- const Data &signature) noexcept;
+ const Data& signature) noexcept;
std::string txnAsRLPHex(Transaction &transaction) const noexcept;
diff --git a/src/Harmony/Transaction.h b/src/Harmony/Transaction.h
index c06e4359513..ac43aa253f0 100644
--- a/src/Harmony/Transaction.h
+++ b/src/Harmony/Transaction.h
@@ -32,7 +32,7 @@ class Transaction {
uint256_t s = uint256_t();
Transaction(uint256_t nonce, uint256_t gasPrice, uint256_t gasLimit, uint256_t fromShardID,
- uint256_t toShardID, Address to, uint256_t amount, Data payload)
+ uint256_t toShardID, Address to, uint256_t amount, const Data& payload)
: nonce(std::move(nonce))
, gasPrice(std::move(gasPrice))
, gasLimit(std::move(gasLimit))
diff --git a/src/IoTeX/Address.h b/src/IoTeX/Address.h
index f34c353e704..a76743a4250 100644
--- a/src/IoTeX/Address.h
+++ b/src/IoTeX/Address.h
@@ -18,12 +18,12 @@ class Address: public Bech32Address {
static const std::string hrp; // HRP_IOTEX
- static bool isValid(const std::string addr) { return Bech32Address::isValid(addr, hrp); }
+ static bool isValid(const std::string& addr) { return Bech32Address::isValid(addr, hrp); }
Address() : Bech32Address(hrp) {}
/// Initializes an address with a key hash.
- Address(Data keyHash) : Bech32Address(hrp, keyHash) {
+ Address(const Data& keyHash) : Bech32Address(hrp, keyHash) {
if (getKeyHash().size() != Address::size) {
throw std::invalid_argument("invalid address data");
}
diff --git a/src/Keystore/EncryptionParameters.cpp b/src/Keystore/EncryptionParameters.cpp
index 91540ad39f2..279cc76761c 100644
--- a/src/Keystore/EncryptionParameters.cpp
+++ b/src/Keystore/EncryptionParameters.cpp
@@ -20,7 +20,7 @@ using namespace TW;
using namespace TW::Keystore;
template
-static Data computeMAC(Iter begin, Iter end, Data key) {
+static Data computeMAC(Iter begin, Iter end, const Data& key) {
auto data = Data();
data.reserve((end - begin) + key.size());
data.insert(data.end(), begin, end);
@@ -28,7 +28,7 @@ static Data computeMAC(Iter begin, Iter end, Data key) {
return Hash::keccak256(data);
}
-EncryptionParameters::EncryptionParameters(const Data& password, Data data) : mac() {
+EncryptionParameters::EncryptionParameters(const Data& password, const Data& data) : mac() {
auto scryptParams = boost::get(kdfParams);
auto derivedKey = Data(scryptParams.desiredKeyLength);
scrypt(reinterpret_cast(password.data()), password.size(), scryptParams.salt.data(),
diff --git a/src/Keystore/EncryptionParameters.h b/src/Keystore/EncryptionParameters.h
index eec3b44a9f3..e1e68933977 100644
--- a/src/Keystore/EncryptionParameters.h
+++ b/src/Keystore/EncryptionParameters.h
@@ -46,7 +46,7 @@ struct EncryptionParameters {
EncryptionParameters() = default;
/// Initializes `EncryptionParameters` with standard values.
- EncryptionParameters(Data encrypted, AESParameters cipherParams, boost::variant kdfParams, Data mac)
+ EncryptionParameters(const Data& encrypted, AESParameters cipherParams, boost::variant kdfParams, const Data& mac)
: encrypted(std::move(encrypted))
, cipherParams(std::move(cipherParams))
, kdfParams(std::move(kdfParams))
@@ -54,7 +54,7 @@ struct EncryptionParameters {
/// Initializes `EncryptionParameters` by encrypting data with a password
/// using standard values.
- EncryptionParameters(const Data& password, Data data);
+ EncryptionParameters(const Data& password, const Data& data);
/// Initializes `EncryptionParameters` with a JSON object.
EncryptionParameters(const nlohmann::json& json);
diff --git a/src/Keystore/PBKDF2Parameters.h b/src/Keystore/PBKDF2Parameters.h
index b99ab79d786..0d473b5615b 100644
--- a/src/Keystore/PBKDF2Parameters.h
+++ b/src/Keystore/PBKDF2Parameters.h
@@ -35,7 +35,7 @@ struct PBKDF2Parameters {
PBKDF2Parameters();
/// Initializes `PBKDF2Parameters` with all values.
- PBKDF2Parameters(Data salt, uint32_t iterations, std::size_t desiredKeyLength)
+ PBKDF2Parameters(const Data& salt, uint32_t iterations, std::size_t desiredKeyLength)
: salt(std::move(salt)), desiredKeyLength(desiredKeyLength), iterations(iterations) {}
/// Initializes `PBKDF2Parameters` with a JSON object.
diff --git a/src/Keystore/ScryptParameters.h b/src/Keystore/ScryptParameters.h
index 460dc4b8e64..10e7c019bd6 100644
--- a/src/Keystore/ScryptParameters.h
+++ b/src/Keystore/ScryptParameters.h
@@ -66,7 +66,7 @@ struct ScryptParameters {
/// Initializes `ScryptParameters` with all values.
///
/// @throws ScryptValidationError if the parameters are invalid.
- ScryptParameters(Data salt, uint32_t n, uint32_t r, uint32_t p, std::size_t desiredKeyLength)
+ ScryptParameters(const Data& salt, uint32_t n, uint32_t r, uint32_t p, std::size_t desiredKeyLength)
: salt(std::move(salt)), desiredKeyLength(desiredKeyLength), n(n), p(p), r(r) {
auto error = validate();
if (error) {
diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp
index b59f6de733b..bba73ee4907 100644
--- a/src/Keystore/StoredKey.cpp
+++ b/src/Keystore/StoredKey.cpp
@@ -78,7 +78,7 @@ StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& na
return key;
}
-StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, Data data)
+StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data)
: type(type), id(), name(std::move(name)), payload(password, data), accounts() {
boost::uuids::random_generator gen;
id = boost::lexical_cast(gen());
diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h
index 00e29ab969d..475271e9283 100644
--- a/src/Keystore/StoredKey.h
+++ b/src/Keystore/StoredKey.h
@@ -119,7 +119,7 @@ class StoredKey {
/// Initializes a `StoredKey` with a type, an encryption password, and unencrypted data.
/// This contstructor will encrypt the provided data with default encryption
/// parameters.
- StoredKey(StoredKeyType type, std::string name, const Data& password, Data data);
+ StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data);
};
} // namespace TW::Keystore
diff --git a/src/NEAR/Serialization.cpp b/src/NEAR/Serialization.cpp
index 9e69a1951cf..4b6e24826de 100644
--- a/src/NEAR/Serialization.cpp
+++ b/src/NEAR/Serialization.cpp
@@ -30,7 +30,7 @@ static void writeU128(Data& data, const std::string& numberData) {
data.insert(std::end(data), std::begin(numberData), std::end(numberData));
}
-template static void writeRawBuffer(Data &data, const T& buf) {
+template static void writeRawBuffer(Data& data, const T& buf) {
data.insert(std::end(data), std::begin(buf), std::end(buf));
}
diff --git a/src/NEO/Address.h b/src/NEO/Address.h
index bd2afc2a44a..d3d78ab7088 100644
--- a/src/NEO/Address.h
+++ b/src/NEO/Address.h
@@ -23,13 +23,13 @@ class Address : public TW::Base58Address {
static const byte version = 0x17;
/// Determines whether a string makes a valid NEO address.
- static bool isValid(const std::string &string);
+ static bool isValid(const std::string& string);
/// Initializes a NEO address with a string representation.
- explicit Address(const std::string &string) : TW::Base58Address(string) {}
+ explicit Address(const std::string& string) : TW::Base58Address(string) {}
/// Initializes a NEO address with a collection of bytes.
- explicit Address(const Data &data) : TW::Base58Address(data) {}
+ explicit Address(const Data& data) : TW::Base58Address(data) {}
/// Initializes an address with a collection of public key.
explicit Address(uint8_t m, const std::vector& publicKeys);
@@ -40,7 +40,7 @@ class Address : public TW::Base58Address {
/// Initializes a NEO address without a public key.
explicit Address();
- Data toScriptHash(const Data &data) const;
+ Data toScriptHash(const Data& data) const;
Data toScriptHash() const;
};
diff --git a/src/NEO/CoinReference.h b/src/NEO/CoinReference.h
index 2b040923ede..d21b8865630 100644
--- a/src/NEO/CoinReference.h
+++ b/src/NEO/CoinReference.h
@@ -29,7 +29,7 @@ class CoinReference : public Serializable {
return Hash::sha256Size + prevIndexSize;
}
- void deserialize(const Data &data, int initial_pos = 0) override {
+ void deserialize(const Data& data, int initial_pos = 0) override {
prevHash = load(readBytes(data, Hash::sha256Size, initial_pos));
prevIndex = decode16LE(data.data() + initial_pos + Hash::sha256Size);
}
diff --git a/src/NEO/ISerializable.h b/src/NEO/ISerializable.h
index 3106328cdc3..64e30ee0754 100644
--- a/src/NEO/ISerializable.h
+++ b/src/NEO/ISerializable.h
@@ -17,7 +17,7 @@ class ISerializable {
virtual ~ISerializable() {}
virtual int64_t size() const = 0;
virtual Data serialize() const = 0;
- virtual void deserialize(const Data &data, int initial_pos = 0) = 0;
+ virtual void deserialize(const Data& data, int initial_pos = 0) = 0;
};
} // namespace TW::NEO
diff --git a/src/NEO/MinerTransaction.h b/src/NEO/MinerTransaction.h
index 01e3235fb06..ca73b306958 100644
--- a/src/NEO/MinerTransaction.h
+++ b/src/NEO/MinerTransaction.h
@@ -15,7 +15,7 @@ class MinerTransaction : public Transaction {
public:
uint32_t nonce;
- virtual int deserializeExclusiveData(const Data &data, int initial_pos = 0) {
+ virtual int deserializeExclusiveData(const Data& data, int initial_pos = 0) {
nonce = decode32LE(data.data() + initial_pos);
return initial_pos + 4;
}
diff --git a/src/NEO/ReadData.cpp b/src/NEO/ReadData.cpp
index e419f944319..f7444e6af3c 100644
--- a/src/NEO/ReadData.cpp
+++ b/src/NEO/ReadData.cpp
@@ -8,14 +8,14 @@
#include "ReadData.h"
-TW::Data TW::readBytes(const TW::Data &from, int max, int initial_pos) {
+TW::Data TW::readBytes(const TW::Data& from, int max, int initial_pos) {
if (from.size() - initial_pos < max) {
throw std::invalid_argument("Data::Cannot read enough bytes!");
}
return TW::Data(from.begin() + initial_pos, from.begin() + initial_pos + max);
}
-TW::Data TW::readVarBytes(const Data &from, int initial_pos, uint32_t* dataRead) {
+TW::Data TW::readVarBytes(const Data& from, int initial_pos, uint32_t* dataRead) {
uint64_t size = readVar(from, initial_pos);
auto shift = varIntSize(size);
if (dataRead) {
@@ -24,7 +24,7 @@ TW::Data TW::readVarBytes(const Data &from, int initial_pos, uint32_t* dataRead)
return readBytes(from, int(size), initial_pos + int(shift));
}
-template<> uint64_t TW::readVar(const TW::Data &from, int initial_pos, const uint64_t &max) {
+template<> uint64_t TW::readVar(const TW::Data& from, int initial_pos, const uint64_t &max) {
byte fb = from[initial_pos];
uint64_t value;
if (fb == 0xFD) {
@@ -43,11 +43,11 @@ template<> uint64_t TW::readVar(const TW::Data &from, int initial_pos, const uin
return value;
}
-template<> int64_t TW::readVar(const TW::Data &from, int initial_pos, const int64_t &max) {
+template<> int64_t TW::readVar(const TW::Data& from, int initial_pos, const int64_t &max) {
return (int64_t) readVar(from, initial_pos, uint64_t(max));
}
-TW::Data TW::writeVarBytes(const Data &from, int initial_pos) {
+TW::Data TW::writeVarBytes(const Data& from, int initial_pos) {
Data resp;
encodeVarInt(uint64_t(from.size() - initial_pos), resp);
resp.insert(resp.end(), from.begin() + initial_pos, from.end());
diff --git a/src/NEO/ReadData.h b/src/NEO/ReadData.h
index 80b86693f02..7f7e0a0b4c7 100644
--- a/src/NEO/ReadData.h
+++ b/src/NEO/ReadData.h
@@ -13,14 +13,14 @@
namespace TW {
-Data readBytes(const Data &from, int max, int initial_pos = 0);
-Data readVarBytes(const Data &from, int initial_pos = 0, uint32_t* dataRead = nullptr);
+Data readBytes(const Data& from, int max, int initial_pos = 0);
+Data readVarBytes(const Data& from, int initial_pos = 0, uint32_t* dataRead = nullptr);
-template T readVar(const TW::Data &from, int initial_pos = 0, const T &max = INT_MAX);
-template<> int64_t readVar(const TW::Data &from, int initial_pos, const int64_t &max);
-template<> uint64_t readVar(const TW::Data &from, int initial_pos, const uint64_t &max);
+template T readVar(const TW::Data& from, int initial_pos = 0, const T &max = INT_MAX);
+template<> int64_t readVar(const TW::Data& from, int initial_pos, const int64_t &max);
+template<> uint64_t readVar(const TW::Data& from, int initial_pos, const uint64_t &max);
-Data writeVarBytes(const Data &from, int initial_pos = 0);
+Data writeVarBytes(const Data& from, int initial_pos = 0);
template
static std::vector concat(const std::vector& v1, const std::vector& v2) {
diff --git a/src/NEO/Script.cpp b/src/NEO/Script.cpp
index 6e89610335b..a168dfe74bb 100644
--- a/src/NEO/Script.cpp
+++ b/src/NEO/Script.cpp
@@ -8,7 +8,7 @@
namespace TW::NEO {
-Data Script::CreateSignatureRedeemScript(Data publicKey) {
+Data Script::CreateSignatureRedeemScript(const Data& publicKey) {
Data result;
result.push_back((byte)PUSHBYTES21);
result.insert(result.end(), publicKey.begin(), publicKey.end());
@@ -16,7 +16,7 @@ Data Script::CreateSignatureRedeemScript(Data publicKey) {
return result;
}
-Data Script::CreateInvocationScript(Data signature) {
+Data Script::CreateInvocationScript(const Data& signature) {
Data result;
result.push_back((byte)PUSHBYTES40);
result.insert(result.end(), signature.begin(), signature.end());
diff --git a/src/NEO/Script.h b/src/NEO/Script.h
index 5cbd4a59d82..64d47982754 100644
--- a/src/NEO/Script.h
+++ b/src/NEO/Script.h
@@ -11,8 +11,8 @@ namespace TW::NEO {
class Script {
public:
- static Data CreateSignatureRedeemScript(Data publicKey);
- static Data CreateInvocationScript(Data signature);
+ static Data CreateSignatureRedeemScript(const Data& publicKey);
+ static Data CreateInvocationScript(const Data& signature);
};
} // namespace TW::NEO
diff --git a/src/NEO/Serializable.h b/src/NEO/Serializable.h
index 423253b861b..51ec20edf73 100644
--- a/src/NEO/Serializable.h
+++ b/src/NEO/Serializable.h
@@ -44,12 +44,9 @@ class Serializable : public ISerializable {
}
template
- static inline int deserialize(std::vector &resp, const Data &data, int initial_pos = 0) {
+ static inline int deserialize(std::vector &resp, const Data& data, int initial_pos = 0) {
uint64_t size = readVar(data, initial_pos, INT_MAX);
- if (size < 0) {
- throw std::invalid_argument("Serializable::deserialize ArgumentOutOfRangeException");
- }
-
+ // assert(size >= 0);
initial_pos += varIntSize(size);
for (uint64_t i = 0; i < size; ++i) {
T value;
diff --git a/src/NEO/Transaction.cpp b/src/NEO/Transaction.cpp
index 897ec967714..6c352b36894 100644
--- a/src/NEO/Transaction.cpp
+++ b/src/NEO/Transaction.cpp
@@ -21,7 +21,7 @@ int64_t Transaction::size() const {
return serialize().size();
}
-void Transaction::deserialize(const Data &data, int initial_pos) {
+void Transaction::deserialize(const Data& data, int initial_pos) {
type = (TransactionType) data[initial_pos++];
version = data[initial_pos++];
initial_pos = deserializeExclusiveData(data, initial_pos);
@@ -33,7 +33,7 @@ void Transaction::deserialize(const Data &data, int initial_pos) {
Serializable::deserialize(outputs, data, initial_pos);
}
-Transaction * Transaction::deserializeFrom(const Data &data, int initial_pos) {
+Transaction * Transaction::deserializeFrom(const Data& data, int initial_pos) {
Transaction * resp = nullptr;
switch ((TransactionType) data[initial_pos]) {
case TransactionType::TT_MinerTransaction:
diff --git a/src/NEO/Transaction.h b/src/NEO/Transaction.h
index 5fb387f5f47..50a311e3d9a 100644
--- a/src/NEO/Transaction.h
+++ b/src/NEO/Transaction.h
@@ -28,18 +28,18 @@ class Transaction : public Serializable {
virtual ~Transaction() {}
int64_t size() const override;
- void deserialize(const Data &data, int initial_pos = 0) override;
+ void deserialize(const Data& data, int initial_pos = 0) override;
Data serialize() const override;
bool operator==(const Transaction &other) const;
- virtual int deserializeExclusiveData(const Data &data, int initial_pos = 0) { return initial_pos; }
+ virtual int deserializeExclusiveData(const Data& data, int initial_pos = 0) { return initial_pos; }
virtual Data serializeExclusiveData() const { return Data(); }
Data getHash() const;
uint256_t getHashUInt256() const;
- static Transaction * deserializeFrom(const Data &data, int initial_pos = 0);
+ static Transaction * deserializeFrom(const Data& data, int initial_pos = 0);
};
} // namespace TW::NEO
diff --git a/src/NEO/TransactionAttribute.h b/src/NEO/TransactionAttribute.h
index 3978484a614..7a5187e65c0 100644
--- a/src/NEO/TransactionAttribute.h
+++ b/src/NEO/TransactionAttribute.h
@@ -24,7 +24,7 @@ class TransactionAttribute : public Serializable {
return 1 + data.size();
}
- void deserialize(const Data &data, int initial_pos = 0) override {
+ void deserialize(const Data& data, int initial_pos = 0) override {
if (data.size() < initial_pos + 1) {
throw std::invalid_argument("Invalid data for deserialization");
}
diff --git a/src/NEO/TransactionOutput.h b/src/NEO/TransactionOutput.h
index 85d05d7d297..1c27d3f3781 100644
--- a/src/NEO/TransactionOutput.h
+++ b/src/NEO/TransactionOutput.h
@@ -31,7 +31,7 @@ class TransactionOutput : public Serializable {
return store(assetId).size() + valueSize + store(scriptHash).size();
}
- void deserialize(const Data &data, int initial_pos = 0) override {
+ void deserialize(const Data& data, int initial_pos = 0) override {
assetId = load(readBytes(data, assetIdSize, initial_pos));
value = decode64LE(data.data() + initial_pos + assetIdSize);
scriptHash = load(readBytes(data, scriptHashSize, initial_pos + assetIdSize + valueSize));
diff --git a/src/NEO/Witness.h b/src/NEO/Witness.h
index 808037b7dcf..6f0e7c9d139 100644
--- a/src/NEO/Witness.h
+++ b/src/NEO/Witness.h
@@ -23,7 +23,7 @@ class Witness : public Serializable {
return invocationScript.size() + verificationScript.size();
}
- void deserialize(const Data &data, int initial_pos = 0) override {
+ void deserialize(const Data& data, int initial_pos = 0) override {
uint32_t size;
invocationScript = readVarBytes(data, initial_pos, &size);
verificationScript = readVarBytes(data, initial_pos + size);
diff --git a/src/Nebulas/Address.cpp b/src/Nebulas/Address.cpp
index acdc595d17d..bbc81447f43 100644
--- a/src/Nebulas/Address.cpp
+++ b/src/Nebulas/Address.cpp
@@ -11,7 +11,7 @@
using namespace TW::Nebulas;
-bool Address::isValid(const std::string &string) {
+bool Address::isValid(const std::string& string) {
auto data = Base58::bitcoin.decode(string);
if (data.size() != (size_t)Address::size) {
return false;
@@ -30,7 +30,7 @@ bool Address::isValid(const std::string &string) {
return ::memcmp(dataSha3.data(), checksum.data(), 4) == 0;
}
-Address::Address(const std::string &string) {
+Address::Address(const std::string& string) {
if (!isValid(string)) {
throw std::invalid_argument("Invalid address string");
}
@@ -39,7 +39,7 @@ Address::Address(const std::string &string) {
std::copy(data.begin(), data.end(), bytes.begin());
}
-Address::Address(const Data &data) {
+Address::Address(const Data& data) {
if (!Base58Address::isValid(data)) {
throw std::invalid_argument("Invalid address data");
}
diff --git a/src/Solana/Address.cpp b/src/Solana/Address.cpp
index a45bcc3ba94..93460cdf9ea 100644
--- a/src/Solana/Address.cpp
+++ b/src/Solana/Address.cpp
@@ -41,8 +41,8 @@ Data Address::vector() const {
return vec;
}
-Address addressFromValidatorSeed(Address& fromAddress, Address& validatorAddress,
- Address& programId) {
+Address addressFromValidatorSeed(const Address& fromAddress, const Address& validatorAddress,
+ const Address& programId) {
Data extended = fromAddress.vector();
std::string seed = validatorAddress.string();
Data vecSeed(seed.begin(), seed.end());
diff --git a/src/Solana/Address.h b/src/Solana/Address.h
index fda8c909415..8bdc71ec85e 100644
--- a/src/Solana/Address.h
+++ b/src/Solana/Address.h
@@ -40,6 +40,6 @@ class Address : public Base58Address<32> {
} // namespace TW::Solana
-TW::Solana::Address addressFromValidatorSeed(TW::Solana::Address& fromAddress,
- TW::Solana::Address& validatorAddress,
- TW::Solana::Address& programId);
+TW::Solana::Address addressFromValidatorSeed(const TW::Solana::Address& fromAddress,
+ const TW::Solana::Address& validatorAddress,
+ const TW::Solana::Address& programId);
diff --git a/src/Solana/Transaction.h b/src/Solana/Transaction.h
index 12ffdbe9c6f..b64cce5335d 100644
--- a/src/Solana/Transaction.h
+++ b/src/Solana/Transaction.h
@@ -54,7 +54,7 @@ struct CompiledInstruction {
// The program input data
Data data;
- CompiledInstruction(uint8_t programIdIndex, Data accounts, Data data)
+ CompiledInstruction(uint8_t programIdIndex, const Data& accounts, const Data& data)
: programIdIndex(programIdIndex), accounts(accounts), data(data) {}
// This constructor creates a default System Transfer instruction
diff --git a/src/TON/Cell.cpp b/src/TON/Cell.cpp
index af70dbfb3c2..be52dc56130 100644
--- a/src/TON/Cell.cpp
+++ b/src/TON/Cell.cpp
@@ -41,7 +41,7 @@ Slice Slice::createFromHex(std::string const& dataStr) {
}
Slice Slice::createFromBits(const Data& data, size_t sizeBits) {
- if (sizeBits <= 0) {
+ if (sizeBits == 0) {
throw std::runtime_error("empty data");
}
Slice s;
diff --git a/src/Tezos/Signer.cpp b/src/Tezos/Signer.cpp
index 0c4aae8ba1f..b0732fd78c9 100644
--- a/src/Tezos/Signer.cpp
+++ b/src/Tezos/Signer.cpp
@@ -45,7 +45,7 @@ Data Signer::signOperationList(const PrivateKey& privateKey, const OperationList
return signData(privateKey, forged);
}
-Data Signer::signData(const PrivateKey& privateKey, Data data) {
+Data Signer::signData(const PrivateKey& privateKey, const Data& data) {
Data watermarkedData = Data();
watermarkedData.push_back(0x03);
append(watermarkedData, data);
diff --git a/src/Tezos/Signer.h b/src/Tezos/Signer.h
index d6b88fcc6b5..798d703ab21 100644
--- a/src/Tezos/Signer.h
+++ b/src/Tezos/Signer.h
@@ -25,7 +25,7 @@ class Signer {
public:
/// Signs the given transaction.
Data signOperationList(const PrivateKey& privateKey, const OperationList& operationList);
- Data signData(const PrivateKey& privateKey, Data data);
+ Data signData(const PrivateKey& privateKey, const Data& data);
};
} // namespace TW::Tezos
diff --git a/src/Theta/Transaction.h b/src/Theta/Transaction.h
index fccc7e5439d..735c21ab1a8 100644
--- a/src/Theta/Transaction.h
+++ b/src/Theta/Transaction.h
@@ -24,7 +24,7 @@ class TxInput {
TxInput(Ethereum::Address address, Coins coins, uint64_t sequence)
: address(std::move(address)), coins(std::move(coins)), sequence(sequence) {}
- TxInput(Ethereum::Address address, Coins coins, uint64_t sequence, Data signature)
+ TxInput(Ethereum::Address address, Coins coins, uint64_t sequence, const Data& signature)
: address(std::move(address)), coins(std::move(coins)), sequence(sequence), signature(std::move(signature)) {}
};
diff --git a/src/VeChain/Clause.h b/src/VeChain/Clause.h
index eb8d1e5dd06..9bbb1bc6435 100644
--- a/src/VeChain/Clause.h
+++ b/src/VeChain/Clause.h
@@ -19,7 +19,7 @@ class Clause {
uint256_t value;
Data data;
- Clause(Ethereum::Address to, uint256_t value, Data data = {})
+ Clause(Ethereum::Address to, uint256_t value, const Data& data = {})
: to(std::move(to)), value(std::move(value)), data(std::move(data)) {}
/// Decodes from a proto representation.
diff --git a/src/Waves/Address.cpp b/src/Waves/Address.cpp
index 7b42ff51dc0..be51732e937 100644
--- a/src/Waves/Address.cpp
+++ b/src/Waves/Address.cpp
@@ -22,7 +22,7 @@ Data Address::secureHash(const T &data) {
return Hash::keccak256(Hash::blake2b(data, 32));
}
-bool Address::isValid(const Data &decoded) {
+bool Address::isValid(const Data& decoded) {
if (decoded.size() != Address::size) {
return false;
}
@@ -44,12 +44,12 @@ bool Address::isValid(const Data &decoded) {
return std::memcmp(data_checksum.data(), calculated_checksum.data(), 4) == 0;
}
-bool Address::isValid(const std::string &string) {
+bool Address::isValid(const std::string& string) {
const auto decoded = Base58::bitcoin.decode(string);
return isValid(decoded);
}
-Address::Address(const std::string &string) {
+Address::Address(const std::string& string) {
const auto decoded = Base58::bitcoin.decode(string);
if (!isValid(string)) {
throw std::invalid_argument("Invalid address key data");
@@ -57,7 +57,7 @@ Address::Address(const std::string &string) {
std::copy(decoded.begin(), decoded.end(), bytes.begin());
}
-Address::Address(const Data &data) {
+Address::Address(const Data& data) {
if (!isValid(data)) {
throw std::invalid_argument("Invalid address data");
}
diff --git a/src/Waves/Address.h b/src/Waves/Address.h
index 81950ee6b93..df518415334 100644
--- a/src/Waves/Address.h
+++ b/src/Waves/Address.h
@@ -17,9 +17,6 @@ namespace TW::Waves {
class Address : public Base58Address<26> {
public:
- /// Number of bytes in an address.
- static const size_t size = 26;
-
/// Address version.
static const signed char v1 = 0x01;
@@ -29,20 +26,16 @@ class Address : public Base58Address<26> {
template
static Data secureHash(const T &data);
- /// Address data consisting of a version and network bytes followed by the public key
- /// hash and the checksum.
- std::array bytes;
-
/// Determines whether a string makes a valid address.
- static bool isValid(const std::string &string);
+ static bool isValid(const std::string& string);
- static bool isValid(const Data &data);
+ static bool isValid(const Data& data);
/// Initializes a address with a string representation.
- explicit Address(const std::string &string);
+ explicit Address(const std::string& string);
/// Initializes a address with a collection of bytes.
- explicit Address(const Data &data);
+ explicit Address(const Data& data);
/// Initializes a address with a public key and a prefix.
explicit Address(const PublicKey &publicKey);
diff --git a/src/Waves/Transaction.cpp b/src/Waves/Transaction.cpp
index 277c1540bc3..ee9d2a5af44 100644
--- a/src/Waves/Transaction.cpp
+++ b/src/Waves/Transaction.cpp
@@ -17,7 +17,7 @@ using json = nlohmann::json;
const std::string Transaction::WAVES = "WAVES";
-Data serializeTransfer(int64_t amount, std::string asset, int64_t fee, std::string fee_asset, Address to, Data attachment, int64_t timestamp, Data pub_key) {
+Data serializeTransfer(int64_t amount, std::string asset, int64_t fee, std::string fee_asset, Address to, const Data& attachment, int64_t timestamp, const Data& pub_key) {
auto data = Data();
if (asset.empty()) {
asset = Transaction::WAVES;
@@ -50,7 +50,7 @@ Data serializeTransfer(int64_t amount, std::string asset, int64_t fee, std::stri
return data;
}
-Data serializeLease(int64_t amount, int64_t fee, Address to, int64_t timestamp, Data pub_key) {
+Data serializeLease(int64_t amount, int64_t fee, Address to, int64_t timestamp, const Data& pub_key) {
auto data = Data();
data.resize(2);
data[0] = static_cast(TransactionType::lease);
@@ -65,7 +65,7 @@ Data serializeLease(int64_t amount, int64_t fee, Address to, int64_t timestamp,
return data;
}
-Data serializeCancelLease(Data leaseId, int64_t fee, int64_t timestamp, Data pub_key) {
+Data serializeCancelLease(const Data& leaseId, int64_t fee, int64_t timestamp, const Data& pub_key) {
auto data = Data();
data.resize(2);
data[0] = static_cast(TransactionType::cancelLease);
@@ -79,7 +79,7 @@ Data serializeCancelLease(Data leaseId, int64_t fee, int64_t timestamp, Data pub
return data;
}
-json jsonTransfer(Data signature, int64_t amount, const std::string &asset, int64_t fee, const std::string &fee_asset, Address to, Data attachment, int64_t timestamp, Data pub_key) {
+json jsonTransfer(const Data& signature, int64_t amount, const std::string& asset, int64_t fee, const std::string& fee_asset, Address to, const Data& attachment, int64_t timestamp, const Data& pub_key) {
json jsonTx;
jsonTx["type"] = TransactionType::transfer;
@@ -101,7 +101,7 @@ json jsonTransfer(Data signature, int64_t amount, const std::string &asset, int6
return jsonTx;
}
-json jsonLease(Data signature, int64_t amount, int64_t fee, Address to, int64_t timestamp, Data pub_key) {
+json jsonLease(const Data& signature, int64_t amount, int64_t fee, Address to, int64_t timestamp, const Data& pub_key) {
json jsonTx;
jsonTx["type"] = TransactionType::lease;
@@ -116,7 +116,7 @@ json jsonLease(Data signature, int64_t amount, int64_t fee, Address to, int64_t
return jsonTx;
}
-json jsonCancelLease(Data signature, Data leaseId, int64_t fee, int64_t timestamp, Data pub_key) {
+json jsonCancelLease(const Data& signature, const Data& leaseId, int64_t fee, int64_t timestamp, const Data& pub_key) {
json jsonTx;
jsonTx["type"] = TransactionType::cancelLease;
@@ -162,7 +162,7 @@ Data Transaction::serializeToSign() const {
-json Transaction::buildJson(Data signature) const {
+json Transaction::buildJson(const Data& signature) const {
if (input.has_transfer_message()) {
auto message = input.transfer_message();
auto attachment = Data(message.attachment().begin(), message.attachment().end());
diff --git a/src/Waves/Transaction.h b/src/Waves/Transaction.h
index 130f44ba095..b22fd54a030 100644
--- a/src/Waves/Transaction.h
+++ b/src/Waves/Transaction.h
@@ -29,7 +29,7 @@ class Transaction {
public:
Data serializeToSign() const;
- nlohmann::json buildJson(Data signature) const;
+ nlohmann::json buildJson(const Data& signature) const;
};
} // namespace TW::Waves
diff --git a/src/XXHash64.h b/src/XXHash64.h
index 34122ebc85e..6147ff42759 100644
--- a/src/XXHash64.h
+++ b/src/XXHash64.h
@@ -33,6 +33,7 @@ class XXHash64
state[1] = seed + Prime2;
state[2] = seed;
state[3] = seed - Prime1;
+ buffer[0] = 0;
bufferSize = 0;
totalLength = 0;
}
diff --git a/src/Zilliqa/Address.h b/src/Zilliqa/Address.h
index 9aa09804f59..be7a7ef234f 100644
--- a/src/Zilliqa/Address.h
+++ b/src/Zilliqa/Address.h
@@ -18,12 +18,12 @@ class Address : public Bech32Address {
public:
static const std::string hrp; // HRP_ZILLIQA
- static bool isValid(const std::string addr) { return Bech32Address::isValid(addr, hrp); }
+ static bool isValid(const std::string& addr) { return Bech32Address::isValid(addr, hrp); }
Address() : Bech32Address(hrp) {}
/// Initializes an address with a key hash.
- Address(Data keyHash) : Bech32Address(hrp, keyHash) {}
+ Address(const Data& keyHash) : Bech32Address(hrp, keyHash) {}
/// Initializes an address with a public key.
Address(const PublicKey& publicKey) : Bech32Address(hrp, HASHER_SHA2, publicKey) {}
diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp
index fcd2587ddf2..d2c028ed584 100644
--- a/src/interface/TWAnyAddress.cpp
+++ b/src/interface/TWAnyAddress.cpp
@@ -36,13 +36,13 @@ bool TWAnyAddressEqual(struct TWAnyAddress* _Nonnull lhs, struct TWAnyAddress* _
}
bool TWAnyAddressIsValid(TWString* _Nonnull string, enum TWCoinType coin) {
- auto& address = *reinterpret_cast(string);
+ const auto& address = *reinterpret_cast(string);
return TW::validateAddress(coin, address);
}
struct TWAnyAddress* _Nullable TWAnyAddressCreateWithString(TWString* _Nonnull string,
enum TWCoinType coin) {
- auto& address = *reinterpret_cast(string);
+ const auto& address = *reinterpret_cast(string);
auto normalized = TW::normalizeAddress(coin, address);
if (normalized.empty()) { return nullptr; }
return new TWAnyAddress{TWStringCreateWithUTF8Bytes(normalized.c_str()), coin};
diff --git a/src/interface/TWBase58.cpp b/src/interface/TWBase58.cpp
index ee38331260e..923b8a33bf0 100644
--- a/src/interface/TWBase58.cpp
+++ b/src/interface/TWBase58.cpp
@@ -13,7 +13,7 @@
using namespace TW;
TWString *_Nonnull TWBase58Encode(TWData *_Nonnull data) {
- auto& d = *reinterpret_cast(data);
+ const auto& d = *reinterpret_cast(data);
const auto str = Base58::bitcoin.encodeCheck(d);
return TWStringCreateWithUTF8Bytes(str.c_str());
}
diff --git a/src/interface/TWBitcoinAddress.cpp b/src/interface/TWBitcoinAddress.cpp
index b18e840364d..8df8de2a37f 100644
--- a/src/interface/TWBitcoinAddress.cpp
+++ b/src/interface/TWBitcoinAddress.cpp
@@ -38,7 +38,7 @@ struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithString(TWString *_N
}
struct TWBitcoinAddress *_Nullable TWBitcoinAddressCreateWithData(TWData *_Nonnull data) {
- auto& d = *reinterpret_cast(data);
+ const auto& d = *reinterpret_cast(data);
try {
return new TWBitcoinAddress{ Address(d) };
} catch (...) {
diff --git a/src/interface/TWData.cpp b/src/interface/TWData.cpp
index 5a0ae87d6b2..ed290bfccf2 100644
--- a/src/interface/TWData.cpp
+++ b/src/interface/TWData.cpp
@@ -70,8 +70,7 @@ void TWDataAppendByte(TWData *_Nonnull data, uint8_t byte) {
void TWDataAppendData(TWData *_Nonnull data, TWData *_Nonnull append) {
auto v = const_cast*>(reinterpret_cast*>(data));
auto av = reinterpret_cast*>(append);
- for (auto& b : *av)
- v->push_back(b);
+ std::copy(av->begin(), av->end(), std::back_inserter(*v));
}
void TWDataReverse(TWData *_Nonnull data) {
diff --git a/src/interface/TWPrivateKey.cpp b/src/interface/TWPrivateKey.cpp
index 9ae603f8ffd..ab6b2b27ccb 100644
--- a/src/interface/TWPrivateKey.cpp
+++ b/src/interface/TWPrivateKey.cpp
@@ -90,7 +90,7 @@ struct TWPublicKey *_Nonnull TWPrivateKeyGetPublicKeyCurve25519(struct TWPrivate
}
TWData *TWPrivateKeySign(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull digest, enum TWCurve curve) {
- auto& d = *reinterpret_cast(digest);
+ const auto& d = *reinterpret_cast(digest);
auto result = pk->impl.sign(d, curve);
if (result.empty()) {
return nullptr;
@@ -110,7 +110,7 @@ TWData *TWPrivateKeySignAsDER(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull
}
TWData *TWPrivateKeySignSchnorr(struct TWPrivateKey *_Nonnull pk, TWData *_Nonnull message, enum TWCurve curve) {
- auto& msg = *reinterpret_cast(message);
+ const auto& msg = *reinterpret_cast(message);
auto result = pk->impl.signSchnorr(msg, curve);
if (result.empty()) {
diff --git a/src/interface/TWPublicKey.cpp b/src/interface/TWPublicKey.cpp
index 9ada3d666d0..83f2c9c4789 100644
--- a/src/interface/TWPublicKey.cpp
+++ b/src/interface/TWPublicKey.cpp
@@ -49,14 +49,14 @@ struct TWPublicKey *_Nonnull TWPublicKeyUncompressed(struct TWPublicKey *_Nonnul
}
bool TWPublicKeyVerify(struct TWPublicKey *_Nonnull pk, TWData *signature, TWData *message) {
- auto& s = *reinterpret_cast(signature);
- auto& m = *reinterpret_cast(message);
+ const auto& s = *reinterpret_cast(signature);
+ const auto& m = *reinterpret_cast(message);
return pk->impl.verify(s, m);
}
bool TWPublicKeyVerifySchnorr(struct TWPublicKey *_Nonnull pk, TWData *_Nonnull signature, TWData *_Nonnull message) {
- auto& s = *reinterpret_cast(signature);
- auto& m = *reinterpret_cast(message);
+ const auto& s = *reinterpret_cast(signature);
+ const auto& m = *reinterpret_cast(message);
return pk->impl.verifySchnorr(s, m);
}
diff --git a/tools/lint-cppcheck-all b/tools/lint-cppcheck-all
new file mode 100755
index 00000000000..09ee00310bf
--- /dev/null
+++ b/tools/lint-cppcheck-all
@@ -0,0 +1,7 @@
+#!/bin/bash
+#
+# This script lints all of the C++ code with cppcheck.
+
+set -e
+
+find src \( -name "*.cpp" -o -name "*.h" \) -not -path "./src/proto/*" -not -path "./src/Tron/Protobuf/*" -exec cppcheck --force --quiet --enable=all '{}' \;
diff --git a/tools/lint-cppcheck-diff b/tools/lint-cppcheck-diff
new file mode 100755
index 00000000000..2b568769fea
--- /dev/null
+++ b/tools/lint-cppcheck-diff
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+#
+# This script lints the files modified in the current branch with cppcheck.
+
+merge_base = `git merge-base HEAD origin/master`.strip
+changed_files = `git diff --name-only HEAD #{merge_base}`.strip.split(/\s/)
+files = changed_files.select { |f| File.extname(f) == '.cpp' || File.extname(f) == '.h' }
+if files.empty?
+ puts 'No files to lint'
+ exit 0
+end
+
+puts "Linting #{files.count} files"
+system "cppcheck --quiet --force --enable=all #{files.join(' ')}"
+exit $?.exitstatus
From 02eab8ab3518b70fb9c6209b7f2633b2f2c8e9f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?=
Date: Wed, 29 Apr 2020 13:10:33 +0300
Subject: [PATCH 13/81] Add Elrond blockchain (#929)
* Registers new coin.
* Define protobuf models
* Implement entry, address and add tests
* Fix AnyAddress, add further address tests
* Implement serialization and signing, add tests
* Add key derivation tests
* Add tests for Android
* Add tests for iOS
* Fix derivation path and tests
* Fix after review (including build issues)
---
.../blockchains/CoinAddressDerivationTests.kt | 1 +
.../blockchains/elrond/TestElrondAddress.kt | 49 ++++++++++
.../blockchains/elrond/TestElrondSigner.kt | 57 ++++++++++++
coins.json | 22 +++++
docs/coins.md | 1 +
include/TrustWalletCore/TWBlockchain.h | 1 +
include/TrustWalletCore/TWCoinType.h | 1 +
src/Coin.cpp | 2 +
src/Elrond/Address.cpp | 17 ++++
src/Elrond/Address.h | 38 ++++++++
src/Elrond/Entry.cpp | 31 +++++++
src/Elrond/Entry.h | 25 ++++++
src/Elrond/Serialization.cpp | 67 ++++++++++++++
src/Elrond/Serialization.h | 21 +++++
src/Elrond/Signer.cpp | 38 ++++++++
src/Elrond/Signer.h | 28 ++++++
src/interface/TWAnyAddress.cpp | 11 +++
src/proto/Elrond.proto | 36 ++++++++
swift/Tests/Blockchains/ElrondTests.swift | 51 +++++++++++
swift/Tests/CoinAddressDerivationTests.swift | 3 +
tests/Bech32AddressTests.cpp | 8 ++
tests/CoinAddressDerivationTests.cpp | 1 +
tests/CoinAddressValidationTests.cpp | 6 ++
tests/Elrond/AddressTests.cpp | 79 ++++++++++++++++
tests/Elrond/SerializationTests.cpp | 54 +++++++++++
tests/Elrond/SignerTests.cpp | 89 +++++++++++++++++++
tests/Elrond/TWAnySignerTests.cpp | 55 ++++++++++++
tests/Elrond/TWCoinTypeTests.cpp | 34 +++++++
tests/Elrond/TestAccounts.h | 17 ++++
tests/interface/TWAnyAddressTests.cpp | 7 ++
tests/interface/TWHDWalletTests.cpp | 10 +++
tests/interface/TWHRPTests.cpp | 3 +
32 files changed, 863 insertions(+)
create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt
create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt
create mode 100644 src/Elrond/Address.cpp
create mode 100644 src/Elrond/Address.h
create mode 100644 src/Elrond/Entry.cpp
create mode 100644 src/Elrond/Entry.h
create mode 100644 src/Elrond/Serialization.cpp
create mode 100644 src/Elrond/Serialization.h
create mode 100644 src/Elrond/Signer.cpp
create mode 100644 src/Elrond/Signer.h
create mode 100644 src/proto/Elrond.proto
create mode 100644 swift/Tests/Blockchains/ElrondTests.swift
create mode 100644 tests/Elrond/AddressTests.cpp
create mode 100644 tests/Elrond/SerializationTests.cpp
create mode 100644 tests/Elrond/SignerTests.cpp
create mode 100644 tests/Elrond/TWAnySignerTests.cpp
create mode 100644 tests/Elrond/TWCoinTypeTests.cpp
create mode 100644 tests/Elrond/TestAccounts.h
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 8bfe4dd5268..18ab0a98320 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
@@ -83,5 +83,6 @@ class CoinAddressDerivationTests {
CARDANO -> assertEquals("addr1snpa4z7ntyfszv7ckquprdw75w4qjqh0qmya9jtkpxxlzxghlqyvv7l0yjamh8fxraw06p3ua8sj2g2gv98v4849s43t9g2999kquuu5egnprk", address)
NEO -> assertEquals("AT6w7PJvwPcSqHvtbNBY2aHPDv12eW5Uuf", address)
FILECOIN -> assertEquals("f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori", address)
+ ELROND -> assertEquals("erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8", address)
}
}
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt
new file mode 100644
index 00000000000..05c17837ddc
--- /dev/null
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondAddress.kt
@@ -0,0 +1,49 @@
+// Copyright © 2017-2020 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.elrond
+
+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 TestElrondAddress {
+
+ init {
+ System.loadLibrary("TrustWalletCore")
+ }
+
+ private val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
+ private var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"
+ private var alicePubKeyHex = "0xfd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"
+
+ @Test
+ fun testAddressFromPrivateKey() {
+ val key = PrivateKey(aliceSeedHex.toHexByteArray())
+ val pubKey = key.publicKeyEd25519
+ val address = AnyAddress(pubKey, CoinType.ELROND)
+
+ assertEquals(alicePubKeyHex, pubKey.data().toHex())
+ assertEquals(aliceBech32, address.description())
+ }
+
+ @Test
+ fun testAddressFromPublicKey() {
+ val pubKey = PublicKey(alicePubKeyHex.toHexByteArray(), PublicKeyType.ED25519)
+ val address = AnyAddress(pubKey, CoinType.ELROND)
+
+ assertEquals(aliceBech32, address.description())
+ }
+
+ @Test
+ fun testAddressFromString() {
+ val address = AnyAddress(aliceBech32, CoinType.ELROND)
+
+ assertEquals(aliceBech32, address.description())
+ }
+}
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt
new file mode 100644
index 00000000000..160dd9d7765
--- /dev/null
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt
@@ -0,0 +1,57 @@
+// Copyright © 2017-2020 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.elrond
+
+import com.google.protobuf.ByteString
+import com.trustwallet.core.app.utils.toHexByteArray
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import wallet.core.java.AnySigner
+import wallet.core.jni.CoinType
+import wallet.core.jni.PrivateKey
+import wallet.core.jni.proto.Elrond
+
+class TestElrondSigner {
+
+ init {
+ System.loadLibrary("TrustWalletCore")
+ }
+
+ val aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
+ var aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"
+ var alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"
+
+ val bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r"
+ var bobSeedHex = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e438297662ea4850e"
+ var bobPubKeyHex = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36"
+
+ @Test
+ fun signTransaction() {
+ val transaction = Elrond.TransactionMessage.newBuilder()
+ .setNonce(0)
+ .setValue("0")
+ .setSender(aliceBech32)
+ .setReceiver(bobBech32)
+ .setGasPrice(200000000000000)
+ .setGasLimit(500000000)
+ .setData("foo")
+ .build()
+
+ val privateKey = ByteString.copyFrom(PrivateKey(aliceSeedHex.toHexByteArray()).data())
+
+ val signingInput = Elrond.SigningInput.newBuilder()
+ .setPrivateKey(privateKey)
+ .setTransaction(transaction)
+ .build()
+
+ val output = AnySigner.sign(signingInput, CoinType.ELROND, Elrond.SigningOutput.parser())
+ val expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"
+
+ assertEquals(expectedSignature, output.signature)
+ assertEquals("""{"nonce":0,"value":"0","receiver":"$bobBech32","sender":"$aliceBech32","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"$expectedSignature"}""", output.encoded)
+ }
+}
diff --git a/coins.json b/coins.json
index 18047f66535..175ef086de3 100644
--- a/coins.json
+++ b/coins.json
@@ -1330,5 +1330,27 @@
"clientPublic": "",
"clientDocs": "https://docs.lotu.sh"
}
+ },
+ {
+ "id": "elrond",
+ "name": "Elrond",
+ "symbol": "ERD",
+ "decimals": 18,
+ "blockchain": "ElrondNetwork",
+ "derivationPath": "m/44'/508'/0'/0'/0'",
+ "curve": "ed25519",
+ "publicKeyType": "ed25519",
+ "hrp": "erd",
+ "explorer": {
+ "url": "https://explorer.elrond.com",
+ "txPath": "/transactions/",
+ "accountPath": "/address/"
+ },
+ "info": {
+ "url": "https://elrond.com/",
+ "client": "https://github.com/ElrondNetwork/elrond-go",
+ "clientPublic": "https://api.elrond.com",
+ "clientDocs": "https://docs.elrond.com"
+ }
}
]
diff --git a/docs/coins.md b/docs/coins.md
index 2fae8caf2e8..c99e9d92157 100644
--- a/docs/coins.md
+++ b/docs/coins.md
@@ -43,6 +43,7 @@ This list is generated from [./coins.json](../coins.json)
| 461 | Filecoin | FIL | | |
| 500 | Theta | THETA | | |
| 501 | Solana | SOL | | |
+| 508 | Elrond | ERD | | |
| 714 | Binance | BNB | | |
| 818 | VeChain | VET | | |
| 820 | Callisto | CLO | | |
diff --git a/include/TrustWalletCore/TWBlockchain.h b/include/TrustWalletCore/TWBlockchain.h
index 8b1b82d6028..6a174d8af7c 100644
--- a/include/TrustWalletCore/TWBlockchain.h
+++ b/include/TrustWalletCore/TWBlockchain.h
@@ -45,6 +45,7 @@ enum TWBlockchain {
TWBlockchainCardano = 30,
TWBlockchainNEO = 31,
TWBlockchainFilecoin = 32,
+ TWBlockchainElrondNetwork = 33,
};
TW_EXTERN_C_END
diff --git a/include/TrustWalletCore/TWCoinType.h b/include/TrustWalletCore/TWCoinType.h
index 0c2a152cec0..bf70c377ee9 100644
--- a/include/TrustWalletCore/TWCoinType.h
+++ b/include/TrustWalletCore/TWCoinType.h
@@ -79,6 +79,7 @@ enum TWCoinType {
TWCoinTypeKusama = 434,
TWCoinTypePolkadot = 354,
TWCoinTypeFilecoin = 461,
+ TWCoinTypeElrond = 508,
};
/// Returns the blockchain for a coin type.
diff --git a/src/Coin.cpp b/src/Coin.cpp
index 8f96291d962..9ea55ffbfb9 100644
--- a/src/Coin.cpp
+++ b/src/Coin.cpp
@@ -51,6 +51,7 @@
#include "Waves/Entry.h"
#include "Zcash/Entry.h"
#include "Zilliqa/Entry.h"
+#include "Elrond/Entry.h"
// end_of_coin_includes_marker_do_not_modify
using namespace TW;
@@ -100,6 +101,7 @@ void setupDispatchers() {
new Waves::Entry(),
new Zcash::Entry(),
new Zilliqa::Entry(),
+ new Elrond::Entry(),
}; // end_of_coin_entries_marker_do_not_modify
dispatchMap.clear();
diff --git a/src/Elrond/Address.cpp b/src/Elrond/Address.cpp
new file mode 100644
index 00000000000..1af84ace200
--- /dev/null
+++ b/src/Elrond/Address.cpp
@@ -0,0 +1,17 @@
+// Copyright © 2017-2020 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.
+
+#include
+
+#include "Address.h"
+
+using namespace TW::Elrond;
+
+const std::string Address::hrp = HRP_ELROND;
+
+bool Address::isValid(const std::string& string) {
+ return Bech32Address::isValid(string, hrp);
+}
diff --git a/src/Elrond/Address.h b/src/Elrond/Address.h
new file mode 100644
index 00000000000..1f96edc6700
--- /dev/null
+++ b/src/Elrond/Address.h
@@ -0,0 +1,38 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../Data.h"
+#include "../PublicKey.h"
+#include "../Bech32Address.h"
+
+#include
+
+namespace TW::Elrond {
+
+class Address : public Bech32Address {
+ public:
+ // The human-readable part of the address, as defined in "coins.json"
+ static const std::string hrp; // HRP_ELROND
+
+ /// Determines whether a string makes a valid address.
+ static bool isValid(const std::string& string);
+
+ Address() : Bech32Address(hrp) {}
+
+ /// Initializes an address with a key hash.
+ Address(Data keyHash) : Bech32Address(hrp, keyHash) {}
+
+ /// Initializes an address with a public key.
+ Address(const PublicKey& publicKey) : Bech32Address(hrp, publicKey.bytes) {}
+
+ static bool decode(const std::string& addr, Address& obj_out) {
+ return Bech32Address::decode(addr, obj_out, hrp);
+ }
+};
+
+} // namespace TW::Elrond
diff --git a/src/Elrond/Entry.cpp b/src/Elrond/Entry.cpp
new file mode 100644
index 00000000000..76b806ff128
--- /dev/null
+++ b/src/Elrond/Entry.cpp
@@ -0,0 +1,31 @@
+// Copyright © 2017-2020 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.
+
+#include "Entry.h"
+
+#include "Address.h"
+#include "Signer.h"
+
+using namespace TW::Elrond;
+using namespace std;
+
+// Note: avoid business logic from here, rather just call into classes like Address, Signer, etc.
+
+bool Entry::validateAddress(TWCoinType coin, const string& address, TW::byte, TW::byte, const char*) const {
+ return Address::isValid(address);
+}
+
+string Entry::deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte, const char*) const {
+ return Address(publicKey).string();
+}
+
+void Entry::sign(TWCoinType coin, const TW::Data& dataIn, TW::Data& dataOut) const {
+ signTemplate(dataIn, dataOut);
+}
+
+string Entry::signJSON(TWCoinType coin, const std::string& json, const Data& key) const {
+ return Signer::signJSON(json, key);
+}
diff --git a/src/Elrond/Entry.h b/src/Elrond/Entry.h
new file mode 100644
index 00000000000..78a5f60a39f
--- /dev/null
+++ b/src/Elrond/Entry.h
@@ -0,0 +1,25 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../CoinEntry.h"
+
+namespace TW::Elrond {
+
+/// Entry point for implementation of Elrond coin.
+/// Note: do not put the implementation here (no matter how simple), to avoid having coin-specific includes in this file
+class Entry: public CoinEntry {
+public:
+ virtual std::vector coinTypes() const { return {TWCoinTypeElrond}; }
+ virtual bool validateAddress(TWCoinType coin, const std::string& address, TW::byte p2pkh, TW::byte p2sh, const char* hrp) const;
+ virtual std::string deriveAddress(TWCoinType coin, const PublicKey& publicKey, TW::byte p2pkh, const char* hrp) const;
+ virtual void sign(TWCoinType coin, const Data& dataIn, Data& dataOut) const;
+ virtual bool supportsJSONSigning() const { return true; }
+ virtual std::string signJSON(TWCoinType coin, const std::string& json, const Data& key) const;
+};
+
+} // namespace TW::Elrond
diff --git a/src/Elrond/Serialization.cpp b/src/Elrond/Serialization.cpp
new file mode 100644
index 00000000000..193daf5d210
--- /dev/null
+++ b/src/Elrond/Serialization.cpp
@@ -0,0 +1,67 @@
+// Copyright © 2017-2020 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.
+
+#include "Serialization.h"
+
+#include "../Elrond/Address.h"
+#include "../proto/Elrond.pb.h"
+#include "Base64.h"
+#include "PrivateKey.h"
+
+using namespace TW;
+
+std::map fields_order {
+ {"nonce", 1},
+ {"value", 2},
+ {"receiver", 3},
+ {"sender", 4},
+ {"gasPrice", 5},
+ {"gasLimit", 6},
+ {"data", 7},
+ {"signature", 8}
+};
+
+struct FieldsSorter {
+ bool operator() (const string& lhs, const string& rhs) const {
+ return fields_order[lhs] < fields_order[rhs];
+ }
+};
+
+template
+using sorted_map = std::map;
+using sorted_json = nlohmann::basic_json;
+
+string Elrond::serializeTransaction(const Proto::TransactionMessage& message) {
+ sorted_json payload {
+ {"nonce", json(message.nonce())},
+ {"value", json(message.value())},
+ {"receiver", json(message.receiver())},
+ {"sender", json(message.sender())},
+ {"gasPrice", json(message.gas_price())},
+ {"gasLimit", json(message.gas_limit())},
+ };
+
+ if (!message.data().empty()) {
+ payload["data"] = json(TW::Base64::encode(TW::data(message.data())));
+ }
+
+ return payload.dump();
+}
+
+string Elrond::serializeSignedTransaction(const Proto::TransactionMessage& message, string signature) {
+ sorted_json payload {
+ {"nonce", json(message.nonce())},
+ {"value", json(message.value())},
+ {"receiver", json(message.receiver())},
+ {"sender", json(message.sender())},
+ {"gasPrice", json(message.gas_price())},
+ {"gasLimit", json(message.gas_limit())},
+ {"data", json(message.data())},
+ {"signature", json(signature)},
+ };
+
+ return payload.dump();
+}
diff --git a/src/Elrond/Serialization.h b/src/Elrond/Serialization.h
new file mode 100644
index 00000000000..e56d8a5bf87
--- /dev/null
+++ b/src/Elrond/Serialization.h
@@ -0,0 +1,21 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../proto/Elrond.pb.h"
+#include "Data.h"
+#include
+
+using string = std::string;
+using json = nlohmann::json;
+
+namespace TW::Elrond {
+
+string serializeTransaction(const Proto::TransactionMessage& message);
+string serializeSignedTransaction(const Proto::TransactionMessage& message, string encodedSignature);
+
+} // namespace
diff --git a/src/Elrond/Signer.cpp b/src/Elrond/Signer.cpp
new file mode 100644
index 00000000000..20519c8b80a
--- /dev/null
+++ b/src/Elrond/Signer.cpp
@@ -0,0 +1,38 @@
+// Copyright © 2017-2020 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.
+
+#include "Signer.h"
+#include "Address.h"
+#include "Serialization.h"
+#include "../PublicKey.h"
+#include "HexCoding.h"
+
+#include
+
+using namespace TW;
+using namespace TW::Elrond;
+
+Proto::SigningOutput Signer::sign(const Proto::SigningInput &input) noexcept {
+ auto privateKey = PrivateKey(input.private_key());
+ auto signableAsString = serializeTransaction(input.transaction());
+ auto signableAsData = TW::data(signableAsString);
+ auto signature = privateKey.sign(signableAsData, TWCurveED25519);
+ auto encodedSignature = hex(signature);
+ auto encoded = serializeSignedTransaction(input.transaction(), encodedSignature);
+
+ auto protoOutput = Proto::SigningOutput();
+ protoOutput.set_signature(encodedSignature);
+ protoOutput.set_encoded(encoded);
+ return protoOutput;
+}
+
+std::string Signer::signJSON(const std::string& json, const Data& key) {
+ auto input = Proto::SigningInput();
+ google::protobuf::util::JsonStringToMessage(json, &input);
+ input.set_private_key(key.data(), key.size());
+ auto output = sign(input);
+ return output.encoded();
+}
diff --git a/src/Elrond/Signer.h b/src/Elrond/Signer.h
new file mode 100644
index 00000000000..046f5e52d67
--- /dev/null
+++ b/src/Elrond/Signer.h
@@ -0,0 +1,28 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "../Data.h"
+#include "../PrivateKey.h"
+#include "../proto/Elrond.pb.h"
+
+namespace TW::Elrond {
+
+/// Helper class that performs Elrond transaction signing.
+class Signer {
+public:
+ /// Hide default constructor
+ Signer() = delete;
+
+ /// Signs a Proto::SigningInput transaction
+ static Proto::SigningOutput sign(const Proto::SigningInput& input) noexcept;
+
+ /// Signs a json Proto::SigningInput with private key
+ static std::string signJSON(const std::string& json, const Data& key);
+};
+
+} // namespace TW::Elrond
diff --git a/src/interface/TWAnyAddress.cpp b/src/interface/TWAnyAddress.cpp
index d2c028ed584..dd6ee615f4c 100644
--- a/src/interface/TWAnyAddress.cpp
+++ b/src/interface/TWAnyAddress.cpp
@@ -20,6 +20,7 @@
#include "../Cardano/AddressV3.h"
#include "../NEO/Address.h"
#include "../Nano/Address.h"
+#include "../Elrond/Address.h"
#include "../Coin.h"
#include "../HexCoding.h"
@@ -184,6 +185,16 @@ TWData* _Nonnull TWAnyAddressData(struct TWAnyAddress* _Nonnull address) {
data = Data(addr.bytes.begin(), addr.bytes.end());
break;
}
+
+ case TWCoinTypeElrond: {
+ Elrond::Address addr;
+ if (Elrond::Address::decode(string, addr)) {
+ data = addr.getKeyHash();
+ }
+
+ break;
+ }
+
default: break;
}
return TWDataCreateWithBytes(data.data(), data.size());
diff --git a/src/proto/Elrond.proto b/src/proto/Elrond.proto
new file mode 100644
index 00000000000..41b4a0efc06
--- /dev/null
+++ b/src/proto/Elrond.proto
@@ -0,0 +1,36 @@
+// Copyright © 2017-2020 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.
+
+syntax = "proto3";
+
+package TW.Elrond.Proto;
+option java_package = "wallet.core.jni.proto";
+
+// A transaction, typical balance transfer
+message TransactionMessage {
+ uint64 nonce = 1;
+ string value = 2;
+ string receiver = 3;
+ string sender = 4;
+ uint64 gas_price = 5;
+ uint64 gas_limit = 6;
+ string data = 7;
+}
+
+// Input data necessary to create a signed transaction.
+message SigningInput {
+ bytes private_key = 1;
+
+ oneof message_oneof {
+ TransactionMessage transaction = 2;
+ }
+}
+
+// Transaction signing output.
+message SigningOutput {
+ string encoded = 1;
+ string signature = 2;
+}
diff --git a/swift/Tests/Blockchains/ElrondTests.swift b/swift/Tests/Blockchains/ElrondTests.swift
new file mode 100644
index 00000000000..c3e3e5b4b8c
--- /dev/null
+++ b/swift/Tests/Blockchains/ElrondTests.swift
@@ -0,0 +1,51 @@
+// Copyright © 2017-2020 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 TrustWalletCore
+import XCTest
+
+class ElrondTests: XCTestCase {
+
+ let aliceBech32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"
+ let aliceSeedHex = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf"
+ let alicePubKeyHex = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"
+ let bobBech32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r"
+
+ func testAddress() {
+ let key = PrivateKey(data: Data(hexString: aliceSeedHex)!)!
+ let pubkey = key.getPublicKeyEd25519()
+ let address = AnyAddress(publicKey: pubkey, coin: .elrond)
+ let addressFromString = AnyAddress(string: aliceBech32, coin: .elrond)!
+
+ XCTAssertEqual(pubkey.data.hexString, alicePubKeyHex)
+ XCTAssertEqual(address.description, addressFromString.description)
+ }
+
+ func testSign() {
+ let privateKey = PrivateKey(data: Data(hexString: aliceSeedHex)!)!
+
+ let input = ElrondSigningInput.with {
+ $0.transaction = ElrondTransactionMessage.with {
+ $0.nonce = 0
+ $0.value = "0"
+ $0.sender = aliceBech32
+ $0.receiver = bobBech32
+ $0.gasPrice = 200000000000000
+ $0.gasLimit = 500000000
+ $0.data = "foo"
+ }
+
+ $0.privateKey = privateKey.data
+ }
+
+ let output: ElrondSigningOutput = AnySigner.sign(input: input, coin: .elrond)
+ let expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308"
+ let expectedEncoded = #"{"nonce":0,"value":"0","receiver":"\#(bobBech32)","sender":"\#(aliceBech32)","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"\#(expectedSignature)"}"#
+
+ XCTAssertEqual(output.signature, expectedSignature)
+ XCTAssertEqual(output.encoded, expectedEncoded)
+ }
+}
diff --git a/swift/Tests/CoinAddressDerivationTests.swift b/swift/Tests/CoinAddressDerivationTests.swift
index 81b55b548ed..2a09ac50169 100644
--- a/swift/Tests/CoinAddressDerivationTests.swift
+++ b/swift/Tests/CoinAddressDerivationTests.swift
@@ -190,6 +190,9 @@ class CoinAddressDerivationTests: XCTestCase {
case .filecoin:
let expectedResult = "f1zzykebxldfcakj5wdb5n3n7priul522fnmjzori"
AssetCoinDerivation(coin, expectedResult, derivedAddress, address)
+ case .elrond:
+ let expectedResult = "erd1jfcy8aeru6vlx4fe6h3pc3vlpe2cnnur5zetxdhp879yagq7vqvs8na4f8"
+ AssetCoinDerivation(coin, expectedResult, derivedAddress, address)
@unknown default:
fatalError()
}
diff --git a/tests/Bech32AddressTests.cpp b/tests/Bech32AddressTests.cpp
index ff425cb7c4f..4b6024ecd5e 100644
--- a/tests/Bech32AddressTests.cpp
+++ b/tests/Bech32AddressTests.cpp
@@ -27,6 +27,10 @@ TEST(Bech32Address, Valid) {
ASSERT_TRUE(Bech32Address::isValid("io187wzp08vnhjjpkydnr97qlh8kh0dpkkytfam8j", "io"));
ASSERT_TRUE(Bech32Address::isValid("zil1fwh4ltdguhde9s7nysnp33d5wye6uqpugufkz7", "zil"));
+
+ ASSERT_TRUE(Bech32Address::isValid("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz", "erd"));
+ ASSERT_TRUE(Bech32Address::isValid("erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r", "erd"));
+ ASSERT_TRUE(Bech32Address::isValid("erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd"));
}
TEST(Bech32Address, Invalid) {
@@ -48,6 +52,10 @@ TEST(Bech32Address, Invalid) {
ASSERT_FALSE(Bech32Address::isValid(""));
ASSERT_FALSE(Bech32Address::isValid("0x"));
ASSERT_FALSE(Bech32Address::isValid("91cddcebe846ce4d47712287eee53cf17c2cfb7"));
+
+ ASSERT_FALSE(Bech32Address::isValid("", "erd"));
+ ASSERT_FALSE(Bech32Address::isValid("erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35!", "erd"));
+ ASSERT_FALSE(Bech32Address::isValid("xerd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0", "erd"));
}
TEST(Bech32Address, InvalidWrongPrefix) {
diff --git a/tests/CoinAddressDerivationTests.cpp b/tests/CoinAddressDerivationTests.cpp
index 16ac09114df..1bf597c6d88 100644
--- a/tests/CoinAddressDerivationTests.cpp
+++ b/tests/CoinAddressDerivationTests.cpp
@@ -71,6 +71,7 @@ TEST(Coin, DeriveAddress) {
EXPECT_EQ(TW::deriveAddress(TWCoinTypeFilecoin, privateKey), "f1qsx7qwiojh5duxbxhbqgnlyx5hmpcf7mcz5oxsy");
EXPECT_EQ(TW::deriveAddress(TWCoinTypeNEAR, privateKey), "NEAR2p5878zbFhxnrm7meL7TmqwtvBaqcBddyp5eGzZbovZ5HYrdGj");
EXPECT_EQ(TW::deriveAddress(TWCoinTypeSolana, privateKey), "H4JcMPicKkHcxxDjkyyrLoQj7Kcibd9t815ak4UvTr9M");
+ EXPECT_EQ(TW::deriveAddress(TWCoinTypeElrond, privateKey), "erd1a6f6fan035ttsxdmn04ellxdlnwpgyhg0lhx5vjv92v6rc8xw9yq83344f");
}
} // namespace TW
diff --git a/tests/CoinAddressValidationTests.cpp b/tests/CoinAddressValidationTests.cpp
index 7b08cf9f61b..86a0d7f309a 100644
--- a/tests/CoinAddressValidationTests.cpp
+++ b/tests/CoinAddressValidationTests.cpp
@@ -373,4 +373,10 @@ TEST(Coin, ValidateAddressVeChain) {
EXPECT_EQ(normalizeAddress(TWCoinTypeVeChain, "0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f"), "0x9d8A62f656a8d1615C1294fd71e9CFb3E4855A4F");
}
+TEST(Coin, ValidateAddressElrond) {
+ EXPECT_TRUE(validateAddress(TWCoinTypeElrond, "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"));
+ EXPECT_FALSE(validateAddress(TWCoinTypeElrond, "xerd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz"));
+}
+
+
} // namespace TW
diff --git a/tests/Elrond/AddressTests.cpp b/tests/Elrond/AddressTests.cpp
new file mode 100644
index 00000000000..3dd1fb6f166
--- /dev/null
+++ b/tests/Elrond/AddressTests.cpp
@@ -0,0 +1,79 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include
+
+#include "HexCoding.h"
+#include "PublicKey.h"
+#include "PrivateKey.h"
+#include "Elrond/Address.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+
+TEST(ElrondAddress, Valid) {
+ ASSERT_TRUE(Address::isValid(ALICE_BECH32));
+ ASSERT_TRUE(Address::isValid(BOB_BECH32));
+ ASSERT_TRUE(Address::isValid(CAROL_BECH32));
+}
+
+TEST(ElrondAddress, Invalid) {
+ ASSERT_FALSE(Address::isValid(""));
+ ASSERT_FALSE(Address::isValid("foo"));
+ ASSERT_FALSE(Address::isValid("10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"));
+ ASSERT_FALSE(Address::isValid("xerd10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"));
+ ASSERT_FALSE(Address::isValid("foo10z9xdugayn528ksaesdwlhf006fw5sg2qmmm0h52fvxczwgesyvq5pwemr"));
+ ASSERT_FALSE(Address::isValid(ALICE_PUBKEY_HEX));
+}
+
+TEST(ElrondAddress, FromString) {
+ Address alice, bob, carol;
+ ASSERT_TRUE(Address::decode(ALICE_BECH32, alice));
+ ASSERT_TRUE(Address::decode(BOB_BECH32, bob));
+ ASSERT_TRUE(Address::decode(CAROL_BECH32, carol));
+
+ ASSERT_EQ(ALICE_PUBKEY_HEX, hex(alice.getKeyHash()));
+ ASSERT_EQ(BOB_PUBKEY_HEX, hex(bob.getKeyHash()));
+ ASSERT_EQ(CAROL_PUBKEY_HEX, hex(carol.getKeyHash()));
+}
+
+TEST(ElrondAddress, FromData) {
+ const auto alice = Address(parse_hex(ALICE_PUBKEY_HEX));
+ const auto bob = Address(parse_hex(BOB_PUBKEY_HEX));
+ const auto carol = Address(parse_hex(CAROL_PUBKEY_HEX));
+
+ ASSERT_EQ(ALICE_BECH32, alice.string());
+ ASSERT_EQ(BOB_BECH32, bob.string());
+ ASSERT_EQ(CAROL_BECH32, carol.string());
+}
+
+TEST(ElrondAddress, FromPrivateKey) {
+ auto aliceKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ auto alice = Address(aliceKey.getPublicKey(TWPublicKeyTypeED25519));
+ ASSERT_EQ(ALICE_BECH32, alice.string());
+
+ auto bobKey = PrivateKey(parse_hex(BOB_SEED_HEX));
+ auto bob = Address(bobKey.getPublicKey(TWPublicKeyTypeED25519));
+ ASSERT_EQ(BOB_BECH32, bob.string());
+
+ auto carolKey = PrivateKey(parse_hex(CAROL_SEED_HEX));
+ auto carol = Address(carolKey.getPublicKey(TWPublicKeyTypeED25519));
+ ASSERT_EQ(CAROL_BECH32, carol.string());
+}
+
+TEST(ElrondAddress, FromPublicKey) {
+ auto alice = PublicKey(parse_hex(ALICE_PUBKEY_HEX), TWPublicKeyTypeED25519);
+ ASSERT_EQ(ALICE_BECH32, Address(alice).string());
+
+ auto bob = PublicKey(parse_hex(BOB_PUBKEY_HEX), TWPublicKeyTypeED25519);
+ ASSERT_EQ(BOB_BECH32, Address(bob).string());
+
+ auto carol = PublicKey(parse_hex(CAROL_PUBKEY_HEX), TWPublicKeyTypeED25519);
+ ASSERT_EQ(CAROL_BECH32, Address(carol).string());
+}
diff --git a/tests/Elrond/SerializationTests.cpp b/tests/Elrond/SerializationTests.cpp
new file mode 100644
index 00000000000..80c048bb9da
--- /dev/null
+++ b/tests/Elrond/SerializationTests.cpp
@@ -0,0 +1,54 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include
+#include "boost/format.hpp"
+
+#include "HexCoding.h"
+#include "Elrond/Serialization.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+TEST(ElrondSerialization, SignableString) {
+ Proto::TransactionMessage message;
+ message.set_nonce(42);
+ message.set_value("43");
+ message.set_sender("alice");
+ message.set_receiver("bob");
+ message.set_data("foobar");
+
+ string jsonString = serializeTransaction(message);
+ ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"bob","sender":"alice","gasPrice":0,"gasLimit":0,"data":"Zm9vYmFy"})", jsonString);
+}
+
+TEST(ElrondSerialization, SignableStringWithRealData) {
+ Proto::TransactionMessage message;
+ message.set_nonce(15);
+ message.set_value("100");
+ message.set_sender(ALICE_BECH32);
+ message.set_receiver(BOB_BECH32);
+ message.set_gas_price(200000000000000);
+ message.set_gas_limit(500000000);
+ message.set_data("for dinner");
+
+ string expected = (boost::format(R"({"nonce":15,"value":"100","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"Zm9yIGRpbm5lcg=="})") % BOB_BECH32 % ALICE_BECH32).str();
+ string actual = serializeTransaction(message);
+ ASSERT_EQ(expected, actual);
+}
+
+TEST(ElrondSerialization, SignableStringWithoutData) {
+ Proto::TransactionMessage message;
+ message.set_nonce(42);
+ message.set_value("43");
+ message.set_sender("feed");
+ message.set_receiver("abba");
+
+ string jsonString = serializeTransaction(message);
+ ASSERT_EQ(R"({"nonce":42,"value":"43","receiver":"abba","sender":"feed","gasPrice":0,"gasLimit":0})", jsonString);
+}
diff --git a/tests/Elrond/SignerTests.cpp b/tests/Elrond/SignerTests.cpp
new file mode 100644
index 00000000000..adda6c83a4d
--- /dev/null
+++ b/tests/Elrond/SignerTests.cpp
@@ -0,0 +1,89 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include "boost/format.hpp"
+
+#include "HexCoding.h"
+#include "PrivateKey.h"
+#include "PublicKey.h"
+#include "Elrond/Signer.h"
+#include "Elrond/Address.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+
+TEST(ElrondSigner, Sign) {
+ auto input = Proto::SigningInput();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size());
+
+ input.mutable_transaction()->set_nonce(0);
+ input.mutable_transaction()->set_value("0");
+ input.mutable_transaction()->set_sender(ALICE_BECH32);
+ input.mutable_transaction()->set_receiver(BOB_BECH32);
+ input.mutable_transaction()->set_gas_price(200000000000000);
+ input.mutable_transaction()->set_gas_limit(500000000);
+ input.mutable_transaction()->set_data("foo");
+
+ auto output = Signer::sign(input);
+ auto signature = output.signature();
+ auto encoded = output.encoded();
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedSignature, signature);
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(ElrondSigner, SignJSON) {
+ // Shuffle some fields, assume arbitrary order in the input
+ auto input = (boost::format(R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000}})") % BOB_BECH32 % ALICE_BECH32).str();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+
+ auto encoded = Signer::signJSON(input, privateKey.bytes);
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(ElrondSigner, SignWithoutData) {
+ auto input = Proto::SigningInput();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size());
+
+ input.mutable_transaction()->set_nonce(0);
+ input.mutable_transaction()->set_value("0");
+ input.mutable_transaction()->set_sender(ALICE_BECH32);
+ input.mutable_transaction()->set_receiver(BOB_BECH32);
+ input.mutable_transaction()->set_gas_price(200000000000000);
+ input.mutable_transaction()->set_gas_limit(500000000);
+ input.mutable_transaction()->set_data("");
+
+ auto output = Signer::sign(input);
+ auto signature = output.signature();
+ auto encoded = output.encoded();
+ auto expectedSignature = "39ab0e18bfce04bf53c9610faa3b9e7cecfca919510a7631e529e9086279b70a4832df32a5d1b8fdceb4e9082f2995da97f9195532c8d611ee749bc312cbf90c";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedSignature, signature);
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(ElrondSigner, SignJSONWithoutData) {
+ // Shuffle some fields, assume arbitrary order in the input
+ auto input = (boost::format(R"({"transaction" : {"value":"0","nonce":0,"receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000}})") % BOB_BECH32 % ALICE_BECH32).str();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+
+ auto encoded = Signer::signJSON(input, privateKey.bytes);
+ auto expectedSignature = "39ab0e18bfce04bf53c9610faa3b9e7cecfca919510a7631e529e9086279b70a4832df32a5d1b8fdceb4e9082f2995da97f9195532c8d611ee749bc312cbf90c";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedEncoded, encoded);
+}
diff --git a/tests/Elrond/TWAnySignerTests.cpp b/tests/Elrond/TWAnySignerTests.cpp
new file mode 100644
index 00000000000..f9366ab52ba
--- /dev/null
+++ b/tests/Elrond/TWAnySignerTests.cpp
@@ -0,0 +1,55 @@
+// Copyright © 2017-2020 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.
+
+#include
+#include "boost/format.hpp"
+
+#include
+#include "HexCoding.h"
+#include "../interface/TWTestUtilities.h"
+#include "Elrond/Signer.h"
+#include "TestAccounts.h"
+
+using namespace TW;
+using namespace TW::Elrond;
+
+
+TEST(TWAnySignerElrond, Sign) {
+ auto input = Proto::SigningInput();
+ auto privateKey = PrivateKey(parse_hex(ALICE_SEED_HEX));
+ input.set_private_key(privateKey.bytes.data(), privateKey.bytes.size());
+
+ input.mutable_transaction()->set_nonce(0);
+ input.mutable_transaction()->set_value("0");
+ input.mutable_transaction()->set_sender(ALICE_BECH32);
+ input.mutable_transaction()->set_receiver(BOB_BECH32);
+ input.mutable_transaction()->set_gas_price(200000000000000);
+ input.mutable_transaction()->set_gas_limit(500000000);
+ input.mutable_transaction()->set_data("foo");
+
+ Proto::SigningOutput output;
+ ANY_SIGN(input, TWCoinTypeElrond);
+
+ auto signature = output.signature();
+ auto encoded = output.encoded();
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_EQ(expectedSignature, signature);
+ ASSERT_EQ(expectedEncoded, encoded);
+}
+
+TEST(TWAnySignerElrond, SignJSON) {
+ // Shuffle some fields, assume arbitrary order in the input
+ auto input = STRING((boost::format(R"({"transaction" : {"data":"foo","value":"0","nonce":0,"receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000}})") % BOB_BECH32 % ALICE_BECH32).str().c_str());
+ auto privateKey = DATA(ALICE_SEED_HEX);
+ auto encoded = WRAPS(TWAnySignerSignJSON(input.get(), privateKey.get(), TWCoinTypeElrond));
+ auto expectedSignature = "b88ad2fe98a7316ea432a0a76c18cd87200fe75f27a8f053ea6532b40317dbec5136c5463aef132ae951b7e60d45d921caaa5903e70821dcda98f237d4ec4308";
+ auto expectedEncoded = (boost::format(R"({"nonce":0,"value":"0","receiver":"%1%","sender":"%2%","gasPrice":200000000000000,"gasLimit":500000000,"data":"foo","signature":"%3%"})") % BOB_BECH32 % ALICE_BECH32 % expectedSignature).str();
+
+ ASSERT_TRUE(TWAnySignerSupportsJSON(TWCoinTypeElrond));
+ assertStringsEqual(encoded, expectedEncoded.c_str());
+}
diff --git a/tests/Elrond/TWCoinTypeTests.cpp b/tests/Elrond/TWCoinTypeTests.cpp
new file mode 100644
index 00000000000..9e73e615721
--- /dev/null
+++ b/tests/Elrond/TWCoinTypeTests.cpp
@@ -0,0 +1,34 @@
+// Copyright © 2017-2020 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 "../interface/TWTestUtilities.h"
+#include
+#include
+
+
+TEST(TWElrondCoinType, TWCoinType) {
+ auto symbol = WRAPS(TWCoinTypeConfigurationGetSymbol(TWCoinTypeElrond));
+ auto txId = TWStringCreateWithUTF8Bytes("1fc9785cb8bea0129a16cf7bddc97630c176a556ea566f0e72923c882b5cb3c8");
+ auto txUrl = WRAPS(TWCoinTypeConfigurationGetTransactionURL(TWCoinTypeElrond, txId));
+ auto accId = TWStringCreateWithUTF8Bytes("erd12yne790km8ezwetkz7m3hmqy9utdc6vdkgsunfzpwguec6v04p2qtk9uqj");
+ auto accUrl = WRAPS(TWCoinTypeConfigurationGetAccountURL(TWCoinTypeElrond, accId));
+ auto id = WRAPS(TWCoinTypeConfigurationGetID(TWCoinTypeElrond));
+ auto name = WRAPS(TWCoinTypeConfigurationGetName(TWCoinTypeElrond));
+
+ ASSERT_EQ(TWCoinTypeConfigurationGetDecimals(TWCoinTypeElrond), 18);
+ ASSERT_EQ(TWBlockchainElrondNetwork, TWCoinTypeBlockchain(TWCoinTypeElrond));
+ ASSERT_EQ(0x0, TWCoinTypeP2shPrefix(TWCoinTypeElrond));
+ ASSERT_EQ(0x0, TWCoinTypeStaticPrefix(TWCoinTypeElrond));
+ assertStringsEqual(symbol, "ERD");
+ assertStringsEqual(txUrl, "https://explorer.elrond.com/transactions/1fc9785cb8bea0129a16cf7bddc97630c176a556ea566f0e72923c882b5cb3c8");
+ assertStringsEqual(accUrl, "https://explorer.elrond.com/address/erd12yne790km8ezwetkz7m3hmqy9utdc6vdkgsunfzpwguec6v04p2qtk9uqj");
+ assertStringsEqual(id, "elrond");
+ assertStringsEqual(name, "Elrond");
+}
diff --git a/tests/Elrond/TestAccounts.h b/tests/Elrond/TestAccounts.h
new file mode 100644
index 00000000000..55060002abd
--- /dev/null
+++ b/tests/Elrond/TestAccounts.h
@@ -0,0 +1,17 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+const auto ALICE_BECH32 = "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz";
+const auto ALICE_SEED_HEX = "1a927e2af5306a9bb2ea777f73e06ecc0ac9aaa72fb4ea3fecf659451394cccf";
+const auto ALICE_PUBKEY_HEX = "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293";
+const auto BOB_BECH32 = "erd1cux02zersde0l7hhklzhywcxk4u9n4py5tdxyx7vrvhnza2r4gmq4vw35r";
+const auto BOB_SEED_HEX = "e3a3a3d1ac40d42d8fd4c569a9749b65a1250dd3d10b6f4e438297662ea4850e";
+const auto BOB_PUBKEY_HEX = "c70cf50b238372fffaf7b7c5723b06b57859d424a2da621bcc1b2f317543aa36";
+const auto CAROL_BECH32 = "erd19nu5t7hszckwah5nlcadmk5rlchtugzplznskffpwecygcu0520s9tnyy0";
+const auto CAROL_SEED_HEX = "a926316cc3daf8ff25ba3e417797e6dfd51f62ae735ab07148234732f7314052";
+const auto CAROL_PUBKEY_HEX = "2cf945faf0162ceede93fe3addda83fe2ebe2041f8a70b2521767044638fa29f";
diff --git a/tests/interface/TWAnyAddressTests.cpp b/tests/interface/TWAnyAddressTests.cpp
index c35b6935a79..dbc77477d5d 100644
--- a/tests/interface/TWAnyAddressTests.cpp
+++ b/tests/interface/TWAnyAddressTests.cpp
@@ -119,4 +119,11 @@ TEST(AnyAddress, Data) {
auto keyHash = WRAPD(TWAnyAddressData(addr.get()));
assertHexEqual(keyHash, "172bdf43265c0adfe105a1a8c45b3f406a38362f24");
}
+ // elrond
+ {
+ auto string = STRING("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz");
+ auto addr = WRAP(TWAnyAddress, TWAnyAddressCreateWithString(string.get(), TWCoinTypeElrond));
+ auto pubkey = WRAPD(TWAnyAddressData(addr.get()));
+ assertHexEqual(pubkey, "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293");
+ }
}
diff --git a/tests/interface/TWHDWalletTests.cpp b/tests/interface/TWHDWalletTests.cpp
index 62f67695f0e..6b286eee3cb 100644
--- a/tests/interface/TWHDWalletTests.cpp
+++ b/tests/interface/TWHDWalletTests.cpp
@@ -231,6 +231,16 @@ TEST(HDWallet, DeriveAlgorand) {
assertHexEqual(privateKeyData, "ce0b7ac644e2b7d9d14d3928b11643f43e48c33d3e328d059fef8add7f070e82");
}
+TEST(HDWallet, DeriveElrond) {
+ auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), passphrase.get()));
+ auto privateKey = WRAP(TWPrivateKey, TWHDWalletGetKeyForCoin(wallet.get(), TWCoinTypeElrond));
+ auto privateKeyData = WRAPD(TWPrivateKeyData(privateKey.get()));
+ auto address = WRAPS(TWCoinTypeDeriveAddress(TWCoinTypeElrond, privateKey.get()));
+
+ assertHexEqual(privateKeyData, "0eb593141de897d60a0883320793eb49e63d556ccdf783a87ec014f150d50453");
+ assertStringsEqual(address, "erd1a6l7q9cfvrgr80xuzm37tapdr4zm3mwrtl6vt8f45df45x7eadfs8ds5vv");
+}
+
TEST(HDWallet, ExtendedKeys) {
auto words = STRING("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
auto wallet = WRAP(TWHDWallet, TWHDWalletCreateWithMnemonic(words.get(), STRING("").get()));
diff --git a/tests/interface/TWHRPTests.cpp b/tests/interface/TWHRPTests.cpp
index 11af1a19e50..3b04ad4f8c3 100644
--- a/tests/interface/TWHRPTests.cpp
+++ b/tests/interface/TWHRPTests.cpp
@@ -28,6 +28,7 @@ TEST(TWHRP, StringForHRP) {
ASSERT_STREQ(stringForHRP(TWHRPMonacoin), "mona");
ASSERT_STREQ(stringForHRP(TWHRPKava), "kava");
ASSERT_STREQ(stringForHRP(TWHRPCardano), "addr");
+ ASSERT_STREQ(stringForHRP(TWHRPElrond), "erd");
}
TEST(TWHRP, HRPForString) {
@@ -47,6 +48,7 @@ TEST(TWHRP, HRPForString) {
ASSERT_EQ(hrpForString("mona"), TWHRPMonacoin);
ASSERT_EQ(hrpForString("kava"), TWHRPKava);
ASSERT_EQ(hrpForString("addr"), TWHRPCardano);
+ ASSERT_EQ(hrpForString("erd"), TWHRPElrond);
}
TEST(TWHPR, HPRByCoinType) {
@@ -65,6 +67,7 @@ TEST(TWHPR, HPRByCoinType) {
ASSERT_EQ(TWHRPMonacoin, TWCoinTypeHRP(TWCoinTypeMonacoin));
ASSERT_EQ(TWHRPKava, TWCoinTypeHRP(TWCoinTypeKava));
ASSERT_EQ(TWHRPCardano, TWCoinTypeHRP(TWCoinTypeCardano));
+ ASSERT_EQ(TWHRPElrond, TWCoinTypeHRP(TWCoinTypeElrond));
ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeAion));
ASSERT_EQ(TWHRPUnknown, TWCoinTypeHRP(TWCoinTypeCallisto));
From be696466158cbabab3fee4e56fa973bf6ddd963c Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Thu, 30 Apr 2020 16:00:47 +0800
Subject: [PATCH 14/81] Add TWFIOAccount (#940)
* Add TWFIOAccount
* Move regex into Actor.cpp, add android test
---
android/app/build.gradle | 2 +-
.../app/blockchains/fio/TestFIOAddress.kt | 20 +++++++
android/build.gradle | 2 +-
include/TrustWalletCore/TWFIOAccount.h | 28 +++++++++
src/Cardano/AddressV3.h | 2 +-
src/FIO/Actor.cpp | 60 +++++++++++++++++++
src/FIO/Actor.h | 27 +++++++++
src/FIO/Signer.cpp | 43 +------------
src/FIO/Signer.h | 12 ----
src/FIO/TransactionBuilder.cpp | 1 +
src/interface/TWFIOAccount.cpp | 39 ++++++++++++
swift/Tests/Blockchains/FIOTests.swift | 16 +++++
tests/FIO/SignerTests.cpp | 1 +
tests/FIO/TWFIOAccountTests.cpp | 46 ++++++++++++++
14 files changed, 242 insertions(+), 57 deletions(-)
create mode 100644 include/TrustWalletCore/TWFIOAccount.h
create mode 100644 src/FIO/Actor.cpp
create mode 100644 src/FIO/Actor.h
create mode 100644 src/interface/TWFIOAccount.cpp
create mode 100644 tests/FIO/TWFIOAccountTests.cpp
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 609fbaf8b18..03b4d26e54b 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -4,7 +4,7 @@ apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
- buildToolsVersion '28.0.3'
+ ndkVersion '21.1.6352462'
defaultConfig {
applicationId "com.trustwallet.core.app"
minSdkVersion 23
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt
index cce536ff660..6b6461e78d1 100644
--- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/fio/TestFIOAddress.kt
@@ -9,6 +9,7 @@ package com.trustwallet.core.app.blockchains.fio
import com.trustwallet.core.app.utils.toHex
import com.trustwallet.core.app.utils.toHexByteArray
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
import org.junit.Test
import wallet.core.jni.*
@@ -28,4 +29,23 @@ class TestFIOAddress {
val addressFromKey = AnyAddress(pubkey, CoinType.FIO)
assertEquals(addressFromKey.description(), "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o")
}
+
+ @Test
+ fun testAccount() {
+ assertEquals(FIOAccount("FIO7uMZoeei5HtXAD24C4yCkpWWbf24bjYtrRNjWdmGCXHZccwuiE").description(), "hhq2g4qgycfb")
+ assertEquals(FIOAccount("hhq2g4qgycfb").description(), "hhq2g4qgycfb")
+ assertEquals(FIOAccount("rewards@wallet").description(), "rewards@wallet")
+
+ var account: FIOAccount? = null
+ var account2: FIOAccount? = null
+ try {
+ account = FIOAccount("asdf19s")
+ account2 = FIOAccount("0x320196ef1b137786be51aa391e78e0a2c756f46b")
+ } catch (ex: Exception) {
+ print(ex)
+ }
+
+ assertNull(account)
+ assertNull(account2)
+ }
}
diff --git a/android/build.gradle b/android/build.gradle
index a710c7f55ed..b10f80b42be 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.2'
+ classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
diff --git a/include/TrustWalletCore/TWFIOAccount.h b/include/TrustWalletCore/TWFIOAccount.h
new file mode 100644
index 00000000000..8012cbf0faf
--- /dev/null
+++ b/include/TrustWalletCore/TWFIOAccount.h
@@ -0,0 +1,28 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "TWBase.h"
+#include "TWString.h"
+
+TW_EXTERN_C_BEGIN
+
+/// Represents a FIO Account name
+TW_EXPORT_CLASS
+struct TWFIOAccount;
+
+TW_EXPORT_STATIC_METHOD
+struct TWFIOAccount *_Nullable TWFIOAccountCreateWithString(TWString *_Nonnull string);
+
+TW_EXPORT_METHOD
+void TWFIOAccountDelete(struct TWFIOAccount *_Nonnull account);
+
+/// Returns the short account string representation.
+TW_EXPORT_PROPERTY
+TWString *_Nonnull TWFIOAccountDescription(struct TWFIOAccount *_Nonnull account);
+
+TW_EXTERN_C_END
diff --git a/src/Cardano/AddressV3.h b/src/Cardano/AddressV3.h
index 960750ccee3..2097396523d 100644
--- a/src/Cardano/AddressV3.h
+++ b/src/Cardano/AddressV3.h
@@ -86,7 +86,7 @@ class AddressV3 {
Data data() const;
private:
- AddressV3() : legacyAddressV2(nullptr), discrimination(Discrim_Production), kind(Kind_Single) {}
+ AddressV3() : discrimination(Discrim_Production), kind(Kind_Single), legacyAddressV2(nullptr) {}
};
inline bool operator==(const AddressV3& lhs, const AddressV3& rhs) {
diff --git a/src/FIO/Actor.cpp b/src/FIO/Actor.cpp
new file mode 100644
index 00000000000..7502f1605b8
--- /dev/null
+++ b/src/FIO/Actor.cpp
@@ -0,0 +1,60 @@
+// Copyright © 2017-2020 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.
+
+#include "Actor.h"
+
+#include
+
+using namespace TW::FIO;
+using namespace std;
+
+string Actor::actor(const Address& addr)
+{
+ uint64_t shortenedKey = shortenKey(addr.bytes);
+ string name13 = name(shortenedKey);
+ // trim to 12 chracters
+ return name13.substr(0, 12);
+}
+
+bool Actor::validate(const std::string& addr) {
+ regex pattern(R"(\b([a-z1-5]{3,})[.@]?\b)");
+ smatch match;
+ return regex_search(addr, match, pattern);
+}
+
+uint64_t Actor::shortenKey(const array& addrKey)
+{
+ uint64_t res = 0;
+ int i = 1; // Ignore key head
+ int len = 0;
+ while (len <= 12) {
+ assert(i < 33); // Means the key has > 20 bytes with trailing zeroes...
+
+ auto trimmed_char = uint64_t(addrKey[i] & (len == 12 ? 0x0f : 0x1f));
+ if (trimmed_char == 0) { i++; continue; } // Skip a zero and move to next
+
+ auto shuffle = len == 12 ? 0 : 5 * (12 - len) - 1;
+ res |= trimmed_char << shuffle;
+
+ len++; i++;
+ }
+ return res;
+}
+
+string Actor::name(uint64_t shortKey) {
+ static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
+
+ string str(13,'.'); //We are forcing the string to be 13 characters
+
+ uint64_t tmp = shortKey;
+ for(uint32_t i = 0; i <= 12; i++ ) {
+ char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)];
+ str[12 - i] = c;
+ tmp >>= (i == 0 ? 4 : 5);
+ }
+
+ return str;
+}
diff --git a/src/FIO/Actor.h b/src/FIO/Actor.h
new file mode 100644
index 00000000000..2024d756c05
--- /dev/null
+++ b/src/FIO/Actor.h
@@ -0,0 +1,27 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include "Address.h"
+#include
+
+namespace TW::FIO {
+/// Helper class for Actor name generation from address
+class Actor {
+ public:
+ /// Generate the actor name of the address
+ static std::string actor(const Address& addr);
+
+ /// Check if the address is valid
+ static bool validate(const std::string& addr);
+
+ /// Used internally, derive shortened uint64 key from adddr bytes
+ static uint64_t shortenKey(const std::array& addrKey);
+ /// Used internally, derive name from uint64 shortened key
+ static std::string name(uint64_t shortKey);
+};
+} // namespace TW::FIO
diff --git a/src/FIO/Signer.cpp b/src/FIO/Signer.cpp
index 3e09738bb4e..43abd7df8d3 100644
--- a/src/FIO/Signer.cpp
+++ b/src/FIO/Signer.cpp
@@ -6,6 +6,7 @@
#include "Signer.h"
#include "Address.h"
+#include "Actor.h"
#include "../Base58.h"
#include "../Hash.h"
@@ -61,46 +62,4 @@ int Signer::isCanonical(uint8_t by, uint8_t sig[64]) {
&& !(sig[32] == 0 && !(sig[33] & 0x80));
}
-string Actor::actor(const Address& addr)
-{
- uint64_t shortenedKey = shortenKey(addr.bytes);
- string name13 = name(shortenedKey);
- // trim to 12 chracters
- return name13.substr(0, 12);
-}
-
-uint64_t Actor::shortenKey(const array& addrKey)
-{
- uint64_t res = 0;
- int i = 1; // Ignore key head
- int len = 0;
- while (len <= 12) {
- assert(i < 33); // Means the key has > 20 bytes with trailing zeroes...
-
- auto trimmed_char = uint64_t(addrKey[i] & (len == 12 ? 0x0f : 0x1f));
- if (trimmed_char == 0) { i++; continue; } // Skip a zero and move to next
-
- auto shuffle = len == 12 ? 0 : 5 * (12 - len) - 1;
- res |= trimmed_char << shuffle;
-
- len++; i++;
- }
- return res;
-}
-
-string Actor::name(uint64_t shortKey) {
- static const char* charmap = ".12345abcdefghijklmnopqrstuvwxyz";
-
- string str(13,'.'); //We are forcing the string to be 13 characters
-
- uint64_t tmp = shortKey;
- for(uint32_t i = 0; i <= 12; i++ ) {
- char c = charmap[tmp & (i == 0 ? 0x0f : 0x1f)];
- str[12 - i] = c;
- tmp >>= (i == 0 ? 4 : 5);
- }
-
- return str;
-}
-
} // namespace TW::FIO
diff --git a/src/FIO/Signer.h b/src/FIO/Signer.h
index b7595e7ae8e..7604ca4f953 100644
--- a/src/FIO/Signer.h
+++ b/src/FIO/Signer.h
@@ -38,16 +38,4 @@ class Signer {
static int isCanonical(uint8_t by, uint8_t sig[64]);
};
-/// Helper class for Actor name generation from address
-class Actor {
- public:
- /// Generate the actor name of the address
- static std::string actor(const Address& addr);
-
- /// Used internally, derive shortened uint64 key from adddr bytes
- static uint64_t shortenKey(const std::array& addrKey);
- /// Used internally, derive name from uint64 shortened key
- static std::string name(uint64_t shortKey);
-};
-
} // namespace TW::FIO
diff --git a/src/FIO/TransactionBuilder.cpp b/src/FIO/TransactionBuilder.cpp
index c7ec086af47..71eaa4764ea 100644
--- a/src/FIO/TransactionBuilder.cpp
+++ b/src/FIO/TransactionBuilder.cpp
@@ -6,6 +6,7 @@
#include "TransactionBuilder.h"
+#include "Actor.h"
#include "Encryption.h"
#include "NewFundsRequest.h"
#include "Signer.h"
diff --git a/src/interface/TWFIOAccount.cpp b/src/interface/TWFIOAccount.cpp
new file mode 100644
index 00000000000..b600d82b493
--- /dev/null
+++ b/src/interface/TWFIOAccount.cpp
@@ -0,0 +1,39 @@
+// Copyright © 2017-2020 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.
+
+#include
+
+#include "FIO/Actor.h"
+#include "FIO/Address.h"
+
+#include
+
+using namespace TW;
+using namespace TW::FIO;
+
+struct TWFIOAccount {
+ std::string description;
+};
+
+struct TWFIOAccount *_Nullable TWFIOAccountCreateWithString(TWString *_Nonnull string) {
+ const auto& account = *reinterpret_cast(string);
+ if (Address::isValid(account)) {
+ const auto addr = Address(account);
+ return new TWFIOAccount{Actor::actor(addr)};
+ }
+ if (Actor::validate(account)) {
+ return new TWFIOAccount{account};
+ }
+ return nullptr;
+}
+
+void TWFIOAccountDelete(struct TWFIOAccount *_Nonnull account) {
+ delete account;
+}
+
+TWString *_Nonnull TWFIOAccountDescription(struct TWFIOAccount *_Nonnull account) {
+ return TWStringCreateWithUTF8Bytes(account->description.c_str());
+}
diff --git a/swift/Tests/Blockchains/FIOTests.swift b/swift/Tests/Blockchains/FIOTests.swift
index 06444088bdb..eb38aebef65 100644
--- a/swift/Tests/Blockchains/FIOTests.swift
+++ b/swift/Tests/Blockchains/FIOTests.swift
@@ -139,4 +139,20 @@ class FIOTests: XCTestCase {
XCTAssertEqual(out.json, expectedJson)
}
+
+ func testAccountNames() {
+ XCTAssertEqual(
+ FIOAccount(string: "FIO7uMZoeei5HtXAD24C4yCkpWWbf24bjYtrRNjWdmGCXHZccwuiE")!.description, "hhq2g4qgycfb"
+ )
+ XCTAssertEqual(
+ FIOAccount(string: "hhq2g4qgycfb")!.description, "hhq2g4qgycfb"
+ )
+
+ XCTAssertEqual(
+ FIOAccount(string: "rewards@wallet")!.description, "rewards@wallet"
+ )
+
+ XCTAssertNil(FIOAccount(string: "asdf19s"))
+ XCTAssertNil(FIOAccount(string: "0x320196ef1b137786be51aa391e78e0a2c756f46b"))
+ }
}
diff --git a/tests/FIO/SignerTests.cpp b/tests/FIO/SignerTests.cpp
index ab452f6a544..cdf1277a11b 100644
--- a/tests/FIO/SignerTests.cpp
+++ b/tests/FIO/SignerTests.cpp
@@ -4,6 +4,7 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
+#include "FIO/Actor.h"
#include "FIO/Signer.h"
#include "HexCoding.h"
diff --git a/tests/FIO/TWFIOAccountTests.cpp b/tests/FIO/TWFIOAccountTests.cpp
new file mode 100644
index 00000000000..3c4764d4801
--- /dev/null
+++ b/tests/FIO/TWFIOAccountTests.cpp
@@ -0,0 +1,46 @@
+// Copyright © 2017-2020 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.
+
+#include "../interface/TWTestUtilities.h"
+#include
+
+#include
+
+TEST(TWFIO, Account) {
+ {
+ auto string = STRING("FIO6XKiobBGrmPZDaHne47TF25CamjFc3cRe8hs7oAiCN59TbJzes");
+ auto account = TWFIOAccountCreateWithString(string.get());
+ auto description = WRAPS(TWFIOAccountDescription(account));
+ assertStringsEqual(description, "rpxtnpsr3gxd");
+ TWFIOAccountDelete(account);
+ }
+
+ {
+ auto account = TWFIOAccountCreateWithString(STRING("lhp1ytjibtea").get());
+ auto account2 = TWFIOAccountCreateWithString(STRING("wrcjejslfplp").get());
+ auto account3 = TWFIOAccountCreateWithString(STRING("rewards@wallet").get());
+ auto description = WRAPS(TWFIOAccountDescription(account));
+ auto description2 = WRAPS(TWFIOAccountDescription(account2));
+ auto description3 = WRAPS(TWFIOAccountDescription(account3));
+ assertStringsEqual(description, "lhp1ytjibtea");
+ assertStringsEqual(description2, "wrcjejslfplp");
+ assertStringsEqual(description3, "rewards@wallet");
+
+ TWFIOAccountDelete(account);
+ TWFIOAccountDelete(account2);
+ TWFIOAccountDelete(account3);
+ }
+
+ {
+ auto string = STRING("asdf19s");
+ auto string2 = STRING("0x320196ef1b137786be51aa391e78e0a2c756f46b");
+ auto account = TWFIOAccountCreateWithString(string.get());
+ auto account2 = TWFIOAccountCreateWithString(string2.get());
+
+ ASSERT_EQ(account, nullptr);
+ ASSERT_EQ(account2, nullptr);
+ }
+}
From cb6e57f52abb713f544335ac10160b79293e93a4 Mon Sep 17 00:00:00 2001
From: Adam R <13562139+catenocrypt@users.noreply.github.com>
Date: Sat, 2 May 2020 23:22:52 +0200
Subject: [PATCH 15/81] Bitcoin Signing coverage (#939)
* Bitcoin Signing coverage: minor SigHashType refactor.
* SigHashType, part 2.
* Extra tests for Bitcoin signing coverage.
* Cleanup.
* One extra test for the last uncovered Transaction line :)
Co-authored-by: Catenocrypt
---
src/Bitcoin/SigHashType.h | 21 +++
src/Bitcoin/SignatureVersion.h | 2 -
src/Bitcoin/Transaction.cpp | 15 +-
src/Bitcoin/Transaction.h | 1 +
src/Bitcoin/TransactionSigner.cpp | 4 +-
src/Decred/Signer.cpp | 4 +-
src/Decred/Transaction.cpp | 13 +-
src/Decred/Transaction.h | 1 +
src/Zcash/Transaction.cpp | 7 +-
src/interface/TWBitcoin.cpp | 5 +-
tests/Bitcoin/TWBitcoinSigningTests.cpp | 239 ++++++++++++++++++++++--
11 files changed, 269 insertions(+), 43 deletions(-)
create mode 100644 src/Bitcoin/SigHashType.h
diff --git a/src/Bitcoin/SigHashType.h b/src/Bitcoin/SigHashType.h
new file mode 100644
index 00000000000..690cfb2ed0b
--- /dev/null
+++ b/src/Bitcoin/SigHashType.h
@@ -0,0 +1,21 @@
+// Copyright © 2017-2020 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.
+
+#pragma once
+
+#include
+
+namespace TW::Bitcoin {
+
+// Defines the number of bits of the hash type which is used to identify which
+// outputs are signed.
+static const uint8_t SigHashMask = 0x1f;
+
+inline bool hashTypeIsSingle(enum TWBitcoinSigHashType type) { return (type & SigHashMask) == TWBitcoinSigHashTypeSingle; }
+
+inline bool hashTypeIsNone(enum TWBitcoinSigHashType type) { return (type & SigHashMask) == TWBitcoinSigHashTypeNone; }
+
+} // namespace TW::Bitcoin
diff --git a/src/Bitcoin/SignatureVersion.h b/src/Bitcoin/SignatureVersion.h
index 87669836277..fa3363eec3f 100644
--- a/src/Bitcoin/SignatureVersion.h
+++ b/src/Bitcoin/SignatureVersion.h
@@ -6,8 +6,6 @@
#pragma once
-#include
-
namespace TW::Bitcoin {
enum SignatureVersion {
BASE,
diff --git a/src/Bitcoin/Transaction.cpp b/src/Bitcoin/Transaction.cpp
index 47d1071a313..a7af607385b 100644
--- a/src/Bitcoin/Transaction.cpp
+++ b/src/Bitcoin/Transaction.cpp
@@ -6,6 +6,7 @@
#include "SegwitAddress.h"
#include "Transaction.h"
+#include "SigHashType.h"
#include "../BinaryCoding.h"
#include "../Hash.h"
@@ -34,7 +35,7 @@ std::vector Transaction::getPreImage(const Script& scriptCode, size_t i
// Input nSequence (none/all, depending on flags)
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 &&
- !TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
+ !hashTypeIsSingle(hashType) && !hashTypeIsNone(hashType)) {
auto hashSequence = getSequenceHash();
std::copy(std::begin(hashSequence), std::end(hashSequence), std::back_inserter(data));
} else {
@@ -51,10 +52,10 @@ std::vector Transaction::getPreImage(const Script& scriptCode, size_t i
encode32LE(inputs[index].sequence, data);
// Outputs (none/one/all, depending on flags)
- if (!TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
+ if (!hashTypeIsSingle(hashType) && !hashTypeIsNone(hashType)) {
auto hashOutputs = getOutputsHash();
copy(begin(hashOutputs), end(hashOutputs), back_inserter(data));
- } else if (TWBitcoinSigHashTypeIsSingle(hashType) && index < outputs.size()) {
+ } else if (hashTypeIsSingle(hashType) && index < outputs.size()) {
auto outputData = std::vector{};
outputs[index].encode(outputData);
auto hashOutputs = TW::Hash::hash(hasher, outputData);
@@ -164,8 +165,8 @@ std::vector Transaction::getSignatureHashBase(const Script& scriptCode,
serializeInput(subindex, scriptCode, index, hashType, data);
}
- auto hashNone = (hashType & 0x1f) == TWBitcoinSigHashTypeNone;
- auto hashSingle = (hashType & 0x1f) == TWBitcoinSigHashTypeSingle;
+ auto hashNone = hashTypeIsNone(hashType);
+ auto hashSingle = hashTypeIsSingle(hashType);
auto serializedOutputCount = hashNone ? 0 : (hashSingle ? index + 1 : outputs.size());
encodeVarInt(serializedOutputCount, data);
for (auto subindex = 0; subindex < serializedOutputCount; subindex += 1) {
@@ -205,8 +206,8 @@ void Transaction::serializeInput(size_t subindex, const Script& scriptCode, size
}
// Serialize the nSequence
- auto hashNone = (hashType & 0x1f) == TWBitcoinSigHashTypeNone;
- auto hashSingle = (hashType & 0x1f) == TWBitcoinSigHashTypeSingle;
+ auto hashNone = hashTypeIsNone(hashType);
+ auto hashSingle = hashTypeIsSingle(hashType);
if (subindex != index && (hashSingle || hashNone)) {
encode32LE(0, data);
} else {
diff --git a/src/Bitcoin/Transaction.h b/src/Bitcoin/Transaction.h
index 19d27b93ddd..0814138b306 100644
--- a/src/Bitcoin/Transaction.h
+++ b/src/Bitcoin/Transaction.h
@@ -6,6 +6,7 @@
#pragma once
+#include
#include "Script.h"
#include "TransactionInput.h"
#include "TransactionOutput.h"
diff --git a/src/Bitcoin/TransactionSigner.cpp b/src/Bitcoin/TransactionSigner.cpp
index acf191cf11d..ed96ae1b575 100644
--- a/src/Bitcoin/TransactionSigner.cpp
+++ b/src/Bitcoin/TransactionSigner.cpp
@@ -9,6 +9,7 @@
#include "TransactionInput.h"
#include "TransactionOutput.h"
#include "UnspentSelector.h"
+#include "SigHashType.h"
#include "../BinaryCoding.h"
#include "../Hash.h"
@@ -25,8 +26,7 @@ Result TransactionSigner::sign() {
std::copy(std::begin(transaction.inputs), std::end(transaction.inputs),
std::back_inserter(signedInputs));
- const bool hashSingle =
- ((input.hash_type() & ~TWBitcoinSigHashTypeAnyoneCanPay) == TWBitcoinSigHashTypeSingle);
+ const auto hashSingle = hashTypeIsSingle(static_cast(input.hash_type()));
for (auto i = 0; i < plan.utxos.size(); i += 1) {
auto& utxo = plan.utxos[i];
diff --git a/src/Decred/Signer.cpp b/src/Decred/Signer.cpp
index 09ddf587313..ec089551258 100644
--- a/src/Decred/Signer.cpp
+++ b/src/Decred/Signer.cpp
@@ -8,6 +8,7 @@
#include "TransactionInput.h"
#include "TransactionOutput.h"
+#include "../Bitcoin/SigHashType.h"
#include "../BinaryCoding.h"
#include "../Hash.h"
@@ -49,8 +50,7 @@ Result Signer::sign() {
std::copy(std::begin(transaction.inputs), std::end(transaction.inputs),
std::back_inserter(signedInputs));
- const bool hashSingle =
- ((input.hash_type() & ~TWBitcoinSigHashTypeAnyoneCanPay) == TWBitcoinSigHashTypeSingle);
+ const auto hashSingle = Bitcoin::hashTypeIsSingle(static_cast(input.hash_type()));
for (auto i = 0; i < txPlan.utxos.size(); i += 1) {
auto& utxo = txPlan.utxos[i];
diff --git a/src/Decred/Transaction.cpp b/src/Decred/Transaction.cpp
index f1b746f474f..9be21fbe88f 100644
--- a/src/Decred/Transaction.cpp
+++ b/src/Decred/Transaction.cpp
@@ -6,6 +6,7 @@
#include "Transaction.h"
+#include "../Bitcoin/SigHashType.h"
#include "../BinaryCoding.h"
#include "../Hash.h"
@@ -23,10 +24,6 @@ static const uint32_t sigHashSerializePrefix = 1;
// Indicates the serialization only contains witness data.
static const uint32_t sigHashSerializeWitness = 3;
-// Defines the number of bits of the hash type which is used to identify which
-// outputs are signed.
-static const byte sigHashMask = 0x1f;
-
std::size_t sigHashWitnessSize(const std::vector& inputs,
const Bitcoin::Script& signScript);
} // namespace
@@ -35,7 +32,7 @@ Data Transaction::computeSignatureHash(const Bitcoin::Script& prevOutScript, siz
enum TWBitcoinSigHashType hashType) const {
assert(index < inputs.size());
- if (TWBitcoinSigHashTypeIsSingle(hashType) && index >= outputs.size()) {
+ if (Bitcoin::hashTypeIsSingle(hashType) && index >= outputs.size()) {
throw std::invalid_argument("attempt to sign single input at index "
"larger than the number of outputs");
}
@@ -48,7 +45,7 @@ Data Transaction::computeSignatureHash(const Bitcoin::Script& prevOutScript, siz
}
auto outputsToSign = outputs;
- switch (hashType & sigHashMask) {
+ switch (hashType & Bitcoin::SigHashMask) {
case TWBitcoinSigHashTypeNone:
outputsToSign = {};
break;
@@ -93,7 +90,7 @@ Data Transaction::computePrefixHash(const std::vector& inputsT
input.previousOutput.encode(preimage);
auto sequence = input.sequence;
- if ((TWBitcoinSigHashTypeIsNone(hashType) || TWBitcoinSigHashTypeIsSingle(hashType)) &&
+ if ((Bitcoin::hashTypeIsNone(hashType) || Bitcoin::hashTypeIsSingle(hashType)) &&
i != signIndex) {
sequence = 0;
}
@@ -106,7 +103,7 @@ Data Transaction::computePrefixHash(const std::vector& inputsT
auto& output = outputsToSign[i];
auto value = output.value;
auto pkScript = output.script;
- if (TWBitcoinSigHashTypeIsSingle(hashType) && i != index) {
+ if (Bitcoin::hashTypeIsSingle(hashType) && i != index) {
value = -1;
pkScript = {};
}
diff --git a/src/Decred/Transaction.h b/src/Decred/Transaction.h
index 69742710246..57aa1650ca0 100644
--- a/src/Decred/Transaction.h
+++ b/src/Decred/Transaction.h
@@ -6,6 +6,7 @@
#pragma once
+#include
#include "TransactionInput.h"
#include "TransactionOutput.h"
#include "Bitcoin/Script.h"
diff --git a/src/Zcash/Transaction.cpp b/src/Zcash/Transaction.cpp
index 29e4b0b153d..f872270d2dc 100644
--- a/src/Zcash/Transaction.cpp
+++ b/src/Zcash/Transaction.cpp
@@ -6,6 +6,7 @@
#include "Transaction.h"
+#include "../Bitcoin/SigHashType.h"
#include "../BinaryCoding.h"
#include "../Hash.h"
#include "../HexCoding.h"
@@ -50,7 +51,7 @@ Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, e
// Input nSequence (none/all, depending on flags)
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 &&
- !TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
+ !Bitcoin::hashTypeIsSingle(hashType) && !Bitcoin::hashTypeIsNone(hashType)) {
auto hashSequence = getSequenceHash();
std::copy(std::begin(hashSequence), std::end(hashSequence), std::back_inserter(data));
} else {
@@ -58,10 +59,10 @@ Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, e
}
// Outputs (none/one/all, depending on flags)
- if (!TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
+ if (!Bitcoin::hashTypeIsSingle(hashType) && !Bitcoin::hashTypeIsNone(hashType)) {
auto hashOutputs = getOutputsHash();
copy(begin(hashOutputs), end(hashOutputs), back_inserter(data));
- } else if (TWBitcoinSigHashTypeIsSingle(hashType) && index < outputs.size()) {
+ } else if (Bitcoin::hashTypeIsSingle(hashType) && index < outputs.size()) {
auto outputData = Data{};
outputs[index].encode(outputData);
auto hashOutputs =
diff --git a/src/interface/TWBitcoin.cpp b/src/interface/TWBitcoin.cpp
index 54359ae3b19..d6cf837ce7e 100644
--- a/src/interface/TWBitcoin.cpp
+++ b/src/interface/TWBitcoin.cpp
@@ -5,11 +5,12 @@
// file LICENSE at the root of the source code distribution tree.
#include
+#include "../Bitcoin/SigHashType.h"
bool TWBitcoinSigHashTypeIsSingle(enum TWBitcoinSigHashType type) {
- return (type & 0x1f) == TWBitcoinSigHashTypeSingle;
+ return TW::Bitcoin::hashTypeIsSingle(type);
}
bool TWBitcoinSigHashTypeIsNone(enum TWBitcoinSigHashType type) {
- return (type & 0x1f) == TWBitcoinSigHashTypeNone;
+ return TW::Bitcoin::hashTypeIsNone(type);
}
diff --git a/tests/Bitcoin/TWBitcoinSigningTests.cpp b/tests/Bitcoin/TWBitcoinSigningTests.cpp
index 45137ad48ef..f7b5a08d1b6 100644
--- a/tests/Bitcoin/TWBitcoinSigningTests.cpp
+++ b/tests/Bitcoin/TWBitcoinSigningTests.cpp
@@ -57,22 +57,8 @@ TEST(BitcoinSigning, EncodeP2WPKH) {
}
TEST(BitcoinSigning, SignP2WPKH) {
- // Build transaction
- auto unsignedTx = Transaction(1, 0x11);
-
auto hash0 = parse_hex("fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f");
- auto outpoint0 = OutPoint(hash0, 0);
- unsignedTx.inputs.emplace_back(outpoint0, Script(), 0xffffffee);
-
auto hash1 = parse_hex("ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a");
- auto outpoint1 = OutPoint(hash1, 1);
- unsignedTx.inputs.emplace_back(outpoint1, Script(), UINT32_MAX);
-
- auto outScript0 = Script(parse_hex("76a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac"));
- unsignedTx.outputs.emplace_back(112'340'000, outScript0);
-
- auto outScript1 = Script(parse_hex("76a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac"));
- unsignedTx.outputs.emplace_back(223'450'000, outScript1);
// Setup input
Proto::SigningInput input;
@@ -137,6 +123,136 @@ TEST(BitcoinSigning, SignP2WPKH) {
);
}
+TEST(BitcoinSigning, SignP2WPKH_HashSingle_TwoInput) {
+ auto hash0 = parse_hex("fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f");
+ auto hash1 = parse_hex("ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a");
+
+ // Setup input
+ Proto::SigningInput input;
+ input.set_hash_type(TWBitcoinSigHashTypeSingle);
+ input.set_amount(335'790'000);
+ input.set_byte_fee(1);
+ input.set_to_address("1Bp9U1ogV3A14FMvKbRJms7ctyso4Z4Tcx");
+ input.set_change_address("1FQc5LdgGHMHEN9nwkjmz6tWkxhPpxBvBU");
+
+ auto utxoKey0 = parse_hex("bbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866");
+ input.add_private_key(utxoKey0.data(), utxoKey0.size());
+
+ auto utxoKey1 = parse_hex("619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9");
+ input.add_private_key(utxoKey1.data(), utxoKey1.size());
+
+ auto scriptPub1 = Script(parse_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1"));
+ auto scriptHash = std::vector();
+ scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash);
+ auto scriptHashHex = hex(scriptHash.begin(), scriptHash.end());
+ ASSERT_EQ(scriptHashHex, "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1");
+
+ auto redeemScript = Script::buildPayToPublicKeyHash(scriptHash);
+ auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end());
+ (*input.mutable_scripts())[scriptHashHex] = scriptString;
+
+ auto utxo0 = input.add_utxo();
+ auto utxo0Script = parse_hex("2103c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432ac");
+ utxo0->set_script(utxo0Script.data(), utxo0Script.size());
+ utxo0->set_amount(210'000'000);
+ utxo0->mutable_out_point()->set_hash(hash0.data(), hash0.size());
+ utxo0->mutable_out_point()->set_index(0);
+ utxo0->mutable_out_point()->set_sequence(UINT32_MAX);
+
+ auto utxo1 = input.add_utxo();
+ auto utxo1Script = parse_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1");
+ utxo1->set_script(utxo0Script.data(), utxo0Script.size());
+ utxo1->set_amount(210'000'000);
+ utxo1->mutable_out_point()->set_hash(hash1.data(), hash1.size());
+ utxo1->mutable_out_point()->set_index(1);
+ utxo0->mutable_out_point()->set_sequence(UINT32_MAX);
+
+ // Sign
+ auto result = TransactionSigner(std::move(input)).sign();
+
+ ASSERT_TRUE(result) << result.error();;
+ auto signedTx = result.payload();
+
+ Data serialized;
+ signedTx.encode(true, serialized);
+ ASSERT_EQ(hex(serialized),
+ "01000000"
+ "0001"
+ "02"
+ "fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f" "00000000" "49483045022100fd8591c3611a07b55f509ec850534c7a9c49713c9b8fa0e844ea06c2e65e19d702205e3806676192e790bc93dd4c28e937c4bf97b15f189158ba1a30d7ecff5ee75503" "ffffffff"
+ "ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a" "01000000" "49483045022100c723312dccfcc1f3716ae1fc8b045dda97a6f381cadad99a11289b73d7ce89390220261e7a75b8ccef3cddc16ab2f5a3cd7c47626a0c3a6e35f4bcf1b31235c9e73403" "00000000"
+ "02"
+ "b0bf031400000000" "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac"
+ "daef040500000000" "1976a9149e089b6889e032d46e3b915a3392edfd616fb1c488ac"
+ "000000000000"
+ );
+}
+
+TEST(BitcoinSigning, SignP2WPKH_HashAnyoneCanPay_TwoInput) {
+ auto hash0 = parse_hex("fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f");
+ auto hash1 = parse_hex("ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a");
+
+ // Setup input
+ Proto::SigningInput input;
+ input.set_hash_type(TWBitcoinSigHashTypeAnyoneCanPay);
+ input.set_amount(335'790'000);
+ input.set_byte_fee(1);
+ input.set_to_address("1Bp9U1ogV3A14FMvKbRJms7ctyso4Z4Tcx");
+ input.set_change_address("1FQc5LdgGHMHEN9nwkjmz6tWkxhPpxBvBU");
+
+ auto utxoKey0 = parse_hex("bbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866");
+ input.add_private_key(utxoKey0.data(), utxoKey0.size());
+
+ auto utxoKey1 = parse_hex("619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9");
+ input.add_private_key(utxoKey1.data(), utxoKey1.size());
+
+ auto scriptPub1 = Script(parse_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1"));
+ auto scriptHash = std::vector();
+ scriptPub1.matchPayToWitnessPublicKeyHash(scriptHash);
+ auto scriptHashHex = hex(scriptHash.begin(), scriptHash.end());
+ ASSERT_EQ(scriptHashHex, "1d0f172a0ecb48aee1be1f2687d2963ae33f71a1");
+
+ auto redeemScript = Script::buildPayToPublicKeyHash(scriptHash);
+ auto scriptString = std::string(redeemScript.bytes.begin(), redeemScript.bytes.end());
+ (*input.mutable_scripts())[scriptHashHex] = scriptString;
+
+ auto utxo0 = input.add_utxo();
+ auto utxo0Script = parse_hex("2103c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432ac");
+ utxo0->set_script(utxo0Script.data(), utxo0Script.size());
+ utxo0->set_amount(210'000'000);
+ utxo0->mutable_out_point()->set_hash(hash0.data(), hash0.size());
+ utxo0->mutable_out_point()->set_index(0);
+ utxo0->mutable_out_point()->set_sequence(UINT32_MAX);
+
+ auto utxo1 = input.add_utxo();
+ auto utxo1Script = parse_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1");
+ utxo1->set_script(utxo0Script.data(), utxo0Script.size());
+ utxo1->set_amount(210'000'000);
+ utxo1->mutable_out_point()->set_hash(hash1.data(), hash1.size());
+ utxo1->mutable_out_point()->set_index(1);
+ utxo0->mutable_out_point()->set_sequence(UINT32_MAX);
+
+ // Sign
+ auto result = TransactionSigner(std::move(input)).sign();
+
+ ASSERT_TRUE(result) << result.error();;
+ auto signedTx = result.payload();
+
+ Data serialized;
+ signedTx.encode(true, serialized);
+ ASSERT_EQ(hex(serialized),
+ "01000000"
+ "0001"
+ "02"
+ "fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f" "00000000" "4847304402206ed3e388d440cb845eef2fce0740b83bdd77764ad0e7dd815a20760718291a5302203f78d743350d80aa2508e90d5a984636c5503d02c1e8656442f0f0275db95baa80" "ffffffff"
+ "ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a" "01000000" "4847304402202cb0d71911596b9527b68829689fe600fdd237fa890826f2fbaf61a43d2a945f022038102d595d27e60a75c396388cb5d8c1d0bd341e0040dba56fbad413c3395bf080" "00000000"
+ "02"
+ "b0bf031400000000" "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac"
+ "daef040500000000" "1976a9149e089b6889e032d46e3b915a3392edfd616fb1c488ac"
+ "000000000000"
+ );
+}
+
TEST(BitcoinSigning, EncodeP2WSH) {
auto unsignedTx = Transaction(1, 0);
@@ -157,10 +273,9 @@ TEST(BitcoinSigning, EncodeP2WSH) {
"00000000");
}
-TEST(BitcoinSigning, SignP2WSH) {
- // Setup input
+Proto::SigningInput buildInputP2WSH(enum TWBitcoinSigHashType hashType) {
Proto::SigningInput input;
- input.set_hash_type(TWBitcoinSigHashTypeAll);
+ input.set_hash_type(hashType);
input.set_amount(1000);
input.set_byte_fee(1);
input.set_to_address("1Bp9U1ogV3A14FMvKbRJms7ctyso4Z4Tcx");
@@ -185,6 +300,12 @@ TEST(BitcoinSigning, SignP2WSH) {
utxo0->mutable_out_point()->set_hash(TWDataBytes(hash0.get()), TWDataSize(hash0.get()));
utxo0->mutable_out_point()->set_index(0);
utxo0->mutable_out_point()->set_sequence(UINT32_MAX);
+ return input;
+}
+
+TEST(BitcoinSigning, SignP2WSH) {
+ // Setup input
+ const auto input = buildInputP2WSH(TWBitcoinSigHashTypeAll);
// Sign
auto result = TransactionSigner(std::move(input)).sign();
@@ -210,6 +331,90 @@ TEST(BitcoinSigning, SignP2WSH) {
);
}
+TEST(BitcoinSigning, SignP2WSH_HashNone) {
+ // Setup input
+ const auto input = buildInputP2WSH(TWBitcoinSigHashTypeNone);
+
+ // Sign
+ auto result = TransactionSigner(std::move(input)).sign();
+
+ ASSERT_TRUE(result) << result.error();;
+ auto signedTx = result.payload();
+
+ // txid = "b588f910d7ff03d5fbc3da91f62e48bab47153229c8d1b114b43cb31b9c4d0dd"
+ // witid = "16a17dd8f6e507220010c56c07a8479e3f909f87791683577d4e6aad61ab113a"
+
+ Data serialized;
+ signedTx.encode(true, serialized);
+ ASSERT_EQ(hex(serialized), "01000000"
+ "0001"
+ "01"
+ "0001000000000000000000000000000000000000000000000000000000000000" "00000000" "00" "ffffffff"
+ "01"
+ "e803000000000000" "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac"
+ "02"
+ "483045022100caa585732cfc50226a90834a306d23d5d2ab1e94af2c66136a637e3d9bad3688022069028750908e53a663bb1f434fd655bcc0cf8d394c6fa1fd5a4983790135722e02232103596d3451025c"
+ "19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac"
+ "00000000"
+ );
+}
+
+TEST(BitcoinSigning, SignP2WSH_HashSingle) {
+ // Setup input
+ const auto input = buildInputP2WSH(TWBitcoinSigHashTypeSingle);
+
+ // Sign
+ auto result = TransactionSigner(std::move(input)).sign();
+
+ ASSERT_TRUE(result) << result.error();;
+ auto signedTx = result.payload();
+
+ // txid = "b588f910d7ff03d5fbc3da91f62e48bab47153229c8d1b114b43cb31b9c4d0dd"
+ // witid = "16a17dd8f6e507220010c56c07a8479e3f909f87791683577d4e6aad61ab113a"
+
+ Data serialized;
+ signedTx.encode(true, serialized);
+ ASSERT_EQ(hex(serialized), "01000000"
+ "0001"
+ "01"
+ "0001000000000000000000000000000000000000000000000000000000000000" "00000000" "00" "ffffffff"
+ "01"
+ "e803000000000000" "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac"
+ "02"
+ "47304402201ba80b2c48fe82915297dc9782ae2141e40263001fafd21b02c04a092503f01e0220666d6c63475c6c52abd09371c200ac319bcf4a7c72eb3782e95790f5c847f0b903232103596d3451025c"
+ "19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac"
+ "00000000"
+ );
+}
+
+TEST(BitcoinSigning, SignP2WSH_HashAnyoneCanPay) {
+ // Setup input
+ const auto input = buildInputP2WSH(TWBitcoinSigHashTypeAnyoneCanPay);
+
+ // Sign
+ auto result = TransactionSigner(std::move(input)).sign();
+
+ ASSERT_TRUE(result) << result.error();;
+ auto signedTx = result.payload();
+
+ // txid = "b588f910d7ff03d5fbc3da91f62e48bab47153229c8d1b114b43cb31b9c4d0dd"
+ // witid = "16a17dd8f6e507220010c56c07a8479e3f909f87791683577d4e6aad61ab113a"
+
+ Data serialized;
+ signedTx.encode(true, serialized);
+ ASSERT_EQ(hex(serialized), "01000000"
+ "0001"
+ "01"
+ "0001000000000000000000000000000000000000000000000000000000000000" "00000000" "00" "ffffffff"
+ "01"
+ "e803000000000000" "1976a914769bdff96a02f9135a1d19b749db6a78fe07dc9088ac"
+ "02"
+ "47304402206fc6f499c9b0080dd444b410ca0599b59321e7891fc8e59ab215f6d2995b2e5f0220182466b434e91d14c9d247d3726d3c7f22a2a1cbf6c172314e1155b307f467b080232103596d3451025c"
+ "19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac"
+ "00000000"
+ );
+}
+
TEST(BitcoinSigning, EncodeP2SH_P2WPKH) {
auto unsignedTx = Transaction(1, 0x492);
From b76214dea46c3fbc68619dfe129329e77e187bf3 Mon Sep 17 00:00:00 2001
From: hewig <360470+hewigovens@users.noreply.github.com>
Date: Wed, 6 May 2020 01:20:27 +0800
Subject: [PATCH 16/81] Replace parse_hex with boost::unhex (#944)
* replace parse_hex with boost::unhex
* Add android test
---
.github/workflows/linux-ci.yml | 2 +-
.../ethereum/TestEthereumAddress.kt | 23 +++++++++++++
src/HexCoding.cpp | 21 ------------
src/HexCoding.h | 33 +++++--------------
swift/Tests/Blockchains/EthereumTests.swift | 5 +++
tests/HexCodingTests.cpp | 22 +++++++++++++
walletconsole/lib/CMakeLists.txt | 2 +-
7 files changed, 60 insertions(+), 48 deletions(-)
create mode 100644 android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt
delete mode 100644 src/HexCoding.cpp
create mode 100644 tests/HexCodingTests.cpp
diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml
index 666c0343f1c..e911669998c 100644
--- a/.github/workflows/linux-ci.yml
+++ b/.github/workflows/linux-ci.yml
@@ -32,7 +32,7 @@ jobs:
run: |
tools/generate-files
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE=ON -DBOOST_ROOT=${BOOST_ROOT_1_72_0}
- make -Cbuild
+ make -Cbuild -j12
build/tests/tests tests --gtest_output=xml
env:
CC: /usr/bin/clang
diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt
new file mode 100644
index 00000000000..f4b29c5db5d
--- /dev/null
+++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/ethereum/TestEthereumAddress.kt
@@ -0,0 +1,23 @@
+package com.trustwallet.core.app.blockchains.ethereum
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import wallet.core.jni.AnyAddress
+import wallet.core.jni.CoinType
+import org.junit.Assert.assertFalse
+
+class TestEthereumAddress {
+
+ init {
+ System.loadLibrary("TrustWalletCore")
+ }
+
+ @Test
+ fun testEthereumAddresses() {
+ val any = AnyAddress("0x7d8bf18c7ce84b3e175b339c4ca93aed1dd166f1", CoinType.ETHEREUM)
+ assertEquals(any.coin(), CoinType.ETHEREUM)
+ assertEquals(any.description(), "0x7d8bf18C7cE84b3E175b339c4Ca93aEd1dD166F1")
+
+ assertFalse(AnyAddress.isValid("0xMQqpqMQgCBuiPkoXfgZZsJvuzCeI1zc00z6vHJj4", CoinType.ETHEREUM))
+ }
+}
diff --git a/src/HexCoding.cpp b/src/HexCoding.cpp
deleted file mode 100644
index 03f43d298b3..00000000000
--- a/src/HexCoding.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright © 2017-2020 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.
-
-#include "HexCoding.h"
-
-#include
-
-std::tuple TW::value(uint8_t c) {
- if (c >= '0' && c <= '9')
- return std::make_tuple(c - '0', true);
- if (c >= 'a' && c <= 'z')
- return std::make_tuple(c - 'a' + 10, true);
- if (c >= 'A' && c <= 'Z')
- return std::make_tuple(c - 'A' + 10, true);
-
- // Invalid digit
- return std::make_tuple(0, false);
-}
diff --git a/src/HexCoding.h b/src/HexCoding.h
index 33f9aecd93d..9f6b0561a4c 100644
--- a/src/HexCoding.h
+++ b/src/HexCoding.h
@@ -8,6 +8,8 @@
#include "Data.h"
+#include
+
#include
#include
#include