Updated on 2026-08-14
This commit is contained in:
commit
0470e1f010
1144 changed files with 48463 additions and 11166 deletions
320
.claude/skills/cleanup-feature-toggles/SKILL.md
Normal file
320
.claude/skills/cleanup-feature-toggles/SKILL.md
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
---
|
||||
name: cleanup-feature-toggles
|
||||
description: Remove released feature toggles (version <= target) — deletes from config, removes toggle properties, inlines `true` in calling code, removes dead branches. CI-safe, no prompts.
|
||||
allowed-tools: Read, Grep, Glob, Bash, Edit, Write, Agent
|
||||
argument-hint: <version> [--dry-run] [--only <TOGGLE_NAME>]
|
||||
---
|
||||
|
||||
Remove all feature toggles whose version is less than or equal to the target release version.
|
||||
|
||||
**CRITICAL: This skill runs on CI. NEVER ask questions. If anything is ambiguous, make the safer choice or skip the toggle.**
|
||||
|
||||
## Constants
|
||||
|
||||
- **Config file**: `core/config-toggles/src/main/assets/configs/feature_toggles_config.json`
|
||||
- **Generated enum** (DO NOT edit): `core/config-toggles/build/generated/source/toggles/com/tangem/core/configtoggle/FeatureToggles.kt`
|
||||
- **Dry-run mode**: check if `$ARGUMENTS` contains `--dry-run`. In dry-run mode, make NO file changes — only output what WOULD be removed (including affected files and usage sites).
|
||||
- **Version**: extract the version number from `$ARGUMENTS` (e.g., `5.35`, `5.35.0`). The version is the first argument that matches a semver-like pattern (`X.Y` or `X.Y.Z`).
|
||||
- **Only mode**: check if `$ARGUMENTS` contains `--only <TOGGLE_NAME>`. If present, process ONLY the specified toggle (it must still satisfy the version check). Multiple `--only` flags can be provided.
|
||||
|
||||
## Phase 0: Preflight Checks
|
||||
|
||||
### 0a. Parse Arguments
|
||||
|
||||
Extract `<version>`, optional `--dry-run`, and optional `--only <TOGGLE_NAME>` (repeatable) from `$ARGUMENTS`.
|
||||
|
||||
- If no version found: STOP with `FATAL: No version provided. Usage: /cleanup-feature-toggles <version> [--dry-run] [--only <TOGGLE_NAME>]`
|
||||
- Validate version matches pattern `\d+\.\d+(\.\d+)?` — if not, STOP with `FATAL: Invalid version format.`
|
||||
- Normalize version: if only `X.Y` is given, treat as `X.Y.0` for comparison.
|
||||
- If `--only` flags are present, collect the toggle names into a filter list.
|
||||
|
||||
### 0b. Verify Git State
|
||||
|
||||
```bash
|
||||
git status --porcelain 2>&1
|
||||
```
|
||||
- If output is empty (clean working tree) — OK.
|
||||
- If there are uncommitted changes — STOP with: `FATAL: Working tree is not clean. Commit or stash changes before running this skill.`
|
||||
|
||||
Initialize an internal results list to track each toggle's outcome.
|
||||
|
||||
## Phase 1: Identify Toggles to Remove
|
||||
|
||||
1. Read `core/config-toggles/src/main/assets/configs/feature_toggles_config.json`.
|
||||
2. For each toggle entry in the JSON array:
|
||||
- If `version == "undefined"` → skip (unreleased feature, must not be removed).
|
||||
- Parse the toggle's version as semver (normalize `X.Y` to `X.Y.0`).
|
||||
- If toggle version **<=** target version → mark for removal.
|
||||
3. If `--only` filter is active: keep only toggles whose `name` matches one of the `--only` values. If a `--only` toggle doesn't satisfy the version check, output a warning but still skip it.
|
||||
4. Output the list of toggles marked for removal with their versions.
|
||||
5. If no toggles match → output `No toggles to remove for version <version>` and stop.
|
||||
6. If `--dry-run` mode → proceed to Phase 2 (research only, all toggles in parallel), then skip to Phase 7 to output the detailed summary. Do NOT make any file changes.
|
||||
|
||||
## Phase 2: Research (parallel)
|
||||
|
||||
Collect all information about all toggles **in parallel** before making any edits. Launch one `Agent` per toggle (all in a single message so they run concurrently). Each agent receives the toggle name and must return a structured report.
|
||||
|
||||
**Error handling rule**: if research fails for a toggle, record the failure reason and continue. Do NOT stop processing.
|
||||
|
||||
### Per-toggle research task (runs inside each Agent)
|
||||
|
||||
Each Agent performs the following read-only searches and returns a structured report:
|
||||
|
||||
#### 2a. Find the toggle property declaration and direct usages
|
||||
|
||||
Use `Grep` to search for `FeatureToggles.<TOGGLE_NAME>` (e.g., `FeatureToggles.WALLET_REORDER_FEATURE_ENABLED`) across the **entire** codebase.
|
||||
|
||||
This will find:
|
||||
1. **`DefaultXxxFeatureToggles` property** — the standard wrapper. Extract:
|
||||
- The **property name** (e.g., `isWalletReorderFeatureEnabled`)
|
||||
- The **DefaultXxxFeatureToggles file path**
|
||||
- The **XxxFeatureToggles interface name** (from the class's supertype)
|
||||
2. **Direct `FeatureTogglesManager.isFeatureEnabled()` calls** — code that bypasses the wrapper and calls the manager directly. These are additional usage sites.
|
||||
|
||||
Also find the interface file:
|
||||
- Use `Glob` to find the `XxxFeatureToggles.kt` file in `features/*/api/` or `core/*/`
|
||||
|
||||
Check if the toggle property or the `DefaultXxxFeatureToggles` class has **comments referencing additional cleanup** (e.g., `// Remove GiveTxPermissionBottomSheet and all dependencies with this toggle`). If found, record the comment text.
|
||||
|
||||
If the toggle reference is not found anywhere: report as `Skipped (no property found)`.
|
||||
|
||||
#### 2b. Find `@RemoveWithToggle` annotated code
|
||||
|
||||
Use `Grep` to search for `RemoveWithToggle` (without `@` or package prefix) across the entire codebase (excluding the annotation definition itself). Then filter matches to only those where the `toggleName` argument equals the current toggle name.
|
||||
|
||||
The annotation is defined in `core/utils/src/main/java/com/tangem/utils/annotations/RemoveWithToggle.kt` (`com.tangem.utils.annotations.RemoveWithToggle`). It has two parameters: `toggleName: String` (the toggle name) and `description: String` (optional hint).
|
||||
|
||||
Support all Kotlin annotation forms:
|
||||
- `@RemoveWithToggle("TOGGLE_NAME")`
|
||||
- `@RemoveWithToggle(toggleName = "TOGGLE_NAME")`
|
||||
- `@com.tangem.utils.annotations.RemoveWithToggle("TOGGLE_NAME")`
|
||||
- `@com.tangem.utils.annotations.RemoveWithToggle(toggleName = "TOGGLE_NAME")`
|
||||
|
||||
For each filtered match, record:
|
||||
- The file path and line number
|
||||
- The annotated element name (class, function, property)
|
||||
- The `description` value if present
|
||||
|
||||
#### 2c. Find all usages of the property in calling code
|
||||
|
||||
Use `Grep` to search for the property name (e.g., `isWalletReorderFeatureEnabled`) across the entire codebase.
|
||||
|
||||
Categorize results:
|
||||
- **Interface declaration** — the `val isX: Boolean` in `XxxFeatureToggles.kt`
|
||||
- **Implementation** — the `override val isX` in `DefaultXxxFeatureToggles.kt`
|
||||
- **Calling code** — any other file that reads `*.isX` (include file path, line number, and the matched line content)
|
||||
|
||||
#### Agent report format
|
||||
|
||||
Each Agent must return a report with:
|
||||
- Toggle name
|
||||
- Property name (e.g., `isWalletReorderFeatureEnabled`) or `null` if not found
|
||||
- Interface name and file path
|
||||
- Implementation file path
|
||||
- List of calling code sites: `[{file, line, content}]`
|
||||
- List of direct `FeatureTogglesManager` usage sites: `[{file, line, content}]`
|
||||
- List of `@RemoveWithToggle` sites: `[{file, line, element, description}]`
|
||||
- Cleanup comments (if any)
|
||||
- Status: `ready` or `skipped (reason)`
|
||||
|
||||
### After all Agents complete
|
||||
|
||||
Collect all reports. If `--dry-run` → skip to Phase 6 with the collected data.
|
||||
|
||||
## Phase 3: Edit (sequential)
|
||||
|
||||
Process each toggle **sequentially** using the research data from Phase 2. Only toggles with status `ready` are processed.
|
||||
|
||||
**Error handling rule**: if ANY step fails for a toggle, record the failure reason and continue to the next toggle. Do NOT stop processing.
|
||||
|
||||
### Step 3a: Replace usages in calling code with `true` and simplify
|
||||
|
||||
For each calling code usage site (from Phase 2 report), `Read` the surrounding context (at least 20 lines around the usage) and apply the appropriate simplification:
|
||||
|
||||
| Pattern | Simplification |
|
||||
|---------|---------------|
|
||||
| `if (toggles.isX) { body }` | Remove `if`, keep `body` (unindent) |
|
||||
| `if (toggles.isX) { A } else { B }` | Keep only `A`, remove if/else structure |
|
||||
| `if (!toggles.isX) { body }` | Remove entire if-block |
|
||||
| `if (!toggles.isX) { A } else { B }` | Keep only `B`, remove if/else structure |
|
||||
| `toggles.isX && expr` | Replace with `expr` |
|
||||
| `expr && toggles.isX` | Replace with `expr` |
|
||||
| `toggles.isX \|\| expr` | Replace with `true` (or simplify enclosing condition since it's always true) |
|
||||
| `val x = toggles.isX` | Replace with `val x = true`, then check if `x` is used in one of the patterns above and simplify transitively |
|
||||
| `property = toggles.isX` | Replace with `property = true` |
|
||||
| `when { toggles.isX -> A; else -> B }` | Keep only `A`, remove the `when` structure |
|
||||
| `when { !toggles.isX -> A; else -> B }` | Keep only `B`, remove the `when` structure |
|
||||
| `when(value) { ... }` with toggle in a branch condition | Evaluate the toggle to `true`, simplify the `when` accordingly |
|
||||
| Complex boolean expression | Replace `toggles.isX` with `true` and algebraically simplify |
|
||||
|
||||
Also process any direct `FeatureTogglesManager.isFeatureEnabled()` call sites the same way (replace with `true` and simplify).
|
||||
|
||||
**After replacing**, check if the file still references the `XxxFeatureToggles` type:
|
||||
- If not → remove the import of `XxxFeatureToggles`
|
||||
- If the type was a constructor/inject parameter and is no longer used → remove the parameter and any `@Inject`/`@Assisted` annotations associated with it
|
||||
- If removing a constructor parameter from a Decompose Model or Component, also remove it from the caller that creates the instance
|
||||
|
||||
**Important**: Use `Edit` for precise changes. Read enough context to make correct edits. Do NOT accidentally delete unrelated code.
|
||||
|
||||
### Step 3b: Remove the property from interface and implementation
|
||||
|
||||
1. **In `XxxFeatureToggles` interface**: remove the `val isPropertyName: Boolean` line.
|
||||
2. **In `DefaultXxxFeatureToggles`**: remove the `override val isPropertyName: Boolean` property (including the `get() = ...` line).
|
||||
3. Check if `DefaultXxxFeatureToggles` still has other properties:
|
||||
- If **yes** → done with this toggle.
|
||||
- If **no** (all properties removed) → the interface and implementation are now empty. Check the **protected list** below — if the interface is protected, keep it and skip deletion. Otherwise, delete them:
|
||||
|
||||
**Protected interfaces (never delete even if empty):**
|
||||
- `TokensFeatureToggles`
|
||||
- `BlockchainSDKFeatureToggles`
|
||||
- `StakingFeatureToggles`
|
||||
- `CardSdkFeatureToggles`
|
||||
- `TangemPayFeatureToggles`
|
||||
- `SwapFeatureToggles`
|
||||
- `SendFeatureToggles`
|
||||
|
||||
If the interface is **protected**: remove the `featureTogglesManager` / `featureToggles` constructor parameter from `DefaultXxxFeatureToggles`, remove unused imports (`FeatureTogglesManager`, `FeatureToggles`), but keep both files.
|
||||
|
||||
If the interface is **not protected** → delete them:
|
||||
1. Delete the `XxxFeatureToggles` interface file.
|
||||
2. Delete the `DefaultXxxFeatureToggles` implementation file.
|
||||
3. Find and remove the Hilt binding for this interface (typically a `@Binds` method in a `*FeatureTogglesModule` or similar Hilt module). If the Hilt module has no remaining bindings after removal, delete the module file as well.
|
||||
4. Use `Grep` to find all remaining references to `XxxFeatureToggles` and `DefaultXxxFeatureToggles` across the codebase. For each reference:
|
||||
- **Constructor/inject parameter** → remove the parameter. If the surrounding class/function no longer uses any feature toggles, cascade the removal to its callers.
|
||||
- **Import statement** → remove it.
|
||||
- **Any other reference** → assess and remove or update as needed.
|
||||
|
||||
Record status as `Removed` with the count of usage sites simplified.
|
||||
|
||||
## Phase 4: Update JSON Config
|
||||
|
||||
1. Read `feature_toggles_config.json`.
|
||||
2. Remove all entries whose `name` matches a successfully removed toggle (status = `Removed`).
|
||||
3. Write back the JSON with proper formatting:
|
||||
- 2-space indentation
|
||||
- Each entry on its own lines
|
||||
- No trailing commas
|
||||
- Match the existing file format exactly
|
||||
|
||||
## Phase 5: Build, Test & Lint Verification
|
||||
|
||||
Run all verification tasks in a **single Gradle invocation** to avoid repeated cold starts:
|
||||
|
||||
### 5a. Build + Tests + Detekt
|
||||
|
||||
```bash
|
||||
./gradlew assembleGoogleDebug unitTest detekt detektMain :app:assembleGoogleMocked :app:assembleGoogleMockedAndroidTest
|
||||
```
|
||||
|
||||
- If the command **fails**:
|
||||
- Read the error output to determine which task failed.
|
||||
- **Compilation error** (`assembleGoogleDebug` or `assembleGoogleMocked`): attempt to fix (one retry — usually missing import removal or unused parameter). If still fails: revert all changes with `git checkout -- .` and output `FATAL: Build failed after cleanup. All changes reverted.` with the error details.
|
||||
- **Unit test failure**: attempt to fix (one retry). If still fails: output the failures as warnings in the summary but do NOT revert.
|
||||
- **Detekt violation**: attempt to fix (one retry — usually unused imports or parameters). If still fails: output the violations as warnings in the summary.
|
||||
- **UI test compilation failure**: attempt to fix (one retry). If still fails: output the failures as warnings in the summary.
|
||||
- After fixing, re-run the **full command** to verify everything passes together.
|
||||
|
||||
## Phase 6: Branch, Commit, Push & PR
|
||||
|
||||
Skip this phase entirely in `--dry-run` mode.
|
||||
|
||||
### 6a. Create Branch and Commit
|
||||
|
||||
```bash
|
||||
git checkout -b tech/cleanup-toggles-<version>
|
||||
git add -A
|
||||
git commit -m "[Tech] Remove feature toggles <= <version>"
|
||||
```
|
||||
|
||||
Replace `<version>` with the target version (e.g., `tech/cleanup-toggles-5.35`).
|
||||
|
||||
### 6b. Push
|
||||
|
||||
```bash
|
||||
git push -u origin tech/cleanup-toggles-<version>
|
||||
```
|
||||
|
||||
### 6c. Create Pull Request
|
||||
|
||||
Use `gh pr create` targeting `develop`:
|
||||
|
||||
```bash
|
||||
gh pr create --base develop --title "Remove feature toggles <= <version>" --body "$(cat <<'EOF'
|
||||
## Summary
|
||||
|
||||
Automated cleanup of feature toggles that are permanently enabled (version <= <version>).
|
||||
|
||||
### Removed toggles
|
||||
|
||||
- `TOGGLE_NAME_1` (version)
|
||||
- `TOGGLE_NAME_2` (version)
|
||||
- ...
|
||||
|
||||
### Manual review required
|
||||
|
||||
<List all @RemoveWithToggle-annotated elements found in Phase 2 research (file path, element name, description) and any cleanup comments. If none found, write "None">
|
||||
|
||||
## Test plan
|
||||
|
||||
- [x] `assembleGoogleDebug` passes
|
||||
- [x] `unitTest` passes
|
||||
- [x] `detekt detektMain` passes
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
Output the PR URL.
|
||||
|
||||
## Phase 7: Output Summary
|
||||
|
||||
Output results as a Markdown table:
|
||||
|
||||
```markdown
|
||||
## Feature Toggle Cleanup Summary
|
||||
|
||||
| Toggle | Version | Interface | Usages Simplified | Status |
|
||||
|--------|---------|-----------|-------------------|--------|
|
||||
| WALLET_REORDER_FEATURE_ENABLED | 5.34 | WalletFeatureToggles | 3 | Removed |
|
||||
| EARN_BLOCK_ENABLED | 5.35 | EarnFeatureToggles | 1 | Removed |
|
||||
| SOME_TOGGLE | 5.33 | SomeFeatureToggles | — | Skipped (no property found) |
|
||||
|
||||
**Total:** X toggles processed, Y removed, Z skipped/failed
|
||||
**Target version:** <version>
|
||||
```
|
||||
|
||||
### Manual Review Hints
|
||||
|
||||
If any toggle had a comment referencing additional cleanup (found in Phase 2 research), output a separate section:
|
||||
|
||||
```markdown
|
||||
### Manual Review Required
|
||||
|
||||
- **GASLESS_APPROVAL_ENABLED**: `// Remove GiveTxPermissionBottomSheet and all dependencies with this toggle`
|
||||
- **OTHER_TOGGLE**: `// Also remove legacy FooBar component`
|
||||
```
|
||||
|
||||
### Dry-run mode output
|
||||
|
||||
In `--dry-run` mode: prepend `[DRY RUN]` to the header, set all statuses to `Would remove`, and add a detailed section per toggle:
|
||||
|
||||
```markdown
|
||||
### WALLET_REORDER_FEATURE_ENABLED (5.34) — Would remove
|
||||
|
||||
**Property:** `WalletFeatureToggles.isWalletReorderFeatureEnabled`
|
||||
**Files affected:**
|
||||
- `features/details/impl/.../UserWalletListModel.kt:42` — `walletFeatureToggles.isWalletReorderFeatureEnabled && userWallets.size > 1`
|
||||
- `features/wallet/impl/.../SomeOtherFile.kt:88` — `if (walletFeatureToggles.isWalletReorderFeatureEnabled)`
|
||||
```
|
||||
|
||||
### Warnings
|
||||
|
||||
If unit tests or detekt failed after fix attempts, list the remaining issues:
|
||||
|
||||
```markdown
|
||||
### Warnings
|
||||
|
||||
- **Unit test failure:** `:features:wallet:impl:testDebugUnitTest` — WalletModelTest.someTest (may need manual update)
|
||||
- **Detekt violation:** UnusedPrivateMember in `SomeFile.kt:15`
|
||||
```
|
||||
|
|
@ -161,7 +161,7 @@ dependencies {
|
|||
implementation(projects.domain.hotWallet)
|
||||
implementation(projects.domain.news)
|
||||
implementation(projects.domain.earn)
|
||||
implementation(projects.domain.tokensync)
|
||||
implementation(projects.domain.assetsdiscovery)
|
||||
implementation(projects.domain.search)
|
||||
|
||||
implementation(projects.common)
|
||||
|
|
@ -192,7 +192,7 @@ dependencies {
|
|||
implementation(projects.data.common)
|
||||
implementation(projects.data.settings)
|
||||
implementation(projects.data.tokens)
|
||||
implementation(projects.data.tokensync)
|
||||
implementation(projects.data.assetsdiscovery)
|
||||
implementation(projects.data.txhistory)
|
||||
implementation(projects.data.wallets)
|
||||
implementation(projects.data.analytics)
|
||||
|
|
@ -274,6 +274,8 @@ dependencies {
|
|||
implementation(projects.features.nft.impl)
|
||||
implementation(projects.features.walletconnect.api)
|
||||
implementation(projects.features.walletconnect.impl)
|
||||
implementation(projects.features.commonFeatures.api)
|
||||
implementation(projects.features.commonFeatures.impl)
|
||||
implementation(projects.features.usedesk.api)
|
||||
implementation(projects.features.usedesk.impl)
|
||||
implementation(projects.features.hotWallet.api)
|
||||
|
|
@ -392,7 +394,6 @@ dependencies {
|
|||
implementation(deps.viewBindingDelegate)
|
||||
implementation(deps.armadillo)
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.reKotlin)
|
||||
implementation(deps.reownCore)
|
||||
implementation(deps.reownWeb3)
|
||||
implementation(deps.prettyLogger)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -8,6 +8,8 @@ import androidx.test.core.app.ActivityScenario
|
|||
import androidx.test.espresso.intent.Intents
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import com.kaspersky.components.alluresupport.interceptors.step.ScreenshotStepInterceptor
|
||||
import com.kaspersky.components.alluresupport.withForcedAllureSupport
|
||||
import com.kaspersky.components.composesupport.config.addComposeSupport
|
||||
|
|
@ -20,13 +22,14 @@ import com.tangem.common.rules.ApiEnvironmentRule
|
|||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.walletmanager.WalletManagersStore
|
||||
import com.tangem.datasource.utils.WireMockRedirectInterceptor
|
||||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.promo.models.PromoId
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.tap.MainActivity
|
||||
import dagger.hilt.android.testing.HiltAndroidRule
|
||||
import io.qameta.allure.kotlin.Allure
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.RuleChain
|
||||
import org.junit.rules.TestRule
|
||||
|
|
@ -58,6 +61,12 @@ abstract class BaseTestCase : TestCase(
|
|||
@Inject
|
||||
lateinit var promoRepository: PromoRepository
|
||||
|
||||
@Inject
|
||||
lateinit var walletManagersStore: WalletManagersStore
|
||||
|
||||
@Inject
|
||||
lateinit var getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase
|
||||
|
||||
private val hiltRule = HiltAndroidRule(this)
|
||||
private val apiEnvironmentRule = ApiEnvironmentRule()
|
||||
private val permissionRule = GrantPermissionRule.grant(
|
||||
|
|
@ -72,7 +81,11 @@ abstract class BaseTestCase : TestCase(
|
|||
|
||||
private val semanticTreePrinterRule = object : TestWatcher() {
|
||||
override fun failed(e: Throwable?, description: Description?) {
|
||||
runCatching { printAllRoots() }
|
||||
runCatching {
|
||||
runBlocking {
|
||||
withTimeoutOrNull(SEMANTIC_TREE_PRINT_TIMEOUT_MS) { printAllRoots() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,5 +187,6 @@ abstract class BaseTestCase : TestCase(
|
|||
|
||||
private companion object {
|
||||
const val WIREMOCK_BASE_URL_ARG = "wiremockBaseUrl"
|
||||
const val SEMANTIC_TREE_PRINT_TIMEOUT_MS = 5_000L
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ object TestConstants {
|
|||
|
||||
const val WAIT_UNTIL_TIMEOUT = 20_000L
|
||||
const val WAIT_UNTIL_TIMEOUT_LONG = 30_000L
|
||||
const val WAIT_UNTIL_TIMEOUT_VERY_LONG = 60_000L
|
||||
|
||||
const val MARKETS_MAIN_NETWORK_SUFFIX = "MAIN"
|
||||
|
||||
|
|
@ -42,5 +43,16 @@ object TestConstants {
|
|||
const val ALLURE_LABEL_VALUE = "Kaspresso"
|
||||
|
||||
const val USER_TOKENS_API_SCENARIO = "user_tokens_api"
|
||||
const val REFERRAL_API_SCENARIO = "referral_api"
|
||||
const val QUOTES_API_SCENARIO = "quotes_api"
|
||||
|
||||
const val SEED_PHRASE_12 = "they cram join fantasy unfair observe true theory buffalo bus exchange walk"
|
||||
const val SEED_PHRASE_15 = "genuine try deer upset connect sausage diary rule price shallow fit faculty leopard " +
|
||||
"hawk when"
|
||||
const val SEED_PHRASE_18 = "crush idle include refuse expose kiss slot budget uphold when dinner certain holiday " +
|
||||
"slow word armor butter suffer"
|
||||
const val SEED_PHRASE_21 = "employ space oval venue wash clog zebra cover icon wash assist word debris inform " +
|
||||
"cable meadow add game meat rigid pride"
|
||||
const val SEED_PHRASE_24 = "force visit fresh brown razor target ill scissors figure cave feel genre cargo category " +
|
||||
"bread much nature basic fun iron benefit egg error prosper"
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package com.tangem.common.utils
|
||||
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
/**
|
||||
* Compares addresses from the app (clipboard JSON) with reference addresses from the QA tools API.
|
||||
*
|
||||
* Both JSON arrays contain objects with fields: blockchain, derivationPath, token (nullable), addresses (array).
|
||||
* Comparison normalizes and sorts both arrays before diffing.
|
||||
*/
|
||||
object AddressComparisonHelper {
|
||||
|
||||
fun compareAddresses(appJson: String, apiJson: String) {
|
||||
val appEntries = parseAndNormalize(appJson)
|
||||
val apiEntries = parseAndNormalize(apiJson)
|
||||
|
||||
val missingInApp = apiEntries - appEntries.toSet()
|
||||
val extraInApp = appEntries - apiEntries.toSet()
|
||||
|
||||
if (missingInApp.isEmpty() && extraInApp.isEmpty()) {
|
||||
TangemLogger.i("Address comparison passed: ${appEntries.size} entries match")
|
||||
return
|
||||
}
|
||||
|
||||
val report = buildString {
|
||||
appendLine("Address comparison FAILED")
|
||||
if (missingInApp.isNotEmpty()) {
|
||||
appendLine("\nMissing in app (expected from API but not found):")
|
||||
missingInApp.forEach { appendLine(" - $it") }
|
||||
}
|
||||
if (extraInApp.isNotEmpty()) {
|
||||
appendLine("\nExtra in app (found in app but not in API):")
|
||||
extraInApp.forEach { appendLine(" - $it") }
|
||||
}
|
||||
appendLine("\nApp entries: ${appEntries.size}, API entries: ${apiEntries.size}")
|
||||
}
|
||||
|
||||
TangemLogger.e(report)
|
||||
assertTrue(report, false)
|
||||
}
|
||||
|
||||
private fun parseAndNormalize(json: String): List<AddressEntry> {
|
||||
val array = JSONArray(json)
|
||||
val entries = mutableListOf<AddressEntry>()
|
||||
|
||||
for (i in 0 until array.length()) {
|
||||
val obj = array.getJSONObject(i)
|
||||
entries.add(
|
||||
AddressEntry(
|
||||
blockchain = normalizeBlockchainName(obj.getString("blockchain")),
|
||||
derivationPath = obj.getString("derivationPath").trim(),
|
||||
token = obj.optString("token", null)?.trim()?.lowercase(),
|
||||
addresses = parseAddresses(obj).sorted(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return entries.sortedWith(
|
||||
compareBy<AddressEntry> { it.blockchain }
|
||||
.thenBy { it.derivationPath }
|
||||
.thenBy { it.token },
|
||||
)
|
||||
}
|
||||
|
||||
private val blockchainNameOverrides = mapOf(
|
||||
"chia network" to "chia",
|
||||
)
|
||||
|
||||
private fun normalizeBlockchainName(name: String): String {
|
||||
val normalized = name.trim().lowercase()
|
||||
return blockchainNameOverrides[normalized] ?: normalized
|
||||
}
|
||||
|
||||
private fun parseAddresses(obj: JSONObject): List<String> {
|
||||
val addressesArray = obj.getJSONArray("addresses")
|
||||
return (0 until addressesArray.length()).map { addressesArray.getString(it) }
|
||||
}
|
||||
|
||||
private data class AddressEntry(
|
||||
val blockchain: String,
|
||||
val derivationPath: String,
|
||||
val token: String?,
|
||||
val addresses: List<String>,
|
||||
)
|
||||
}
|
||||
|
|
@ -16,10 +16,10 @@ fun getWcUri(
|
|||
TangemLogger.i("Getting WC URI for network: $network")
|
||||
|
||||
val client = OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS) // Таймаут подключения
|
||||
.readTimeout(60, TimeUnit.SECONDS) // Таймаут чтения ответа
|
||||
.writeTimeout(30, TimeUnit.SECONDS) // Таймаут записи
|
||||
.callTimeout(90, TimeUnit.SECONDS) // Общий таймаут запроса
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.callTimeout(90, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
|
|
@ -58,6 +58,59 @@ fun getWcUri(
|
|||
}
|
||||
}
|
||||
|
||||
fun getAddressesFromApi(
|
||||
seedKey: String,
|
||||
baseUrl: String = "[REDACTED_ENV_URL]",
|
||||
): String? {
|
||||
TangemLogger.i("Getting addresses for seed key: $seedKey")
|
||||
|
||||
val client = OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.callTimeout(90, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url("$baseUrl/addresses")
|
||||
.get()
|
||||
.build()
|
||||
|
||||
return try {
|
||||
client.newCall(request).execute().use { response ->
|
||||
TangemLogger.i("Response code: ${response.code}")
|
||||
|
||||
if (response.isSuccessful) {
|
||||
val body = response.body?.string() ?: ""
|
||||
|
||||
val contentType = response.header("Content-Type") ?: ""
|
||||
if (!contentType.contains("application/json") && !body.trimStart().startsWith("{")) {
|
||||
TangemLogger.e("Unexpected response (not JSON), Content-Type: $contentType, body: $body")
|
||||
return null
|
||||
}
|
||||
|
||||
val jsonObject = JSONObject(body)
|
||||
val data = jsonObject.optJSONObject("data") ?: jsonObject
|
||||
val seedData = data.optJSONArray(seedKey)
|
||||
|
||||
if (seedData != null) {
|
||||
TangemLogger.i("Got addresses for $seedKey: ${seedData.length()} entries")
|
||||
seedData.toString()
|
||||
} else {
|
||||
TangemLogger.e("No data found for seed key: $seedKey")
|
||||
null
|
||||
}
|
||||
} else {
|
||||
val errorBody = response.body?.string() ?: "No error body"
|
||||
TangemLogger.e("Request failed: ${response.code}, body: $errorBody")
|
||||
null
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
TangemLogger.e("Error getting addresses", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun checkServiceHealth(
|
||||
baseUrl: String = "[REDACTED_ENV_URL]"
|
||||
): String? {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.screens.accounts.onAccountDetailsScreen
|
||||
import com.tangem.screens.accounts.onArchivedAccountsScreen
|
||||
import com.tangem.screens.onDetailsScreen
|
||||
import com.tangem.screens.onDialog
|
||||
import com.tangem.screens.onMainScreenTopBar
|
||||
import com.tangem.screens.onWalletSettingsScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.openWalletSettingsScreen() {
|
||||
step("Open 'Wallet details' screen") {
|
||||
onMainScreenTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Open 'Wallet settings' screen") {
|
||||
onDetailsScreen { walletNameButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openAccountDetails(accountName: String) {
|
||||
step("Click on account: '$accountName'") {
|
||||
onWalletSettingsScreen { accountItem(accountName).clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Account details' screen is displayed") {
|
||||
onAccountDetailsScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.archiveAccount() {
|
||||
step("Assert 'Archive' button is displayed") {
|
||||
onAccountDetailsScreen { archiveAccountButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Archive' button") {
|
||||
onAccountDetailsScreen { archiveAccountButton.clickWithAssertion() }
|
||||
}
|
||||
step("Confirm archivation in dialog") {
|
||||
onDialog { archiveButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.assertArchiveConfirmationDialog() {
|
||||
step("Assert confirmation dialog is displayed") {
|
||||
onDialog { dialogContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert confirmation dialog has 'Cancel' button") {
|
||||
onDialog { cancelButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert confirmation dialog has 'Archive' button") {
|
||||
onDialog { archiveButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.assertErrorDialog(expectedTitle: String, expectedMessage: String) {
|
||||
step("Assert error dialog is displayed") {
|
||||
onDialog { dialogContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert error dialog has proper title") {
|
||||
onDialog {
|
||||
title.assertTextContains(expectedTitle)
|
||||
}
|
||||
}
|
||||
step("Assert error dialog has explanatory text") {
|
||||
onDialog {
|
||||
text.assertTextContains(expectedMessage)
|
||||
}
|
||||
}
|
||||
step("Assert error dialog has 'OK' button") {
|
||||
onDialog { okButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.dismissErrorDialog() {
|
||||
step("Dismiss error dialog by clicking 'Ok' button") {
|
||||
onDialog { okButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openArchivedAccountsScreen() {
|
||||
step("Click on 'Archived accounts' button") {
|
||||
onWalletSettingsScreen { openArchivedAccountsButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.assertArchivedAccountIsDisplayed(accountName: String) {
|
||||
step("Assert archived account with name '$accountName' is displayed") {
|
||||
onArchivedAccountsScreen {
|
||||
findArchivedAccountItemByName(accountName)
|
||||
.container.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.restoreArchivedAccount(accountName: String) {
|
||||
step("Restore account with name '$accountName'") {
|
||||
onArchivedAccountsScreen {
|
||||
findArchivedAccountItemByName(accountName)
|
||||
.restoreButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import android.view.KeyEvent
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_VERY_LONG
|
||||
import com.tangem.common.utils.AddressComparisonHelper
|
||||
import com.tangem.common.utils.getClipboardText
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onTesterMenuScreen
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import org.junit.Assert.assertNotNull
|
||||
|
||||
private const val WALLET_MANAGERS_SETTLE_MS = 5_000L
|
||||
private const val WALLET_MANAGERS_POLL_INTERVAL_MS = 500L
|
||||
|
||||
fun BaseTestCase.verifyAddresses(seedPhrase: String, apiAddressesJson: String) {
|
||||
var appAddressesJson: String? = null
|
||||
|
||||
step("Open 'Main Screen' with existing hot wallet") {
|
||||
openMainScreenWithExistingHotWallet(seedPhrase)
|
||||
}
|
||||
step("Assert wallet balance = '$DASH_SIGN'") {
|
||||
composeTestRule.waitUntil(timeoutMillis = WAIT_UNTIL_TIMEOUT_VERY_LONG) {
|
||||
runCatching { onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) } }.isSuccess
|
||||
}
|
||||
}
|
||||
step("Assert 'Organize tokens' button is enabled") {
|
||||
composeTestRule.waitUntil(timeoutMillis = WAIT_UNTIL_TIMEOUT_VERY_LONG) {
|
||||
runCatching { onMainScreen { organizeTokensButton().assertIsEnabled() } }.isSuccess
|
||||
}
|
||||
}
|
||||
step("Wait for all wallet managers to initialize") {
|
||||
awaitWalletManagersStabilized()
|
||||
}
|
||||
step("Open tester menu") {
|
||||
openTesterMenu()
|
||||
}
|
||||
step("Click on 'Addresses info' button") {
|
||||
onTesterMenuScreen { addressesInfoButton.performClick() }
|
||||
}
|
||||
step("Click on 'JSON' tab") {
|
||||
onTesterMenuScreen { jsonTab.performClick() }
|
||||
}
|
||||
step("Click on 'Copy' button") {
|
||||
onTesterMenuScreen { copyButton.performClick() }
|
||||
}
|
||||
step("Get addresses JSON from clipboard") {
|
||||
appAddressesJson = getClipboardText(ApplicationProvider.getApplicationContext())
|
||||
assertNotNull("Clipboard is empty after copying addresses", appAddressesJson)
|
||||
}
|
||||
step("Compare app addresses with API reference") {
|
||||
AddressComparisonHelper.compareAddresses(
|
||||
appJson = requireNotNull(appAddressesJson),
|
||||
apiJson = apiAddressesJson,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val TESTER_MENU_MAX_ATTEMPTS = 3
|
||||
|
||||
/**
|
||||
* Presses 'Volume Down' twice to open tester menu.
|
||||
* Retries up to [TESTER_MENU_MAX_ATTEMPTS] times if the menu doesn't appear.
|
||||
*/
|
||||
private fun BaseTestCase.openTesterMenu() {
|
||||
repeat(TESTER_MENU_MAX_ATTEMPTS) { attempt ->
|
||||
waitForIdle()
|
||||
device.uiDevice.pressKeyCode(KeyEvent.KEYCODE_VOLUME_DOWN)
|
||||
device.uiDevice.pressKeyCode(KeyEvent.KEYCODE_VOLUME_DOWN)
|
||||
|
||||
val opened = runCatching {
|
||||
onTesterMenuScreen { addressesInfoButton.assertIsDisplayed() }
|
||||
}.isSuccess
|
||||
|
||||
if (opened) {
|
||||
TangemLogger.i("Tester menu opened on attempt ${attempt + 1}")
|
||||
return
|
||||
}
|
||||
TangemLogger.w("Tester menu not opened on attempt ${attempt + 1}, retrying...")
|
||||
}
|
||||
error("Failed to open tester menu after $TESTER_MENU_MAX_ATTEMPTS attempts")
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls [walletManagersStore] until the wallet manager count stops growing for [WALLET_MANAGERS_SETTLE_MS].
|
||||
|
||||
*
|
||||
* Uses [getAllSync] with a polling interval instead of Flow, because the Flow only emits on changes —
|
||||
* if the count stabilizes, there would be no new emission to check the settle timeout against.
|
||||
*/
|
||||
private fun BaseTestCase.awaitWalletManagersStabilized() {
|
||||
val walletId = getSelectedWalletSyncUseCase().getOrNull()?.walletId
|
||||
?: error("No selected wallet found")
|
||||
var lastSize = -1
|
||||
var stableStart = System.currentTimeMillis()
|
||||
|
||||
runBlocking {
|
||||
withTimeout(WAIT_UNTIL_TIMEOUT_VERY_LONG) {
|
||||
while (true) {
|
||||
val currentSize = walletManagersStore.getAllSync(walletId).size
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
if (currentSize != lastSize) {
|
||||
TangemLogger.i("Wallet managers count: $currentSize (was $lastSize)")
|
||||
lastSize = currentSize
|
||||
stableStart = now
|
||||
} else if (now - stableStart >= WALLET_MANAGERS_SETTLE_MS) {
|
||||
TangemLogger.i("Wallet managers stabilized at $currentSize entries")
|
||||
return@withTimeout
|
||||
}
|
||||
|
||||
delay(WALLET_MANAGERS_POLL_INTERVAL_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,11 +15,10 @@ fun BaseTestCase.scanCard(
|
|||
mockContent: MockContent? = null,
|
||||
isTwinsCard: Boolean = false,
|
||||
) {
|
||||
if (productType != null) {
|
||||
MockProvider.setMocks(productType)
|
||||
}
|
||||
if (mockContent != null) {
|
||||
MockProvider.setMocks(mockContent)
|
||||
when {
|
||||
mockContent != null -> MockProvider.setMocks(mockContent)
|
||||
productType != null -> MockProvider.setMocks(productType)
|
||||
else -> MockProvider.setMocks(ProductType.Wallet)
|
||||
}
|
||||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
|
|
@ -60,6 +59,57 @@ fun BaseTestCase.openMainScreen(
|
|||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openMainScreenWithExistingHotWallet(seedPhrase: String) {
|
||||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Get started' button") {
|
||||
onStoriesScreen { getStartedButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Start with Mobile Wallet' button") {
|
||||
onCreateWalletStartScreen { startWithMobileWalletButton.performClick() }
|
||||
}
|
||||
step("Click on 'Import existing wallet' button") {
|
||||
onCreateMobileWalletScreen { importExistingWalletButton.performClick() }
|
||||
}
|
||||
step("Click on 'Phrase text field'") {
|
||||
onImportWalletScreen { phraseTextField.performClick() }
|
||||
}
|
||||
step("Type seed phrase in 'Phrase text field'") {
|
||||
onImportWalletScreen { phraseTextField.performTextReplacement(seedPhrase) }
|
||||
}
|
||||
step("Click on 'Import' button") {
|
||||
onImportWalletScreen {
|
||||
importButton.assertIsEnabled()
|
||||
importButton.performClick()
|
||||
}
|
||||
}
|
||||
step("Click on 'Continue' button") {
|
||||
onImportWalletScreen {
|
||||
continueButton.assertIsEnabled()
|
||||
continueButton.performClick()
|
||||
}
|
||||
}
|
||||
step("Click on 'Skip' button") {
|
||||
onImportWalletScreen { skipButton.performClick() }
|
||||
}
|
||||
step("Click on 'Skip anyway' dialog button") {
|
||||
onDialog { skipAnywayButton.performClick() }
|
||||
}
|
||||
step("Click on 'Finish' button") {
|
||||
onImportWalletScreen {
|
||||
finishButton.assertIsEnabled()
|
||||
finishButton.performClick()
|
||||
}
|
||||
}
|
||||
step("Assert 'Main' screen is displayed") {
|
||||
onMainScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Dismiss Market Tooltip by clicking close button") {
|
||||
onMarketsTooltipScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.synchronizeAddresses(
|
||||
balance: String? = null,
|
||||
isBalanceAvailable: Boolean = true
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@ package com.tangem.scenarios
|
|||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.QUOTES_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.common.extensions.assertIsDimmed
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onSendConfirmScreen
|
||||
import com.tangem.screens.onSendScreen
|
||||
import com.tangem.screens.onTokenDetailsScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.openSendScreen(tokenName: String, mockState: String = "") {
|
||||
|
|
@ -72,8 +70,10 @@ fun BaseTestCase.openSendConfirmScreen(
|
|||
step("Type recipient address") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
step("Click 'Next' button until 'Send Confirm' screen opens") {
|
||||
composeTestRule.waitUntil(timeoutMillis = WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
runCatching { openSendConfirmScreenViaNextButton() }.isSuccess
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +84,9 @@ fun BaseTestCase.openSendAddressScreen(
|
|||
step("Click on token with name: '$tokenName'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Send' button is not dimmed") {
|
||||
onTokenDetailsScreen { sendButton().assertIsDimmed(false) }
|
||||
}
|
||||
step("Click on 'Send' button") {
|
||||
onTokenDetailsScreen { sendButton().performClick() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.R
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class CreateMobileWalletPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<CreateMobileWalletPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val importExistingWalletButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.hw_import_existing_wallet))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onCreateMobileWalletScreen(function: CreateMobileWalletPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -17,6 +17,11 @@ class CreateWalletStartPageObject(semanticsProvider: SemanticsNodeInteractionsPr
|
|||
hasText(getResourceString(OnboardingImplR.string.welcome_unlock_card))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val startWithMobileWalletButton: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.welcome_create_wallet_mobile_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onCreateWalletStartScreen(function: CreateWalletStartPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
hasText(getResourceString(R.string.common_confirm))
|
||||
}
|
||||
|
||||
val archiveButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.account_details_archive_action))
|
||||
}
|
||||
|
||||
val continueButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_continue))
|
||||
|
|
@ -64,6 +69,11 @@ class DialogPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.common_change))
|
||||
}
|
||||
|
||||
val skipAnywayButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasText(getResourceString(R.string.access_code_alert_skip_ok))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onDialog(function: DialogPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.R
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.ImportWalletScreenTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class ImportWalletPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<ImportWalletPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val phraseTextField: KNode = child {
|
||||
hasTestTag(ImportWalletScreenTestTags.PHRASE_TEXT_FIELD)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val passphraseTextField: KNode = child {
|
||||
hasTestTag(ImportWalletScreenTestTags.PASSPHRASE_TEXT_FIELD)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val importButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasAnyChild(withText(getResourceString(R.string.common_import)))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val continueButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasAnyChild(withText(getResourceString(R.string.common_continue)))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val skipButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.MORE_BUTTON)
|
||||
hasText(getResourceString(R.string.common_skip))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val finishButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasAnyChild(withText(getResourceString(R.string.common_finish)))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onImportWalletScreen(function: ImportWalletPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.feature.tester.impl.R as TesterImplR
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class TesterMenuPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<TesterMenuPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val backButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val addressesInfoButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(TesterImplR.string.addresses_info))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val jsonTab: KNode = child {
|
||||
hasText("JSON")
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val copyButton: KNode = child {
|
||||
hasContentDescription("Copy")
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onTesterMenuScreen(function: TesterMenuPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -38,6 +38,18 @@ class WalletSettingsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
hasText(getResourceString(R.string.settings_forget_wallet))
|
||||
}
|
||||
|
||||
val accountsListContainer: KNode = walletSettingsItem.child {
|
||||
hasTestTag(WalletSettingsScreenTestTags.ACCOUNTS_CONTAINER)
|
||||
}
|
||||
|
||||
val addAccountButton: KNode = walletSettingsItem.child {
|
||||
hasText(getResourceString(R.string.account_form_create_button))
|
||||
}
|
||||
|
||||
val openArchivedAccountsButton: KNode = walletSettingsItem.child {
|
||||
hasText(getResourceString(R.string.account_archived_accounts))
|
||||
}
|
||||
|
||||
fun accountItem(accountName: String): KNode = walletSettingsItem.child {
|
||||
hasTestTag(WalletSettingsScreenTestTags.USER_ACCOUNT_ITEM)
|
||||
hasAnyDescendant(withText(accountName))
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.screens
|
||||
package com.tangem.screens.accounts
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.AccountDetailsScreenTestTags
|
||||
import com.tangem.core.ui.test.accounts.AccountDetailsScreenTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
|
|
@ -11,6 +11,10 @@ import io.github.kakaocup.compose.node.element.KNode
|
|||
class AccountDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<AccountDetailsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val screenContainer: KNode = child {
|
||||
hasTestTag(AccountDetailsScreenTestTags.ACCOUNT_DETAILS_CONTAINER)
|
||||
}
|
||||
|
||||
val topAppBarBackButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
}
|
||||
|
|
@ -18,7 +22,16 @@ class AccountDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvi
|
|||
val manageTokensButton: KNode = child {
|
||||
hasTestTag(AccountDetailsScreenTestTags.MANAGE_TOKENS_BUTTON)
|
||||
}
|
||||
|
||||
val archiveAccountButton: KNode = child {
|
||||
hasTestTag(AccountDetailsScreenTestTags.ARCHIVE_ACCOUNT_BUTTON)
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onAccountDetails(function: AccountDetailsPageObject.() -> Unit) =
|
||||
val editAccountButton: KNode = child {
|
||||
hasTestTag(AccountDetailsScreenTestTags.EDIT_ACCOUNT_BUTTON)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onAccountDetailsScreen(function: AccountDetailsPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package com.tangem.screens.accounts
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import com.tangem.core.ui.test.accounts.AccountRowTestTags
|
||||
import com.tangem.core.ui.test.accounts.ArchivedAccountsScreenTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class ArchivedAccountsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<ArchivedAccountsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val screenContainer: KNode = child {
|
||||
hasTestTag(ArchivedAccountsScreenTestTags.ARCHIVED_ACCOUNTS_SCREEN_CONTAINER)
|
||||
}
|
||||
|
||||
val topAppBarBackButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
}
|
||||
|
||||
val topAppBarTitle: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.account_archived_accounts))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a composite handle for a single archived account row, scoped by account name.
|
||||
* All sub-elements (icon, title, tokens, networks, restore button) are children of this row.
|
||||
*/
|
||||
fun findArchivedAccountItemByName(accountName: String): ArchivedAccountRow {
|
||||
val container: KNode = child {
|
||||
hasTestTag(ArchivedAccountsScreenTestTags.ARCHIVED_ACCOUNT_ITEM)
|
||||
hasAnyDescendant(withText(accountName))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
return ArchivedAccountRow(container)
|
||||
}
|
||||
|
||||
class ArchivedAccountRow(val container: KNode) {
|
||||
|
||||
val icon: KNode = container.child {
|
||||
hasTestTag(AccountRowTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val title: KNode = container.child {
|
||||
hasTestTag(AccountRowTestTags.TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val subtitle: KNode = container.child {
|
||||
hasTestTag(AccountRowTestTags.SUBTITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val restoreButton: KNode = container.child {
|
||||
hasTestTag(ArchivedAccountsScreenTestTags.RESTORE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onArchivedAccountsScreen(function: ArchivedAccountsPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -8,6 +8,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.extensions.clickAndWaitFor
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.card.ScanFailsRequester
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import com.tangem.scenarios.checkFailedTransactionDialog
|
||||
|
|
@ -28,16 +29,19 @@ import com.tangem.screens.onStoriesScreen
|
|||
import com.tangem.screens.onTokenDetailsScreen
|
||||
import com.tangem.screens.onMainScreenTopBar
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import com.tangem.tap.store
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltAndroidTest
|
||||
class FeedbackTest : BaseTestCase() {
|
||||
|
||||
@Inject
|
||||
lateinit var scanFailsRequester: ScanFailsRequester
|
||||
|
||||
@AllureId("894")
|
||||
@DisplayName("Send feedback: from details")
|
||||
@Test
|
||||
|
|
@ -177,9 +181,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
}
|
||||
step("Force show 'Scan warning' dialog"){
|
||||
runOnUiThread {
|
||||
val requester = store.state.daggerGraphState.scanFailsRequester!!
|
||||
MainScope().launch {
|
||||
requester.show(AnalyticsParam.ScreensSources.Main)
|
||||
scanFailsRequester.show(AnalyticsParam.ScreensSources.Main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,253 @@
|
|||
package com.tangem.tests.accounts
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.REFERRAL_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.screens.accounts.onAccountDetailsScreen
|
||||
import com.tangem.screens.accounts.onArchivedAccountsScreen
|
||||
import com.tangem.screens.onDialog
|
||||
import com.tangem.screens.onWalletSettingsScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class AccountArchivationsTest : BaseTestCase() {
|
||||
|
||||
private val userTokensScenario = USER_TOKENS_API_SCENARIO
|
||||
private val referralScenario = REFERRAL_API_SCENARIO
|
||||
|
||||
@Test
|
||||
@AllureId("5979")
|
||||
@DisplayName("Accounts: Verify main account archivation button not available")
|
||||
fun mainAccountArchivationAttemptTest() {
|
||||
val mainAccountName = "Main account"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") { openMainScreen() }
|
||||
step("Synchronize addresses") { synchronizeAddresses() }
|
||||
step("Open wallet settings") { openWalletSettingsScreen() }
|
||||
step("Open wallet account with name $mainAccountName") { openAccountDetails(mainAccountName) }
|
||||
step("Assert archive button is NOT displayed") {
|
||||
onAccountDetailsScreen { archiveAccountButton.assertDoesNotExist() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("5974")
|
||||
@DisplayName("Accounts: archive a non-main account")
|
||||
fun archiveSuccessfullyAccountTest() {
|
||||
val accountToArchiveName = "Account 2"
|
||||
val userAccountsState = "TwoAccountsArchivable"
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsState)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(userTokensScenario)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Main Screen'") { openMainScreen() }
|
||||
step("Synchronize addresses") { synchronizeAddresses() }
|
||||
step("Open wallet settings") { openWalletSettingsScreen() }
|
||||
step("Open wallet account with name $accountToArchiveName") {
|
||||
openAccountDetails(accountToArchiveName)
|
||||
}
|
||||
|
||||
step("Assert 'Archive' button is displayed") {
|
||||
onAccountDetailsScreen { archiveAccountButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Archive' button") {
|
||||
onAccountDetailsScreen { archiveAccountButton.clickWithAssertion() }
|
||||
}
|
||||
step("Verify 'Archive confirmation' dialog appeared with all elements") {
|
||||
assertArchiveConfirmationDialog()
|
||||
}
|
||||
step("Click 'Archive' in confirmation menu") {
|
||||
onDialog { archiveButton.clickWithAssertion() }
|
||||
}
|
||||
|
||||
step("Verify app returned to 'Wallet settings' screen") {
|
||||
onWalletSettingsScreen { addAccountButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Verify archived account '$accountToArchiveName' is no longer listed") {
|
||||
onWalletSettingsScreen {
|
||||
accountItem(accountToArchiveName).assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("6844")
|
||||
@DisplayName("Accounts: account archivation error on UI")
|
||||
fun archiveAccountErrorTest() {
|
||||
val accountToArchiveName = "Account 2"
|
||||
val userAccountsState = "TwoAccountsArchivable"
|
||||
val userAccountsErrorState = "AccountsPutError"
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsState)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(userTokensScenario)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Main Screen'") { openMainScreen() }
|
||||
step("Synchronize addresses") { synchronizeAddresses() }
|
||||
step("Open wallet settings") { openWalletSettingsScreen() }
|
||||
step("Open wallet account with name $accountToArchiveName") {
|
||||
openAccountDetails(accountToArchiveName)
|
||||
}
|
||||
|
||||
step("Forcing network error scenario") {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsErrorState)
|
||||
}
|
||||
step("Attempt to archive the account") { archiveAccount() }
|
||||
step("Assert error dialog details") {
|
||||
assertErrorDialog(
|
||||
expectedTitle = getResourceString(R.string.common_something_went_wrong),
|
||||
expectedMessage = getResourceString(R.string.account_generic_error_dialog_message),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("5981")
|
||||
@DisplayName("Accounts: archive account with referral program error")
|
||||
fun archiveAccountReferralErrorTest() {
|
||||
val accountToArchiveName = "Account 2"
|
||||
val userAccountsState = "TwoAccountsArchivableAndReferral"
|
||||
val referralActiveState = "Participating"
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsState)
|
||||
setWireMockScenarioState(referralScenario, referralActiveState)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(userTokensScenario)
|
||||
resetWireMockScenarioState(referralScenario)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Main Screen'") { openMainScreen() }
|
||||
step("Synchronize addresses") { synchronizeAddresses() }
|
||||
step("Open wallet settings") { openWalletSettingsScreen() }
|
||||
step("Open wallet account with name $accountToArchiveName") {
|
||||
openAccountDetails(accountToArchiveName)
|
||||
}
|
||||
step("Attempt to archive the account") { archiveAccount() }
|
||||
|
||||
step("Assert error dialog details") {
|
||||
assertErrorDialog(
|
||||
expectedTitle = getResourceString(R.string.account_could_not_archive_referral_program_title),
|
||||
expectedMessage = getResourceString(R.string.account_could_not_archive_referral_program_message),
|
||||
)
|
||||
}
|
||||
step("Dismiss error dialog") { dismissErrorDialog() }
|
||||
step("Assert 'Archive' button is still visible after error") {
|
||||
onAccountDetailsScreen { archiveAccountButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("5976")
|
||||
@DisplayName("Accounts: restore an archived account")
|
||||
fun restoreArchivedAccountTest() {
|
||||
val archivedAccountName = "Account 3"
|
||||
val userAccountsInitialState = "TwoAccountsWithArchivedAccounts"
|
||||
val userAccountsAfterArchivationState = "ReadyToRestore"
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsInitialState)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(userTokensScenario)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Main Screen'") { openMainScreen() }
|
||||
step("Synchronize addresses") { synchronizeAddresses() }
|
||||
step("Open wallet settings") { openWalletSettingsScreen() }
|
||||
step("Open 'Archived accounts' screen") { openArchivedAccountsScreen() }
|
||||
step("Verify archived wallet account with name '$archivedAccountName' is present") {
|
||||
assertArchivedAccountIsDisplayed(archivedAccountName)
|
||||
}
|
||||
|
||||
step("Switch WireMock to '$userAccountsAfterArchivationState' users scenario state") {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsAfterArchivationState)
|
||||
}
|
||||
step("Restore account with name '$archivedAccountName'") {
|
||||
restoreArchivedAccount(archivedAccountName)
|
||||
}
|
||||
|
||||
step("Assert 'Wallet settings' screen is displayed") {
|
||||
onWalletSettingsScreen { addAccountButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert restored account '$archivedAccountName' appears in 'Active accounts' list") {
|
||||
onWalletSettingsScreen { accountItem(archivedAccountName).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@AllureId("7962")
|
||||
@DisplayName("Accounts: restore archived account error")
|
||||
fun restoreArchivedAccountErrorTest() {
|
||||
val archivedAccountName = "Account 3"
|
||||
val userAccountsInitialState = "TwoAccountsWithArchivedAccounts"
|
||||
val userAccountsRestorationErrorState = "AccountsPutError"
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsInitialState)
|
||||
},
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(userTokensScenario)
|
||||
},
|
||||
).run {
|
||||
step("Open 'Main Screen'") { openMainScreen() }
|
||||
step("Synchronize addresses") { synchronizeAddresses() }
|
||||
step("Open wallet settings") { openWalletSettingsScreen() }
|
||||
step("Open 'Archived accounts' screen") { openArchivedAccountsScreen() }
|
||||
step("Verify archived wallet account with name '$archivedAccountName' is present") {
|
||||
assertArchivedAccountIsDisplayed(archivedAccountName)
|
||||
}
|
||||
|
||||
step("Switch WireMock to '$userAccountsRestorationErrorState' user" +
|
||||
"accounts scenario state to simulate restoration failure") {
|
||||
setWireMockScenarioState(userTokensScenario, userAccountsRestorationErrorState)
|
||||
}
|
||||
step("Attempt restore account with name '$archivedAccountName'") {
|
||||
restoreArchivedAccount(archivedAccountName)
|
||||
}
|
||||
|
||||
step("Assert error dialog details") {
|
||||
assertErrorDialog(
|
||||
expectedTitle = getResourceString(R.string.common_something_went_wrong),
|
||||
expectedMessage = getResourceString(R.string.account_generic_error_dialog_message),
|
||||
)
|
||||
}
|
||||
step("Dismiss error dialog") { dismissErrorDialog() }
|
||||
|
||||
step("Assert archived account '$archivedAccountName' is still in archived list") {
|
||||
onArchivedAccountsScreen {
|
||||
findArchivedAccountItemByName(archivedAccountName)
|
||||
.container.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package com.tangem.tests.hotWallet
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.annotations.ApiEnv
|
||||
import com.tangem.common.annotations.ApiEnvConfig
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_12
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_15
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_18
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_21
|
||||
import com.tangem.common.constants.TestConstants.SEED_PHRASE_24
|
||||
import com.tangem.common.utils.checkServiceHealth
|
||||
import com.tangem.common.utils.getAddressesFromApi
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.scenarios.verifyAddresses
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class AddressesTest : BaseTestCase() {
|
||||
|
||||
private var apiAddressesJson: String? = null
|
||||
|
||||
private fun setupAddressTestHooks(seedKey: String) = setupHooks(
|
||||
additionalBeforeAppLaunchSection = {
|
||||
val status = checkServiceHealth()
|
||||
assertNotNull("QA tools service is unreachable ([REDACTED_ENV_URL]", status)
|
||||
|
||||
apiAddressesJson = getAddressesFromApi(seedKey)
|
||||
assertNotNull("Failed to fetch reference addresses for '$seedKey'", apiAddressesJson)
|
||||
},
|
||||
)
|
||||
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@AllureId("1792")
|
||||
@DisplayName("Hot wallet: auto derivation addresses for seed 12")
|
||||
@Test
|
||||
fun seed12AddressesTest() {
|
||||
setupAddressTestHooks("twelve").run {
|
||||
verifyAddresses(SEED_PHRASE_12, requireNotNull(apiAddressesJson))
|
||||
}
|
||||
}
|
||||
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@AllureId("5106")
|
||||
@DisplayName("Hot wallet: auto derivation addresses for seed 15")
|
||||
@Test
|
||||
fun seed15AddressesTest() {
|
||||
setupAddressTestHooks("fifteen").run {
|
||||
verifyAddresses(SEED_PHRASE_15, requireNotNull(apiAddressesJson))
|
||||
}
|
||||
}
|
||||
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@AllureId("5107")
|
||||
@DisplayName("Hot wallet: auto derivation addresses for seed 18")
|
||||
@Test
|
||||
fun seed18AddressesTest() {
|
||||
setupAddressTestHooks("eighteen").run {
|
||||
verifyAddresses(SEED_PHRASE_18, requireNotNull(apiAddressesJson))
|
||||
}
|
||||
}
|
||||
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@AllureId("5108")
|
||||
@DisplayName("Hot wallet: auto derivation addresses for seed 21")
|
||||
@Test
|
||||
fun seed21AddressesTest() {
|
||||
setupAddressTestHooks("twenty_one").run {
|
||||
verifyAddresses(SEED_PHRASE_21, requireNotNull(apiAddressesJson))
|
||||
}
|
||||
}
|
||||
|
||||
@ApiEnv(ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD))
|
||||
@AllureId("5109")
|
||||
@DisplayName("Hot wallet: auto derivation addresses for seed 24")
|
||||
@Test
|
||||
fun seed24AddressesTest() {
|
||||
setupAddressTestHooks("twenty_four").run {
|
||||
verifyAddresses(SEED_PHRASE_24, requireNotNull(apiAddressesJson))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import com.tangem.common.utils.setWireMockScenarioState
|
|||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.accounts.onAccountDetailsScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -93,7 +94,7 @@ class HideTokenTest : BaseTestCase() {
|
|||
onWalletSettingsScreen { accountItem(accountName).performClick() }
|
||||
}
|
||||
step("Click on 'Manage tokens' button") {
|
||||
onAccountDetails { manageTokensButton.performClick() }
|
||||
onAccountDetailsScreen { manageTokensButton.performClick() }
|
||||
}
|
||||
step("Click on token: '$tokenTitle'") {
|
||||
onManageTokensScreen { tokenItem(tokenTitle).performClick() }
|
||||
|
|
@ -118,7 +119,7 @@ class HideTokenTest : BaseTestCase() {
|
|||
}
|
||||
step("Click on 'Account details' screen 'Back' button") {
|
||||
waitForIdle()
|
||||
onAccountDetails { topAppBarBackButton.performClick() }
|
||||
onAccountDetailsScreen { topAppBarBackButton.performClick() }
|
||||
}
|
||||
step("Click on 'Wallet settings' screen 'Back' button") {
|
||||
waitForIdle()
|
||||
|
|
@ -162,7 +163,7 @@ class HideTokenTest : BaseTestCase() {
|
|||
onWalletSettingsScreen { accountItem(accountName).performClick() }
|
||||
}
|
||||
step("Click on 'Manage tokens' button") {
|
||||
onAccountDetails { manageTokensButton.performClick() }
|
||||
onAccountDetailsScreen { manageTokensButton.performClick() }
|
||||
}
|
||||
step("Click on token: '$tokenTitle'") {
|
||||
onManageTokensScreen { tokenItem(tokenTitle).performClick() }
|
||||
|
|
@ -187,7 +188,7 @@ class HideTokenTest : BaseTestCase() {
|
|||
}
|
||||
step("Click on 'Account details' screen 'Back' button") {
|
||||
waitForIdle()
|
||||
onAccountDetails { topAppBarBackButton.performClick() }
|
||||
onAccountDetailsScreen { topAppBarBackButton.performClick() }
|
||||
}
|
||||
step("Click on 'Wallet settings' screen 'Back' button") {
|
||||
waitForIdle()
|
||||
|
|
@ -308,5 +309,4 @@ class HideTokenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
package com.tangem.tests.send.warnings
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.CARDANO_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.QUOTES_API_SCENARIO
|
||||
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.scenarios.checkSendWarning
|
||||
import com.tangem.scenarios.openSendScreen
|
||||
import com.tangem.screens.onSendAddressScreen
|
||||
import com.tangem.screens.onSendScreen
|
||||
import com.tangem.wallet.R
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class CardanoWarningsTest : BaseTestCase() {
|
||||
private val tokenName = "Cardano"
|
||||
private val minAmount = "ADA 1.00"
|
||||
|
||||
private val invalidAmountTitle = getResourceString(R.string.send_notification_invalid_amount_title)
|
||||
private val invalidAmountMessage =
|
||||
getResourceString(R.string.send_notification_invalid_minimum_amount_text, minAmount, minAmount)
|
||||
|
||||
@AllureId("4204")
|
||||
@DisplayName("Warnings: check warning, when remains less than 1 ADA")
|
||||
@Test
|
||||
fun afterTransactionRemainsLessThanMinimumAmountTest() {
|
||||
val sendAmount = "19"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(QUOTES_API_SCENARIO)
|
||||
}
|
||||
).run {
|
||||
|
||||
step("Open 'Send Screen' with token: $tokenName") {
|
||||
openSendScreen(tokenName)
|
||||
}
|
||||
step("Type '$sendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(sendAmount)
|
||||
}
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Type address in input text field") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(CARDANO_ADDRESS) }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Invalid amount' warning is displayed") {
|
||||
checkSendWarning(
|
||||
title = invalidAmountTitle,
|
||||
message = invalidAmountMessage,
|
||||
isDisplayed = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("4207")
|
||||
@DisplayName("Warnings: check warning, when amount more than 1 ADA")
|
||||
@Test
|
||||
fun transactionAmountMoreThanOneTest() {
|
||||
val sendAmount = "2.5"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(QUOTES_API_SCENARIO)
|
||||
}
|
||||
).run {
|
||||
|
||||
step("Open 'Send Screen' with token: $tokenName") {
|
||||
openSendScreen(tokenName)
|
||||
}
|
||||
step("Type '$sendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(sendAmount)
|
||||
}
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Type address in input text field") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(CARDANO_ADDRESS) }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Invalid amount' warning is not displayed") {
|
||||
checkSendWarning(
|
||||
title = invalidAmountTitle,
|
||||
message = invalidAmountMessage,
|
||||
isDisplayed = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("4210")
|
||||
@DisplayName("Warnings: check warning, when remains more than 1 ADA")
|
||||
@Test
|
||||
fun afterTransactionRemainsMoreThanMinimumAmountTest() {
|
||||
val sendAmount = "18"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
|
||||
resetWireMockScenarioState(QUOTES_API_SCENARIO)
|
||||
}
|
||||
).run {
|
||||
|
||||
step("Open 'Send Screen' with token: $tokenName") {
|
||||
openSendScreen(tokenName)
|
||||
}
|
||||
step("Type '$sendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(sendAmount)
|
||||
}
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Type address in input text field") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(CARDANO_ADDRESS) }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Invalid amount' warning is not displayed") {
|
||||
checkSendWarning(
|
||||
title = invalidAmountTitle,
|
||||
message = invalidAmountMessage,
|
||||
isDisplayed = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
package com.tangem.tests.send.warnings
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.ETHEREUM_RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.scenarios.checkSendWarning
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.openSendConfirmScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onSendConfirmScreen
|
||||
import com.tangem.screens.onSendSelectNetworkFeeBottomSheet
|
||||
import com.tangem.wallet.R
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class CommonWarningsTest : BaseTestCase() {
|
||||
|
||||
@AllureId("4293")
|
||||
@DisplayName("Warnings: check warning, when custom fee lower than 'Slow'")
|
||||
@Test
|
||||
fun warningDisplayedWhenCustomFeeLowerThanSlowTest() {
|
||||
val tokenName = "Ethereum"
|
||||
val sendAmount = "0.01"
|
||||
val feeUpTo = getResourceString(R.string.send_max_fee)
|
||||
val customFee = "0.000000001"
|
||||
val warningTitle = getResourceString(R.string.send_notification_transaction_delay_title)
|
||||
val warningMessage = getResourceString(R.string.send_notification_transaction_delay_text)
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main' screen") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Send Confirm' screen with token: $tokenName") {
|
||||
openSendConfirmScreen(tokenName, sendAmount, ETHEREUM_RECIPIENT_ADDRESS)
|
||||
}
|
||||
step("Click on fee selector icon") {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
onSendConfirmScreen { feeSelectorIcon.performClick() }
|
||||
onSendSelectNetworkFeeBottomSheet { customSelectorItem.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Click on 'Custom' selector item") {
|
||||
onSendSelectNetworkFeeBottomSheet { customSelectorItem.performClick() }
|
||||
}
|
||||
step("Type '$customFee' into input text field") {
|
||||
onSendSelectNetworkFeeBottomSheet {
|
||||
inputTextFieldValue(title = feeUpTo).performClick()
|
||||
inputTextFieldValue(title = feeUpTo).performTextReplacement(customFee)
|
||||
}
|
||||
}
|
||||
step("Click on 'Done' button") {
|
||||
onSendSelectNetworkFeeBottomSheet { doneButton.performClick() }
|
||||
}
|
||||
step("Assert 'Transaction delays are possible' warning is displayed") {
|
||||
checkSendWarning(
|
||||
title = warningTitle,
|
||||
message = warningMessage,
|
||||
isDisplayed = true,
|
||||
sendButtonIsDisabled = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("4221")
|
||||
@DisplayName("Warnings: check warning, when amount exceeds total balance")
|
||||
@Test
|
||||
fun warningDisplayedWhenAmountExceedsTotalBalanceTest() {
|
||||
val tokenName = "Ethereum"
|
||||
val sendAmount = "0.9999"
|
||||
val network = "ETH 0.00032"
|
||||
val amount = "\$0.81"
|
||||
val warningTitle = getResourceString(R.string.send_network_fee_warning_title)
|
||||
val warningMessage = getResourceString(R.string.common_network_fee_warning_content, network, amount)
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main' screen") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
}
|
||||
step("Open 'Send Confirm' screen with token: $tokenName") {
|
||||
openSendConfirmScreen(tokenName, sendAmount, ETHEREUM_RECIPIENT_ADDRESS)
|
||||
}
|
||||
step("Assert 'Network fee coverage' warning is displayed") {
|
||||
checkSendWarning(
|
||||
title = warningTitle,
|
||||
message = warningMessage,
|
||||
isDisplayed = true,
|
||||
sendButtonIsDisabled = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("4294")
|
||||
@DisplayName("Warnings: check warning, when custom fee is high")
|
||||
@Test
|
||||
fun warningDisplayedWhenCustomFeeIsHighTest() {
|
||||
val tokenName = "Ethereum"
|
||||
val sendAmount = "0.01"
|
||||
val feeUpTo = getResourceString(R.string.send_max_fee)
|
||||
val customFee = "0.004"
|
||||
val timesHigher = "7"
|
||||
val warningTitle = getResourceString(R.string.send_notification_fee_too_high_title)
|
||||
val warningMessage = getResourceString(R.string.send_notification_fee_too_high_text, timesHigher)
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main' screen") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Send Confirm' screen with token: $tokenName") {
|
||||
openSendConfirmScreen(tokenName, sendAmount, ETHEREUM_RECIPIENT_ADDRESS)
|
||||
}
|
||||
step("Click on fee selector icon") {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
onSendConfirmScreen { feeSelectorIcon.performClick() }
|
||||
onSendSelectNetworkFeeBottomSheet { customSelectorItem.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Click on 'Custom' selector item") {
|
||||
onSendSelectNetworkFeeBottomSheet { customSelectorItem.performClick() }
|
||||
}
|
||||
step("Type '$customFee' into input text field") {
|
||||
onSendSelectNetworkFeeBottomSheet {
|
||||
inputTextFieldValue(title = feeUpTo).performClick()
|
||||
inputTextFieldValue(title = feeUpTo).performTextReplacement(customFee)
|
||||
}
|
||||
}
|
||||
step("Click on 'Done' button") {
|
||||
onSendSelectNetworkFeeBottomSheet { doneButton.performClick() }
|
||||
}
|
||||
step("Assert 'Custom fee is high' warning is displayed") {
|
||||
checkSendWarning(
|
||||
title = warningTitle,
|
||||
message = warningMessage,
|
||||
isDisplayed = true,
|
||||
sendButtonIsDisabled = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -232,6 +232,17 @@
|
|||
android:scheme="tangem" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="token_exchanges"
|
||||
android:scheme="tangem" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
|
|
|
|||
|
|
@ -2,156 +2,57 @@ package com.tangem.tap
|
|||
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.abtests.manager.ABTestsManager
|
||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.core.analytics.paramsinterceptor.SendTransactionSignerInfoInterceptor
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.decompose.di.GlobalUiMessageSender
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.settings.SettingsManager
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.data.card.TransactionSignerFactory
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
||||
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
|
||||
import com.tangem.datasource.local.logs.AppLogsStore
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
|
||||
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.ScanFailsRequester
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.repository.OnboardingRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.walletconnect.usecase.initialize.WcInitializeUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
import com.tangem.hot.sdk.TangemHotSdk
|
||||
import com.tangem.tap.common.analytics.CustomerIoFeatureToggles
|
||||
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
||||
import com.tangem.tap.common.analytics.handlers.appsflyer.AppsFlyerClient
|
||||
import com.tangem.tap.common.log.TangemAppLoggerInitializer
|
||||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Suppress("TooManyFunctions")
|
||||
interface ApplicationEntryPoint {
|
||||
|
||||
fun getAppStateHolder(): AppStateHolder
|
||||
|
||||
fun getIssuersConfigStorage(): IssuersConfigStorage
|
||||
|
||||
fun getEnvironmentConfig(): EnvironmentConfig
|
||||
|
||||
fun getFeatureTogglesManager(): FeatureTogglesManager
|
||||
|
||||
fun getExcludedBlockchainsManager(): ExcludedBlockchainsManager
|
||||
|
||||
fun getNetworkConnectionManager(): NetworkConnectionManager
|
||||
|
||||
fun getCardScanningFeatureToggles(): CardScanningFeatureToggles
|
||||
|
||||
fun getScanCardProcessor(): ScanCardProcessor
|
||||
|
||||
fun getAppCurrencyRepository(): AppCurrencyRepository
|
||||
|
||||
fun getWalletManagersFacade(): WalletManagersFacade
|
||||
|
||||
fun getAppThemeModeRepository(): AppThemeModeRepository
|
||||
|
||||
fun getBalanceHidingRepository(): BalanceHidingRepository
|
||||
|
||||
fun getAppPreferencesStore(): AppPreferencesStore
|
||||
|
||||
fun getGetAppThemeModeUseCase(): GetAppThemeModeUseCase
|
||||
|
||||
fun getWalletsRepository(): WalletsRepository
|
||||
|
||||
fun getOneTimeEventFilter(): OneTimeEventFilter
|
||||
|
||||
fun getWasTwinsOnboardingShownUseCase(): WasTwinsOnboardingShownUseCase
|
||||
|
||||
fun getSaveTwinsOnboardingShownUseCase(): SaveTwinsOnboardingShownUseCase
|
||||
|
||||
fun getCardRepository(): CardRepository
|
||||
|
||||
fun getTangemSdkLogger(): TangemSdkLogger
|
||||
|
||||
fun getSettingsRepository(): SettingsRepository
|
||||
|
||||
fun getBlockchainSDKFactory(): BlockchainSDKFactory
|
||||
|
||||
fun getSendFeedbackEmailUseCase(): SendFeedbackEmailUseCase
|
||||
|
||||
fun getWalletMetaInfoUseCase(): GetWalletMetaInfoUseCase
|
||||
|
||||
fun getUrlOpener(): UrlOpener
|
||||
|
||||
fun getShareManager(): ShareManager
|
||||
|
||||
fun getAppRouter(): AppRouter
|
||||
|
||||
fun getTangemAppLogger(): TangemAppLoggerInitializer
|
||||
|
||||
fun getTransactionSignerFactory(): TransactionSignerFactory
|
||||
|
||||
fun getOnboardingV2FeatureToggles(): OnboardingV2FeatureToggles
|
||||
|
||||
fun getOnboardingRepository(): OnboardingRepository
|
||||
|
||||
fun getExcludedBlockchains(): ExcludedBlockchains
|
||||
|
||||
fun getAppLogsStore(): AppLogsStore
|
||||
|
||||
fun getClipboardManager(): ClipboardManager
|
||||
|
||||
fun getSettingsManager(): SettingsManager
|
||||
|
||||
fun getBlockchainExceptionHandler(): BlockchainExceptionHandler
|
||||
|
||||
@GlobalUiMessageSender
|
||||
fun getUiMessageSender(): UiMessageSender
|
||||
|
||||
fun getWorkerFactory(): HiltWorkerFactory
|
||||
|
||||
fun getColdUserWalletBuilderFactory(): ColdUserWalletBuilder.Factory
|
||||
|
||||
fun getApiConfigsManager(): ApiConfigsManager
|
||||
|
||||
fun getUserWalletsListRepository(): UserWalletsListRepository
|
||||
|
||||
fun getTangemHotSdk(): TangemHotSdk
|
||||
|
||||
fun getWcInitializeUseCase(): WcInitializeUseCase
|
||||
|
||||
fun getTrackingContextProxy(): TrackingContextProxy
|
||||
|
||||
fun getABTestsManager(): ABTestsManager
|
||||
|
||||
fun getAppsFlyerClientFactory(): AppsFlyerClient.Factory
|
||||
|
||||
fun getCustomerIoFeatureToggles(): CustomerIoFeatureToggles
|
||||
|
||||
fun getScanFailsRequester(): ScanFailsRequester
|
||||
fun getSendTransactionSignerInfoInterceptor(): SendTransactionSignerInfoInterceptor
|
||||
}
|
||||
|
|
@ -7,12 +7,12 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
|
||||
import com.tangem.tap.LockTimerWorker.Companion.TAG
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -30,6 +30,7 @@ internal class LockUserWalletsTimer(
|
|||
private val coroutineScope: CoroutineScope,
|
||||
private val clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase,
|
||||
private val passwordRequester: HotWalletPasswordRequester,
|
||||
private val appRouter: AppRouter,
|
||||
) : LifecycleOwner by context as LifecycleOwner,
|
||||
DefaultLifecycleObserver {
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ internal class LockUserWalletsTimer(
|
|||
if (shouldOpenWelcomeScreenOnResume) {
|
||||
passwordRequester.dismiss()
|
||||
clearAllHotWalletContextualUnlockUseCase.invoke()
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
appRouter.replaceAll(AppRoute.Welcome())
|
||||
settingsRepository.setShouldOpenWelcomeScreenOnResume(value = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -121,7 +122,7 @@ internal class LockUserWalletsTimer(
|
|||
.onRight {
|
||||
passwordRequester.dismiss()
|
||||
clearAllHotWalletContextualUnlockUseCase.invoke()
|
||||
store.dispatchNavigationAction { replaceAll(AppRoute.Welcome()) }
|
||||
appRouter.replaceAll(AppRoute.Welcome())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
|||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.testTagsAsResourceId
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.core.net.toUri
|
||||
|
|
@ -26,6 +28,7 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.WEBLINK_KEY
|
||||
import com.tangem.common.routing.deeplink.PayloadToDeeplinkConverter
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
|
|
@ -37,7 +40,6 @@ import com.tangem.core.navigation.url.UrlOpener
|
|||
import com.tangem.data.balancehiding.DefaultDeviceFlipDetector
|
||||
import com.tangem.data.card.sdk.CardSdkOwner
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
|
|
@ -59,7 +61,6 @@ import com.tangem.tap.common.analytics.events.Push
|
|||
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
|
||||
import com.tangem.tap.features.intentHandler.handlers.BackgroundScanIntentHandler
|
||||
import com.tangem.tap.features.main.MainViewModel
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphAction
|
||||
import com.tangem.tap.routing.component.RoutingComponent
|
||||
import com.tangem.tap.routing.configurator.AppRouterConfig
|
||||
import com.tangem.tap.routing.utils.DeepLinkFactory
|
||||
|
|
@ -102,9 +103,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
lateinit var injectedTangemSdkManager: TangemSdkManager
|
||||
|
||||
@Inject
|
||||
lateinit var scanCardUseCase: ScanCardUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var settingsRepository: SettingsRepository
|
||||
|
||||
|
|
@ -121,6 +119,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
@Inject
|
||||
internal lateinit var appRouterConfig: AppRouterConfig
|
||||
|
||||
@Inject
|
||||
internal lateinit var appRouter: AppRouter
|
||||
|
||||
@Inject
|
||||
internal lateinit var routingComponentFactory: RoutingComponent.Factory
|
||||
|
||||
|
|
@ -244,7 +245,11 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
|
||||
setContent {
|
||||
CompositionLocalProvider(LocalUserInteractionTracker provides userInteractionTracker) {
|
||||
routingComponent.Content(Modifier.fillMaxSize())
|
||||
routingComponent.Content(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.semantics { testTagsAsResourceId = true },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -263,13 +268,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
userWalletsListRepository = userWalletsListRepository,
|
||||
clearAllHotWalletContextualUnlockUseCase = clearAllHotWalletContextualUnlockUseCase,
|
||||
passwordRequester = passwordRequester,
|
||||
)
|
||||
|
||||
store.dispatch(
|
||||
DaggerGraphAction.SetActivityDependencies(
|
||||
scanCardUseCase = scanCardUseCase,
|
||||
cardSdkConfigRepository = cardSdkConfigRepository,
|
||||
),
|
||||
appRouter = appRouter,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,54 +13,24 @@ import com.tangem.Log
|
|||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchain.common.ExceptionHandler
|
||||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.abtests.manager.ABTestsManager
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.api.ParamsInterceptor
|
||||
import com.tangem.core.analytics.filter.AppsFlyerEventFilter
|
||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.analytics.models.Basic.TransactionSent.WalletForm
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.settings.SettingsManager
|
||||
import com.tangem.core.ui.clipboard.ClipboardManager
|
||||
import com.tangem.data.card.TransactionSignerFactory
|
||||
import com.tangem.datasource.api.common.MoshiConverter
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
||||
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
|
||||
import com.tangem.datasource.local.logs.AppLogsStore
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.utils.NetworkLogsSaveInterceptor
|
||||
import com.tangem.datasource.utils.WireMockRedirectInterceptor
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
|
||||
import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
||||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.domain.onboarding.repository.OnboardingRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.builder.ColdUserWalletBuilder
|
||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
import com.tangem.operations.attestation.api.TangemApiServiceSettings
|
||||
import com.tangem.tap.common.analytics.AnalyticsFactory
|
||||
import com.tangem.tap.common.analytics.CustomerIoFeatureToggles
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.tap.common.analytics.handlers.BlockchainExceptionHandler
|
||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||
|
|
@ -70,20 +40,14 @@ import com.tangem.tap.common.analytics.handlers.customerio.CustomerIoAnalyticsHa
|
|||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
import com.tangem.tap.common.log.TangemAppLoggerInitializer
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.appReducer
|
||||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import dagger.hilt.EntryPoints
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Store
|
||||
|
||||
lateinit var store: Store<AppState>
|
||||
lateinit var walletsRepository: WalletsRepository
|
||||
|
||||
val foregroundActivityObserver = ForegroundActivityObserver
|
||||
|
||||
|
|
@ -93,12 +57,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
private val entryPoint: ApplicationEntryPoint
|
||||
get() = EntryPoints.get(this, ApplicationEntryPoint::class.java)
|
||||
|
||||
private val appStateHolder: AppStateHolder
|
||||
get() = entryPoint.getAppStateHolder()
|
||||
|
||||
private val issuersConfigStorage: IssuersConfigStorage
|
||||
get() = entryPoint.getIssuersConfigStorage()
|
||||
|
||||
private val environmentConfig: EnvironmentConfig
|
||||
get() = entryPoint.getEnvironmentConfig()
|
||||
|
||||
|
|
@ -108,99 +66,21 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
private val excludedBlockchainsManager: ExcludedBlockchainsManager
|
||||
get() = entryPoint.getExcludedBlockchainsManager()
|
||||
|
||||
private val networkConnectionManager: NetworkConnectionManager
|
||||
get() = entryPoint.getNetworkConnectionManager()
|
||||
|
||||
private val cardScanningFeatureToggles: CardScanningFeatureToggles
|
||||
get() = entryPoint.getCardScanningFeatureToggles()
|
||||
|
||||
private val scanCardProcessor: ScanCardProcessor
|
||||
get() = entryPoint.getScanCardProcessor()
|
||||
|
||||
private val appCurrencyRepository: AppCurrencyRepository
|
||||
get() = entryPoint.getAppCurrencyRepository()
|
||||
|
||||
private val walletManagersFacade: WalletManagersFacade
|
||||
get() = entryPoint.getWalletManagersFacade()
|
||||
|
||||
private val appThemeModeRepository: AppThemeModeRepository
|
||||
get() = entryPoint.getAppThemeModeRepository()
|
||||
|
||||
private val balanceHidingRepository: BalanceHidingRepository
|
||||
get() = entryPoint.getBalanceHidingRepository()
|
||||
|
||||
private val appPreferencesStore: AppPreferencesStore
|
||||
get() = entryPoint.getAppPreferencesStore()
|
||||
|
||||
val getAppThemeModeUseCase: GetAppThemeModeUseCase
|
||||
get() = entryPoint.getGetAppThemeModeUseCase()
|
||||
|
||||
private val walletsRepository: WalletsRepository
|
||||
get() = entryPoint.getWalletsRepository()
|
||||
|
||||
private val oneTimeEventFilter: OneTimeEventFilter
|
||||
get() = entryPoint.getOneTimeEventFilter()
|
||||
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase
|
||||
get() = entryPoint.getWasTwinsOnboardingShownUseCase()
|
||||
|
||||
private val saveTwinsOnboardingShownUseCase: SaveTwinsOnboardingShownUseCase
|
||||
get() = entryPoint.getSaveTwinsOnboardingShownUseCase()
|
||||
|
||||
private val cardRepository: CardRepository
|
||||
get() = entryPoint.getCardRepository()
|
||||
|
||||
private val tangemSdkLogger: TangemSdkLogger
|
||||
get() = entryPoint.getTangemSdkLogger()
|
||||
|
||||
private val settingsRepository: SettingsRepository
|
||||
get() = entryPoint.getSettingsRepository()
|
||||
|
||||
private val blockchainSDKFactory: BlockchainSDKFactory
|
||||
get() = entryPoint.getBlockchainSDKFactory()
|
||||
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase
|
||||
get() = entryPoint.getSendFeedbackEmailUseCase()
|
||||
|
||||
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase
|
||||
get() = entryPoint.getWalletMetaInfoUseCase()
|
||||
|
||||
private val urlOpener
|
||||
get() = entryPoint.getUrlOpener()
|
||||
|
||||
private val shareManager
|
||||
get() = entryPoint.getShareManager()
|
||||
|
||||
private val appRouter: AppRouter
|
||||
get() = entryPoint.getAppRouter()
|
||||
|
||||
private val tangemAppLoggerInitializer: TangemAppLoggerInitializer
|
||||
get() = entryPoint.getTangemAppLogger()
|
||||
|
||||
private val transactionSignerFactory: TransactionSignerFactory
|
||||
get() = entryPoint.getTransactionSignerFactory()
|
||||
|
||||
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles
|
||||
get() = entryPoint.getOnboardingV2FeatureToggles()
|
||||
|
||||
private val onboardingRepository: OnboardingRepository
|
||||
get() = entryPoint.getOnboardingRepository()
|
||||
|
||||
private val excludedBlockchains: ExcludedBlockchains
|
||||
get() = entryPoint.getExcludedBlockchains()
|
||||
|
||||
private val appLogsStore: AppLogsStore
|
||||
get() = entryPoint.getAppLogsStore()
|
||||
|
||||
private val clipboardManager: ClipboardManager
|
||||
get() = entryPoint.getClipboardManager()
|
||||
|
||||
private val settingsManager: SettingsManager
|
||||
get() = entryPoint.getSettingsManager()
|
||||
|
||||
private val uiMessageSender: UiMessageSender
|
||||
get() = entryPoint.getUiMessageSender()
|
||||
|
||||
private val blockchainExceptionHandler: BlockchainExceptionHandler
|
||||
get() = entryPoint.getBlockchainExceptionHandler()
|
||||
|
||||
|
|
@ -212,35 +92,20 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
.setWorkerFactory(workerFactory)
|
||||
.build()
|
||||
|
||||
private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory
|
||||
get() = entryPoint.getColdUserWalletBuilderFactory()
|
||||
|
||||
private val apiConfigsManager: ApiConfigsManager
|
||||
get() = entryPoint.getApiConfigsManager()
|
||||
|
||||
private val userWalletsListRepository
|
||||
get() = entryPoint.getUserWalletsListRepository()
|
||||
|
||||
private val tangemHotSdk
|
||||
get() = entryPoint.getTangemHotSdk()
|
||||
|
||||
private val wcInitializeUseCase
|
||||
get() = entryPoint.getWcInitializeUseCase()
|
||||
|
||||
private val trackingContextProxy
|
||||
get() = entryPoint.getTrackingContextProxy()
|
||||
|
||||
private val abTestsManager: ABTestsManager
|
||||
get() = entryPoint.getABTestsManager()
|
||||
|
||||
private val appsFlyerClientFactory: AppsFlyerClient.Factory
|
||||
get() = entryPoint.getAppsFlyerClientFactory()
|
||||
|
||||
private val customerIoFeatureToggles: CustomerIoFeatureToggles
|
||||
get() = entryPoint.getCustomerIoFeatureToggles()
|
||||
|
||||
private val scanFailsRequester
|
||||
get() = entryPoint.getScanFailsRequester()
|
||||
private val sendTransactionSignerInfoInterceptor
|
||||
get() = entryPoint.getSendTransactionSignerInfoInterceptor()
|
||||
|
||||
// endregion
|
||||
|
||||
|
|
@ -282,9 +147,9 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
}
|
||||
|
||||
fun init() {
|
||||
apiConfigsManager.initialize()
|
||||
walletsRepository = entryPoint.getWalletsRepository()
|
||||
|
||||
store = createReduxStore()
|
||||
apiConfigsManager.initialize()
|
||||
|
||||
TangemLogger.i("APP STARTED")
|
||||
if (BuildConfig.TESTER_MENU_ENABLED) {
|
||||
|
|
@ -326,57 +191,11 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
)
|
||||
}
|
||||
|
||||
appStateHolder.mainStore = store
|
||||
|
||||
wcInitializeUseCase.init(
|
||||
projectId = environmentConfig.walletConnectProjectId,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createReduxStore(): Store<AppState> {
|
||||
return Store(
|
||||
reducer = { action, state -> appReducer(action, requireNotNull(state)) },
|
||||
middleware = AppState.getMiddleware(),
|
||||
state = AppState(
|
||||
daggerGraphState = DaggerGraphState(
|
||||
networkConnectionManager = networkConnectionManager,
|
||||
cardScanningFeatureToggles = cardScanningFeatureToggles,
|
||||
scanCardProcessor = scanCardProcessor,
|
||||
appCurrencyRepository = appCurrencyRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
appStateHolder = appStateHolder,
|
||||
appThemeModeRepository = appThemeModeRepository,
|
||||
balanceHidingRepository = balanceHidingRepository,
|
||||
walletsRepository = walletsRepository,
|
||||
wasTwinsOnboardingShownUseCase = wasTwinsOnboardingShownUseCase,
|
||||
saveTwinsOnboardingShownUseCase = saveTwinsOnboardingShownUseCase,
|
||||
cardRepository = cardRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
blockchainSDKFactory = blockchainSDKFactory,
|
||||
sendFeedbackEmailUseCase = sendFeedbackEmailUseCase,
|
||||
getWalletMetaInfoUseCase = getWalletMetaInfoUseCase,
|
||||
issuersConfigStorage = issuersConfigStorage,
|
||||
urlOpener = urlOpener,
|
||||
shareManager = shareManager,
|
||||
appRouter = appRouter,
|
||||
transactionSignerFactory = transactionSignerFactory,
|
||||
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
|
||||
onboardingRepository = onboardingRepository,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
clipboardManager = clipboardManager,
|
||||
settingsManager = settingsManager,
|
||||
uiMessageSender = uiMessageSender,
|
||||
coldUserWalletBuilderFactory = coldUserWalletBuilderFactory,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
tangemHotSdk = tangemHotSdk,
|
||||
trackingContextProxy = trackingContextProxy,
|
||||
scanFailsRequester = scanFailsRequester,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateLogFiles() {
|
||||
appLogsStore.deleteOldLogsFile()
|
||||
|
||||
|
|
@ -415,9 +234,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder())
|
||||
factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder(appsFlyerClientFactory))
|
||||
|
||||
if (customerIoFeatureToggles.isFeatureEnabled) {
|
||||
factory.addHandlerBuilder(CustomerIoAnalyticsHandler.Builder())
|
||||
}
|
||||
|
||||
factory.addFilter(oneTimeEventFilter)
|
||||
factory.addFilter(AppsFlyerEventFilter())
|
||||
|
|
@ -430,23 +247,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
|
|||
jsonConverter = MoshiConverter.sdkMoshiConverter,
|
||||
)
|
||||
|
||||
Analytics.addParamsInterceptor(
|
||||
interceptor = object : ParamsInterceptor {
|
||||
override fun id(): String = "SendTransactionSignerInfoInterceptor"
|
||||
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Basic.TransactionSent
|
||||
|
||||
override fun intercept(params: MutableMap<String, String>) {
|
||||
val isLastSignWithRing = store.state.globalState.isLastSignWithRing
|
||||
|
||||
params[AnalyticsParam.WALLET_FORM] = if (isLastSignWithRing) {
|
||||
WalletForm.Ring.name
|
||||
} else {
|
||||
WalletForm.Card.name
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
Analytics.addParamsInterceptor(interceptor = sendTransactionSignerInfoInterceptor)
|
||||
|
||||
factory.build(Analytics, buildData)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.tap.common
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
|
||||
object TestActions {
|
||||
|
||||
// It used only for the test actions in debug or debug_beta builds
|
||||
var isTestAmountInjectionForWalletManagerEnabled = false
|
||||
}
|
||||
|
||||
typealias TestAction = Pair<String, () -> Unit>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import com.tangem.core.configtoggle.FeatureToggles
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class CustomerIoFeatureToggles @Inject constructor(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) {
|
||||
|
||||
val isFeatureEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(toggle = FeatureToggles.CUSTOMER_IO_ENABLED)
|
||||
}
|
||||
|
|
@ -3,7 +3,9 @@ package com.tangem.tap.common.analytics.handlers.amplitude
|
|||
import com.tangem.core.analytics.api.AnalyticsHandler
|
||||
import com.tangem.core.analytics.api.AnalyticsUserIdHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
|
||||
import com.tangem.wallet.BuildConfig
|
||||
|
||||
class AmplitudeAnalyticsHandler(
|
||||
private val client: AmplitudeAnalyticsClient,
|
||||
|
|
@ -29,10 +31,20 @@ class AmplitudeAnalyticsHandler(
|
|||
class Builder : AnalyticsHandlerBuilder {
|
||||
override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler {
|
||||
return AmplitudeAnalyticsHandler(
|
||||
client = if (data.logConfig.isAmplitudeLogEnabled) {
|
||||
AmplitudeLogClient(data.jsonConverter)
|
||||
client = if (BuildConfig.TESTER_MENU_ENABLED) {
|
||||
AmplitudeClient(
|
||||
application = data.application,
|
||||
key = requireNotNull(data.config.amplitudeApiKeyDev) {
|
||||
"Amplitude api key not found in ${BuildConfig.BUILD_TYPE}"
|
||||
},
|
||||
logger = AnalyticsEventsLogger(name = ID, jsonConverter = data.jsonConverter),
|
||||
)
|
||||
} else {
|
||||
AmplitudeClient(data.application, data.config.amplitudeApiKey)
|
||||
AmplitudeClient(
|
||||
application = data.application,
|
||||
key = data.config.amplitudeApiKey,
|
||||
logger = null,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import com.amplitude.api.Amplitude
|
|||
import com.amplitude.api.AmplitudeClient
|
||||
import com.tangem.core.analytics.api.EventLogger
|
||||
import com.tangem.core.analytics.api.UserIdHolder
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
|
|
@ -16,6 +18,7 @@ interface AmplitudeAnalyticsClient : EventLogger, UserIdHolder
|
|||
internal class AmplitudeClient(
|
||||
application: Application,
|
||||
key: String,
|
||||
private val logger: AnalyticsEventsLogger?,
|
||||
) : AmplitudeAnalyticsClient {
|
||||
|
||||
private val client: AmplitudeClient = Amplitude.getInstance()
|
||||
|
|
@ -23,6 +26,7 @@ internal class AmplitudeClient(
|
|||
init {
|
||||
client.initialize(application, key)
|
||||
client.enableForegroundTracking(application)
|
||||
client.enableLogging(BuildConfig.TESTER_MENU_ENABLED)
|
||||
}
|
||||
|
||||
override fun setUserId(userId: String) {
|
||||
|
|
@ -34,6 +38,7 @@ internal class AmplitudeClient(
|
|||
}
|
||||
|
||||
override fun logEvent(event: String, params: Map<String, String>) {
|
||||
logger?.logEvent(event, params)
|
||||
client.logEvent(event, ParamsToJSONObjectConverter().convert(params))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package com.tangem.tap.common.analytics.handlers.amplitude
|
||||
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventsLogger
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class AmplitudeLogClient(
|
||||
jsonConverter: MoshiJsonConverter,
|
||||
) : AmplitudeAnalyticsClient {
|
||||
|
||||
private val logger: AnalyticsEventsLogger = AnalyticsEventsLogger(AmplitudeAnalyticsHandler.ID, jsonConverter)
|
||||
|
||||
private var userId: String? = null
|
||||
|
||||
override fun setUserId(userId: String) {
|
||||
this.userId = userId
|
||||
}
|
||||
|
||||
override fun clearUserId() {
|
||||
this.userId = null
|
||||
}
|
||||
|
||||
override fun logEvent(event: String, params: Map<String, String>) {
|
||||
logger.logEvent(event, params)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,8 @@ import com.tangem.domain.card.common.util.cardTypesResolver
|
|||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.walletsRepository
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
|
|
@ -23,8 +21,6 @@ class CardContextInterceptor(
|
|||
private val scanResponse: ScanResponse,
|
||||
) : ParamsInterceptor {
|
||||
|
||||
private val walletsRepository = store.inject(DaggerGraphState::walletsRepository)
|
||||
|
||||
private val userWalletId = UserWalletIdBuilder.scanResponse(scanResponse).build()
|
||||
|
||||
override fun id(): String = CardContextInterceptor.id()
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.content.*
|
||||
import android.content.pm.*
|
||||
import android.content.res.*
|
||||
import android.net.*
|
||||
import androidx.annotation.*
|
||||
import androidx.core.content.*
|
||||
|
||||
/**
|
||||
* Get uri to any resource type via given Resource Instance
|
||||
* @param resId - resource id
|
||||
* @throws Resources.NotFoundException if the given ID does not exist.
|
||||
* @return - Uri to resource by the given ID
|
||||
*/
|
||||
@Throws(Resources.NotFoundException::class)
|
||||
fun Context.resourceUri(@AnyRes resId: Int): Uri {
|
||||
return Uri.parse(
|
||||
ContentResolver.SCHEME_ANDROID_RESOURCE +
|
||||
"://" + resources.getResourcePackageName(resId) +
|
||||
'/' + resources.getResourceTypeName(resId) +
|
||||
'/' + resources.getResourceEntryName(resId),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Store
|
||||
|
||||
/**
|
||||
* Dispatch action with creating the new coroutine with the Main dispatcher
|
||||
*
|
||||
* @see dispatchWithMain
|
||||
*/
|
||||
fun Store<*>.dispatchOnMain(action: Action) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
dispatch(action)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch action on the Main coroutine context
|
||||
*
|
||||
* @param action [Action] to be dispatched
|
||||
*
|
||||
* @see dispatchOnMain
|
||||
* */
|
||||
suspend fun Store<*>.dispatchWithMain(action: Action) {
|
||||
withMainContext {
|
||||
dispatch(action)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun Store<AppState>.onUserWalletSelected(userWallet: UserWallet) {
|
||||
state.globalState.tapWalletManager.onWalletSelected(userWallet)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch action inside a coroutine with the Main dispatcher
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Use dispatchWithMain instead",
|
||||
replaceWith = ReplaceWith(expression = "dispatchWithMain"),
|
||||
)
|
||||
suspend fun dispatchOnMain(vararg actions: Action) {
|
||||
withMainContext { actions.forEach { store.dispatch(it) } }
|
||||
}
|
||||
|
||||
fun Store<AppState>.dispatchNavigationAction(action: AppRouter.() -> Unit) {
|
||||
inject(DaggerGraphState::appRouter).action()
|
||||
}
|
||||
|
||||
inline fun <reified T> Store<AppState>.inject(getDependency: DaggerGraphState.() -> T?): T {
|
||||
return requireNotNull(state.daggerGraphState.getDependency()) {
|
||||
"${T::class.simpleName.orEmpty()} isn't initialized "
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +1,11 @@
|
|||
@file:Suppress("TooManyFunctions")
|
||||
|
||||
package com.tangem.tap.common.extensions
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
fun Context.getDrawableCompat(@DrawableRes drawableResId: Int): Drawable? {
|
||||
return ContextCompat.getDrawable(this, drawableResId)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun Context.getColorCompat(@ColorRes colorRes: Int): Int {
|
||||
return ContextCompat.getColor(this, colorRes)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun View.getColor(@ColorRes colorRes: Int): Int {
|
||||
return ContextCompat.getColor(context, colorRes)
|
||||
}
|
||||
|
||||
fun View.getString(@StringRes id: Int): String {
|
||||
return context.getString(id)
|
||||
}
|
||||
|
||||
fun View.getString(@StringRes id: Int, vararg formatArgs: String): String {
|
||||
return context.getString(id, *formatArgs)
|
||||
}
|
||||
|
||||
fun View.show(show: Boolean, invokeBeforeStateChanged: (() -> Unit)? = null) {
|
||||
return if (show) this.show(invokeBeforeStateChanged) else this.hide(invokeBeforeStateChanged)
|
||||
}
|
||||
|
||||
fun View.show(invokeBeforeStateChanged: (() -> Unit)? = null) {
|
||||
if (this.visibility == View.VISIBLE) return
|
||||
|
||||
invokeBeforeStateChanged?.invoke()
|
||||
this.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun View.hide(invokeBeforeStateChanged: (() -> Unit)? = null) {
|
||||
if (this.visibility == View.GONE) return
|
||||
|
||||
invokeBeforeStateChanged?.invoke()
|
||||
this.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
|
||||
return context.getString(resId, *formatArgs)
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchainsdk.utils.amountToCreateAccount
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.getFirstToken
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Use WalletStoresManager.fetch({userWalletId}, refresh = true) (to update all user wallet tokens)" +
|
||||
"or WalletCurrenciesManager.update(...) (to update only one user wallet blockchain and its tokens) instead",
|
||||
)
|
||||
@Suppress("MagicNumber")
|
||||
suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try {
|
||||
if (isDemoCard || TestActions.isTestAmountInjectionForWalletManagerEnabled) {
|
||||
delay(500)
|
||||
TestActions.isTestAmountInjectionForWalletManagerEnabled = false
|
||||
Result.Success(wallet)
|
||||
} else {
|
||||
update()
|
||||
Result.Success(wallet)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
TangemLogger.e("Error", exception)
|
||||
|
||||
val networkConnectionManager = store.inject(DaggerGraphState::networkConnectionManager)
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
Result.Failure(TapError.NoInternetConnection())
|
||||
} else {
|
||||
val blockchain = wallet.blockchain
|
||||
val amountToCreateAccount = blockchain.amountToCreateAccount(this, wallet.getFirstToken())
|
||||
|
||||
if (exception is BlockchainSdkError.AccountNotFound && amountToCreateAccount != null) {
|
||||
Result.Failure(TapError.WalletManager.NoAccountError(amountToCreateAccount.toString()))
|
||||
} else {
|
||||
when (exception) {
|
||||
is BlockchainSdkError -> Result.Failure(exception)
|
||||
else -> {
|
||||
val message = exception.cause?.localizedMessage ?: "Unknown error"
|
||||
Result.Failure(TapError.WalletManager.InternalError(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,15 @@ package com.tangem.tap.common.libs.blockchainsdk
|
|||
import com.tangem.Message
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.blockchain.common.TransactionSigner
|
||||
import com.tangem.core.analytics.models.Basic.TransactionSent.WalletForm
|
||||
import com.tangem.core.analytics.store.LastSignedWalletFormStore
|
||||
import com.tangem.data.card.TransactionSignerFactory
|
||||
import com.tangem.domain.card.models.TwinKey
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TangemSigner
|
||||
import com.tangem.tap.store
|
||||
|
||||
internal class DefaultTransactionSignerFactory : TransactionSignerFactory {
|
||||
internal class DefaultTransactionSignerFactory(
|
||||
private val lastSignedWalletFormStore: LastSignedWalletFormStore,
|
||||
) : TransactionSignerFactory {
|
||||
|
||||
override fun createTransactionSigner(cardId: String?, sdk: TangemSdk, twinKey: TwinKey?): TransactionSigner {
|
||||
return TangemSigner(
|
||||
|
|
@ -18,7 +20,9 @@ internal class DefaultTransactionSignerFactory : TransactionSignerFactory {
|
|||
initialMessage = Message(),
|
||||
twinKey = twinKey,
|
||||
) { signResponse ->
|
||||
store.dispatch(action = GlobalAction.IsSignWithRing(signResponse.isRing))
|
||||
lastSignedWalletFormStore.update(
|
||||
if (signResponse.isRing) WalletForm.Ring else WalletForm.Card,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,19 +3,12 @@ package com.tangem.tap.common.pushes
|
|||
import android.annotation.SuppressLint
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import com.tangem.tap.common.analytics.CustomerIoFeatureToggles
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.customer.messagingpush.CustomerIOFirebaseMessagingService
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
@SuppressLint("MissingFirebaseInstanceTokenRefresh")
|
||||
internal class TangemPushNotificationService : FirebaseMessagingService() {
|
||||
|
||||
@Inject
|
||||
lateinit var customerIoFeatureToggles: CustomerIoFeatureToggles
|
||||
|
||||
private val pushNotificationDelegate: PushNotificationDelegate by lazy {
|
||||
PushNotificationDelegate(applicationContext)
|
||||
}
|
||||
|
|
@ -24,21 +17,17 @@ internal class TangemPushNotificationService : FirebaseMessagingService() {
|
|||
super.onNewToken(token)
|
||||
TangemLogger.d("New FCM token received: $token")
|
||||
|
||||
if (customerIoFeatureToggles.isFeatureEnabled) {
|
||||
CustomerIOFirebaseMessagingService.onNewToken(applicationContext, token)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMessageReceived(message: RemoteMessage) {
|
||||
super.onMessageReceived(message)
|
||||
|
||||
if (customerIoFeatureToggles.isFeatureEnabled) {
|
||||
CustomerIOFirebaseMessagingService.onMessageReceived(
|
||||
context = applicationContext,
|
||||
remoteMessage = message,
|
||||
handleNotificationTrigger = false,
|
||||
)
|
||||
}
|
||||
|
||||
val notification = message.notification ?: return
|
||||
val channelId = notification.channelId ?: TANGEM_CHANNEL_ID
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class AccessCodeRequestPolicyMiddleware {
|
||||
val middleware: Middleware<AppState> = { _, _ ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
if (action is GlobalAction.SaveScanResponse) {
|
||||
updateAccessCodeRequestPolicy(action.scanResponse)
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAccessCodeRequestPolicy(scanResponse: ScanResponse) {
|
||||
mainScope.launch {
|
||||
val shouldSaveAccessCodes = store.inject(DaggerGraphState::settingsRepository).shouldSaveAccessCodes()
|
||||
|
||||
store.inject(DaggerGraphState::cardSdkConfigRepository).setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = shouldSaveAccessCodes && scanResponse.card.isAccessCodeSet,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.common.redux.global.globalReducer
|
||||
import com.tangem.tap.features.details.redux.DetailsReducer
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphReducer
|
||||
import org.rekotlin.Action
|
||||
|
||||
fun appReducer(action: Action, state: AppState): AppState {
|
||||
if (action is AppAction.RestoreState) return action.state
|
||||
|
||||
return AppState(
|
||||
globalState = globalReducer(action, state),
|
||||
detailsState = DetailsReducer.reduce(action, state),
|
||||
daggerGraphState = DaggerGraphReducer.reduce(action, state),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class AppAction : Action {
|
||||
data class RestoreState(val state: AppState) : AppAction()
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.common.redux.global.GlobalMiddleware
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.redux.legacy.LegacyMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsMiddleware
|
||||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphMiddleware
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import org.rekotlin.Middleware
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class AppState(
|
||||
val globalState: GlobalState = GlobalState(),
|
||||
val detailsState: DetailsState = DetailsState(),
|
||||
val daggerGraphState: DaggerGraphState = DaggerGraphState(),
|
||||
) : StateType {
|
||||
|
||||
companion object {
|
||||
fun getMiddleware(): List<Middleware<AppState>> {
|
||||
return listOf(
|
||||
logMiddleware,
|
||||
GlobalMiddleware.handler,
|
||||
DetailsMiddleware().detailsMiddleware,
|
||||
LockUserWalletsTimerMiddleware().middleware,
|
||||
AccessCodeRequestPolicyMiddleware().middleware,
|
||||
DaggerGraphMiddleware.daggerGraphMiddleware,
|
||||
LegacyMiddleware.legacyMiddleware,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.tap.lockUserWalletsTimer
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
class LockUserWalletsTimerMiddleware {
|
||||
val middleware: Middleware<AppState> = { _, _ ->
|
||||
{ nextDispatch ->
|
||||
{ action ->
|
||||
lockUserWalletsTimer?.restart()
|
||||
nextDispatch(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package com.tangem.tap.common.redux
|
||||
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
val logMiddleware: Middleware<AppState> = { _, _ ->
|
||||
{ nextDispatch ->
|
||||
{ action ->
|
||||
TangemLogger.i("Dispatch action: ${action::class.java.simpleName}")
|
||||
nextDispatch(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class GlobalAction : Action {
|
||||
|
||||
data class SaveScanResponse(val scanResponse: ScanResponse) : GlobalAction()
|
||||
|
||||
data class ChangeAppCurrency(val appCurrency: AppCurrency) : GlobalAction()
|
||||
object RestoreAppCurrency : GlobalAction() {
|
||||
data class Success(val appCurrency: AppCurrency) : GlobalAction()
|
||||
}
|
||||
|
||||
data class IsSignWithRing(val isSignWithRing: Boolean) : GlobalAction()
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Action
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
object GlobalMiddleware {
|
||||
val handler = globalMiddlewareHandler
|
||||
}
|
||||
|
||||
private val globalMiddlewareHandler: Middleware<AppState> = { _, _ ->
|
||||
{ nextDispatch ->
|
||||
{ action ->
|
||||
handleAction(action)
|
||||
nextDispatch(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAction(action: Action) {
|
||||
when (action) {
|
||||
is GlobalAction.RestoreAppCurrency -> restoreAppCurrency()
|
||||
}
|
||||
}
|
||||
|
||||
private fun restoreAppCurrency() {
|
||||
scope.launch {
|
||||
val currency = store.inject(DaggerGraphState::appCurrencyRepository)
|
||||
.getSelectedAppCurrency()
|
||||
.firstOrNull()
|
||||
?: AppCurrency.Default
|
||||
|
||||
store.dispatchWithMain(GlobalAction.RestoreAppCurrency.Success(currency))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Action
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
fun globalReducer(action: Action, state: AppState): GlobalState {
|
||||
if (action !is GlobalAction) return state.globalState
|
||||
|
||||
val globalState = state.globalState
|
||||
|
||||
return when (action) {
|
||||
is GlobalAction.SaveScanResponse -> {
|
||||
globalState.copy(scanResponse = action.scanResponse)
|
||||
}
|
||||
is GlobalAction.ChangeAppCurrency -> {
|
||||
globalState.copy(appCurrency = action.appCurrency)
|
||||
}
|
||||
is GlobalAction.RestoreAppCurrency.Success -> {
|
||||
globalState.copy(appCurrency = action.appCurrency)
|
||||
}
|
||||
is GlobalAction.IsSignWithRing -> globalState.copy(isLastSignWithRing = action.isSignWithRing)
|
||||
else -> globalState
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.domain.TapWalletManager
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class GlobalState(
|
||||
@Deprecated("Use scan response from selected user wallet")
|
||||
val scanResponse: ScanResponse? = null,
|
||||
val tapWalletManager: TapWalletManager = TapWalletManager(),
|
||||
val appCurrency: AppCurrency = AppCurrency.Default,
|
||||
val isLastSignWithRing: Boolean = false,
|
||||
) : StateType
|
||||
|
||||
typealias CryptoCurrencyName = String
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
package com.tangem.tap.common.redux.legacy
|
||||
|
||||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.redux.LegacyAction
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.details.redux.AppSettingsState
|
||||
import com.tangem.tap.features.details.redux.DetailsAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
@Suppress("MemberNameEqualsClassName")
|
||||
internal object LegacyMiddleware {
|
||||
private val prepareDetailsScreenJobHolder = JobHolder()
|
||||
|
||||
val legacyMiddleware: Middleware<AppState> = { _, _ ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
is LegacyAction.PrepareDetailsScreen -> {
|
||||
selectedUserWallet()
|
||||
.distinctUntilChanged { old, new ->
|
||||
if (old is UserWallet.Cold && new is UserWallet.Cold) {
|
||||
old.walletId == new.walletId &&
|
||||
old.scanResponse == new.scanResponse
|
||||
} else {
|
||||
old.walletId == new.walletId
|
||||
}
|
||||
}
|
||||
.onEach { selectedUserWallet ->
|
||||
val initializedAppSettingsStateContent = initializeAppSettingsState()
|
||||
store.dispatchWithMain(
|
||||
DetailsAction.PrepareScreen(
|
||||
scanResponse = (selectedUserWallet as? UserWallet.Cold)?.scanResponse,
|
||||
initializedAppSettingsState = initializedAppSettingsStateContent,
|
||||
),
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.IO)
|
||||
.launchIn(scope)
|
||||
.saveIn(prepareDetailsScreenJobHolder)
|
||||
}
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectedUserWallet(): Flow<UserWallet> {
|
||||
return store.inject(DaggerGraphState::userWalletsListRepository).selectedUserWallet.filterNotNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* LEGACY: We need to initialize [AppSettingsState] async to avoid drawing blocking
|
||||
* previously it was initialized in runBlocking and blocked details screen
|
||||
*/
|
||||
private suspend fun initializeAppSettingsState(): AppSettingsState {
|
||||
return AppSettingsState(
|
||||
selectedAppCurrency = store.state.globalState.appCurrency,
|
||||
selectedThemeMode = store.inject(DaggerGraphState::appThemeModeRepository).getAppThemeMode().firstOrNull()
|
||||
?: AppThemeMode.DEFAULT,
|
||||
requireAccessCode = store.inject(DaggerGraphState::walletsRepository).requireAccessCode(),
|
||||
useBiometricAuthentication = store.inject(DaggerGraphState::walletsRepository).useBiometricAuthentication(),
|
||||
isHidingEnabled = store.inject(DaggerGraphState::balanceHidingRepository)
|
||||
.getBalanceHidingSettings().isHidingEnabledInSettings,
|
||||
needEnrollBiometrics = runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() == true,
|
||||
hasSecuredWallets = store.inject(DaggerGraphState::userWalletsListRepository).hasSecuredWallets(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.tap.core.ui
|
||||
|
||||
import com.tangem.core.configtoggle.FeatureToggles
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.core.ui.HoldToConfirmButtonFeatureToggles
|
||||
import javax.inject.Inject
|
||||
|
||||
class DefaultHoldToConfirmButtonFeatureToggles @Inject constructor(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) : HoldToConfirmButtonFeatureToggles {
|
||||
override val isHoldToConfirmEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(FeatureToggles.HOLD_TO_CONFIRM_BUTTON_ENABLED)
|
||||
}
|
||||
|
|
@ -1,26 +1,27 @@
|
|||
package com.tangem.datasource.info
|
||||
package com.tangem.tap.data
|
||||
|
||||
import android.os.Build
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
import java.util.*
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AndroidAppInfoProvider @Inject constructor(
|
||||
private val appVersionProvider: AppVersionProvider,
|
||||
) : AppInfoProvider {
|
||||
internal class DefaultAppInfoProvider @Inject constructor() : AppInfoProvider {
|
||||
override val platform: String
|
||||
get() = "Android"
|
||||
override val device: String
|
||||
get() = "${Build.MANUFACTURER} ${Build.MODEL}"
|
||||
override val osVersion: String
|
||||
get() = Build.VERSION.RELEASE
|
||||
override val sdkVersion: Int
|
||||
get() = Build.VERSION.SDK_INT
|
||||
override val language: String
|
||||
get() = Locale.getDefault().language
|
||||
get() = Locale.getDefault().toLanguageTag()
|
||||
override val timezone: String
|
||||
get() = TimeZone.getDefault().id
|
||||
override val appVersion: String
|
||||
get() = appVersionProvider.versionName
|
||||
override val appVersion: String = BuildConfig.VERSION_NAME
|
||||
override val appVersionCode: Int = BuildConfig.VERSION_CODE
|
||||
override val isHuaweiDevice: Boolean
|
||||
get() = Build.MANUFACTURER.equals("HUAWEI", ignoreCase = true) ||
|
||||
Build.BRAND.equals("HUAWEI", ignoreCase = true)
|
||||
|
|
@ -32,7 +32,6 @@ import com.tangem.tap.foregroundActivityObserver
|
|||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
|
@ -48,7 +47,6 @@ internal class DefaultCardSdkProvider @Inject constructor(
|
|||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
appVersionProvider: AppVersionProvider,
|
||||
appInfoProvider: AppInfoProvider,
|
||||
authProvider: AuthProvider,
|
||||
) : CardSdkProvider, CardSdkOwner {
|
||||
|
|
@ -74,10 +72,7 @@ internal class DefaultCardSdkProvider @Inject constructor(
|
|||
val apiEnvironment = Provider {
|
||||
apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemTech).environment
|
||||
}
|
||||
val platformHeaders = RequestHeader.AppVersionPlatformHeaders(
|
||||
appVersionProvider = appVersionProvider,
|
||||
appInfoProvider = appInfoProvider,
|
||||
)
|
||||
val platformHeaders = RequestHeader.AppVersionPlatformHeaders(appInfoProvider)
|
||||
val apiKeyHeader = RequestHeader.TangemApiKeyHeader(authProvider, apiEnvironment)
|
||||
TangemApiServiceSettings.addInterceptors(
|
||||
AddHeadersInterceptor(platformHeaders.values + apiKeyHeader.values),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import com.tangem.datasource.api.moonpay.MoonPayApi
|
|||
import com.tangem.datasource.local.config.environment.EnvironmentConfig
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.express.ExpressServiceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -14,8 +13,7 @@ import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
|||
import com.tangem.tap.network.exchangeServices.DefaultRampManager
|
||||
import com.tangem.tap.network.exchangeServices.SellService
|
||||
import com.tangem.tap.network.exchangeServices.moonpay.MoonPayService
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -45,13 +43,13 @@ internal object ActivityModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideDefaultRampManager(
|
||||
appStateHolder: AppStateHolder,
|
||||
sellService: SellService,
|
||||
expressServiceFetcher: ExpressServiceFetcher,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): RampStateManager {
|
||||
return DefaultRampManager(
|
||||
sellService = Provider { requireNotNull(appStateHolder.sellService) },
|
||||
sellService = sellService,
|
||||
expressServiceFetcher = expressServiceFetcher,
|
||||
currenciesRepository = currenciesRepository,
|
||||
dispatchers = dispatchers,
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface AppStateHolderModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindsReduxStateHolder(appStateHolder: AppStateHolder): ReduxStateHolder
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.di
|
|||
import android.content.Context
|
||||
import com.tangem.core.analytics.api.AnalyticsErrorHandler
|
||||
import com.tangem.domain.card.BuildConfig
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
|
||||
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
|
||||
|
|
@ -36,6 +37,7 @@ internal class TangemSdkManagerModule {
|
|||
dynamicAddressesFeatureToggles: DynamicAddressesFeatureToggles,
|
||||
blockchainToDeriveFinder: BlockchainToDeriveFinder,
|
||||
analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
cardRepository: CardRepository,
|
||||
): TangemSdkManager {
|
||||
return if (BuildConfig.MOCK_DATA_SOURCE) {
|
||||
MockTangemSdkManager(resources = context.resources)
|
||||
|
|
@ -50,6 +52,7 @@ internal class TangemSdkManagerModule {
|
|||
dynamicAddressesFeatureToggles = dynamicAddressesFeatureToggles,
|
||||
blockchainToDeriveFinder = blockchainToDeriveFinder,
|
||||
analyticsErrorHandler = analyticsErrorHandler,
|
||||
cardRepository = cardRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import com.tangem.tap.common.settings.IntentSettingsManager
|
|||
import com.tangem.tap.common.share.IntentShareManager
|
||||
import com.tangem.tap.common.url.CustomTabsUrlOpener
|
||||
import com.tangem.tap.core.DefaultAppCoroutineScope
|
||||
import com.tangem.tap.data.DefaultAppInfoProvider
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -28,6 +30,10 @@ internal interface UtilsModule {
|
|||
@Binds
|
||||
fun provideAppScope(defaultAppScope: DefaultAppCoroutineScope): AppCoroutineScope
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindAppInfoProvider(impl: DefaultAppInfoProvider): AppInfoProvider
|
||||
|
||||
companion object {
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.tap.di.core.ui
|
||||
|
||||
import com.tangem.core.ui.DesignFeatureToggles
|
||||
import com.tangem.core.ui.HoldToConfirmButtonFeatureToggles
|
||||
import com.tangem.tap.core.ui.DefaultDesignFeatureToggles
|
||||
import com.tangem.tap.core.ui.DefaultHoldToConfirmButtonFeatureToggles
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -15,9 +13,4 @@ interface CoreUiBindsModule {
|
|||
|
||||
@Binds
|
||||
fun bindDesignFeatureToggles(impl: DefaultDesignFeatureToggles): DesignFeatureToggles
|
||||
|
||||
@Binds
|
||||
fun bindHoldToConfirmButtonFeatureToggles(
|
||||
impl: DefaultHoldToConfirmButtonFeatureToggles,
|
||||
): HoldToConfirmButtonFeatureToggles
|
||||
}
|
||||
|
|
@ -1,12 +1,18 @@
|
|||
package com.tangem.tap.di.data
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.data.card.sdk.CardSdkOwner
|
||||
import com.tangem.data.card.sdk.CardSdkProvider
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.operations.attestation.CardArtworksProvider
|
||||
import com.tangem.tap.data.DefaultCardSdkProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import java.io.File
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
|
@ -20,4 +26,22 @@ internal interface CardSdkModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun providerCardSdkLifecycleObserver(defaultCardSdkProvider: DefaultCardSdkProvider): CardSdkOwner
|
||||
|
||||
companion object {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCardArtworksProvider(
|
||||
sdkRepository: CardSdkConfigRepository,
|
||||
@ApplicationContext context: Context,
|
||||
): CardArtworksProvider {
|
||||
return CardArtworksProvider(
|
||||
tangemApiBaseUrlProvider = { sdkRepository.sdk.config.tangemApiBaseUrl },
|
||||
artworksDirectory = File(
|
||||
context.getExternalFilesDir(null) ?: context.filesDir,
|
||||
"card_artworks",
|
||||
).apply { mkdirs() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.assetsdiscovery.repository.AssetsDiscoveryRepository
|
||||
import com.tangem.domain.assetsdiscovery.usecase.AcknowledgeAssetsDiscoveryCompletionUseCase
|
||||
import com.tangem.domain.assetsdiscovery.usecase.ObserveAssetsDiscoveryUseCase
|
||||
import com.tangem.domain.assetsdiscovery.usecase.StartAssetsDiscoveryUseCase
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AssetsDiscoveryDomainModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideObserveAssetsDiscoveryUseCase(
|
||||
assetsDiscoveryRepository: AssetsDiscoveryRepository,
|
||||
): ObserveAssetsDiscoveryUseCase {
|
||||
return ObserveAssetsDiscoveryUseCase(
|
||||
assetsDiscoveryRepository = assetsDiscoveryRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAcknowledgeAssetsDiscoveryCompletionUseCase(
|
||||
assetsDiscoveryRepository: AssetsDiscoveryRepository,
|
||||
): AcknowledgeAssetsDiscoveryCompletionUseCase {
|
||||
return AcknowledgeAssetsDiscoveryCompletionUseCase(
|
||||
assetsDiscoveryRepository = assetsDiscoveryRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStartAssetsDiscoveryUseCase(
|
||||
assetsDiscoveryRepository: AssetsDiscoveryRepository,
|
||||
manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
appCoroutineScope: AppCoroutineScope,
|
||||
): StartAssetsDiscoveryUseCase {
|
||||
return StartAssetsDiscoveryUseCase(
|
||||
assetsDiscoveryRepository = assetsDiscoveryRepository,
|
||||
manageCryptoCurrenciesUseCase = manageCryptoCurrenciesUseCase,
|
||||
analyticsEventHandler = analyticsEventHandler,
|
||||
appCoroutineScope = appCoroutineScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
|||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.tap.domain.card.DefaultDeleteSavedAccessCodesUseCase
|
||||
import com.tangem.tap.domain.card.DefaultResetCardUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -56,7 +55,7 @@ internal object CardDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideDeleteSavedAccessCodesUseCase(tangemSdkManager: TangemSdkManager): DeleteSavedAccessCodesUseCase {
|
||||
return DefaultDeleteSavedAccessCodesUseCase(tangemSdkManager)
|
||||
return DeleteSavedAccessCodesUseCase(tangemSdkManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
|||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||
import com.tangem.tap.domain.scanCard.DefaultScanCardProcessor
|
||||
import com.tangem.tap.domain.scanCard.LegacyScanProcessor
|
||||
import com.tangem.tap.domain.scanCard.UseCaseScanProcessor
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -25,8 +26,16 @@ internal object CardLegacyDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideScanCardProcessor(legacyScanProcessor: LegacyScanProcessor): ScanCardProcessor {
|
||||
return DefaultScanCardProcessor(legacyScanProcessor = legacyScanProcessor)
|
||||
fun provideScanCardProcessor(
|
||||
legacyScanProcessor: LegacyScanProcessor,
|
||||
useCaseScanProcessor: UseCaseScanProcessor,
|
||||
cardScanningFeatureToggles: CardScanningFeatureToggles,
|
||||
): ScanCardProcessor {
|
||||
return DefaultScanCardProcessor(
|
||||
legacyScanProcessor = legacyScanProcessor,
|
||||
useCaseScanProcessor = useCaseScanProcessor,
|
||||
cardScanningFeatureToggles = cardScanningFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.dynamicaddresses.CreateConsolidationTransactionUseCase
|
||||
import com.tangem.domain.dynamicaddresses.DisableDynamicAddressesUseCase
|
||||
import com.tangem.domain.dynamicaddresses.EnableDynamicAddressesUseCase
|
||||
import com.tangem.domain.dynamicaddresses.GetDynamicAddressesStatusUseCase
|
||||
import com.tangem.domain.dynamicaddresses.GetDynamicReceiveAddressUseCase
|
||||
import com.tangem.domain.dynamicaddresses.GetDerivedXpubUseCase
|
||||
import com.tangem.domain.dynamicaddresses.IsXpubSupportedUseCase
|
||||
import com.tangem.domain.dynamicaddresses.repository.ConsolidationRepository
|
||||
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object DynamicAddressesDomainModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideEnableDynamicAddressesUseCase(
|
||||
dynamicAddressesRepository: DynamicAddressesRepository,
|
||||
): EnableDynamicAddressesUseCase {
|
||||
return EnableDynamicAddressesUseCase(dynamicAddressesRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDisableDynamicAddressesUseCase(
|
||||
dynamicAddressesRepository: DynamicAddressesRepository,
|
||||
): DisableDynamicAddressesUseCase {
|
||||
return DisableDynamicAddressesUseCase(dynamicAddressesRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetDynamicAddressesStatusUseCase(
|
||||
dynamicAddressesRepository: DynamicAddressesRepository,
|
||||
): GetDynamicAddressesStatusUseCase {
|
||||
return GetDynamicAddressesStatusUseCase(dynamicAddressesRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetDynamicReceiveAddressUseCase(
|
||||
dynamicAddressesRepository: DynamicAddressesRepository,
|
||||
): GetDynamicReceiveAddressUseCase {
|
||||
return GetDynamicReceiveAddressUseCase(dynamicAddressesRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCreateConsolidationTransactionUseCase(
|
||||
consolidationRepository: ConsolidationRepository,
|
||||
): CreateConsolidationTransactionUseCase {
|
||||
return CreateConsolidationTransactionUseCase(consolidationRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideIsXpubSupportedUseCase(walletManagersFacade: WalletManagersFacade): IsXpubSupportedUseCase {
|
||||
return IsXpubSupportedUseCase(walletManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetDerivedXpubUseCase(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
derivationsRepository: DerivationsRepository,
|
||||
): GetDerivedXpubUseCase {
|
||||
return GetDerivedXpubUseCase(walletManagersFacade, derivationsRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.domain.staking.*
|
||||
import com.tangem.domain.staking.repositories.*
|
||||
import com.tangem.domain.staking.toggles.StakingFeatureToggles
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.usecase.StakingAvailabilityListUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
|
@ -226,8 +227,14 @@ internal object StakingDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingIdFactory(walletManagersFacade: WalletManagersFacade): StakingIdFactory {
|
||||
return StakingIdFactory(walletManagersFacade = walletManagersFacade)
|
||||
fun provideStakingIdFactory(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
stakingFeatureToggles: StakingFeatureToggles,
|
||||
): StakingIdFactory {
|
||||
return StakingIdFactory(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
stakingFeatureToggles = stakingFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -49,6 +49,18 @@ internal object SwapDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetSwapPairUseCase(
|
||||
swapRepositoryV2: SwapRepositoryV2,
|
||||
swapErrorResolver: SwapErrorResolver,
|
||||
): GetSwapPairUseCase {
|
||||
return GetSwapPairUseCase(
|
||||
swapRepositoryV2 = swapRepositoryV2,
|
||||
swapErrorResolver = swapErrorResolver,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSelectInitialPairUseCase(
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokensync.repository.TokenSyncRepository
|
||||
import com.tangem.domain.tokensync.usecase.AcknowledgeTokenSyncCompletionUseCase
|
||||
import com.tangem.domain.tokensync.usecase.ObserveTokenSyncUseCase
|
||||
import com.tangem.domain.tokensync.usecase.StartTokenSyncUseCase
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object TokenSyncDomainModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideObserveTokenSyncUseCase(tokenSyncRepository: TokenSyncRepository): ObserveTokenSyncUseCase {
|
||||
return ObserveTokenSyncUseCase(
|
||||
tokenSyncRepository = tokenSyncRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAcknowledgeTokenSyncCompletionUseCase(
|
||||
tokenSyncRepository: TokenSyncRepository,
|
||||
): AcknowledgeTokenSyncCompletionUseCase {
|
||||
return AcknowledgeTokenSyncCompletionUseCase(
|
||||
tokenSyncRepository = tokenSyncRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStartTokenSyncUseCase(
|
||||
tokenSyncRepository: TokenSyncRepository,
|
||||
manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
|
||||
appCoroutineScope: AppCoroutineScope,
|
||||
): StartTokenSyncUseCase {
|
||||
return StartTokenSyncUseCase(
|
||||
tokenSyncRepository = tokenSyncRepository,
|
||||
manageCryptoCurrenciesUseCase = manageCryptoCurrenciesUseCase,
|
||||
appCoroutineScope = appCoroutineScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,9 @@ import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
|||
import com.tangem.domain.account.supplier.SingleAccountListSupplier
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.dynamicaddresses.DynamicAddressesFeatureToggles
|
||||
import com.tangem.domain.dynamicaddresses.GetDynamicReceiveAddressUseCase
|
||||
import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
||||
import com.tangem.domain.notifications.repository.PushNotificationsRepository
|
||||
|
|
@ -257,10 +260,16 @@ internal object TransactionDomainModule {
|
|||
fun provideReceiveAddressesFactory(
|
||||
getEnsNameUseCase: GetEnsNameUseCase,
|
||||
getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
getDynamicReceiveAddressUseCase: GetDynamicReceiveAddressUseCase,
|
||||
dynamicAddressesRepository: DynamicAddressesRepository,
|
||||
dynamicAddressesFeatureToggles: DynamicAddressesFeatureToggles,
|
||||
): ReceiveAddressesFactory {
|
||||
return ReceiveAddressesFactory(
|
||||
getEnsNameUseCase = getEnsNameUseCase,
|
||||
getViewedTokenReceiveWarningUseCase = getViewedTokenReceiveWarningUseCase,
|
||||
getDynamicReceiveAddressUseCase = getDynamicReceiveAddressUseCase,
|
||||
dynamicAddressesRepository = dynamicAddressesRepository,
|
||||
dynamicAddressesFeatureToggles = dynamicAddressesFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.blockchain.common.TransactionSigner
|
||||
import com.tangem.data.wallets.hot.TangemHotWalletSigner
|
||||
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.card.models.TwinKey
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.walletconnect.CheckIsWalletConnectAvailableUseCase
|
||||
import com.tangem.domain.walletconnect.WcTransactionSignerProvider
|
||||
import com.tangem.domain.walletconnect.repository.WalletConnectRepository
|
||||
import com.tangem.domain.walletconnect.repository.WcSessionsManager
|
||||
import com.tangem.domain.walletconnect.usecase.WcSessionsUseCase
|
||||
|
|
@ -27,4 +34,27 @@ internal object WalletConnectDomainModule {
|
|||
fun providesWcSessionsUseCase(sessionsManager: WcSessionsManager): WcSessionsUseCase {
|
||||
return WcSessionsUseCase(sessionsManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesWcTransactionSignerProvider(
|
||||
cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
|
||||
): WcTransactionSignerProvider {
|
||||
return object : WcTransactionSignerProvider {
|
||||
override fun createSigner(wallet: UserWallet): TransactionSigner {
|
||||
return when (wallet) {
|
||||
is UserWallet.Hot -> tangemHotWalletSignerFactory.create(wallet)
|
||||
is UserWallet.Cold -> {
|
||||
val card = wallet.scanResponse.card
|
||||
val isCardNotBackedUp = card.backupStatus?.isActive != true && !card.isTangemTwins
|
||||
cardSdkConfigRepository.getCommonSigner(
|
||||
cardId = card.cardId.takeIf { isCardNotBackedUp },
|
||||
twinKey = TwinKey.getOrNull(scanResponse = wallet.scanResponse),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.domain.account.repository.AccountsCRUDRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletSelectedHandler
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.transaction.WalletAddressServiceRepository
|
||||
import com.tangem.domain.transaction.usecase.ParseSharedAddressUseCase
|
||||
import com.tangem.domain.transaction.usecase.ValidateWalletAddressUseCase
|
||||
|
|
@ -24,6 +24,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyApyUpdateUseCase
|
|||
import com.tangem.feature.wallet.presentation.wallet.domain.IsWalletNFTEnabledSyncUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
|
||||
import com.tangem.operations.attestation.CardArtworksProvider
|
||||
import com.tangem.tap.domain.DefaultUserWalletSelectedHandler
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -151,14 +152,14 @@ internal object WalletsDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesSelectWalletUseCase(
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
reduxStateHolder: ReduxStateHolder,
|
||||
): SelectWalletUseCase {
|
||||
return SelectWalletUseCase(
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
reduxStateHolder = reduxStateHolder,
|
||||
)
|
||||
fun providesSelectWalletUseCase(userWalletsListRepository: UserWalletsListRepository): SelectWalletUseCase {
|
||||
return SelectWalletUseCase(userWalletsListRepository = userWalletsListRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesUserWalletSelectedHandler(handler: DefaultUserWalletSelectedHandler): UserWalletSelectedHandler {
|
||||
return handler
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di.libs.blockchainsdk
|
||||
|
||||
import com.tangem.core.analytics.store.LastSignedWalletFormStore
|
||||
import com.tangem.data.card.TransactionSignerFactory
|
||||
import com.tangem.tap.common.libs.blockchainsdk.DefaultTransactionSignerFactory
|
||||
import dagger.Module
|
||||
|
|
@ -17,7 +18,9 @@ internal class TransactionSignerFactoryModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTransactionSignerFactory(): TransactionSignerFactory {
|
||||
return DefaultTransactionSignerFactory()
|
||||
fun provideTransactionSignerFactory(
|
||||
lastSignedWalletFormStore: LastSignedWalletFormStore,
|
||||
): TransactionSignerFactory {
|
||||
return DefaultTransactionSignerFactory(lastSignedWalletFormStore)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletSelectedHandler
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveInAndJoin
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Default implementation of [UserWalletSelectedHandler].
|
||||
*
|
||||
* Runs three side effects on every selection: updates the analytics tracking context, updates the
|
||||
* Tangem SDK displayed card-id numbers count (cold wallets only), and recomputes the access code
|
||||
* request policy (cold wallets only). Hot wallets trigger only the tracking-context update.
|
||||
*
|
||||
* Invocations are serialised via [JobHolder]: if a new [invoke] arrives while the previous one is
|
||||
* still running, the previous load is cancelled and the new one replaces it. The method suspends
|
||||
* until the newly launched load completes.
|
||||
*/
|
||||
@Singleton
|
||||
internal class DefaultUserWalletSelectedHandler @Inject constructor(
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val cardSdkConfigRepository: CardSdkConfigRepository,
|
||||
private val appCoroutineScope: AppCoroutineScope,
|
||||
) : UserWalletSelectedHandler {
|
||||
|
||||
private val loadUserWalletDataJob: JobHolder = JobHolder()
|
||||
|
||||
override suspend fun invoke(userWallet: UserWallet) {
|
||||
appCoroutineScope.launch { loadUserWalletData(userWallet) }
|
||||
.saveInAndJoin(loadUserWalletDataJob)
|
||||
}
|
||||
|
||||
private suspend fun loadUserWalletData(userWallet: UserWallet) {
|
||||
trackingContextProxy.setContext(userWallet)
|
||||
|
||||
if (userWallet is UserWallet.Cold) {
|
||||
val scanResponse = userWallet.scanResponse
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
|
||||
updateAccessCodeRequestPolicy(scanResponse)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateAccessCodeRequestPolicy(scanResponse: ScanResponse) {
|
||||
val shouldSaveAccessCodes = settingsRepository.shouldSaveAccessCodes()
|
||||
|
||||
cardSdkConfigRepository.setAccessCodeRequestPolicy(
|
||||
isBiometricsRequestPolicy = shouldSaveAccessCodes && scanResponse.card.isAccessCodeSet,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.wallet.R
|
||||
|
||||
interface TapErrors
|
||||
|
||||
interface ArgError {
|
||||
val args: List<Any>?
|
||||
}
|
||||
|
||||
interface MultiMessageError : TapErrors {
|
||||
val errorList: List<TapError>
|
||||
val builder: (List<String>) -> String
|
||||
}
|
||||
|
||||
sealed class TapError(
|
||||
@StringRes val messageResource: Int,
|
||||
override val args: List<Any>? = null,
|
||||
) : Throwable(), TapErrors, ArgError {
|
||||
|
||||
class UnknownError : TapError(R.string.send_error_unknown)
|
||||
open class CustomError(val customMessage: String) : TapError(R.string.common_custom_string, listOf(customMessage))
|
||||
|
||||
class NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
|
||||
|
||||
sealed class WalletManager {
|
||||
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
||||
class InternalError(message: String) : CustomError(message)
|
||||
class BlockchainIsUnreachableTryLater : TapError(R.string.wallet_balance_blockchain_unreachable_try_later)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TapSdkError(override val messageResId: Int?) : TangemError(code = 50100) {
|
||||
override var customMessage: String = code.toString()
|
||||
|
||||
class CardForDifferentApp : TapSdkError(R.string.alert_unsupported_card)
|
||||
class CardNotSupportedByRelease : TapSdkError(R.string.error_wrong_card_type)
|
||||
}
|
||||
|
||||
fun TapErrors.assembleErrors(): MutableList<Pair<Int, List<Any>?>> {
|
||||
val idList = mutableListOf<Pair<Int, List<Any>?>>()
|
||||
when (this) {
|
||||
is MultiMessageError -> this.errorList.forEach { idList.addAll(it.assembleErrors()) }
|
||||
is TapError -> idList.add(Pair(this.messageResource, this.args))
|
||||
}
|
||||
return idList
|
||||
}
|
||||
11
app/src/main/java/com/tangem/tap/domain/TapSdkError.kt
Normal file
11
app/src/main/java/com/tangem/tap/domain/TapSdkError.kt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.wallet.R
|
||||
|
||||
sealed class TapSdkError(override val messageResId: Int?) : TangemError(code = 50100) {
|
||||
override var customMessage: String = code.toString()
|
||||
|
||||
class CardForDifferentApp : TapSdkError(R.string.alert_unsupported_card)
|
||||
class CardNotSupportedByRelease : TapSdkError(R.string.error_wrong_card_type)
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class TapWalletManager(
|
||||
private val dispatchers: CoroutineDispatcherProvider = AppCoroutineDispatcherProvider(),
|
||||
) {
|
||||
|
||||
private var loadUserWalletDataJob: Job? = null
|
||||
set(value) {
|
||||
field?.cancel()
|
||||
field = value
|
||||
}
|
||||
|
||||
suspend fun onWalletSelected(userWallet: UserWallet) {
|
||||
// If a previous job was running, it gets cancelled before the new one starts,
|
||||
// ensuring that only one job is active at any given time.
|
||||
loadUserWalletDataJob = CoroutineScope(dispatchers.io)
|
||||
.launch { loadUserWalletData(userWallet) }
|
||||
.apply { join() }
|
||||
}
|
||||
|
||||
/**
|
||||
* [REDACTED_TODO_COMMENT]
|
||||
*/
|
||||
private suspend fun loadUserWalletData(userWallet: UserWallet) {
|
||||
val trackingContextProxy = store.inject(DaggerGraphState::trackingContextProxy)
|
||||
trackingContextProxy.setContext(userWallet)
|
||||
|
||||
if (userWallet is UserWallet.Cold) {
|
||||
val scanResponse = userWallet.scanResponse
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
|
||||
withMainContext {
|
||||
// Order is important
|
||||
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Wallet.getFirstToken(): Token? = getTokens().toList().getOrNull(index = 0)
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package com.tangem.tap.domain.card
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
|
||||
internal class DefaultDeleteSavedAccessCodesUseCase(
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
) : DeleteSavedAccessCodesUseCase {
|
||||
|
||||
override suspend fun invoke(cardId: String): Either<Throwable, Unit> {
|
||||
tangemSdkManager.deleteSavedUserCodes(setOf(cardId))
|
||||
.doOnFailure { return it.left() }
|
||||
.doOnSuccess { return Unit.right() }
|
||||
|
||||
return Unit.right()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
package com.tangem.tap.domain.model
|
||||
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.blockchain.common.Blockchain as SdkBlockchain
|
||||
import com.tangem.blockchain.common.Token as SdkToken
|
||||
|
||||
sealed interface Currency {
|
||||
val blockchain: SdkBlockchain
|
||||
val currencySymbol: CryptoCurrencyName
|
||||
val currencySymbol: String
|
||||
val derivationPath: String?
|
||||
val decimals
|
||||
get() = when (this) {
|
||||
|
|
@ -26,6 +25,6 @@ sealed interface Currency {
|
|||
override val blockchain: SdkBlockchain,
|
||||
override val derivationPath: String?,
|
||||
) : Currency {
|
||||
override val currencySymbol: CryptoCurrencyName = blockchain.currency
|
||||
override val currencySymbol: String = blockchain.currency
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.tangem.tap.domain.model
|
||||
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
|
||||
data class PendingTransaction(
|
||||
val transactionData: TransactionData.Uncompiled,
|
||||
val type: PendingTransactionType,
|
||||
) {
|
||||
val address: String? = when (type) {
|
||||
PendingTransactionType.Incoming -> nullIfUnknown(transactionData.sourceAddress)
|
||||
PendingTransactionType.Outgoing -> nullIfUnknown(transactionData.destinationAddress)
|
||||
PendingTransactionType.Unknown -> null
|
||||
}
|
||||
|
||||
val currency: String = transactionData.amount.currencySymbol
|
||||
|
||||
private fun nullIfUnknown(address: String): String? = if (address == "unknown") null else address
|
||||
}
|
||||
|
||||
enum class PendingTransactionType { Incoming, Outgoing, Unknown }
|
||||
|
||||
fun TransactionData.Uncompiled.toPendingTransaction(walletAddress: String): PendingTransaction? {
|
||||
if (this.status == TransactionStatus.Confirmed) return null
|
||||
|
||||
val type: PendingTransactionType = when {
|
||||
this.sourceAddress == walletAddress -> PendingTransactionType.Outgoing
|
||||
this.destinationAddress == walletAddress -> PendingTransactionType.Incoming
|
||||
else -> PendingTransactionType.Unknown
|
||||
}
|
||||
return PendingTransaction(this, type)
|
||||
}
|
||||
|
||||
fun List<TransactionData.Uncompiled>.toPendingTransactions(walletAddress: String): List<PendingTransaction> {
|
||||
return this.mapNotNull { it.toPendingTransaction(walletAddress) }
|
||||
}
|
||||
|
||||
fun Wallet.getPendingTransactions(type: PendingTransactionType? = null): List<PendingTransaction> {
|
||||
val txs = recentTransactions.toPendingTransactions(address)
|
||||
return when (type) {
|
||||
null -> txs
|
||||
else -> txs.filter { it.type == type }
|
||||
}
|
||||
}
|
||||
|
||||
fun Wallet.hasPendingTransactions(): Boolean {
|
||||
return getPendingTransactions().isNotEmpty()
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.tap.domain.model
|
||||
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
|
||||
internal data class WalletAddressData(
|
||||
val address: String,
|
||||
val type: AddressType,
|
||||
val shareUrl: String,
|
||||
val exploreUrl: String,
|
||||
)
|
||||
|
|
@ -5,16 +5,15 @@ import com.tangem.common.core.TangemError
|
|||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
|
||||
// TODO: Remove this object after feature toggle was removed and use ScanCardUseCase instead
|
||||
internal class DefaultScanCardProcessor(
|
||||
private val legacyScanProcessor: LegacyScanProcessor,
|
||||
private val useCaseScanProcessor: UseCaseScanProcessor,
|
||||
private val cardScanningFeatureToggles: CardScanningFeatureToggles,
|
||||
) : ScanCardProcessor {
|
||||
private val isNewCardScanningEnabled: Boolean
|
||||
get() = store.inject(DaggerGraphState::cardScanningFeatureToggles).isNewCardScanningEnabled
|
||||
get() = cardScanningFeatureToggles.isNewCardScanningEnabled
|
||||
|
||||
override suspend fun scan(
|
||||
cardId: String?,
|
||||
|
|
@ -23,7 +22,7 @@ internal class DefaultScanCardProcessor(
|
|||
shouldCheckIsAlreadyActivated: Boolean,
|
||||
): CompletionResult<ScanResponse> {
|
||||
return if (isNewCardScanningEnabled) {
|
||||
UseCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
|
||||
useCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository)
|
||||
} else {
|
||||
legacyScanProcessor.scan(
|
||||
analyticsSource = analyticsSource,
|
||||
|
|
@ -47,7 +46,7 @@ internal class DefaultScanCardProcessor(
|
|||
onSuccess: suspend (scanResponse: ScanResponse) -> Unit,
|
||||
) {
|
||||
if (isNewCardScanningEnabled) {
|
||||
UseCaseScanProcessor.scan(
|
||||
useCaseScanProcessor.scan(
|
||||
analyticsSource = analyticsSource,
|
||||
cardId = cardId,
|
||||
onProgressStateChange = onProgressStateChange,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
|
@ -21,19 +22,17 @@ import com.tangem.core.ui.extensions.toWrappedList
|
|||
import com.tangem.core.ui.message.dialog.Dialogs
|
||||
import com.tangem.domain.card.ScanFailsCounter
|
||||
import com.tangem.domain.card.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.sdk.extensions.localizedDescriptionRes
|
||||
import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -44,11 +43,17 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Suppress("LongParameterList")
|
||||
internal class LegacyScanProcessor @Inject constructor(
|
||||
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val scanFailsCounter: ScanFailsCounter,
|
||||
private val appRouter: AppRouter,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase,
|
||||
private val cardRepository: CardRepository,
|
||||
private val onboardingHelper: OnboardingHelper,
|
||||
) {
|
||||
|
||||
suspend fun scan(
|
||||
|
|
@ -139,16 +144,12 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
Analytics.send(analyticsEvent)
|
||||
}
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private suspend inline fun showDisclaimerIfNeed(
|
||||
scanResponse: ScanResponse,
|
||||
crossinline disclaimerWillShow: () -> Unit = {},
|
||||
crossinline nextHandler: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
val disclaimer = scanResponse.card.createDisclaimer()
|
||||
|
||||
if (disclaimer.isAccepted()) {
|
||||
if (cardRepository.isTangemTOSAccepted()) {
|
||||
nextHandler(scanResponse)
|
||||
} else {
|
||||
scope.launch {
|
||||
|
|
@ -157,9 +158,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
withContext(Dispatchers.Main.immediate) {
|
||||
disclaimerWillShow()
|
||||
|
||||
store.dispatchNavigationAction {
|
||||
push(AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
appRouter.push(AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +188,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
mainScope.launch {
|
||||
onCancel()
|
||||
|
||||
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
|
||||
sendFeedbackEmailUseCase.invoke(
|
||||
type = FeedbackEmailType.CardAttestationFailed,
|
||||
)
|
||||
}
|
||||
|
|
@ -202,14 +201,13 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod", "LongParameterList", "MagicNumber")
|
||||
private suspend inline fun onScanSuccess(
|
||||
scanResponse: ScanResponse,
|
||||
crossinline onProgressStateChange: suspend (showProgress: Boolean) -> Unit,
|
||||
crossinline onWalletNotCreated: suspend () -> Unit,
|
||||
crossinline onSuccess: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
|
||||
if (onboardingHelper.isOnboardingCase(scanResponse)) {
|
||||
trackingContextProxy.addContext(scanResponse)
|
||||
onWalletNotCreated()
|
||||
navigateTo(
|
||||
|
|
@ -221,8 +219,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
} else {
|
||||
trackingContextProxy.setContext(scanResponse)
|
||||
|
||||
val wasTwinsOnboardingShown =
|
||||
store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase).invokeSync()
|
||||
val wasTwinsOnboardingShown = wasTwinsOnboardingShownUseCase.invokeSync()
|
||||
|
||||
if (scanResponse.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
||||
onWalletNotCreated()
|
||||
|
|
@ -241,7 +238,7 @@ internal class LegacyScanProcessor @Inject constructor(
|
|||
|
||||
private suspend inline fun navigateTo(route: AppRoute, onProgressStateChange: (showProgress: Boolean) -> Unit) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
appRouter.push(route)
|
||||
onProgressStateChange(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,33 +4,46 @@ import arrow.fx.coroutines.resourceScope
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.Basic
|
||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.ScanFailsRequester
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.tap.common.analytics.events.TangemSdkErrorEvent
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.domain.scanCard.chains.*
|
||||
import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
internal object UseCaseScanProcessor {
|
||||
@Singleton
|
||||
@Suppress("LongParameterList")
|
||||
internal class UseCaseScanProcessor @Inject constructor(
|
||||
private val scanCardUseCase: ScanCardUseCase,
|
||||
private val scanFailsRequester: ScanFailsRequester,
|
||||
private val appRouter: AppRouter,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase,
|
||||
private val cardRepository: CardRepository,
|
||||
private val onboardingHelper: OnboardingHelper,
|
||||
) {
|
||||
private val scanCardExceptionConverter = ScanCardExceptionConverter()
|
||||
|
||||
suspend fun scan(
|
||||
cardId: String? = null,
|
||||
allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
): CompletionResult<ScanResponse> {
|
||||
val scanCardUseCase = store.inject(DaggerGraphState::scanCardUseCase)
|
||||
|
||||
return scanCardUseCase(cardId, allowsRequestAccessCodeFromRepository)
|
||||
.fold(
|
||||
ifLeft = { scanCardException ->
|
||||
|
|
@ -53,7 +66,6 @@ internal object UseCaseScanProcessor {
|
|||
onFailure: suspend (error: TangemError) -> Unit,
|
||||
onSuccess: suspend (scanResponse: ScanResponse) -> Unit,
|
||||
) = progressScope(onProgressStateChange) {
|
||||
val scanCardUseCase = store.inject(DaggerGraphState::scanCardUseCase)
|
||||
val chains = buildList {
|
||||
add(
|
||||
FailedScansCounterChain(
|
||||
|
|
@ -61,8 +73,8 @@ internal object UseCaseScanProcessor {
|
|||
),
|
||||
)
|
||||
add(AnalyticsChain(Basic.CardWasScanned(analyticsSource)))
|
||||
add(DisclaimerChain(store, disclaimerWillShow))
|
||||
add(CheckForOnboardingChain(store))
|
||||
add(DisclaimerChain(appRouter, cardRepository, disclaimerWillShow))
|
||||
add(CheckForOnboardingChain(trackingContextProxy, wasTwinsOnboardingShownUseCase, onboardingHelper))
|
||||
}
|
||||
|
||||
scanCardUseCase(cardId, afterScanChains = chains).fold(
|
||||
|
|
@ -73,7 +85,7 @@ internal object UseCaseScanProcessor {
|
|||
|
||||
private fun showScanFailsDialog(source: AnalyticsParam.ScreensSources) {
|
||||
scope.launch {
|
||||
store.inject(DaggerGraphState::scanFailsRequester).show(source)
|
||||
scanFailsRequester.show(source)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +98,6 @@ internal object UseCaseScanProcessor {
|
|||
is ScanCardException.ChainException -> proceedWithScanChainException(
|
||||
exception,
|
||||
onWalletNotCreated,
|
||||
onFailure,
|
||||
)
|
||||
is ScanCardException.UnknownException,
|
||||
is ScanCardException.UserCancelled,
|
||||
|
|
@ -109,16 +120,12 @@ internal object UseCaseScanProcessor {
|
|||
private suspend fun proceedWithScanChainException(
|
||||
exception: ScanCardException.ChainException,
|
||||
onWalletNotCreated: suspend () -> Unit,
|
||||
onFailure: suspend (error: TangemError) -> Unit,
|
||||
) {
|
||||
when (exception) {
|
||||
is ScanChainException.OnboardingNeeded -> {
|
||||
navigateTo(exception.onboardingRoute)
|
||||
onWalletNotCreated()
|
||||
}
|
||||
is ScanChainException.DisclaimerWasCanceled -> {
|
||||
onFailure(scanCardExceptionConverter.convertBack(exception))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +143,6 @@ internal object UseCaseScanProcessor {
|
|||
|
||||
private suspend inline fun navigateTo(route: AppRoute) {
|
||||
delay(DELAY_SDK_DIALOG_CLOSE)
|
||||
store.dispatchNavigationAction { push(route) }
|
||||
appRouter.push(route)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,18 +3,16 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.utils.TrackingContextProxy
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.card.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.core.chain.ResultChain
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.domain.onboarding.WasTwinsOnboardingShownUseCase
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.utils.extensions.DELAY_SDK_DIALOG_CLOSE
|
||||
import kotlinx.coroutines.delay
|
||||
import org.rekotlin.Store
|
||||
|
||||
/**
|
||||
* Handles the verification process to determine if the scanned card requires onboarding.
|
||||
|
|
@ -22,19 +20,17 @@ import org.rekotlin.Store
|
|||
* Returns:
|
||||
* - [ScanChainException.OnboardingNeeded] if onboarding required.
|
||||
*
|
||||
* @param store the [Store] that holds the state of the app.
|
||||
*
|
||||
* @see Chain for more information about the Chain interface.
|
||||
*/
|
||||
class CheckForOnboardingChain(
|
||||
private val store: Store<AppState>,
|
||||
private val trackingContextProxy: TrackingContextProxy,
|
||||
private val wasTwinsOnboardingShownUseCase: WasTwinsOnboardingShownUseCase,
|
||||
private val onboardingHelper: OnboardingHelper,
|
||||
) : ResultChain<ScanCardException, ScanResponse>() {
|
||||
|
||||
override suspend fun launch(previousChainResult: ScanResponse): ScanChainResult {
|
||||
val trackingContextProxy = store.inject(DaggerGraphState::trackingContextProxy)
|
||||
|
||||
return when {
|
||||
OnboardingHelper.isOnboardingCase(previousChainResult) -> {
|
||||
onboardingHelper.isOnboardingCase(previousChainResult) -> {
|
||||
trackingContextProxy.addContext(previousChainResult)
|
||||
ScanChainException.OnboardingNeeded(
|
||||
AppRoute.Onboarding(
|
||||
|
|
@ -46,8 +42,7 @@ class CheckForOnboardingChain(
|
|||
else -> {
|
||||
trackingContextProxy.setContext(previousChainResult)
|
||||
|
||||
val wasTwinsOnboardingShown = store.inject(DaggerGraphState::wasTwinsOnboardingShownUseCase)
|
||||
.invokeSync()
|
||||
val wasTwinsOnboardingShown = wasTwinsOnboardingShownUseCase.invokeSync()
|
||||
|
||||
// If twins was twinned previously but twins welcome not shown
|
||||
if (previousChainResult.twinsIsTwinned() && !wasTwinsOnboardingShown) {
|
||||
|
|
|
|||
|
|
@ -2,43 +2,34 @@ package com.tangem.tap.domain.scanCard.chains
|
|||
|
||||
import arrow.core.right
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.core.chain.Chain
|
||||
import com.tangem.domain.core.chain.ResultChain
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import org.rekotlin.Store
|
||||
|
||||
/**
|
||||
* Handles disclaimer display after the card scanning operation.
|
||||
*
|
||||
* Returns [ScanChainException.DisclaimerWasCanceled] if the disclaimer is dismissed by the user.
|
||||
*
|
||||
* @param store the [Store] that holds the state of the app, used here to dispatch actions related to disclaimers.
|
||||
* @param disclaimerWillShow an optional function to be invoked when a disclaimer is about to be shown. Default is an
|
||||
* empty function.
|
||||
*
|
||||
* @see Chain for more information about the Chain interface.
|
||||
*/
|
||||
internal class DisclaimerChain(
|
||||
private val store: Store<AppState>,
|
||||
private val appRouter: AppRouter,
|
||||
private val cardRepository: CardRepository,
|
||||
private val disclaimerWillShow: () -> Unit = {},
|
||||
) : ResultChain<ScanCardException, ScanResponse>() {
|
||||
|
||||
override suspend fun launch(previousChainResult: ScanResponse): ScanChainResult {
|
||||
val disclaimer = previousChainResult.card.createDisclaimer()
|
||||
|
||||
return if (disclaimer.isAccepted()) {
|
||||
return if (cardRepository.isTangemTOSAccepted()) {
|
||||
previousChainResult.right()
|
||||
} else {
|
||||
disclaimerWillShow()
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
store.dispatchNavigationAction {
|
||||
push(route = AppRoute.Disclaimer(isTosAccepted = false))
|
||||
}
|
||||
appRouter.push(route = AppRoute.Disclaimer(isTosAccepted = false))
|
||||
|
||||
previousChainResult.right()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,6 @@ import com.tangem.domain.card.ScanCardException
|
|||
|
||||
sealed class ScanChainException : ScanCardException.ChainException() {
|
||||
|
||||
/**
|
||||
* May be returned from [DisclaimerChain]
|
||||
* */
|
||||
class DisclaimerWasCanceled : ScanChainException() {
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private fun readResolve(): Any = DisclaimerWasCanceled()
|
||||
}
|
||||
|
||||
/**
|
||||
* May be returned from [CheckForOnboardingChain]
|
||||
*
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ internal class ScanCardExceptionConverter : TwoWayConverter<TangemError, ScanCar
|
|||
|
||||
private fun concertScanChainException(value: ScanCardException.ChainException): TangemSdkError {
|
||||
return when (val e = value as? ScanChainException) {
|
||||
is ScanChainException.DisclaimerWasCanceled -> TangemSdkError.UserCancelled()
|
||||
is ScanChainException.OnboardingNeeded,
|
||||
null,
|
||||
-> TangemSdkError.ExceptionError(e?.cause)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.tangem.crypto.bip39.DefaultMnemonic
|
|||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -72,6 +73,7 @@ internal class DefaultTangemSdkManager(
|
|||
private val dynamicAddressesFeatureToggles: DynamicAddressesFeatureToggles,
|
||||
private val blockchainToDeriveFinder: BlockchainToDeriveFinder,
|
||||
private val analyticsErrorHandler: AnalyticsErrorHandler,
|
||||
private val cardRepository: CardRepository,
|
||||
) : TangemSdkManager {
|
||||
|
||||
private val tangemSdk: TangemSdk
|
||||
|
|
@ -146,6 +148,7 @@ internal class DefaultTangemSdkManager(
|
|||
shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated,
|
||||
isDynamicAddressesEnabled = dynamicAddressesFeatureToggles.isDynamicAddressesEnabled,
|
||||
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
|
||||
cardRepository = cardRepository,
|
||||
),
|
||||
cardId = cardId,
|
||||
initialMessage = message,
|
||||
|
|
@ -453,6 +456,7 @@ internal class DefaultTangemSdkManager(
|
|||
twinPublicKey = secondCardPublicKey,
|
||||
issuerKeys = issuerKeyPair,
|
||||
isDynamicAddressesEnabled = dynamicAddressesFeatureToggles.isDynamicAddressesEnabled,
|
||||
cardRepository = cardRepository,
|
||||
),
|
||||
cardId = cardId,
|
||||
initialMessage = initialMessage,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.tangem.common.KeyPair
|
|||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.authentication.keystore.DummyKeystoreManager
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.core.UserCodeRequestPolicy
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.common.services.InMemoryStorage
|
||||
|
|
@ -32,6 +33,8 @@ import com.tangem.sdk.api.TangemSdkManager
|
|||
import com.tangem.sdk.api.visa.VisaCardActivationResponse
|
||||
import com.tangem.sdk.api.visa.VisaCardActivationTaskMode
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import com.tangem.tap.domain.sdk.mocks.showMockCardPicker
|
||||
import com.tangem.tap.foregroundActivityObserver
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
class MockTangemSdkManager(
|
||||
|
|
@ -61,6 +64,17 @@ class MockTangemSdkManager(
|
|||
allowsRequestAccessCodeFromRepository: Boolean,
|
||||
shouldCheckIsAlreadyActivated: Boolean,
|
||||
): CompletionResult<ScanResponse> {
|
||||
if (!MockProvider.isPreset) {
|
||||
val activity = foregroundActivityObserver.foregroundActivity
|
||||
if (activity != null) {
|
||||
val selectedMock = showMockCardPicker(activity)
|
||||
if (selectedMock != null) {
|
||||
MockProvider.setMocksWithoutPresetFlag(selectedMock)
|
||||
} else {
|
||||
return CompletionResult.Failure(TangemSdkError.UserCancelled())
|
||||
}
|
||||
}
|
||||
}
|
||||
return MockProvider.getScanResponse()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.tap.domain.sdk.mocks
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.wallet.R
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
internal suspend fun showMockCardPicker(activity: AppCompatActivity): MockContent? = withContext(Dispatchers.Main) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
val mocks = MockProvider.availableMocks
|
||||
val names = mocks.map { it.first }.toTypedArray()
|
||||
|
||||
val dialog = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.mock_card_picker_title)
|
||||
.setItems(names) { _, which ->
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(mocks[which].second)
|
||||
}
|
||||
}
|
||||
.setOnCancelListener {
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(null)
|
||||
}
|
||||
}
|
||||
.create()
|
||||
|
||||
continuation.invokeOnCancellation { activity.runOnUiThread { dialog.dismiss() } }
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
|
@ -11,10 +11,40 @@ object MockProvider {
|
|||
|
||||
private var content: MockContent = getMockContent(ProductType.Wallet)
|
||||
|
||||
var isPreset: Boolean = false
|
||||
private set
|
||||
|
||||
private var isEmulatingError: Boolean = false
|
||||
|
||||
private var emulatedError: TangemError = TangemSdkError.TagLost()
|
||||
|
||||
val availableMocks: List<Pair<String, MockContent>> = listOf(
|
||||
"Wallet" to WalletMockContent,
|
||||
"Note" to NoteMockContent,
|
||||
"Twins" to TwinsMockContent,
|
||||
"Ring" to RingMockContent,
|
||||
"Wallet 2" to Wallet2MockContent,
|
||||
"Wallet 2 (No Backup)" to Wallet2NoBackupMockContent,
|
||||
"Wallet 2 (No Backup, No Wallets)" to Wallet2NoBackupNoWalletsMockContent,
|
||||
"Wallet 2 (Seed Phrase)" to Wallet2WithSeedPhraseMockContent,
|
||||
"Shiba" to ShibaMockContent,
|
||||
"Shiba (No Backup)" to ShibaNoBackupMockContent,
|
||||
"Shiba (No Backup, No Wallets)" to ShibaNoBackupNoWalletsMockContent,
|
||||
"Ed25519 Curve" to EdCurveMockContent,
|
||||
"Secp256k1 Curve" to Secpk1CurveMockContent,
|
||||
"Backup Wallet" to BackupWalletMockContent,
|
||||
"Dev Wallet" to DevWalletMockContent,
|
||||
"Firmware 4.12" to Firmware412MockContent,
|
||||
"French Blue (Triple)" to FrenchBlueMockContent,
|
||||
"French White (Double)" to FrenchWhiteMockContent,
|
||||
"Football Black (Double)" to FootballBlackMockContent,
|
||||
"Football Dark Green (Triple)" to FootballDarkGreenMockContent,
|
||||
"Metaplanet (Triple)" to MetaplanetMockContent,
|
||||
"Metaplanet (Double)" to MetaplanetDoubleMockContent,
|
||||
"Red Panda (Triple)" to RedPandaMockContent,
|
||||
"Red Panda (Double)" to RedPandaDoubleMockContent,
|
||||
)
|
||||
|
||||
fun setEmulateError(error: TangemError? = null) {
|
||||
isEmulatingError = true
|
||||
error?.let {
|
||||
|
|
@ -28,10 +58,16 @@ object MockProvider {
|
|||
|
||||
fun setMocks(productType: ProductType) {
|
||||
content = getMockContent(productType)
|
||||
isPreset = true
|
||||
}
|
||||
|
||||
fun setMocks(mockContent: MockContent) {
|
||||
content = mockContent
|
||||
isPreset = true
|
||||
}
|
||||
|
||||
fun setMocksWithoutPresetFlag(mockContent: MockContent) {
|
||||
content = mockContent
|
||||
}
|
||||
|
||||
fun getSuccessResponse() = CompletionResult.Success(content.successResponse).orFailure()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object FootballBlackMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "AF99009000000000",
|
||||
batchId = "AF990090",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "AF99009000000000",
|
||||
batchId = "AF990090",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(1),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "AF99009000000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object FootballDarkGreenMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "AF99008900000000",
|
||||
batchId = "AF990089",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "AF99008900000000",
|
||||
batchId = "AF990089",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(2),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "AF99008900000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object FrenchBlueMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "AF99008400000000",
|
||||
batchId = "AF990084",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "AF99008400000000",
|
||||
batchId = "AF990084",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(2),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "AF99008400000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object FrenchWhiteMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "AF99008500000000",
|
||||
batchId = "AF990085",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "AF99008500000000",
|
||||
batchId = "AF990085",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(1),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "AF99008500000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object MetaplanetDoubleMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "BB00004000000000",
|
||||
batchId = "BB000040",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "BB00004000000000",
|
||||
batchId = "BB000040",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(1),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "BB00004000000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object MetaplanetMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "BB00004000000000",
|
||||
batchId = "BB000040",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "BB00004000000000",
|
||||
batchId = "BB000040",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(2),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "BB00004000000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object RedPandaDoubleMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "BB00003800000000",
|
||||
batchId = "BB000038",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "BB00003800000000",
|
||||
batchId = "BB000038",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(1),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "BB00003800000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
package com.tangem.tap.domain.sdk.mocks.content
|
||||
|
||||
import com.tangem.common.SuccessResponse
|
||||
import com.tangem.common.card.*
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.attestation.Attestation
|
||||
import com.tangem.operations.backup.PrimaryCard
|
||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.sdk.api.CreateProductWalletTaskResponse
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import java.util.Date
|
||||
|
||||
object RedPandaMockContent : MockContent {
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "BB00003800000000",
|
||||
batchId = "BB000038",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
linkingKey = byteArrayOf( //
|
||||
2, 121, 98, 127, -70, 14, 5, -23, -76, 115, -30, -26, 111, 17, 110, 34, -100, -121,
|
||||
-57, -123, 74, 3, -91, 56, -20, 56, 50, -40, -101, 96, 82, 70, -91,
|
||||
),
|
||||
existingWalletsCount = 5, isHDWalletAllowed = true,
|
||||
issuer = Card.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
manufacturer = Card.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1743759687),
|
||||
signature = byteArrayOf(),
|
||||
),
|
||||
walletCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
firmwareVersion = FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
isKeysImportAllowed = false,
|
||||
certificate = null,
|
||||
)
|
||||
|
||||
override val cardDto = CardDTO(
|
||||
cardId = "BB00003800000000",
|
||||
batchId = "BB000038",
|
||||
cardPublicKey = byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
firmwareVersion = CardDTO.FirmwareVersion(
|
||||
major = 6,
|
||||
minor = 33,
|
||||
patch = 0,
|
||||
type = FirmwareVersion.FirmwareType.Release,
|
||||
),
|
||||
manufacturer = CardDTO.Manufacturer(
|
||||
name = "TANGEM",
|
||||
manufactureDate = Date(1698094800000),
|
||||
signature = byteArrayOf(51, -12, 14, -56, 7, -39, 5, 63, 59, 24, 102, 99, -126, 124, -127, -108, -118, 71, -19, -71, 4, -47, -121, -46, 49, -51, -31, 100, -56, -15, 96, -37, 25, 82, 94, -88, 48, 98, -105, -97, -40, 41, 27, 116, 65, 26, 78, -85, 66, -94, -92, 15, 50, -2, 7, -69, 41, 56, -75, 59, 86, 68, -38, -3),
|
||||
),
|
||||
issuer = CardDTO.Issuer(
|
||||
name = "TANGEM SDK",
|
||||
publicKey = byteArrayOf(2, 95, 22, -67, 29, 46, -81, -28, 99, -26, 42, 51, 90, 9, -26, -78, -69, -53, -48, 68, 82, 82, 104, -123, -53, 103, -97, -60, -46, 122, -15, -67, 34),
|
||||
),
|
||||
settings = CardDTO.Settings(
|
||||
securityDelay = 15000,
|
||||
maxWalletsCount = 20,
|
||||
isSettingAccessCodeAllowed = true,
|
||||
isSettingPasscodeAllowed = true,
|
||||
isResettingUserCodesAllowed = false,
|
||||
isLinkedTerminalEnabled = true,
|
||||
isBackupAllowed = true,
|
||||
supportedEncryptionModes = listOf(EncryptionMode.Strong, EncryptionMode.Fast, EncryptionMode.None),
|
||||
isFilesAllowed = true,
|
||||
isHDWalletAllowed = true,
|
||||
isKeysImportAllowed = true,
|
||||
),
|
||||
userSettings = CardDTO.UserSettings(isUserCodeRecoveryAllowed = true),
|
||||
linkedTerminalStatus = CardDTO.LinkedTerminalStatus.None,
|
||||
isAccessCodeSet = true,
|
||||
isPasscodeSet = false,
|
||||
supportedCurves = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
EllipticCurve.Secp256r1,
|
||||
EllipticCurve.Ed25519Slip0010,
|
||||
EllipticCurve.Bls12381G2,
|
||||
EllipticCurve.Bls12381G2Pop,
|
||||
EllipticCurve.Bip0340,
|
||||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(3, 17, 59, -102, -56, 66, 10, 36, 97, -106, -92, -117, -105, -88, -2, -3, -95, -75, -54, -2, 57, 27, -90, -19, 82, 103, -12, -52, -126, -105, -120, -55, -2),
|
||||
chainCode = byteArrayOf(-34, -28, -28, -12, 80, -109, -90, -31, -74, 36, -78, -21, 39, -125, -39, -91, 63, 40, -26, 3, 66, 27, -62, -55, -97, 52, -65, -11, 26, -80, 33, -45),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 0,
|
||||
hasBackup = true,
|
||||
derivedKeys = mapOf(
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 55, -114, -94, -73, -61, -50, 51, -115, 55, -79, 63, -96, -44, -64, -24, -36, -122, -123, -38, 81, -15, -127, -97, -42, 72, -85, -62, -98, 46, 119, 16, -55),
|
||||
chainCode = byteArrayOf(31, 17, 71, -28, -29, 17, 72, -29, -98, 112, 31, -8, 72, -75, 4, -11, 60, -100, 9, 35, 58, -42, -38, 96, -71, -68, 24, -119, -43, -18, -122, 72),
|
||||
),
|
||||
DerivationPath("m/84'/0'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -26, 103, 96, 112, 127, -125, 0, 7, 53, 30, -12, -82, 45, 14, 107, -9, 126, 75, 104, -67, -49, 35, -12, -82, -90, 101, -101, 125, -76, 88, -54, 99),
|
||||
chainCode = byteArrayOf(-42, 36, 97, 65, -64, -113, 76, -91, -9, 11, 89, 123, -9, -3, 21, 103, -113, -60, 48, -31, -34, 108, 111, -38, -110, -80, 109, 17, -29, 2, 45, -71),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -96, -3, -83, 101, 63, -25, -125, -4, -65, -42, -56, 24, -52, 118, -11, -104, -105, 40, -59, 20, -109, -97, 29, -95, -6, -80, 2, 67, 103, -80, -22, -94),
|
||||
chainCode = byteArrayOf(-125, 27, -91, 38, -66, 109, -92, 16, -37, 93, 107, -29, -128, -1, 115, -64, 108, -63, 17, 27, 58, 78, -2, 39, 88, -39, 44, 89, 32, -38, -16, -38),
|
||||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-109, 42, -80, -115, -12, 44, 48, -118, -89, 10, 21, 59, 98, -110, -86, -14, 123, 105, -30, -49, -40, -4, -7, 32, 60, 67, -88, -52, -96, -10, -14, 123),
|
||||
chainCode = byteArrayOf(-101, -10, -92, 72, 19, 121, -38, 105, -55, -82, -68, 13, -6, 17, 66, -10, -75, 58, 119, -127, 74, 68, 82, 25, 45, -110, 3, 3, 108, -97, -51, -127),
|
||||
curve = EllipticCurve.Ed25519,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 1,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-64, 18, -128, 121, -89, -37, -99, 44, -125, -72, -111, -79, 7, 85, 40, 67, -39, 117, 123, 11, 105, -6, -5, -79, 19, -10, -29, 20, -14, -40, 5, 90),
|
||||
chainCode = byteArrayOf(33, -97, 53, -112, 61, 112, -24, 74, -87, -85, -124, -4, 103, -94, -97, 76, -41, -27, 118, 33, 55, 121, -17, -52, 60, 122, 27, 25, 29, -76, 78, 11),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-118, -77, -109, 8, -119, 101, -91, 46, -44, 15, 52, -64, -92, 5, -102, 126, 52, 121, 63, -76, -54, 80, -82, -5, 31, -35, 105, -119, -96, -54, 38, 2, -6, 109, 117, -26, -47, -20, 108, 106, -69, 72, -37, -117, -30, -9, 104, -123),
|
||||
chainCode = null,
|
||||
curve = EllipticCurve.Bls12381G2Aug,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 1,
|
||||
remainingSignatures = null,
|
||||
index = 2,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = null,
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(17, -78, 53, 101, 96, -110, -10, -48, -84, 88, -64, 58, -26, -13, -2, -6, -25, 23, -79, -45, 58, 77, 52, -75, -123, 121, 32, 92, 84, -74, -111, -8),
|
||||
chainCode = byteArrayOf(-110, 73, -124, -65, -1, -70, 64, -89, 95, -74, 15, 46, -110, 87, 15, -61, 120, -51, 111, 111, -45, 37, 123, -114, 65, -116, 21, 39, -77, 86, -3, -26),
|
||||
curve = EllipticCurve.Bip0340,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 3,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(115, 14, 11, 0, -93, 81, -103, -95, -75, -84, 18, -120, -31, 76, -83, -81, 91, 25, -75, 36, -99, -53, -25, -15, -1, -57, 14, -39, 98, -116, -63, -123),
|
||||
chainCode = byteArrayOf(23, 5, 38, -48, 67, -42, -31, -21, 89, 11, 22, -28, 44, -19, -115, -78, 123, -27, 57, 57, -24, -86, 55, 15, 104, 114, -36, 80, 81, -108, -41, 112),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(-52, -92, 64, 108, -8, -100, 87, -86, -60, 18, -18, -81, 114, -84, 76, -24, 84, 52, -34, 79, -30, -66, -112, -55, -35, -119, 127, -109, 35, 18, -29, -25),
|
||||
chainCode = byteArrayOf(94, -33, -94, -63, 40, -20, -26, 71, 111, 9, 87, -36, -42, -33, 40, -53, 85, 31, -36, -29, 65, -121, 2, -23, -119, -51, 114, -17, -39, -74, 23, -97),
|
||||
curve = EllipticCurve.Ed25519Slip0010,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
totalSignedHashes = 0,
|
||||
remainingSignatures = null,
|
||||
index = 4,
|
||||
hasBackup = true,
|
||||
derivedKeys = emptyMap(),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(-43, 1, -81, -47, -8, -103, -66, 42, 37, -7, 65, 54, 57, -24, 127, -89, 69, -112, 42, -46, -128, 36, -117, -28, 30, -48, 37, 52, 93, -47, 92, -47),
|
||||
chainCode = byteArrayOf(4, -97, 81, -37, 76, -67, -87, -4, -82, -36, -45, -28, -117, -59, -62, 93, -73, 50, 65, -91, -83, 25, -95, 89, -64, -40, 113, 28, 59, 113, -99, 89),
|
||||
),
|
||||
isImported = false,
|
||||
),
|
||||
),
|
||||
attestation = Attestation(
|
||||
cardKeyAttestation = Attestation.Status.Verified,
|
||||
walletKeysAttestation = Attestation.Status.Skipped,
|
||||
firmwareAttestation = Attestation.Status.Skipped,
|
||||
cardUniquenessAttestation = Attestation.Status.Skipped,
|
||||
),
|
||||
backupStatus = CardDTO.BackupStatus.Active(2),
|
||||
)
|
||||
|
||||
override val scanResponse = ScanResponse(
|
||||
card = cardDto,
|
||||
productType = ProductType.Wallet2,
|
||||
walletData = null,
|
||||
secondTwinPublicKey = null,
|
||||
derivedKeys = emptyMap(),
|
||||
primaryCard = null,
|
||||
)
|
||||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/3'/0'/0/0") to ExtendedPublicKey( // doge
|
||||
publicKey = byteArrayOf(3, -25, -24, -97, -124, 24, -89, 44, 75, 123, 92, -86, -73, -93, 25, -90, -89, -95, 88, 3, 107, 37, -1, -85, -32, -57, -123, -41, 108, -9, -96, 77, -124),
|
||||
chainCode = byteArrayOf(119, 3, 41, 112, 71, 54, 72, 30, 39, 25, 25, -104, 92, 46, -109, 63, 93, 67, 43, -102, -87, 39, -95, 106, 45, 67, 109, -29, -35, 10, -107, 104),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override val extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -93, -36, -105, 121, -52, -30, -43, -67, -7, -31, -26, -35, 25, 99, 25, -20, 118, -20, -125, -89, 12, -101, -86, 74, -91, 23, -24, 93, -86, 20, -53, -8),
|
||||
chainCode = byteArrayOf(32, 60, 63, -96, 97, 58, 121, 108, 75, 59, 63, -113, 60, -49, 47, 33, 15, -65, -69, 45, -7, -26, 65, -5, -91, -55, -42, -102, -127, -104, -111, 96),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
)
|
||||
|
||||
override val successResponse = SuccessResponse(cardId = "BB00003800000000")
|
||||
|
||||
override val createProductWalletTaskResponse = CreateProductWalletTaskResponse(
|
||||
card = cardDto,
|
||||
derivedKeys = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(3, 23, -112, -57, 109, 60, -82, -36, 45, -14, -34, -12, 10, -89, 14, 37, 38, 36, -102, 37, 93, 90, 69, -113, -117, 120, -29, 12, -125, 43, -40, -31, 5),
|
||||
)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
DerivationPath("m/44'/0'/0'/0/0") to ExtendedPublicKey( // btc
|
||||
publicKey = byteArrayOf(3, 45, 58, -110, -52, -51, -83, -4, -45, -118, 119, 37, 123, -17, 66, -83, 61, -106, 115, 47, 121, 66, 84, -122, -57, -45, 7, -79, 70, -13, 28, -125, -52),
|
||||
chainCode = byteArrayOf(93, 51, 52, -66, -39, -38, 34, -84, 50, 1, -127, -20, 80, -20, -30, -72, 2, 1, -78, -81, -17, 51, -52, -25, 12, 108, 50, 89, -66, 18, 65, 70),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
|
||||
override val importWalletResponse: CreateProductWalletTaskResponse
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override val createFirstTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val createSecondTwinResponse: CreateWalletResponse
|
||||
get() = error("Available only for Twin")
|
||||
|
||||
override val finalizeTwinResponse: ScanResponse
|
||||
get() = error("Available only for Twin")
|
||||
}
|
||||
|
|
@ -24,6 +24,9 @@ import java.util.Date
|
|||
@Suppress("LargeClass")
|
||||
object WalletMockContent : MockContent {
|
||||
|
||||
private val secp256k1WalletPublicKey =
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5)
|
||||
|
||||
private val primaryCard = PrimaryCard(
|
||||
cardId = "AC05000000086747",
|
||||
batchId = "AC05",
|
||||
|
|
@ -100,7 +103,7 @@ object WalletMockContent : MockContent {
|
|||
),
|
||||
wallets = listOf(
|
||||
CardDTO.Wallet(
|
||||
publicKey = byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
publicKey = secp256k1WalletPublicKey,
|
||||
chainCode = byteArrayOf(80, 13, -8, -108, -35, 116, -92, 125, -65, -28, 85, 72, -113, 59, 83, 13, 5, -83, -102, 123, 124, -22, 94, 108, -71, 95, 65, -2, 38, 38, -108, 14),
|
||||
curve = EllipticCurve.Secp256k1,
|
||||
settings = CardWallet.Settings(isPermanent = false),
|
||||
|
|
@ -117,11 +120,15 @@ object WalletMockContent : MockContent {
|
|||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/1") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
),
|
||||
DerivationPath("m/44'/1'/0'/0/0") to ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
),
|
||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( // Tron Network
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
),
|
||||
|
|
@ -137,7 +144,7 @@ object WalletMockContent : MockContent {
|
|||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
),
|
||||
DerivationPath("m/44'/501'/0'") to ExtendedPublicKey(
|
||||
DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
),
|
||||
|
|
@ -151,7 +158,7 @@ object WalletMockContent : MockContent {
|
|||
),
|
||||
),
|
||||
extendedPublicKey = ExtendedPublicKey(
|
||||
publicKey = byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
publicKey = secp256k1WalletPublicKey,
|
||||
chainCode = byteArrayOf(80, 13, -8, -108, -35, 116, -92, 125, -65, -28, 85, 72, -113, 59, 83, 13, 5, -83, -102, 123, 124, -22, 94, 108, -71, 95, 65, -2, 38, 38, -108, 14),
|
||||
),
|
||||
isImported = false,
|
||||
|
|
@ -193,9 +200,7 @@ object WalletMockContent : MockContent {
|
|||
|
||||
override val derivationTaskResponse = DerivationTaskResponse(
|
||||
entries = mapOf(
|
||||
ByteArrayKey(
|
||||
byteArrayOf(2, -109, 28, -27, -124, -58, -97, -61, 43, -84, 90, -9, -5, 4, 90, 17, 112, -125, -108, 44, 19, -79, -60, -23, 34, -20, -20, 61, 84, 113, 120, -90, -5),
|
||||
)
|
||||
ByteArrayKey(secp256k1WalletPublicKey)
|
||||
to
|
||||
ExtendedPublicKeysMap(
|
||||
mapOf(
|
||||
|
|
@ -220,6 +225,20 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/1") to ExtendedPublicKey( // eth (account 2)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/3") to ExtendedPublicKey( // eth (account 3)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/145'/0'/0/0") to ExtendedPublicKey( // bch
|
||||
publicKey = byteArrayOf(2, 38, -6, 92, -37, -91, -59, -108, -18, -119, -55, 41, 38, -33, 44, 59, 24, -79, -14, -38, -10, -123, 106, 56, 39, 8, 112, 29, -41, 99, 70, -104, -121),
|
||||
chainCode = byteArrayOf(105, -21, -61, -50, 68, -89, 119, 53, -96, -40, 119, 77, -122, 121, 16, 40, -50, -48, -105, -101, -74, -7, -94, -59, -90, 96, 59, 99, 43, -91, 115, -29),
|
||||
|
|
@ -241,7 +260,14 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey(
|
||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( // Tron (account 0)
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/195'/1'/0/0") to ExtendedPublicKey( // Tron (account 2)
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
|
|
@ -269,6 +295,13 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/111111'/1'/0/0") to ExtendedPublicKey( // Kaspa (account 2)
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/330'/0'/0/0") to ExtendedPublicKey( // Terra
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
|
|
@ -305,7 +338,14 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana
|
||||
DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana (account 1)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/501'/1'") to ExtendedPublicKey( // Solana (account 2)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
|
|
@ -386,6 +426,13 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/3") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/60'/0'/0/0") to ExtendedPublicKey( // eth
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
|
|
@ -407,7 +454,30 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/111111'/1'/0/0") to ExtendedPublicKey( // Kaspa (account 2)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6,
|
||||
77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67,),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/818'/0'/0/0") to ExtendedPublicKey( // Vechain
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6,
|
||||
77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82, -67,),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/195'/0'/0/0") to ExtendedPublicKey( // Tron (account 1)
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/195'/1'/0/0") to ExtendedPublicKey( // Tron (account 2)
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
depth = 0,
|
||||
|
|
@ -436,9 +506,16 @@ object WalletMockContent : MockContent {
|
|||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana
|
||||
publicKey = byteArrayOf(2, -40, 115, -15, 80, 104, 100, -29, 80, 29, 112, -35, -54, 64, -98, 45, 115, 108, 93, 113, -71, 89, 17, 72, 98, 21, 126, 82, -50, 50, -12, -87, -62),
|
||||
chainCode = byteArrayOf(-27, 56, 57, 54, 27, -40, 65, 109, 119, -54, -94, 88, -29, -115, -45, -112, -31, 57, 53, 56, 118, 87, 34, -16, -64, -45, 105, 77, 91, -106, -92, 41),
|
||||
DerivationPath("m/44'/501'/0'") to ExtendedPublicKey( // Solana (account 1)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
),
|
||||
DerivationPath("m/44'/501'/1'") to ExtendedPublicKey( // Solana (account 2)
|
||||
publicKey = byteArrayOf(2, 34, 6, 119, -106, 5, -119, 111, -22, 8, 23, -108, -72, -56, 6, 77, -17, -61, -101, -85, 16, 28, 18, 3, -3, -89, -81, -108, 48, -7, -86, -82),
|
||||
chainCode = byteArrayOf(-75, 55, 107, -106, -37, -81, -15, 72, -102, 94, 55, -39, 9, -112, 1, 90, -50, 103, 53, 120, -92, -36, -85, -39, -65, 1, 88, 46, 92, 104, -13, -109),
|
||||
depth = 0,
|
||||
parentFingerprint = byteArrayOf(0, 0, 0, 0),
|
||||
childNumber = 0,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue