Fraschetti/18343 - Add contract test for wallet_getDerivedAddresses and move legacy code

Add contract test for wallet_getDerivedAddresses and move legacy code
This commit is contained in:
Flavio Fraschetti 2024-03-12 13:21:23 -03:00 committed by GitHub
parent 0efdea6962
commit 0828e9aa55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 268 additions and 13 deletions

View File

@ -1888,6 +1888,36 @@ void _InitLogging(const FunctionCallbackInfo<Value>& args) {
delete c;
}
void _RestoreAccountAndLogin(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
if (args.Length() != 1) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8Literal(isolate, "Wrong number of arguments for RestoreAccountAndLogin")));
return;
}
// Check the argument types
if (!args[0]->IsString()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8Literal(isolate, "Wrong argument type for 'RestoreAccountAndLogin'")));
return;
}
String::Utf8Value arg0Obj(isolate, args[0]->ToString(context).ToLocalChecked());
char *arg0 = *arg0Obj;
// Call exported Go function, which returns a C string
char *c = RestoreAccountAndLogin(arg0);
Local<String> ret = String::NewFromUtf8(isolate, c).ToLocalChecked();
args.GetReturnValue().Set(ret);
delete c;
}
void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "multiAccountGenerateAndDeriveAddresses", _MultiAccountGenerateAndDeriveAddresses);
@ -1945,6 +1975,7 @@ void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "connectionChange", _ConnectionChange);
NODE_SET_METHOD(exports, "pollSignal", _PollSignal);
NODE_SET_METHOD(exports, "initLogging", _InitLogging);
NODE_SET_METHOD(exports, "restoreAccountAndLogin", _RestoreAccountAndLogin);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, init)

View File

@ -2,7 +2,7 @@
(:require-macros [legacy.status-im.utils.slurp :refer [slurp]])
(:require
[legacy.status-im.fleet.default-fleet :refer (default-fleets)])
(:require [legacy.status-im.utils.test :as utils.test]))
(:require [tests.test-utils :as utils.test]))
;; to generate a js Proxy at js/__STATUS_MOBILE_JS_IDENTITY_PROXY__ that accept any (.xxx) call and
;; return itself

View File

@ -5,7 +5,7 @@
(defmacro with-app-initialized
[& body]
`(do
(legacy.status-im.utils.test/init!)
(tests.test-utils/init!)
(if (test-helpers.integration/app-initialized)
(do ~@body)
(do
@ -22,3 +22,15 @@
(rf-test/wait-for [:messenger-started]
(test-helpers.integration/assert-messenger-started)
~@body))))
(defmacro with-recovered-account
[& body]
`(if (test-helpers.integration/messenger-started)
(do ~@body)
(do
(test-helpers.integration/recover-multiaccount!)
(rf-test/wait-for
[:messenger-started]
(test-helpers.integration/enable-testnet!)
(test-helpers.integration/assert-messenger-started)
~@body))))

View File

