Merge branch 'main' of https://github.com/cake-tech/cake_wallet into fix-p2sh
# Conflicts: # cw_bitcoin/lib/electrum_wallet_addresses.dart
5
.github/workflows/cache_dependencies.yml
vendored
|
@ -23,9 +23,10 @@ jobs:
|
||||||
docker-images: true
|
docker-images: true
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: "17.x"
|
distribution: "temurin"
|
||||||
|
java-version: "17"
|
||||||
- name: Configure placeholder git details
|
- name: Configure placeholder git details
|
||||||
run: |
|
run: |
|
||||||
git config --global user.email "CI@cakewallet.com"
|
git config --global user.email "CI@cakewallet.com"
|
||||||
|
|
34
.github/workflows/pr_test_build_android.yml
vendored
|
@ -13,6 +13,9 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
PR_test_build:
|
PR_test_build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
api-level: [29]
|
||||||
env:
|
env:
|
||||||
STORE_PASS: test@cake_wallet
|
STORE_PASS: test@cake_wallet
|
||||||
KEY_PASS: test@cake_wallet
|
KEY_PASS: test@cake_wallet
|
||||||
|
@ -39,9 +42,10 @@ jobs:
|
||||||
docker-images: true
|
docker-images: true
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: "17.x"
|
distribution: "temurin"
|
||||||
|
java-version: "17"
|
||||||
- name: Configure placeholder git details
|
- name: Configure placeholder git details
|
||||||
run: |
|
run: |
|
||||||
git config --global user.email "CI@cakewallet.com"
|
git config --global user.email "CI@cakewallet.com"
|
||||||
|
@ -92,6 +96,25 @@ jobs:
|
||||||
cd /opt/android/cake_wallet
|
cd /opt/android/cake_wallet
|
||||||
flutter pub get
|
flutter pub get
|
||||||
|
|
||||||
|
|
||||||
|
- name: Install go and gomobile
|
||||||
|
run: |
|
||||||
|
# install go > 1.23:
|
||||||
|
wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz
|
||||||
|
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz
|
||||||
|
export PATH=$PATH:/usr/local/go/bin
|
||||||
|
export PATH=$PATH:~/go/bin
|
||||||
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
|
gomobile init
|
||||||
|
|
||||||
|
- name: Build mwebd
|
||||||
|
run: |
|
||||||
|
# paths are reset after each step, so we need to set them again:
|
||||||
|
export PATH=$PATH:/usr/local/go/bin
|
||||||
|
export PATH=$PATH:~/go/bin
|
||||||
|
cd /opt/android/cake_wallet/scripts/android/
|
||||||
|
./build_mwebd.sh --dont-install
|
||||||
|
|
||||||
- name: Generate KeyStore
|
- name: Generate KeyStore
|
||||||
run: |
|
run: |
|
||||||
cd /opt/android/cake_wallet/android/app
|
cd /opt/android/cake_wallet/android/app
|
||||||
|
@ -148,6 +171,8 @@ jobs:
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||||
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
|
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -167,6 +192,10 @@ jobs:
|
||||||
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
||||||
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||||
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||||
|
echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
|
||||||
|
|
||||||
- name: Rename app
|
- name: Rename app
|
||||||
run: |
|
run: |
|
||||||
|
@ -195,6 +224,7 @@ jobs:
|
||||||
cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
|
cd /opt/android/cake_wallet/build/app/outputs/flutter-apk
|
||||||
mkdir test-apk
|
mkdir test-apk
|
||||||
cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
|
cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk
|
||||||
|
cp app-x86_64-release.apk test-apk/${{env.BRANCH_NAME}}_x86.apk
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: kittaakos/upload-artifact-as-is@v0
|
uses: kittaakos/upload-artifact-as-is@v0
|
||||||
|
|
25
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -89,6 +89,25 @@ jobs:
|
||||||
cd /opt/android/cake_wallet
|
cd /opt/android/cake_wallet
|
||||||
flutter pub get
|
flutter pub get
|
||||||
|
|
||||||
|
- name: Install go and gomobile
|
||||||
|
run: |
|
||||||
|
# install go > 1.23:
|
||||||
|
wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz
|
||||||
|
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz
|
||||||
|
export PATH=$PATH:/usr/local/go/bin
|
||||||
|
export PATH=$PATH:~/go/bin
|
||||||
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
|
gomobile init
|
||||||
|
|
||||||
|
- name: Build mwebd
|
||||||
|
run: |
|
||||||
|
# paths are reset after each step, so we need to set them again:
|
||||||
|
export PATH=$PATH:/usr/local/go/bin
|
||||||
|
export PATH=$PATH:~/go/bin
|
||||||
|
# build mwebd:
|
||||||
|
cd /opt/android/cake_wallet/scripts/android/
|
||||||
|
./build_mwebd.sh --dont-install
|
||||||
|
|
||||||
- name: Generate localization
|
- name: Generate localization
|
||||||
run: |
|
run: |
|
||||||
cd /opt/android/cake_wallet
|
cd /opt/android/cake_wallet
|
||||||
|
@ -125,6 +144,8 @@ jobs:
|
||||||
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
|
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -154,6 +175,10 @@ jobs:
|
||||||
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
|
||||||
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||||
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
|
||||||
|
echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart
|
||||||
|
|
||||||
- name: Rename app
|
- name: Rename app
|
||||||
run: |
|
run: |
|
||||||
|
|
3
.gitignore
vendored
|
@ -171,6 +171,9 @@ macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
|
||||||
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
|
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
|
||||||
macos/Runner/Configs/AppInfo.xcconfig
|
macos/Runner/Configs/AppInfo.xcconfig
|
||||||
|
|
||||||
|
|
||||||
|
integration_test/playground.dart
|
||||||
|
|
||||||
# Monero.dart (Monero_C)
|
# Monero.dart (Monero_C)
|
||||||
scripts/monero_c
|
scripts/monero_c
|
||||||
# iOS generated framework bin
|
# iOS generated framework bin
|
||||||
|
|
|
@ -161,7 +161,9 @@ The only parts to be translated, if needed, are the values m and s after the var
|
||||||
|
|
||||||
4. Add the language to `lib/entities/language_service.dart` under both `supportedLocales` and `localeCountryCode`. Use the name of the language in the local language and in English in parentheses after for `supportedLocales`. Use the [ISO 3166-1 alpha-3 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) for `localeCountryCode`. You must choose one country, so choose the country with the most native speakers of this language or is otherwise best associated with this language.
|
4. Add the language to `lib/entities/language_service.dart` under both `supportedLocales` and `localeCountryCode`. Use the name of the language in the local language and in English in parentheses after for `supportedLocales`. Use the [ISO 3166-1 alpha-3 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) for `localeCountryCode`. You must choose one country, so choose the country with the most native speakers of this language or is otherwise best associated with this language.
|
||||||
|
|
||||||
5. Add a relevant flag to `assets/images/flags/XXXX.png`, replacing XXXX with the 3 digit localeCountryCode. The image must be 42x26 pixels with a 3 pixels of transparent margin on all 4 sides. You can resize the flag with [paint.net](https://www.getpaint.net/) to 36x20 pixels, expand the canvas to 42x26 pixels with the flag anchored in the middle, and then manually delete the 3 pixels on each side to make transparent. Or you can use another program like Photoshop.
|
5. Add a relevant flag to `assets/images/flags/XXXX.png`, replacing XXXX with the 3 letters localeCountryCode. The image must be 42x26 pixels with a 3 pixels of transparent margin on all 4 sides. You can resize the flag with [paint.net](https://www.getpaint.net/) to 36x20 pixels, expand the canvas to 42x26 pixels with the flag anchored in the middle, and then manually delete the 3 pixels on each side to make transparent. Or you can use another program like Photoshop.
|
||||||
|
|
||||||
|
6. Add the new language code to `tool/utils/translation/translation_constants.dart`
|
||||||
|
|
||||||
## Add a new fiat currency
|
## Add a new fiat currency
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
include: package:lints/recommended.yaml
|
include: package:lints/recommended.yaml
|
||||||
|
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
exclude: [
|
exclude: [
|
||||||
build/**,
|
build/**,
|
||||||
|
@ -10,7 +11,18 @@ analyzer:
|
||||||
lib/generated/*.dart,
|
lib/generated/*.dart,
|
||||||
cw_monero/ios/External/**,
|
cw_monero/ios/External/**,
|
||||||
cw_shared_external/**,
|
cw_shared_external/**,
|
||||||
shared_external/**]
|
shared_external/**,
|
||||||
|
lib/bitcoin/cw_bitcoin.dart,
|
||||||
|
lib/bitcoin_cash/cw_bitcoin_cash.dart,
|
||||||
|
lib/ethereum/cw_ethereum.dart,
|
||||||
|
lib/haven/cw_haven.dart,
|
||||||
|
lib/monero/cw_monero.dart,
|
||||||
|
lib/nano/cw_nano.dart,
|
||||||
|
lib/polygon/cw_polygon.dart,
|
||||||
|
lib/solana/cw_solana.dart,
|
||||||
|
lib/tron/cw_tron.dart,
|
||||||
|
lib/wownero/cw_wownero.dart,
|
||||||
|
]
|
||||||
language:
|
language:
|
||||||
strict-casts: true
|
strict-casts: true
|
||||||
strict-raw-types: true
|
strict-raw-types: true
|
||||||
|
|
|
@ -1,35 +1,30 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="__APP_PACKAGE__">
|
package="__APP_PACKAGE__">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
||||||
|
|
||||||
<!--bibo01 : hardware option-->
|
<!-- bibo01 : hardware option-->
|
||||||
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/>
|
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
|
||||||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
|
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
|
||||||
|
|
||||||
<!-- required for API 18 - 30 -->
|
<!-- required for API 18 - 30 -->
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
|
||||||
android:name="android.permission.BLUETOOTH"
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
||||||
android:maxSdkVersion="30" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.BLUETOOTH_ADMIN"
|
|
||||||
android:maxSdkVersion="30" />
|
|
||||||
|
|
||||||
<!-- API 31+ -->
|
<!-- required for API <= 29 -->
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
|
||||||
|
|
||||||
|
<!-- API 31+ -->
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
|
||||||
android:name="android.permission.BLUETOOTH_SCAN"
|
|
||||||
android:usesPermissionFlags="neverForLocation" />
|
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||||
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".Application"
|
android:name=".Application"
|
||||||
android:label="${APP_NAME}"
|
android:label="${APP_NAME}"
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
-
|
-
|
||||||
uri: bitcoincash.stackwallet.com:50002
|
uri: bitcoincash.stackwallet.com:50002
|
||||||
is_default: true
|
is_default: true
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: bch.aftrek.org:50002
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: node.minisatoshi.cash:50002
|
||||||
|
useSSL: true
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
useSSL: true
|
useSSL: true
|
||||||
-
|
-
|
||||||
uri: btc-electrum.cakewallet.com:50002
|
uri: btc-electrum.cakewallet.com:50002
|
||||||
|
useSSL: true
|
||||||
isDefault: true
|
isDefault: true
|
||||||
-
|
-
|
||||||
uri: electrs.cakewallet.com:50001
|
uri: electrs.cakewallet.com:50001
|
||||||
|
-
|
||||||
|
uri: fulcrum.sethforprivacy.com:50002
|
||||||
|
useSSL: true
|
||||||
|
|
BIN
assets/images/cards.png
Normal file
After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/flags/arm.png
Normal file
After Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 913 B |
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1,005 B After Width: | Height: | Size: 788 B |
Before Width: | Height: | Size: 855 B After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 753 B |
Before Width: | Height: | Size: 860 B After Width: | Height: | Size: 840 B |
Before Width: | Height: | Size: 217 B After Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 915 B After Width: | Height: | Size: 830 B |
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 801 B After Width: | Height: | Size: 387 B |
Before Width: | Height: | Size: 431 B After Width: | Height: | Size: 553 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1,005 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 700 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 432 B After Width: | Height: | Size: 762 B |
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1,023 B After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 728 B After Width: | Height: | Size: 373 B |
Before Width: | Height: | Size: 684 B After Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 845 B After Width: | Height: | Size: 975 B |
Before Width: | Height: | Size: 615 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 867 B After Width: | Height: | Size: 424 B |
Before Width: | Height: | Size: 937 B After Width: | Height: | Size: 994 B |
Before Width: | Height: | Size: 705 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 896 B After Width: | Height: | Size: 851 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 429 B After Width: | Height: | Size: 849 B |
Before Width: | Height: | Size: 1,013 B After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 902 B After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 193 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 898 B After Width: | Height: | Size: 424 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 899 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 366 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 705 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 750 B |
Before Width: | Height: | Size: 476 B After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 902 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 390 B |
Before Width: | Height: | Size: 774 B After Width: | Height: | Size: 384 B |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 1,005 B |
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 366 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 597 B |
Before Width: | Height: | Size: 1,009 B After Width: | Height: | Size: 887 B |
Before Width: | Height: | Size: 448 B After Width: | Height: | Size: 882 B |
BIN
assets/images/hardware_wallet/ledger_flex.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/hardware_wallet/ledger_nano_s.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/hardware_wallet/ledger_nano_x.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/hardware_wallet/ledger_stax.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB |
5
assets/images/letsexchange_icon.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||||
|
d="M16 1.37854C16 0.764286 16.6636 0.379192 17.1969 0.68395L23 4L29.4961 7.71208C29.8077 7.89012 30 8.22147 30 8.58032V16L23.9923 12.567C23.3774 12.2157 22.6226 12.2157 22.0077 12.567L16 16V8V1.37854ZM2 16V8.58032C2 8.22147 2.19229 7.89012 2.50386 7.71208L8.00772 4.56702C8.62259 4.21566 9.37741 4.21566 9.99228 4.56702L16 8L2 16ZM16 30.6215C16 31.2357 15.3364 31.6208 14.8031 31.3161L9 28L2.50386 24.2879C2.19229 24.1099 2 23.7785 2 23.4197V16L8.00772 19.433C8.62259 19.7843 9.37741 19.7843 9.99228 19.433L16 16V24V30.6215ZM22.0077 27.433C22.6226 27.7843 23.3774 27.7843 23.9923 27.433L29.4961 24.2879C29.8077 24.1099 30 23.7785 30 23.4197V16L16 24L22.0077 27.433Z"
|
||||||
|
fill="#159DFF"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 846 B |
BIN
assets/images/mweb_logo.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
assets/images/nanogpt.png
Normal file
After Width: | Height: | Size: 505 KiB |
BIN
assets/images/stealthex.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/images/ton_icon.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/wallet_group_bright.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
assets/images/wallet_group_dark.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
assets/images/wallet_group_light.png
Normal file
After Width: | Height: | Size: 7 KiB |
|
@ -17,6 +17,3 @@
|
||||||
-
|
-
|
||||||
uri: node.community.rino.io:18081
|
uri: node.community.rino.io:18081
|
||||||
is_default: false
|
is_default: false
|
||||||
-
|
|
||||||
uri: node.moneroworld.com:18089
|
|
||||||
is_default: false
|
|
||||||
|
|
|
@ -5,3 +5,6 @@
|
||||||
-
|
-
|
||||||
uri: api.mainnet-beta.solana.com:443
|
uri: api.mainnet-beta.solana.com:443
|
||||||
useSSL: true
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: solana-rpc.publicnode.com:443
|
||||||
|
useSSL: true
|
|
@ -1,3 +1,3 @@
|
||||||
Scan and verify messages
|
Monero enhancements
|
||||||
Synchronization enhancements
|
Introducing StealthEx and LetxExchange
|
||||||
Bug fixes
|
Bug fixes
|
|
@ -1,3 +1,7 @@
|
||||||
Scan and verify messages
|
Added Litecoin MWEB
|
||||||
Synchronization enhancements
|
Added wallet groups
|
||||||
|
Silent Payment enhancements for speed & reliability
|
||||||
|
Monero enhancements
|
||||||
|
Introducing StealthEx and LetxExchange
|
||||||
|
Additional ERC20 tokens scam detection
|
||||||
Bug fixes
|
Bug fixes
|
|
@ -15,7 +15,7 @@ These steps will help you configure and execute a build of CakeWallet from its s
|
||||||
|
|
||||||
### 1. Installing Package Dependencies
|
### 1. Installing Package Dependencies
|
||||||
|
|
||||||
CakeWallet requires some packages to be install on your build system. You may easily install them on your build system with the following command:
|
CakeWallet requires some packages to be installed on your build system. You may easily install them on your build system with the following command:
|
||||||
|
|
||||||
`$ sudo apt install build-essential cmake pkg-config git curl autoconf libtool`
|
`$ sudo apt install build-essential cmake pkg-config git curl autoconf libtool`
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ Path to executable file will be:
|
||||||
|
|
||||||
# Flatpak
|
# Flatpak
|
||||||
|
|
||||||
For package the built application into flatpak you need fistly to install `flatpak` and `flatpak-builder`:
|
For package the built application into flatpak you need firstly to install `flatpak` and `flatpak-builder`:
|
||||||
|
|
||||||
`$ sudo apt install flatpak flatpak-builder`
|
`$ sudo apt install flatpak flatpak-builder`
|
||||||
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin;
|
|
||||||
|
|
||||||
List<int> addressToOutputScript(String address, bitcoin.BasedUtxoNetwork network) {
|
|
||||||
try {
|
|
||||||
if (network == bitcoin.BitcoinCashNetwork.mainnet) {
|
|
||||||
return bitcoin.BitcoinCashAddress(address).baseAddress.toScriptPubKey().toBytes();
|
|
||||||
}
|
|
||||||
return bitcoin.addressToOutputScript(address: address, network: network);
|
|
||||||
} catch (err) {
|
|
||||||
print(err);
|
|
||||||
return Uint8List(0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/script_hash.dart' as sh;
|
|
||||||
|
|
||||||
abstract class BaseBitcoinAddressRecord {
|
abstract class BaseBitcoinAddressRecord {
|
||||||
BaseBitcoinAddressRecord(
|
BaseBitcoinAddressRecord(
|
||||||
|
@ -65,8 +64,8 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
required super.type,
|
required super.type,
|
||||||
String? scriptHash,
|
String? scriptHash,
|
||||||
required super.network,
|
required super.network,
|
||||||
}) : scriptHash =
|
}) : scriptHash = scriptHash ??
|
||||||
scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null);
|
(network != null ? BitcoinAddressUtils.scriptHash(address, network: network) : null);
|
||||||
|
|
||||||
factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) {
|
factory BitcoinAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) {
|
||||||
final decoded = json.decode(jsonSource) as Map;
|
final decoded = json.decode(jsonSource) as Map;
|
||||||
|
@ -92,7 +91,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
|
||||||
|
|
||||||
String getScriptHash(BasedUtxoNetwork network) {
|
String getScriptHash(BasedUtxoNetwork network) {
|
||||||
if (scriptHash != null) return scriptHash!;
|
if (scriptHash != null) return scriptHash!;
|
||||||
scriptHash = sh.scriptHash(address, network: network);
|
scriptHash = BitcoinAddressUtils.scriptHash(address, network: network);
|
||||||
return scriptHash!;
|
return scriptHash!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,30 +5,31 @@ import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||||
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
|
|
||||||
class BitcoinHardwareWalletService {
|
class BitcoinHardwareWalletService {
|
||||||
BitcoinHardwareWalletService(this.ledger, this.device);
|
BitcoinHardwareWalletService(this.ledgerConnection);
|
||||||
|
|
||||||
final Ledger ledger;
|
final LedgerConnection ledgerConnection;
|
||||||
final LedgerDevice device;
|
|
||||||
|
|
||||||
Future<List<HardwareAccountData>> getAvailableAccounts({int index = 0, int limit = 5}) async {
|
Future<List<HardwareAccountData>> getAvailableAccounts(
|
||||||
final bitcoinLedgerApp = BitcoinLedgerApp(ledger);
|
{int index = 0, int limit = 5}) async {
|
||||||
|
final bitcoinLedgerApp = BitcoinLedgerApp(ledgerConnection);
|
||||||
|
|
||||||
final masterFp = await bitcoinLedgerApp.getMasterFingerprint(device);
|
final masterFp = await bitcoinLedgerApp.getMasterFingerprint();
|
||||||
print(masterFp);
|
|
||||||
|
|
||||||
final accounts = <HardwareAccountData>[];
|
final accounts = <HardwareAccountData>[];
|
||||||
final indexRange = List.generate(limit, (i) => i + index);
|
final indexRange = List.generate(limit, (i) => i + index);
|
||||||
|
|
||||||
for (final i in indexRange) {
|
for (final i in indexRange) {
|
||||||
final derivationPath = "m/84'/0'/$i'";
|
final derivationPath = "m/84'/0'/$i'";
|
||||||
final xpub = await bitcoinLedgerApp.getXPubKey(device, derivationPath: derivationPath);
|
final xpub =
|
||||||
|
await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath);
|
||||||
Bip32Slip10Secp256k1 hd =
|
Bip32Slip10Secp256k1 hd =
|
||||||
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
|
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
|
||||||
|
|
||||||
final address = generateP2WPKHAddress(hd: hd, index: 0, network: BitcoinNetwork.mainnet);
|
final address = generateP2WPKHAddress(
|
||||||
|
hd: hd, index: 0, network: BitcoinNetwork.mainnet);
|
||||||
|
|
||||||
accounts.add(HardwareAccountData(
|
accounts.add(HardwareAccountData(
|
||||||
address: address,
|
address: address,
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:cryptography/cryptography.dart' as cryptography;
|
import 'package:cryptography/cryptography.dart' as cryptography;
|
||||||
import 'package:cw_core/sec_random_native.dart';
|
import 'package:cw_core/sec_random_native.dart';
|
||||||
import 'package:cw_core/utils/text_normalizer.dart';
|
import 'package:cw_core/utils/text_normalizer.dart';
|
||||||
|
|
||||||
const segwit = '100';
|
const segwit = '100';
|
||||||
|
const mweb = 'eb';
|
||||||
final wordlist = englishWordlist;
|
final wordlist = englishWordlist;
|
||||||
|
|
||||||
double logBase(num x, num base) => log(x) / log(base);
|
double logBase(num x, num base) => log(x) / log(base);
|
||||||
|
@ -59,11 +61,7 @@ void maskBytes(Uint8List bytes, int bits) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String bufferToBin(Uint8List data) {
|
String bufferToBin(Uint8List data) => data.map((e) => e.toRadixString(2).padLeft(8, '0')).join('');
|
||||||
final q1 = data.map((e) => e.toRadixString(2).padLeft(8, '0'));
|
|
||||||
final q2 = q1.join('');
|
|
||||||
return q2;
|
|
||||||
}
|
|
||||||
|
|
||||||
String encode(Uint8List data) {
|
String encode(Uint8List data) {
|
||||||
final dataBitLen = data.length * 8;
|
final dataBitLen = data.length * 8;
|
||||||
|
@ -112,22 +110,23 @@ Future<bool> checkIfMnemonicIsElectrum2(String mnemonic) async {
|
||||||
Future<String> getMnemonicHash(String mnemonic) async {
|
Future<String> getMnemonicHash(String mnemonic) async {
|
||||||
final hmacSha512 = Hmac(sha512, utf8.encode('Seed version'));
|
final hmacSha512 = Hmac(sha512, utf8.encode('Seed version'));
|
||||||
final digest = hmacSha512.convert(utf8.encode(normalizeText(mnemonic)));
|
final digest = hmacSha512.convert(utf8.encode(normalizeText(mnemonic)));
|
||||||
final hx = digest.toString();
|
return digest.toString();
|
||||||
return hx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List> mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) async {
|
Future<Uint8List> mnemonicToSeedBytes(String mnemonic,
|
||||||
|
{String prefix = segwit, String passphrase = ''}) async {
|
||||||
final pbkdf2 =
|
final pbkdf2 =
|
||||||
cryptography.Pbkdf2(macAlgorithm: cryptography.Hmac.sha512(), iterations: 2048, bits: 512);
|
cryptography.Pbkdf2(macAlgorithm: cryptography.Hmac.sha512(), iterations: 2048, bits: 512);
|
||||||
final text = normalizeText(mnemonic);
|
final text = normalizeText(mnemonic);
|
||||||
// pbkdf2.deriveKey(secretKey: secretKey, nonce: nonce)
|
final passphraseBytes = utf8.encode(normalizeText(passphrase));
|
||||||
final key = await pbkdf2.deriveKey(
|
final key = await pbkdf2.deriveKey(
|
||||||
secretKey: cryptography.SecretKey(text.codeUnits), nonce: 'electrum'.codeUnits);
|
secretKey: cryptography.SecretKey(text.codeUnits),
|
||||||
|
nonce: [...'electrum'.codeUnits, ...passphraseBytes]);
|
||||||
final bytes = await key.extractBytes();
|
final bytes = await key.extractBytes();
|
||||||
return Uint8List.fromList(bytes);
|
return Uint8List.fromList(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matchesAnyPrefix(String mnemonic) => prefixMatches(mnemonic, [segwit]).any((el) => el);
|
bool matchesAnyPrefix(String mnemonic) => prefixMatches(mnemonic, [segwit, mweb]).any((el) => el);
|
||||||
|
|
||||||
bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
|
bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -7,5 +7,6 @@ class MnemonicBip39 {
|
||||||
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);
|
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);
|
||||||
|
|
||||||
/// Create root seed from mnemonic
|
/// Create root seed from mnemonic
|
||||||
static Uint8List toSeed(String mnemonic) => bip39.mnemonicToSeed(mnemonic);
|
static Uint8List toSeed(String mnemonic, {String? passphrase}) =>
|
||||||
|
bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? '');
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
static const p2tr = BitcoinReceivePageOption._('Taproot (P2TR)');
|
static const p2tr = BitcoinReceivePageOption._('Taproot (P2TR)');
|
||||||
static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
|
static const p2wsh = BitcoinReceivePageOption._('Segwit (P2WSH)');
|
||||||
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
|
static const p2pkh = BitcoinReceivePageOption._('Legacy (P2PKH)');
|
||||||
|
static const mweb = BitcoinReceivePageOption._('MWEB');
|
||||||
|
|
||||||
static const silent_payments = BitcoinReceivePageOption._('Silent Payments');
|
static const silent_payments = BitcoinReceivePageOption._('Silent Payments');
|
||||||
|
|
||||||
|
@ -27,6 +28,11 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
BitcoinReceivePageOption.p2pkh
|
BitcoinReceivePageOption.p2pkh
|
||||||
];
|
];
|
||||||
|
|
||||||
|
static const allLitecoin = [
|
||||||
|
BitcoinReceivePageOption.p2wpkh,
|
||||||
|
BitcoinReceivePageOption.mweb,
|
||||||
|
];
|
||||||
|
|
||||||
BitcoinAddressType toType() {
|
BitcoinAddressType toType() {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case BitcoinReceivePageOption.p2tr:
|
case BitcoinReceivePageOption.p2tr:
|
||||||
|
@ -39,6 +45,8 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
return P2shAddressType.p2wshInP2sh;
|
return P2shAddressType.p2wshInP2sh;
|
||||||
case BitcoinReceivePageOption.silent_payments:
|
case BitcoinReceivePageOption.silent_payments:
|
||||||
return SilentPaymentsAddresType.p2sp;
|
return SilentPaymentsAddresType.p2sp;
|
||||||
|
case BitcoinReceivePageOption.mweb:
|
||||||
|
return SegwitAddresType.mweb;
|
||||||
case BitcoinReceivePageOption.p2wpkh:
|
case BitcoinReceivePageOption.p2wpkh:
|
||||||
default:
|
default:
|
||||||
return SegwitAddresType.p2wpkh;
|
return SegwitAddresType.p2wpkh;
|
||||||
|
@ -51,6 +59,8 @@ class BitcoinReceivePageOption implements ReceivePageOption {
|
||||||
return BitcoinReceivePageOption.p2tr;
|
return BitcoinReceivePageOption.p2tr;
|
||||||
case SegwitAddresType.p2wsh:
|
case SegwitAddresType.p2wsh:
|
||||||
return BitcoinReceivePageOption.p2wsh;
|
return BitcoinReceivePageOption.p2wsh;
|
||||||
|
case SegwitAddresType.mweb:
|
||||||
|
return BitcoinReceivePageOption.mweb;
|
||||||
case P2pkhAddressType.p2pkh:
|
case P2pkhAddressType.p2pkh:
|
||||||
return BitcoinReceivePageOption.p2pkh;
|
return BitcoinReceivePageOption.p2pkh;
|
||||||
case P2shAddressType.p2wshInP2sh:
|
case P2shAddressType.p2wshInP2sh:
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
import 'package:cw_core/output_info.dart';
|
import 'package:cw_core/output_info.dart';
|
||||||
|
import 'package:cw_core/unspent_coin_type.dart';
|
||||||
|
|
||||||
class BitcoinTransactionCredentials {
|
class BitcoinTransactionCredentials {
|
||||||
BitcoinTransactionCredentials(this.outputs,
|
BitcoinTransactionCredentials(this.outputs,
|
||||||
{required this.priority, this.feeRate});
|
{required this.priority, this.feeRate, this.coinTypeToSpendFrom = UnspentCoinType.any});
|
||||||
|
|
||||||
final List<OutputInfo> outputs;
|
final List<OutputInfo> outputs;
|
||||||
final BitcoinTransactionPriority? priority;
|
final BitcoinTransactionPriority? priority;
|
||||||
final int? feeRate;
|
final int? feeRate;
|
||||||
|
final UnspentCoinType coinTypeToSpendFrom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ class LitecoinTransactionPriority extends BitcoinTransactionPriority {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get units => 'Latoshi';
|
String get units => 'Litoshi';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
|
|
@ -5,13 +5,13 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_derivations.dart';
|
import 'package:cw_bitcoin/electrum_derivations.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||||
import 'package:cw_bitcoin/psbt_transaction_builder.dart';
|
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -19,7 +19,7 @@ import 'package:cw_core/wallet_keys_file.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'bitcoin_wallet.g.dart';
|
part 'bitcoin_wallet.g.dart';
|
||||||
|
@ -61,8 +61,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
encryptionFileUtils: encryptionFileUtils,
|
encryptionFileUtils: encryptionFileUtils,
|
||||||
currency:
|
currency: networkParam == BitcoinNetwork.testnet
|
||||||
networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
|
? CryptoCurrency.tbtc
|
||||||
|
: CryptoCurrency.btc,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
) {
|
) {
|
||||||
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
// in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here)
|
||||||
|
@ -80,11 +81,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||||
network: networkParam ?? network,
|
network: networkParam ?? network,
|
||||||
masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
masterHd:
|
||||||
|
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
||||||
|
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||||
);
|
);
|
||||||
|
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
this.walletAddresses.isEnabledAutoGenerateSubaddress =
|
||||||
|
this.isEnabledAutoGenerateSubaddress;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +119,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
break;
|
break;
|
||||||
case DerivationType.electrum:
|
case DerivationType.electrum:
|
||||||
default:
|
default:
|
||||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return BitcoinWallet(
|
return BitcoinWallet(
|
||||||
|
@ -185,8 +189,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
walletInfo.derivationInfo ??= DerivationInfo();
|
walletInfo.derivationInfo ??= DerivationInfo();
|
||||||
|
|
||||||
// set the default if not present:
|
// set the default if not present:
|
||||||
walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
|
walletInfo.derivationInfo!.derivationPath ??=
|
||||||
walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
|
snp?.derivationPath ?? electrum_path;
|
||||||
|
walletInfo.derivationInfo!.derivationType ??=
|
||||||
|
snp?.derivationType ?? DerivationType.electrum;
|
||||||
|
|
||||||
Uint8List? seedBytes = null;
|
Uint8List? seedBytes = null;
|
||||||
final mnemonic = keysData.mnemonic;
|
final mnemonic = keysData.mnemonic;
|
||||||
|
@ -195,7 +201,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
if (mnemonic != null) {
|
if (mnemonic != null) {
|
||||||
switch (walletInfo.derivationInfo!.derivationType) {
|
switch (walletInfo.derivationInfo!.derivationType) {
|
||||||
case DerivationType.electrum:
|
case DerivationType.electrum:
|
||||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||||
break;
|
break;
|
||||||
case DerivationType.bip39:
|
case DerivationType.bip39:
|
||||||
default:
|
default:
|
||||||
|
@ -228,15 +234,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ledger? _ledger;
|
LedgerConnection? _ledgerConnection;
|
||||||
LedgerDevice? _ledgerDevice;
|
|
||||||
BitcoinLedgerApp? _bitcoinLedgerApp;
|
BitcoinLedgerApp? _bitcoinLedgerApp;
|
||||||
|
|
||||||
void setLedger(Ledger setLedger, LedgerDevice setLedgerDevice) {
|
@override
|
||||||
_ledger = setLedger;
|
void setLedgerConnection(LedgerConnection connection) {
|
||||||
_ledgerDevice = setLedgerDevice;
|
_ledgerConnection = connection;
|
||||||
_bitcoinLedgerApp =
|
_bitcoinLedgerApp = BitcoinLedgerApp(_ledgerConnection!,
|
||||||
BitcoinLedgerApp(_ledger!, derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -251,12 +256,14 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
||||||
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
||||||
}) async {
|
}) async {
|
||||||
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint(_ledgerDevice!);
|
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint();
|
||||||
|
|
||||||
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
||||||
for (final utxo in utxos) {
|
for (final utxo in utxos) {
|
||||||
final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
final rawTx =
|
||||||
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
|
||||||
|
final publicKeyAndDerivationPath =
|
||||||
|
publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
|
||||||
|
|
||||||
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
|
||||||
utxo: utxo.utxo,
|
utxo: utxo.utxo,
|
||||||
|
@ -268,10 +275,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
final psbt =
|
final psbt = PSBTTransactionBuild(
|
||||||
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
||||||
|
|
||||||
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
|
final rawHex = await _bitcoinLedgerApp!.signPsbt(psbt: psbt.psbt);
|
||||||
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,14 +286,16 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
Future<String> signMessage(String message, {String? address = null}) async {
|
Future<String> signMessage(String message, {String? address = null}) async {
|
||||||
if (walletInfo.isHardwareWallet) {
|
if (walletInfo.isHardwareWallet) {
|
||||||
final addressEntry = address != null
|
final addressEntry = address != null
|
||||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
|
? walletAddresses.allAddresses
|
||||||
|
.firstWhere((element) => element.address == address)
|
||||||
: null;
|
: null;
|
||||||
final index = addressEntry?.index ?? 0;
|
final index = addressEntry?.index ?? 0;
|
||||||
final isChange = addressEntry?.isHidden == true ? 1 : 0;
|
final isChange = addressEntry?.isHidden == true ? 1 : 0;
|
||||||
final accountPath = walletInfo.derivationInfo?.derivationPath;
|
final accountPath = walletInfo.derivationInfo?.derivationPath;
|
||||||
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
|
final derivationPath =
|
||||||
|
accountPath != null ? "$accountPath/$isChange/$index" : null;
|
||||||
|
|
||||||
final signature = await _bitcoinLedgerApp!.signMessage(_ledgerDevice!,
|
final signature = await _bitcoinLedgerApp!.signMessage(
|
||||||
message: ascii.encode(message), signDerivationPath: derivationPath);
|
message: ascii.encode(message), signDerivationPath: derivationPath);
|
||||||
return base64Encode(signature);
|
return base64Encode(signature);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
required super.mainHd,
|
required super.mainHd,
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
|
required super.isHardwareWallet,
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
|
|
@ -3,17 +3,24 @@ import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
|
||||||
class BitcoinNewWalletCredentials extends WalletCredentials {
|
class BitcoinNewWalletCredentials extends WalletCredentials {
|
||||||
BitcoinNewWalletCredentials(
|
BitcoinNewWalletCredentials({
|
||||||
{required String name,
|
required String name,
|
||||||
WalletInfo? walletInfo,
|
WalletInfo? walletInfo,
|
||||||
String? password,
|
String? password,
|
||||||
DerivationType? derivationType,
|
DerivationType? derivationType,
|
||||||
String? derivationPath})
|
String? derivationPath,
|
||||||
: super(
|
String? passphrase,
|
||||||
|
this.mnemonic,
|
||||||
|
String? parentAddress,
|
||||||
|
}) : super(
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
password: password,
|
password: password,
|
||||||
|
passphrase: passphrase,
|
||||||
|
parentAddress: parentAddress,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final String? mnemonic;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
|
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
|
||||||
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
@ -35,8 +36,21 @@ class BitcoinWalletService extends WalletService<
|
||||||
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
||||||
credentials.walletInfo?.network = network.value;
|
credentials.walletInfo?.network = network.value;
|
||||||
|
|
||||||
|
final String mnemonic;
|
||||||
|
switch ( credentials.walletInfo?.derivationInfo?.derivationType) {
|
||||||
|
case DerivationType.bip39:
|
||||||
|
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
|
||||||
|
|
||||||
|
mnemonic = credentials.mnemonic ?? await MnemonicBip39.generate(strength: strength);
|
||||||
|
break;
|
||||||
|
case DerivationType.electrum:
|
||||||
|
default:
|
||||||
|
mnemonic = await generateElectrumMnemonic();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
final wallet = await BitcoinWalletBase.create(
|
final wallet = await BitcoinWalletBase.create(
|
||||||
mnemonic: await generateElectrumMnemonic(),
|
mnemonic: mnemonic,
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
passphrase: credentials.passphrase,
|
passphrase: credentials.passphrase,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
|
|