@ -5,7 +5,6 @@
legacy.status-im.events
[legacy.status-im.multiaccounts.logout.core :as logout]
legacy.status-im.subs.root
[legacy.status-im.utils.test :as legacy-test]
[native-module.core :as native-module]
[promesa.core :as p]
[re-frame.core :as rf]
@ -15,7 +14,20 @@
status-im.subs.root
[taoensso.timbre :as log]
[tests.integration-test.constants :as constants]
[utils.collection :as collection]))
[tests.test-utils :as test-utils]
[utils.collection :as collection]
[utils.security.core :as security]
[utils.transforms :as transforms]))
(defn validate-mnemonic
[mnemonic on-success on-error]
(native-module/validate-mnemonic
(security/safe-unmask-data mnemonic)
(fn [result]
(let [{:keys [error keyUID]} (transforms/json->clj result)]
(if (seq error)
(when on-error (on-error error))
(on-success mnemonic keyUID))))))
(def default-re-frame-wait-for-timeout-ms
"Controls the maximum time allowed to wait for all events to be processed by
@ -125,7 +137,7 @@
(defn setup-app
[]
(legacy-test/init!)
(test-utils/init!)
(if (app-initialized)
(p/resolved ::app-initialized)
(do
@ -223,3 +235,30 @@
(set! rf.interop/debug-enabled? false))
:after (fn []
(set! rf.interop/debug-enabled? true))})
(defn recover-and-login
[seed-phrase]
(rf/dispatch [:profile.recover/recover-and-login
{:display-name (:name constants/recovery-account)
:seed-phrase seed-phrase
:password constants/password
:color "blue"}]))
(defn enable-testnet!
[]
(rf/dispatch [:profile.settings/profile-update :test-networks-enabled?
true {}])
(rf/dispatch [:wallet/initialize]))
(defn recover-multiaccount!
[]
(let [masked-seed-phrase (security/mask-data (:seed-phrase constants/recovery-account))]
(validate-mnemonic
masked-seed-phrase
(fn [mnemonic key-uid]
(rf/dispatch [:onboarding/seed-phrase-validated
(security/mask-data mnemonic) key-uid])
(rf/dispatch [:pop-to-root :profiles])
(rf/dispatch [:profile/profile-selected key-uid])
(recover-and-login mnemonic))
#())))

View File

@ -5,12 +5,12 @@
legacy.status-im.events
[legacy.status-im.multiaccounts.logout.core :as logout]
legacy.status-im.subs.root
[legacy.status-im.utils.test :as utils.test]
[re-frame.core :as rf]
status-im.events
status-im.navigation.core
status-im.subs.root
[test-helpers.integration :as h]))
[test-helpers.integration :as h]
[tests.test-utils :as utils.test]))
(deftest initialize-app-test
(h/log-headline :initialize-app-test)

View File

@ -5,6 +5,7 @@
legacy.status-im.events
[legacy.status-im.multiaccounts.logout.core :as logout]
legacy.status-im.subs.root
[native-module.core :as native-module]
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
[status-im.constants :as constants]
[status-im.contexts.wallet.data-store :as data-store]
@ -12,7 +13,8 @@
status-im.navigation.core
status-im.subs.root
[test-helpers.integration :as h]
[tests.contract-test.utils :as contract-utils]))
[tests.contract-test.utils :as contract-utils]
[tests.integration-test.constants :as integration-constants]))
(defn assert-accounts-get-accounts
[result]
@ -84,3 +86,31 @@
(h/logout)
(rf-test/wait-for
[::logout/logout-method])))))
(defn get-main-account
[accounts]
(:address (first accounts)))
(def test-password integration-constants/password)
(defn assert-derived-account
[response]
(is (= (:address response) (:address response)))
(is (= (:public-key response) (:public-key response)))
(is (= "m/43'/60'/1581'/0'/0" (:path (first response)))))
(deftest wallet-get-derived-addressess-contract
(h/log-headline :wallet/create-derived-addresses)
(rf-test/run-test-async
(h/with-app-initialized
(h/with-recovered-account
(let [sha3-pwd (native-module/sha3 test-password)
derivation-path ["m/43'/60'/1581'/0'/0"]
main-account (contract-utils/call-rpc-endpoint
{:rpc-endpoint "accounts_getAccounts"
:action get-main-account})]
(contract-utils/call-rpc-endpoint
{:rpc-endpoint "wallet_getDerivedAddresses"
:params [sha3-pwd main-account derivation-path]
:action assert-derived-account}))))))

View File

@ -5,3 +5,10 @@
(def community {:membership 1 :name "foo" :description "bar"})
(def account-name "account-abc")
(def recovery-account
{:name "wallet-abc"
:seed-phrase "destroy end torch puzzle develop note wise island disease chaos kind bus"
:key-uid "0x6827f3d1e21ae723a24e0dcbac1853b5ed4d651c821a2326492ce8f2367ec905"
:public-key "0x48b8b9e2a8f71e1beae729d83bcd385ffc6af0d5"
:main-account "0x48b8b9e2a8f71e1beae729d83bcd385ffc6af0d5"})

View File

@ -4,19 +4,19 @@
legacy.status-im.events
[legacy.status-im.multiaccounts.logout.core :as logout]
legacy.status-im.subs.root
[legacy.status-im.utils.test :as utils.test]
[promesa.core :as p]
[re-frame.core :as rf]
status-im.events
status-im.navigation.core
status-im.subs.root
[test-helpers.integration :as h]))
[test-helpers.integration :as h]
[tests.test-utils :as test-utils]))
(deftest initialize-app-test
(h/integration-test ::initialize-app
(fn []
(p/do
(utils.test/init!)
(test-utils/init!)
(rf/dispatch [:app-started])
;; Use initialize-view because it has the longest avg. time and is
;; dispatched by initialize-multiaccounts (last non-view event).

View File

@ -1,10 +1,10 @@
(ns tests.integration-test.profile-test
(:require
[cljs.test :refer [deftest is use-fixtures]]
[legacy.status-im.utils.test :as utils.test]
[promesa.core :as p]
[status-im.contexts.profile.utils :as profile.utils]
[test-helpers.integration :as h]
[tests.test-utils :as test-utils]
[utils.re-frame :as rf]))
(use-fixtures :each (h/fixture-session))
@ -24,7 +24,7 @@
(h/integration-test ::edit-profile-picture
(fn []
(let [mock-image "resources/images/mock2/monkey.png"
absolute-path (.resolve utils.test/path mock-image)]
absolute-path (.resolve test-utils/path mock-image)]
(p/do
(rf/dispatch [:profile/edit-picture absolute-path 80 80])
(h/wait-for [:profile/update-local-picture :toasts/upsert])

136
src/tests/test_utils.cljs Normal file
View File

@ -0,0 +1,136 @@
(ns tests.test-utils
(:require
[legacy.status-im.utils.deprecated-types :as types]
[re-frame.core :as re-frame]))
(def native-status (js/require "../../modules/react-native-status/nodejs/bindings"))
(def fs (js/require "fs"))
(def path (js/require "path"))
(def os (js/require "os"))
(def tmpdir (.tmpdir os))
(def test-dir-prefix (.join path tmpdir "status-mobile-tests"))
(def test-dir (.mkdtempSync fs test-dir-prefix))
(def initialized? (atom false))
(defn signal-received-callback
[a]
(re-frame/dispatch [:signals/signal-received a]))
;; We poll for signals, could not get callback working
(defn init!
[]
(when-not @initialized?
(.setSignalEventCallback native-status)
(reset! initialized? true)
(js/setInterval (fn []
(.pollSignal native-status signal-received-callback)
100))))
(def ui-helper
(clj->js
{:clearCookies identity
:clearStorageAPIs identity}))
(def encryption-utils
(clj->js
{:sha3
(fn [s] (.sha3 native-status s))
:setBlankPreviewFlag
identity
:encodeTransfer
(fn [to-norm amount-hex]
(.encodeTransfer native-status to-norm amount-hex))
:hexToNumber
(fn [hex] (.hexToNumber native-status hex))
:decodeParameters
(fn [decode-param-json]
(.decodeParameters native-status decode-param-json))
:numberToHex
(fn [num-str] (.numberToHex native-status num-str))
:initKeystore
(fn [key-uid callback]
(callback (.initKeystore native-status
(str test-dir "/keystore/" key-uid))))
:multiformatDeserializePublicKey
(fn [public-key deserialization-key callback]
(callback (.multiformatDeserializePublicKey
native-status
public-key
deserialization-key)))}))
(def account-manager
(clj->js
{:openAccounts
(fn [callback]
(callback (.openAccounts native-status test-dir)))
:createAccountAndLogin
(fn [request] (.createAccountAndLogin native-status request))
:restoreAccountAndLogin
(fn [request]
(prn native-status)
(.restoreAccountAndLogin native-status request))
:loginAccount
(fn [request] (.loginAccount native-status request))
:logout
(fn [] (.logout native-status))
:multiAccountImportMnemonic
(fn [json callback]
(callback (.multiAccountImportMnemonic native-status json)))
:multiAccountLoadAccount
(fn [json callback]
(callback (.multiAccountLoadAccount native-status json)))
:multiAccountDeriveAddresses
(fn [json callback]
(callback (.multiAccountDeriveAddresses native-status json)))
:multiAccountGenerateAndDeriveAddresses
(fn [json callback]
(callback (.multiAccountGenerateAndDeriveAddresses native-status json)))
:multiAccountStoreDerived
(fn [json callback]
(callback (.multiAccountStoreDerivedAccounts native-status json)))}))
(def utils
(clj->js
{:backupDisabledDataDir
(fn [] (str test-dir "/backup"))
:keystoreDir (fn [] "")
:toChecksumAddress
(fn [address] (.toChecksumAddress native-status address))
:checkAddressChecksum
(fn [address] (.checkAddressChecksum native-status address))
:validateMnemonic
(fn [json callback] (callback (.validateMnemonic native-status json)))
:isAddress
(fn [address] (.isAddress native-status address))}))
(def log-manager
(clj->js
{:logFileDirectory
(fn [] (str test-dir "/log"))
:initLogging
(fn [enabled mobile-system log-level callback]
(callback (.initLogging native-status
(types/clj->json {:Enabled enabled
:MobileSystem mobile-system
:Level log-level
:File (str test-dir "/geth.log")}))))}))
(def network
(clj->js
{:callPrivateRPC
(fn [payload callback]
(callback (.callPrivateRPC native-status payload)))}))
(def status
(clj->js
{:getNodeConfig
(fn [] (types/clj->json {:WakuV2Config ""}))
:fleets
(fn [] (.fleets native-status))
:startLocalNotifications
identity}))