Compare commits
95 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c2cca1ff37 | ||
|
5aeb6b7522 | ||
|
b3c20a5818 | ||
|
d0827dd39e | ||
|
900304d405 | ||
|
73588071ba | ||
|
1a5601f755 | ||
|
04c86c567f | ||
|
65bb917bfb | ||
|
af89603b81 | ||
|
4434ad7363 | ||
|
5082dc20f3 | ||
|
18c2ba9366 | ||
|
4b137bc968 | ||
|
21d5c51cc9 | ||
|
edaf485993 | ||
|
150becb679 | ||
|
c6cb48096d | ||
|
65402ba1eb | ||
|
17d99e5451 | ||
|
85d3e727e2 | ||
|
4fb2fc47ad | ||
|
a96b493b60 | ||
|
fe0c9ecc0e | ||
|
e5d0194f11 | ||
|
8457a45c2a | ||
|
b0edf1fe75 | ||
|
1d6e594e04 | ||
|
1134915920 | ||
|
418fdb62d3 | ||
|
d332377a2b | ||
|
b77c22b0df | ||
|
b79fb6af1f | ||
|
1fa1181c82 | ||
|
9a426ee5d4 | ||
|
c2b138c65c | ||
|
46a73de82e | ||
|
41fa97a203 | ||
|
2f2b45f844 | ||
|
eede8fa6c7 | ||
|
78bb170533 | ||
|
90aee053cd | ||
|
e03dcc7fe9 | ||
|
d342173239 | ||
|
df88914628 | ||
|
7b8ddf9685 | ||
|
e52bceda3a | ||
|
df20e22fae | ||
|
fd3158293e | ||
|
939e5d9279 | ||
|
1aac17676d | ||
|
d356d5bfcb | ||
|
773adfaaca | ||
|
b872b43b75 | ||
|
43808992ec | ||
|
79faeb98af | ||
|
dcaeac9b85 | ||
|
1e5568fc1b | ||
|
1c7dd02a53 | ||
|
914561716d | ||
|
c12daced40 | ||
|
bc52cf485e | ||
|
557e1c9839 | ||
|
66efce4d70 | ||
|
1b2e3f2ee1 | ||
|
40084ec532 | ||
|
ca8dbf3c81 | ||
|
ca2c953cf4 | ||
|
82e3ebf4fa | ||
|
4a08e18f00 | ||
|
e7fd1582a8 | ||
|
b4e16a05b1 | ||
|
b1fc9ba2e5 | ||
|
51a4954fcb | ||
|
b28ea4199c | ||
|
5b43cb5373 | ||
|
a9e05073a5 | ||
|
c6f9d12a8e | ||
|
cab4792388 | ||
|
b7473594cb | ||
|
cd0844dcc1 | ||
|
eccc94a019 | ||
|
a2294c4a06 | ||
|
dd8413bae2 | ||
|
cb257e1391 | ||
|
2a6dad2257 | ||
|
d4190cbb0f | ||
|
69c2e458d5 | ||
|
0e4c9bb138 | ||
|
4448adb49d | ||
|
b25cb527cb | ||
|
0188535eb9 | ||
|
da8a82a10f | ||
|
e527083871 | ||
|
d86c501fc5 |
10
.github/workflows/automated_integration_test.yml
vendored
|
@ -55,7 +55,7 @@ jobs:
|
||||||
- name: Flutter action
|
- name: Flutter action
|
||||||
uses: subosito/flutter-action@v1
|
uses: subosito/flutter-action@v1
|
||||||
with:
|
with:
|
||||||
flutter-version: "3.27.4"
|
flutter-version: "3.27.0"
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
- name: Install package dependencies
|
- name: Install package dependencies
|
||||||
|
@ -153,8 +153,8 @@ jobs:
|
||||||
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
|
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
|
echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
|
||||||
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||||
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -168,6 +168,7 @@ jobs:
|
||||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -178,7 +179,8 @@ jobs:
|
||||||
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
|
||||||
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
||||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
|
21
.github/workflows/no_http_imports.yaml
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: No http imports
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
PR_test_build:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check for http package usage
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
run: |
|
||||||
|
GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) | (grep -v very_insecure_http_do_not_use || test $? = 1) || true)"
|
||||||
|
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
|
||||||
|
echo "$GIT_GREP_OUT"
|
||||||
|
echo "There are .dart files which use http imports"
|
||||||
|
echo "Using http package breaks proxy integration"
|
||||||
|
echo "Please use ProxyWrapper.getHttpClient() from package:cw_core/utils/proxy_wrapper.dart"
|
||||||
|
exit 1
|
||||||
|
|
15
.github/workflows/pr_test_build_android.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
||||||
PR_test_build:
|
PR_test_build:
|
||||||
runs-on: linux-amd64
|
runs-on: linux-amd64
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
|
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
|
||||||
env:
|
env:
|
||||||
STORE_PASS: test@cake_wallet
|
STORE_PASS: test@cake_wallet
|
||||||
KEY_PASS: test@cake_wallet
|
KEY_PASS: test@cake_wallet
|
||||||
|
@ -98,8 +98,8 @@ jobs:
|
||||||
else
|
else
|
||||||
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||||
fi
|
fi
|
||||||
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -113,6 +113,7 @@ jobs:
|
||||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -124,7 +125,8 @@ jobs:
|
||||||
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 nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_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
|
||||||
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
||||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -253,6 +255,11 @@ jobs:
|
||||||
|
|
||||||
- name: Build generated code
|
- name: Build generated code
|
||||||
run: |
|
run: |
|
||||||
|
flutter --version
|
||||||
|
flutter clean
|
||||||
|
rm -rf .dart_tool
|
||||||
|
rm pubspec.lock
|
||||||
|
flutter pub get
|
||||||
./model_generator.sh async
|
./model_generator.sh async
|
||||||
|
|
||||||
- name: Generate key properties
|
- name: Generate key properties
|
||||||
|
|
10
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
||||||
PR_test_build:
|
PR_test_build:
|
||||||
runs-on: linux-amd64
|
runs-on: linux-amd64
|
||||||
container:
|
container:
|
||||||
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
|
image: ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
|
||||||
env:
|
env:
|
||||||
STORE_PASS: test@cake_wallet
|
STORE_PASS: test@cake_wallet
|
||||||
KEY_PASS: test@cake_wallet
|
KEY_PASS: test@cake_wallet
|
||||||
|
@ -91,8 +91,8 @@ jobs:
|
||||||
else
|
else
|
||||||
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||||
fi
|
fi
|
||||||
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
echo "const changeNowMoneroApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -106,6 +106,7 @@ jobs:
|
||||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const trocadorMoneroApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -117,7 +118,8 @@ jobs:
|
||||||
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 nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_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
|
||||||
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const exolixCakeWalletApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const exolixMoneroApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
||||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
|
18
Dockerfile
|
@ -1,4 +1,4 @@
|
||||||
# docker buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1
|
# docker buildx build --push --pull --platform linux/amd64,linux/arm64 . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly
|
||||||
|
|
||||||
# Heavily inspired by cirrusci images
|
# Heavily inspired by cirrusci images
|
||||||
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
|
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
|
||||||
|
@ -15,11 +15,11 @@ LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet
|
||||||
ENV GOLANG_VERSION=1.24.1
|
ENV GOLANG_VERSION=1.24.1
|
||||||
|
|
||||||
# Pin Flutter version to latest known-working version
|
# Pin Flutter version to latest known-working version
|
||||||
ENV FLUTTER_VERSION=3.27.4
|
ENV FLUTTER_VERSION=3.27.0
|
||||||
|
|
||||||
# Pin Android Studio, platform, and build tools versions to latest known-working version
|
# Pin Android Studio, platform, and build tools versions to latest known-working version
|
||||||
# Comes from https://developer.android.com/studio/#command-tools
|
# Comes from https://developer.android.com/studio/#command-tools
|
||||||
ENV ANDROID_SDK_TOOLS_VERSION=11076708
|
ENV ANDROID_SDK_TOOLS_VERSION=13114758
|
||||||
# Comes from https://developer.android.com/studio/releases/build-tools
|
# Comes from https://developer.android.com/studio/releases/build-tools
|
||||||
ENV ANDROID_PLATFORM_VERSION=35
|
ENV ANDROID_PLATFORM_VERSION=35
|
||||||
ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0
|
ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0
|
||||||
|
@ -164,9 +164,12 @@ RUN (addgroup kvm || true) && \
|
||||||
ENV PATH=${HOME}/.cargo/bin:${PATH}
|
ENV PATH=${HOME}/.cargo/bin:${PATH}
|
||||||
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \
|
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \
|
||||||
cargo install cargo-ndk && \
|
cargo install cargo-ndk && \
|
||||||
|
for toolchain in stable nightly; \
|
||||||
|
do \
|
||||||
for target in aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu; \
|
for target in aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu; \
|
||||||
do \
|
do \
|
||||||
rustup target add --toolchain stable $target; \
|
rustup target add --toolchain $toolchain $target; \
|
||||||
|
done \
|
||||||
done
|
done
|
||||||
|
|
||||||
# Download and install Flutter
|
# Download and install Flutter
|
||||||
|
@ -175,8 +178,11 @@ ENV FLUTTER_HOME=${HOME}/sdks/flutter/${FLUTTER_VERSION}
|
||||||
ENV FLUTTER_ROOT=$FLUTTER_HOME
|
ENV FLUTTER_ROOT=$FLUTTER_HOME
|
||||||
ENV PATH=${PATH}:${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin
|
ENV PATH=${PATH}:${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin
|
||||||
|
|
||||||
RUN git clone --depth 1 --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} \
|
RUN git clone --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} && \
|
||||||
&& yes | flutter doctor --android-licenses \
|
cd ${FLUTTER_HOME} && \
|
||||||
|
git fetch -a
|
||||||
|
|
||||||
|
RUN yes | flutter doctor --android-licenses \
|
||||||
&& flutter doctor \
|
&& flutter doctor \
|
||||||
&& chown -R root:root ${FLUTTER_HOME}
|
&& chown -R root:root ${FLUTTER_HOME}
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,8 @@
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="nano-gpt" />
|
<data android:scheme="nano-gpt" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
|
||||||
</activity>
|
</activity>
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
|
|
BIN
assets/images/2fa.png
Normal file
After Width: | Height: | Size: 281 KiB |
86
assets/images/2fa_warning_dark.svg
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<svg width="260" height="298" viewBox="0 0 260 298" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M119.655 6.27832C126.055 3.53578 133.272 3.45033 139.723 6.02148L140.345 6.27832L243.044 50.293C252.699 54.431 258.96 63.925 258.96 74.4297V128.542C258.96 175.815 236.309 220.2 198.085 247.94L197.18 248.593L145.264 285.676C136.276 292.096 124.25 292.197 115.167 285.978L114.736 285.676L62.8203 248.593C24.0499 220.899 1.04004 176.187 1.04004 128.542V74.4297C1.04004 64.0891 7.10644 54.7283 16.5059 50.4912L16.9561 50.293L119.655 6.27832Z" stroke="#708BF4" stroke-opacity="0.05" stroke-width="2.08"/>
|
||||||
|
<path d="M120.451 17.2793C126.358 14.7477 133.02 14.6687 138.975 17.042L139.549 17.2793L234.349 57.9082C243.261 61.7279 249.04 70.491 249.04 80.1875V130.138C249.04 173.775 228.131 214.745 192.848 240.352L192.012 240.954L144.089 275.185C135.792 281.111 124.692 281.204 116.308 275.463L115.911 275.185L67.9883 240.954C32.2001 215.391 10.96 174.118 10.96 130.138V80.1875C10.9601 70.6424 16.56 62.0019 25.2363 58.0908L25.6514 57.9082L120.451 17.2793Z" stroke="#708BF4" stroke-opacity="0.15" stroke-width="1.92"/>
|
||||||
|
<path d="M121.294 28.3906C126.68 26.0825 132.754 26.0099 138.183 28.1738L138.706 28.3906L225.605 65.6328C233.731 69.1153 239 77.1057 239 85.9463V131.733C239 171.381 220.152 208.625 188.301 232.109L186.774 233.218L142.846 264.596C135.282 269.999 125.161 270.083 117.517 264.849L117.154 264.596L73.2256 233.218C40.4513 209.807 21 172.01 21 131.733V85.9463C21 77.2438 26.1053 69.3657 34.0156 65.7998L34.3945 65.6328L121.294 28.3906Z" stroke="#708BF4" stroke-opacity="0.5" stroke-width="2"/>
|
||||||
|
<path d="M77.8584 226.327L117.794 254.852C125.096 260.068 134.904 260.068 142.206 254.852L182.141 226.327C212.176 204.874 230 170.238 230 133.329V91.7041C230 83.3035 224.994 75.7112 217.272 72.4021L138.272 38.5449C132.99 36.281 127.01 36.281 121.728 38.5449L42.7277 72.4021C35.0063 75.7112 30 83.3035 30 91.7041V133.329C30 170.238 47.8247 204.874 77.8584 226.327Z" fill="black"/>
|
||||||
|
<path d="M77.8584 226.327L117.794 254.852C125.096 260.068 134.904 260.068 142.206 254.852L182.141 226.327C212.176 204.874 230 170.238 230 133.329V91.7041C230 83.3035 224.994 75.7112 217.272 72.4021L138.272 38.5449C132.99 36.281 127.01 36.281 121.728 38.5449L42.7277 72.4021C35.0063 75.7112 30 83.3035 30 91.7041V133.329C30 170.238 47.8247 204.874 77.8584 226.327Z" fill="url(#paint0_linear_4774_13703)"/>
|
||||||
|
<path d="M123.479 42.6295C127.513 40.9005 132.063 40.8473 136.13 42.4684L136.521 42.6295L215.521 76.4869C221.609 79.0957 225.556 85.0812 225.556 91.7037V133.329C225.556 168.248 208.955 201.05 180.902 221.734L179.559 222.711L139.623 251.236C134.047 255.219 126.615 255.343 120.923 251.609L120.377 251.236L80.4414 222.711C51.5757 202.092 34.4443 168.802 34.4443 133.329V91.7037C34.4445 85.2882 38.1486 79.4709 43.9141 76.7418L44.4785 76.4869L123.479 42.6295Z" stroke="url(#paint1_linear_4774_13703)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6295C127.513 40.9005 132.063 40.8473 136.13 42.4684L136.521 42.6295L215.521 76.4869C221.609 79.0957 225.556 85.0812 225.556 91.7037V133.329C225.556 168.248 208.955 201.05 180.902 221.734L179.559 222.711L139.623 251.236C134.047 255.219 126.615 255.343 120.923 251.609L120.377 251.236L80.4414 222.711C51.5757 202.092 34.4443 168.802 34.4443 133.329V91.7037C34.4445 85.2882 38.1486 79.4709 43.9141 76.7418L44.4785 76.4869L123.479 42.6295Z" stroke="url(#paint2_linear_4774_13703)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6295C127.513 40.9005 132.063 40.8473 136.13 42.4684L136.521 42.6295L215.521 76.4869C221.609 79.0957 225.556 85.0812 225.556 91.7037V133.329C225.556 168.248 208.955 201.05 180.902 221.734L179.559 222.711L139.623 251.236C134.047 255.219 126.615 255.343 120.923 251.609L120.377 251.236L80.4414 222.711C51.5757 202.092 34.4443 168.802 34.4443 133.329V91.7037C34.4445 85.2882 38.1486 79.4709 43.9141 76.7418L44.4785 76.4869L123.479 42.6295Z" stroke="url(#paint3_linear_4774_13703)" stroke-width="8.88889"/>
|
||||||
|
<g filter="url(#filter0_ii_4774_13703)">
|
||||||
|
<path d="M77.8584 226.327L117.794 254.852C125.096 260.068 134.904 260.068 142.206 254.852L182.141 226.327C212.176 204.874 230 170.238 230 133.329V91.7041C230 83.3035 224.994 75.7112 217.272 72.4021L138.272 38.5449C132.99 36.281 127.01 36.281 121.728 38.5449L42.7277 72.4021C35.0063 75.7112 30 83.3035 30 91.7041V133.329C30 170.238 47.8247 204.874 77.8584 226.327Z" fill="black" fill-opacity="0.01"/>
|
||||||
|
</g>
|
||||||
|
<rect x="66.5" y="110.5" width="127" height="69.5833" rx="9.33333" fill="url(#paint4_linear_4774_13703)" fill-opacity="0.15" stroke="url(#paint5_linear_4774_13703)" stroke-width="3"/>
|
||||||
|
<g filter="url(#filter1_d_4774_13703)">
|
||||||
|
<path d="M85.027 155.008L85.4252 147.997L79.5392 151.857L77.4272 148.187L83.7113 145.037L77.4272 141.886L79.5392 138.216L85.4252 142.076L85.027 135.065H89.2338L88.8529 142.076L94.739 138.216L96.851 141.886L90.5495 145.037L96.851 148.187L94.739 151.857L88.8529 147.997L89.2338 155.008H85.027ZM113.447 155.008L113.845 147.997L107.959 151.857L105.847 148.187L112.131 145.037L105.847 141.886L107.959 138.216L113.845 142.076L113.447 135.065H117.654L117.273 142.076L123.159 138.216L125.271 141.886L118.969 145.037L125.271 148.187L123.159 151.857L117.273 147.997L117.654 155.008H113.447ZM141.866 155.008L142.265 147.997L136.379 151.857L134.267 148.187L140.551 145.037L134.267 141.886L136.379 138.216L142.265 142.076L141.866 135.065H146.073L145.692 142.076L151.578 138.216L153.69 141.886L147.389 145.037L153.69 148.187L151.578 151.857L145.692 147.997L146.073 155.008H141.866ZM170.286 155.008L170.684 147.997L164.798 151.857L162.686 148.187L168.971 145.037L162.686 141.886L164.798 138.216L170.684 142.076L170.286 135.065H174.493L174.112 142.076L179.998 138.216L182.11 141.886L175.809 145.037L182.11 148.187L179.998 151.857L174.112 147.997L174.493 155.008H170.286Z" fill="#EFEFF8"/>
|
||||||
|
</g>
|
||||||
|
<path d="M164.716 223.419H215.284C220.845 223.419 224.31 217.386 221.508 212.583L196.224 169.239C193.443 164.473 186.556 164.473 183.776 169.239L158.492 212.583C155.69 217.386 159.155 223.419 164.716 223.419Z" fill="#D9D9D9"/>
|
||||||
|
<path d="M164.716 223.419H215.284C220.845 223.419 224.31 217.386 221.508 212.583L196.224 169.239C193.443 164.473 186.556 164.473 183.776 169.239L158.492 212.583C155.69 217.386 159.155 223.419 164.716 223.419Z" fill="url(#paint6_linear_4774_13703)"/>
|
||||||
|
<path d="M164.716 223.419H215.284C220.845 223.419 224.31 217.386 221.508 212.583L196.224 169.239C193.443 164.473 186.556 164.473 183.776 169.239L158.492 212.583C155.69 217.386 159.155 223.419 164.716 223.419Z" stroke="#312938" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M164.716 223.419H215.284C220.845 223.419 224.31 217.386 221.508 212.583L196.224 169.239C193.443 164.473 186.556 164.473 183.776 169.239L158.492 212.583C155.69 217.386 159.155 223.419 164.716 223.419Z" stroke="url(#paint7_linear_4774_13703)" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M164.716 223.419H215.284C220.845 223.419 224.31 217.386 221.508 212.583L196.224 169.239C193.443 164.473 186.556 164.473 183.776 169.239L158.492 212.583C155.69 217.386 159.155 223.419 164.716 223.419Z" stroke="url(#paint8_linear_4774_13703)" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M189.925 208.897H189.961M189.925 198.089V187.281" stroke="#312938" stroke-width="7.20545" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_ii_4774_13703" x="30" y="36.8469" width="200" height="221.917" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="plus-lighter" in2="shape" result="effect1_innerShadow_4774_13703"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="-2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect1_innerShadow_4774_13703" result="effect2_innerShadow_4774_13703"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_d_4774_13703" x="68.1106" y="125.748" width="123.316" height="38.5765" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="4.65833"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0.937255 0 0 0 0 0.937255 0 0 0 0 0.972549 0 0 0 0.3 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4774_13703"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4774_13703" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_4774_13703" x1="130" y1="34.9996" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#19233C"/>
|
||||||
|
<stop offset="1" stop-color="#1647C3"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4774_13703" x1="130" y1="34.9996" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.42" stop-color="#2077F8"/>
|
||||||
|
<stop offset="0.700262" stop-color="#000F4D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_4774_13703" x1="130" y1="34.9996" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_4774_13703" x1="130" y1="34.9996" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D8E3FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_4774_13703" x1="130" y1="109" x2="130" y2="181.583" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#5590FF"/>
|
||||||
|
<stop offset="1" stop-color="#5590FF" stop-opacity="0.5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_4774_13703" x1="190.695" y1="181.583" x2="69.3054" y2="109" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EFEFF8" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="#EFEFF8"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_4774_13703" x1="190" y1="165.664" x2="190.433" y2="233.264" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FFC414"/>
|
||||||
|
<stop offset="1" stop-color="#FF9500"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_4774_13703" x1="190" y1="165.664" x2="190" y2="223.419" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#5C486E"/>
|
||||||
|
<stop offset="1" stop-color="#312938"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_4774_13703" x1="190" y1="165.664" x2="190" y2="223.419" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#EBD4FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
101
assets/images/2fa_warning_light.svg
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
<svg width="260" height="298" viewBox="0 0 260 298" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M119.655 6.2793C126.055 3.53675 133.272 3.4513 139.723 6.02246L140.345 6.2793L243.044 50.2939C252.699 54.432 258.96 63.9259 258.96 74.4307V128.543C258.96 175.816 236.309 220.201 198.085 247.941L197.18 248.594L145.264 285.677C136.276 292.097 124.25 292.198 115.167 285.979L114.736 285.677L62.8203 248.594C24.0499 220.9 1.04004 176.188 1.04004 128.543V74.4307C1.04004 64.09 7.10644 54.7293 16.5059 50.4922L16.9561 50.2939L119.655 6.2793Z" stroke="#4A98DC" stroke-opacity="0.05" stroke-width="2.08"/>
|
||||||
|
<path d="M120.451 17.2803C126.358 14.7487 133.02 14.6696 138.975 17.043L139.549 17.2803L234.349 57.9092C243.261 61.7289 249.04 70.492 249.04 80.1885V130.139C249.04 173.775 228.131 214.746 192.848 240.353L192.012 240.955L144.089 275.186C135.792 281.112 124.692 281.205 116.308 275.464L115.911 275.186L67.9883 240.955C32.2001 215.392 10.96 174.119 10.96 130.139V80.1885C10.9601 70.6434 16.56 62.0028 25.2363 58.0918L25.6514 57.9092L120.451 17.2803Z" stroke="#4B98DC" stroke-opacity="0.15" stroke-width="1.92"/>
|
||||||
|
<path d="M121.294 28.3916C126.68 26.0835 132.754 26.0109 138.183 28.1748L138.706 28.3916L225.605 65.6338C233.731 69.1163 239 77.1066 239 85.9473V131.734C239 171.382 220.152 208.626 188.301 232.11L186.774 233.219L142.846 264.597C135.282 270 125.161 270.084 117.517 264.85L117.154 264.597L73.2256 233.219C40.4513 209.808 21 172.011 21 131.734V85.9473C21 77.2448 26.1053 69.3666 34.0156 65.8008L34.3945 65.6338L121.294 28.3916Z" stroke="#4895DB" stroke-opacity="0.35" stroke-width="2"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.853C125.096 260.069 134.904 260.069 142.206 254.853L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7051C230 83.3045 224.994 75.7122 217.272 72.403L138.272 38.5459C132.99 36.2819 127.01 36.2819 121.728 38.5459L42.7277 72.403C35.0063 75.7122 30 83.3045 30 91.7051V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="black"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.853C125.096 260.069 134.904 260.069 142.206 254.853L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7051C230 83.3045 224.994 75.7122 217.272 72.403L138.272 38.5459C132.99 36.2819 127.01 36.2819 121.728 38.5459L42.7277 72.403C35.0063 75.7122 30 83.3045 30 91.7051V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint0_linear_4774_13798)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.853C125.096 260.069 134.904 260.069 142.206 254.853L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7051C230 83.3045 224.994 75.7122 217.272 72.403L138.272 38.5459C132.99 36.2819 127.01 36.2819 121.728 38.5459L42.7277 72.403C35.0063 75.7122 30 83.3045 30 91.7051V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint1_linear_4774_13798)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.853C125.096 260.069 134.904 260.069 142.206 254.853L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7051C230 83.3045 224.994 75.7122 217.272 72.403L138.272 38.5459C132.99 36.2819 127.01 36.2819 121.728 38.5459L42.7277 72.403C35.0063 75.7122 30 83.3045 30 91.7051V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint2_linear_4774_13798)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.853C125.096 260.069 134.904 260.069 142.206 254.853L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7051C230 83.3045 224.994 75.7122 217.272 72.403L138.272 38.5459C132.99 36.2819 127.01 36.2819 121.728 38.5459L42.7277 72.403C35.0063 75.7122 30 83.3045 30 91.7051V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint3_linear_4774_13798)"/>
|
||||||
|
<path d="M123.479 42.6305C127.513 40.9015 132.063 40.8482 136.13 42.4693L136.521 42.6305L215.521 76.4879C221.609 79.0967 225.556 85.0821 225.556 91.7047V133.33C225.556 168.249 208.955 201.051 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.22 126.615 255.344 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7047C34.4445 85.2892 38.1486 79.4719 43.9141 76.7428L44.4785 76.4879L123.479 42.6305Z" stroke="url(#paint4_linear_4774_13798)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6305C127.513 40.9015 132.063 40.8482 136.13 42.4693L136.521 42.6305L215.521 76.4879C221.609 79.0967 225.556 85.0821 225.556 91.7047V133.33C225.556 168.249 208.955 201.051 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.22 126.615 255.344 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7047C34.4445 85.2892 38.1486 79.4719 43.9141 76.7428L44.4785 76.4879L123.479 42.6305Z" stroke="url(#paint5_linear_4774_13798)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6305C127.513 40.9015 132.063 40.8482 136.13 42.4693L136.521 42.6305L215.521 76.4879C221.609 79.0967 225.556 85.0821 225.556 91.7047V133.33C225.556 168.249 208.955 201.051 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.22 126.615 255.344 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7047C34.4445 85.2892 38.1486 79.4719 43.9141 76.7428L44.4785 76.4879L123.479 42.6305Z" stroke="url(#paint6_linear_4774_13798)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6305C127.513 40.9015 132.063 40.8482 136.13 42.4693L136.521 42.6305L215.521 76.4879C221.609 79.0967 225.556 85.0821 225.556 91.7047V133.33C225.556 168.249 208.955 201.051 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.22 126.615 255.344 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7047C34.4445 85.2892 38.1486 79.4719 43.9141 76.7428L44.4785 76.4879L123.479 42.6305Z" stroke="url(#paint7_linear_4774_13798)" stroke-width="8.88889"/>
|
||||||
|
<g filter="url(#filter0_ii_4774_13798)">
|
||||||
|
<path d="M77.8584 226.328L117.794 254.853C125.096 260.069 134.904 260.069 142.206 254.853L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7051C230 83.3045 224.994 75.7122 217.272 72.403L138.272 38.5459C132.99 36.2819 127.01 36.2819 121.728 38.5459L42.7277 72.403C35.0063 75.7122 30 83.3045 30 91.7051V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="black" fill-opacity="0.01"/>
|
||||||
|
</g>
|
||||||
|
<rect x="67" y="111" width="126" height="68.5833" rx="8.83333" fill="url(#paint8_linear_4774_13798)" stroke="url(#paint9_linear_4774_13798)" stroke-width="4"/>
|
||||||
|
<g filter="url(#filter1_d_4774_13798)">
|
||||||
|
<path d="M85.027 155.008L85.4252 147.997L79.5392 151.857L77.4272 148.187L83.7113 145.037L77.4272 141.886L79.5392 138.216L85.4252 142.076L85.027 135.065H89.2338L88.8529 142.076L94.739 138.216L96.851 141.886L90.5495 145.037L96.851 148.187L94.739 151.857L88.8529 147.997L89.2338 155.008H85.027ZM113.447 155.008L113.845 147.997L107.959 151.857L105.847 148.187L112.131 145.037L105.847 141.886L107.959 138.216L113.845 142.076L113.447 135.065H117.654L117.273 142.076L123.159 138.216L125.271 141.886L118.969 145.037L125.271 148.187L123.159 151.857L117.273 147.997L117.654 155.008H113.447ZM141.866 155.008L142.265 147.997L136.379 151.857L134.267 148.187L140.551 145.037L134.267 141.886L136.379 138.216L142.265 142.076L141.866 135.065H146.073L145.692 142.076L151.578 138.216L153.69 141.886L147.389 145.037L153.69 148.187L151.578 151.857L145.692 147.997L146.073 155.008H141.866ZM170.286 155.008L170.684 147.997L164.798 151.857L162.686 148.187L168.971 145.037L162.686 141.886L164.798 138.216L170.684 142.076L170.286 135.065H174.493L174.112 142.076L179.998 138.216L182.11 141.886L175.809 145.037L182.11 148.187L179.998 151.857L174.112 147.997L174.493 155.008H170.286Z" fill="#2C71CC"/>
|
||||||
|
</g>
|
||||||
|
<path d="M164.716 223.418H215.284C220.845 223.418 224.31 217.386 221.508 212.582L196.224 169.239C193.443 164.472 186.556 164.472 183.776 169.239L158.492 212.582C155.69 217.386 159.155 223.418 164.716 223.418Z" fill="#D9D9D9"/>
|
||||||
|
<path d="M164.716 223.418H215.284C220.845 223.418 224.31 217.386 221.508 212.582L196.224 169.239C193.443 164.472 186.556 164.472 183.776 169.239L158.492 212.582C155.69 217.386 159.155 223.418 164.716 223.418Z" fill="url(#paint10_linear_4774_13798)"/>
|
||||||
|
<path d="M164.716 223.418H215.284C220.845 223.418 224.31 217.386 221.508 212.582L196.224 169.239C193.443 164.472 186.556 164.472 183.776 169.239L158.492 212.582C155.69 217.386 159.155 223.418 164.716 223.418Z" stroke="#312938" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M164.716 223.418H215.284C220.845 223.418 224.31 217.386 221.508 212.582L196.224 169.239C193.443 164.472 186.556 164.472 183.776 169.239L158.492 212.582C155.69 217.386 159.155 223.418 164.716 223.418Z" stroke="url(#paint11_linear_4774_13798)" stroke-width="3.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M189.925 208.896H189.961M189.925 198.088V187.28" stroke="#312938" stroke-width="7.20545" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_ii_4774_13798" x="30" y="36.8479" width="200" height="221.917" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_4774_13798"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="-2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0.022328 0 0 0 0 0.298259 0 0 0 0 0.663462 0 0 0 1 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect1_innerShadow_4774_13798" result="effect2_innerShadow_4774_13798"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_d_4774_13798" x="68.1106" y="125.748" width="123.316" height="38.5765" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="4.65833"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0.172549 0 0 0 0 0.443137 0 0 0 0 0.8 0 0 0 0.3 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4774_13798"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4774_13798" result="shape"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#002A52"/>
|
||||||
|
<stop offset="1" stop-color="#0652DF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#19233C"/>
|
||||||
|
<stop offset="1" stop-color="#144CD8"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#19233C"/>
|
||||||
|
<stop offset="1" stop-color="#1647C3"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop offset="0.144488" stop-color="#FAFAFA"/>
|
||||||
|
<stop offset="1" stop-color="#72AAFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.42" stop-color="#2077F8"/>
|
||||||
|
<stop offset="0.700262" stop-color="#000F4D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D8E3FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_4774_13798" x1="130" y1="35.0006" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#68BEEF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#2C71CC"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_4774_13798" x1="147.5" y1="170" x2="69.5" y2="100" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop offset="0.0455724" stop-color="white" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0.5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint9_linear_4774_13798" x1="65" y1="109" x2="195" y2="185.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#4794DA"/>
|
||||||
|
<stop offset="0.954879" stop-color="#72AAFF" stop-opacity="0.2"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint10_linear_4774_13798" x1="190" y1="165.664" x2="190.433" y2="233.264" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FFC414"/>
|
||||||
|
<stop offset="1" stop-color="#FF9500"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint11_linear_4774_13798" x1="190" y1="165.664" x2="190" y2="223.418" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#5C486E"/>
|
||||||
|
<stop offset="1" stop-color="#312938"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 151 KiB |
|
@ -1,31 +0,0 @@
|
||||||
<svg width="163" height="178" viewBox="0 0 163 178" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M47.5763 28.5814C46.1363 28.5814 44.9689 27.414 44.9689 25.974V22.2461C44.9689 20.8061 46.1363 19.6387 47.5763 19.6387C49.0163 19.6387 50.1837 20.8061 50.1837 22.2461V25.974C50.1837 27.414 49.0163 28.5814 47.5763 28.5814Z" fill="#14C846"/>
|
|
||||||
<path d="M81.252 28.5814C79.812 28.5814 78.6445 27.414 78.6445 25.974V22.2461C78.6445 20.8061 79.812 19.6387 81.252 19.6387C82.6919 19.6387 83.8594 20.8061 83.8594 22.2461V25.974C83.8594 27.414 82.6919 28.5814 81.252 28.5814Z" fill="#14C846"/>
|
|
||||||
<path d="M114.928 28.5814C113.488 28.5814 112.32 27.414 112.32 25.974V22.2461C112.32 20.8061 113.488 19.6387 114.928 19.6387C116.368 19.6387 117.535 20.8061 117.535 22.2461V25.974C117.535 27.414 116.368 28.5814 114.928 28.5814Z" fill="#14C846"/>
|
|
||||||
<path d="M119.675 5.23777C118.208 2.28443 115.374 -2.62586 112.117 1.72088C109.646 5.02118 107.251 11.045 111.084 14.2782C113.143 16.0161 116.707 16.0196 118.771 14.2782C121.501 11.9753 121.084 8.07603 119.675 5.23777Z" fill="#FC914A"/>
|
|
||||||
<path d="M85.9992 5.23777C84.5328 2.28443 81.698 -2.62586 78.4419 1.72088C75.9701 5.02118 73.5754 11.045 77.408 14.2782C79.4678 16.0161 83.0317 16.0196 85.0957 14.2782C87.8255 11.9753 87.4086 8.07603 85.9992 5.23777Z" fill="#FC914A"/>
|
|
||||||
<path d="M147.295 113.917H15.2089V60.2027C15.2089 54.4747 19.8525 49.8311 25.5805 49.8311H136.923C142.651 49.8311 147.295 54.4747 147.295 60.2027V113.917Z" fill="#A06047"/>
|
|
||||||
<path d="M120.67 56.9909H109.185C108.196 56.9909 107.395 56.1892 107.395 55.2005V27.7645C107.395 26.7758 108.196 25.9741 109.185 25.9741H120.67C121.659 25.9741 122.461 26.7758 122.461 27.7645V55.2008C122.461 56.1896 121.659 56.9909 120.67 56.9909Z" fill="#14C846"/>
|
|
||||||
<path d="M86.9945 56.9909H75.5094C74.5206 56.9909 73.7189 56.1892 73.7189 55.2005V27.7645C73.7189 26.7758 74.5206 25.9741 75.5094 25.9741H86.9945C87.9832 25.9741 88.7849 26.7758 88.7849 27.7645V55.2008C88.7846 56.1896 87.9832 56.9909 86.9945 56.9909Z" fill="#14C846"/>
|
|
||||||
<path d="M52.3235 5.23777C50.8571 2.28443 48.0223 -2.62586 44.7662 1.72088C42.2943 5.02118 39.8997 11.045 43.7322 14.2782C45.7921 16.0161 49.3559 16.0196 51.4199 14.2782C54.1497 11.9753 53.7326 8.07603 52.3235 5.23777Z" fill="#FC914A"/>
|
|
||||||
<path d="M51.4183 14.2785C49.8107 15.6354 47.2898 15.9327 45.2776 15.1737C45.8432 14.9589 46.3696 14.6616 46.8243 14.2785C49.5527 11.9764 49.1373 8.07705 47.7265 5.2374C47.1 3.96985 46.2191 2.34421 45.1591 1.24145C48.249 -2.23546 50.9131 2.40158 52.3239 5.2374C53.7316 8.07705 54.1505 11.9764 51.4183 14.2785Z" fill="#EA7636"/>
|
|
||||||
<path d="M85.0943 14.2785C83.4867 15.6354 80.9659 15.9327 78.9536 15.1737C79.5193 14.9589 80.0456 14.6616 80.5004 14.2785C83.2288 11.9764 82.8133 8.07705 81.4025 5.2374C80.776 3.96985 79.8951 2.34421 78.8351 1.24145C81.925 -2.23546 84.5891 2.40158 85.9999 5.2374C87.4076 8.07705 87.8265 11.9764 85.0943 14.2785Z" fill="#EA7636"/>
|
|
||||||
<path d="M118.77 14.2785C117.163 15.6354 114.642 15.9327 112.63 15.1737C113.195 14.9589 113.722 14.6616 114.176 14.2785C116.905 11.9764 116.489 8.07705 115.078 5.2374C114.452 3.96985 113.571 2.34421 112.511 1.24145C115.601 -2.23546 118.265 2.40158 119.676 5.2374C121.083 8.07705 121.502 11.9764 118.77 14.2785Z" fill="#EA7636"/>
|
|
||||||
<path d="M53.3189 56.9909H41.8338C40.845 56.9909 40.0433 56.1892 40.0433 55.2005V27.7645C40.0433 26.7758 40.845 25.9741 41.8338 25.9741H53.3189C54.3076 25.9741 55.1093 26.7758 55.1093 27.7645V55.2008C55.109 56.1896 54.3076 56.9909 53.3189 56.9909Z" fill="#14C846"/>
|
|
||||||
<path d="M55.11 27.7659V55.2005C55.11 56.1888 54.3079 56.9909 53.3196 56.9909H48.8331V25.9758H53.3196C54.3079 25.9758 55.11 26.7744 55.11 27.7659Z" fill="#0EA939"/>
|
|
||||||
<path d="M88.7846 27.7659V55.2005C88.7846 56.1888 87.9826 56.9909 86.9942 56.9909H82.5077V25.9758H86.9942C87.9826 25.9758 88.7846 26.7744 88.7846 27.7659Z" fill="#0EA939"/>
|
|
||||||
<path d="M122.461 27.7659V55.2005C122.461 56.1888 121.659 56.9909 120.67 56.9909H116.184V25.9758H120.67C121.659 25.9758 122.461 26.7744 122.461 27.7659Z" fill="#0EA939"/>
|
|
||||||
<path d="M147.295 60.2028V113.916H134.809V60.2028C134.809 54.4738 130.169 49.8298 124.44 49.8298H136.922C142.651 49.8298 147.295 54.4738 147.295 60.2028Z" fill="#824730"/>
|
|
||||||
<path d="M147.296 60.2028V65.6885C144.844 67.6973 142.502 69.7953 137.607 69.7953C136.569 69.7953 135.645 69.7022 134.811 69.5304V60.2028C134.811 54.4738 130.17 49.8298 124.441 49.8298H136.923C142.652 49.8298 147.296 54.4738 147.296 60.2028Z" fill="#F7D443"/>
|
|
||||||
<path d="M162.503 178H0.000671387V124.286C0.000671387 118.558 4.64431 113.915 10.3723 113.915H152.131C157.859 113.915 162.503 118.558 162.503 124.286L162.503 178Z" fill="#A06047"/>
|
|
||||||
<path d="M162.503 124.286V177.999H147.296V124.286C147.296 118.557 142.652 113.916 136.923 113.916H152.13C157.859 113.916 162.503 118.557 162.503 124.286Z" fill="#824730"/>
|
|
||||||
<path d="M162.503 124.286V129.771C159.488 131.78 156.602 133.882 150.583 133.882C149.37 133.882 148.281 133.796 147.296 133.642V124.286C147.296 118.557 142.652 113.917 136.923 113.917H152.13C157.859 113.916 162.503 118.557 162.503 124.286Z" fill="#F7D443"/>
|
|
||||||
<path d="M147.293 83.5281H15.2078V96.4157H147.293V83.5281Z" fill="white"/>
|
|
||||||
<path d="M147.294 83.5281H134.808V96.4157H147.294V83.5281Z" fill="#C7ABA1"/>
|
|
||||||
<path d="M162.502 147.615H0.000671387V160.502H162.502V147.615Z" fill="white"/>
|
|
||||||
<path d="M162.504 147.615H147.296V160.502H162.504V147.615Z" fill="#C7ABA1"/>
|
|
||||||
<path d="M147.295 60.2028V65.6868C144.844 67.6973 142.501 69.7971 137.606 69.7971C128.214 69.7971 128.214 62.0638 118.822 62.0638C109.43 62.0638 109.43 69.7971 100.034 69.7971C90.6422 69.7971 90.6422 62.0638 81.2502 62.0638C71.8583 62.0638 71.8583 69.7971 62.4664 69.7971C53.0745 69.7971 53.0745 62.0638 43.6826 62.0638C34.2907 62.0638 34.2907 69.7971 24.8988 69.7971C20.0076 69.7971 17.6644 67.6976 15.2131 65.6868V60.2028C15.2131 54.4738 19.8574 49.8298 25.5861 49.8298H136.922C142.651 49.8298 147.295 54.4738 147.295 60.2028Z" fill="#2194FF"/>
|
|
||||||
<path d="M147.296 61.03V65.6883C144.844 67.697 142.502 69.7951 137.607 69.7951C136.569 69.7951 135.645 69.7019 134.811 69.5302V60.2026C134.811 54.4736 130.17 49.8296 124.441 49.8296H136.096C143.689 49.8299 147.296 54.6637 147.296 61.03Z" fill="#1585EC"/>
|
|
||||||
<path d="M162.504 125.114V129.77C159.488 131.781 156.604 133.881 150.584 133.881C139.026 133.881 139.026 126.148 127.469 126.148C115.916 126.148 115.916 133.881 104.359 133.881C92.8053 133.881 92.8053 126.148 81.2481 126.148C69.6949 126.148 69.6949 133.881 58.1377 133.881C46.5845 133.881 46.5845 126.148 35.0273 126.148C23.4741 126.148 23.4741 133.881 11.9169 133.881C5.89659 133.881 3.01591 131.781 0 129.77V124.287C0 118.558 4.64433 113.914 10.373 113.914H151.305C157.49 113.914 162.504 118.928 162.504 125.114Z" fill="#2194FF"/>
|
|
||||||
<path d="M162.503 125.113V129.771C159.488 131.78 156.602 133.882 150.583 133.882C149.37 133.882 148.281 133.796 147.296 133.642V124.286C147.296 118.557 142.652 113.916 136.923 113.916H151.593C158.474 113.916 162.503 118.048 162.503 125.113Z" fill="#1585EC"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 6.9 KiB |
BIN
assets/images/btc_lock_dark.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/images/btc_lock_light.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 2.4 KiB |
3
assets/images/cake_logo_dark.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="28" height="37" viewBox="0 0 28 37" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M26.0117 0.00835344C26.0523 -0.000438375 26.0914 -0.00211226 26.1279 0.00249407C26.3832 0.0346771 26.5225 0.363833 26.3174 0.5689L11.9326 14.9625C11.4874 15.4075 11.2364 16.0124 11.2354 16.6421V35.7369C11.2354 35.8853 11.146 35.9965 11.0303 36.0445C10.9723 36.0685 10.9079 36.0769 10.8447 36.066C10.7815 36.055 10.7195 36.0247 10.667 35.9722L0.396484 25.7056C0.20853 25.5177 0.10361 25.2641 0.103516 24.9996V7.18218C0.103551 6.28774 0.727312 5.51391 1.60156 5.32378L26.0107 0.00835344H26.0117ZM27.1025 20.2906C27.1024 20.5551 26.9964 20.8079 26.8096 20.9947L12.9443 34.8316C12.9218 34.8541 12.8953 34.867 12.8682 34.8716C12.8413 34.8762 12.8137 34.873 12.7891 34.8628C12.7394 34.8423 12.7012 34.7942 12.7012 34.731L12.7031 27.6763L17.3975 23.0289C18.0656 22.4518 18.3422 22.2068 18.7549 22.1832C18.8235 22.1792 18.896 22.1822 18.9746 22.19C19.0532 22.1978 19.138 22.2106 19.2314 22.2291C19.6039 22.3026 19.9558 22.357 20.2842 22.3755C20.4156 22.3829 20.5432 22.3847 20.667 22.3794C21.2241 22.356 21.7026 22.1937 22.0898 21.7945C22.427 21.4466 22.853 20.8957 23.0713 19.4947C23.2236 18.5107 23.33 17.8883 23.5439 17.3169C23.7579 16.7456 24.0748 16.3552 24.4551 15.9761V15.9752L27.1201 13.2974L27.1025 20.2906ZM26.9834 7.87359C27.0584 7.90479 27.1162 7.97749 27.1162 8.07378L27.0967 11.2144L24.1006 14.3306C23.5194 14.8954 22.9476 15.67 22.6914 16.2759C22.4364 16.8808 22.1497 17.8845 22.0049 18.7476C21.8611 19.6097 21.8812 20.1323 21.1377 20.6011C20.9985 20.6888 20.8632 20.7369 20.7295 20.7574C20.6402 20.7711 20.5516 20.7729 20.4629 20.7652C20.0187 20.7267 19.5718 20.4629 19.0273 20.4019C18.973 20.3958 18.9177 20.3918 18.8613 20.3902L18.8604 20.3912C17.9582 20.3653 17.3076 21.023 17.3057 21.025L12.7021 25.6441V22.5533C12.7021 22.1752 12.8521 21.8114 13.1201 21.5435L26.749 7.92046C26.7832 7.88634 26.8233 7.86688 26.8643 7.85992C26.9048 7.85303 26.9462 7.85813 26.9834 7.87359ZM26.9277 2.16753C27.0287 2.17924 27.12 2.26134 27.1201 2.3814V5.49956H27.1211L12.7021 19.9498V16.8648C12.7022 16.4869 12.8522 16.1238 13.1201 15.856L26.752 2.22906C26.8026 2.17847 26.8672 2.16051 26.9277 2.16753Z" fill="#D7E2F7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
3
assets/images/cake_logo_light.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="28" height="37" viewBox="0 0 28 37" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M26.0117 0.00769167C26.0523 -0.00110449 26.0914 -0.00180576 26.1279 0.00280886C26.3831 0.0350288 26.5224 0.363182 26.3174 0.568239L11.9326 14.9618C11.4874 15.4069 11.2364 16.0127 11.2354 16.6425V35.7372C11.2353 35.8856 11.1461 35.9969 11.0303 36.0448C10.9724 36.0688 10.9078 36.0772 10.8447 36.0663C10.7815 36.0554 10.7195 36.025 10.667 35.9725L0.396484 25.7059C0.208445 25.518 0.103516 25.2635 0.103516 24.9989V7.1825C0.103516 6.28802 0.727287 5.51423 1.60156 5.3241L26.0107 0.00769167H26.0117ZM27.1025 20.2899C27.1025 20.5545 26.9964 20.8071 26.8096 20.994L12.9443 34.8319C12.9218 34.8543 12.8952 34.8674 12.8682 34.8719C12.8413 34.8765 12.8138 34.8724 12.7891 34.8622C12.7396 34.8417 12.7013 34.7944 12.7012 34.7313L12.7031 27.6757L17.3975 23.0282C18.0655 22.4511 18.3423 22.2071 18.7549 22.1835C18.8235 22.1795 18.896 22.1815 18.9746 22.1893C19.0532 22.1971 19.138 22.2109 19.2314 22.2294C19.6039 22.303 19.9558 22.3574 20.2842 22.3759C20.4155 22.3833 20.5432 22.385 20.667 22.3798C21.224 22.3563 21.7026 22.1939 22.0898 21.7948C22.427 21.447 22.853 20.896 23.0713 19.495C23.2236 18.5109 23.33 17.8887 23.5439 17.3173C23.7579 16.7458 24.0747 16.3556 24.4551 15.9764V15.9755L27.1201 13.2977L27.1025 20.2899ZM26.9834 7.8739C27.0584 7.90515 27.1162 7.97782 27.1162 8.0741L27.0967 11.2137L24.1006 14.3309C23.5192 14.8958 22.9476 15.6702 22.6914 16.2762C22.4364 16.8812 22.1497 17.8848 22.0049 18.7479C21.8611 19.61 21.8812 20.1316 21.1377 20.6005C20.9984 20.6882 20.8633 20.7372 20.7295 20.7577C20.6402 20.7714 20.5516 20.7722 20.4629 20.7645C20.0188 20.7261 19.5717 20.4632 19.0273 20.4022C18.973 20.3961 18.9177 20.3912 18.8613 20.3895L18.8604 20.3915C17.9569 20.3655 17.3057 21.0253 17.3057 21.0253L12.7021 25.6444V22.5526C12.7022 22.1746 12.8523 21.8117 13.1201 21.5438L26.749 7.92078C26.7832 7.88666 26.8233 7.8672 26.8643 7.86023C26.9049 7.85331 26.9462 7.85839 26.9834 7.8739ZM26.9277 2.16785C27.0288 2.17959 27.1201 2.2615 27.1201 2.38172V5.4989H27.1211L12.7021 19.9501V16.8651C12.7021 16.4872 12.8523 16.1242 13.1201 15.8563L26.752 2.22937C26.8026 2.17876 26.8671 2.16081 26.9277 2.16785Z" fill="#1C1B1C"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/images/contact.png
Normal file
After Width: | Height: | Size: 26 KiB |
5
assets/images/hero/cw_welcome_dark.svg
Normal file
After Width: | Height: | Size: 10 KiB |
5
assets/images/hero/cw_welcome_light.svg
Normal file
After Width: | Height: | Size: 10 KiB |
10
assets/images/history.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_67_21)">
|
||||||
|
<path d="M70.4443 8.33334C101.173 8.33336 126 33.1598 126 63.889C126 94.6181 101.173 119.445 70.4443 119.445C53.0832 119.445 37.4581 111.458 27.3887 98.9583L37.2842 89.0628C44.7495 98.9587 56.9027 105.556 70.4443 105.556C93.361 105.556 112.111 86.8056 112.111 63.889C112.111 40.9723 93.361 22.222 70.4443 22.222C56.9027 22.222 44.7495 28.8193 37.2842 38.7152C33.1175 44.0971 30.3405 50.521 29.2988 57.639C28.9516 59.7223 28.7773 61.8057 28.7773 63.889H42.667L21.833 84.722L1 63.889H14.8887C14.8887 61.9793 14.8891 60.2431 15.2363 58.3333C15.7572 52.7778 17.146 47.5692 19.0557 42.5345C27.3891 22.5694 47.3542 8.33334 70.4443 8.33334ZM75.6523 35.4163V60.9378L93.708 78.9925L83.8125 88.889L61.7637 66.6663V35.4163H75.6523Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_67_21">
|
||||||
|
<rect width="128" height="128" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 984 B |
6
assets/images/home_screen_setting_icon.svg
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<svg width="45" height="46" viewBox="0 0 45 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="22.5" cy="23" r="22.5" fill="#312938" fill-opacity="0.1"/>
|
||||||
|
<path d="M25.391 19.4402C24.7502 15.2551 21.1352 12.0498 16.7708 12.0498C11.9548 12.0498 8.04984 15.9548 8.04984 20.7708C8.04984 24.1914 10.0183 27.1505 12.8847 28.5797C13.9003 29.087 15.0296 29.401 16.2246 29.4738C16.405 29.4857 16.5874 29.4917 16.7708 29.4917C20.8542 29.4917 24.2807 26.686 25.2306 22.8977C25.401 22.2169 25.4917 21.5043 25.4917 20.7708C25.4917 20.3183 25.4568 19.8738 25.391 19.4402ZM16.7708 26.5017C16.4518 26.5017 16.1379 26.4757 15.8329 26.4249C14.7794 26.2505 13.8226 25.788 13.0452 25.1223C11.8183 24.0708 11.0399 22.51 11.0399 20.7708C11.0399 17.6113 13.6113 15.0399 16.7708 15.0399C19.1429 15.0399 21.1821 16.488 22.0512 18.5462C22.3412 19.2309 22.5017 19.9824 22.5017 20.7708C22.5017 21.0508 22.4817 21.3259 22.4429 21.595C22.0422 24.3658 19.6512 26.5017 16.7708 26.5017Z" fill="#312938"/>
|
||||||
|
<path d="M36.4551 15.7874H34.2126V13.5448C34.2126 12.7196 33.5429 12.0498 32.7176 12.0498C31.8924 12.0498 31.2226 12.7196 31.2226 13.5448V15.7874H28.9801C28.1548 15.7874 27.485 16.4571 27.485 17.2824C27.485 18.1076 28.1548 18.7774 28.9801 18.7774H31.2226V21.0199C31.2226 21.8452 31.8924 22.5149 32.7176 22.5149C33.5429 22.5149 34.2126 21.8452 34.2126 21.0199V18.7774H36.4551C37.2804 18.7774 37.9502 18.1076 37.9502 17.2824C37.9502 16.4571 37.2804 15.7874 36.4551 15.7874Z" fill="#312938"/>
|
||||||
|
<path d="M25.391 19.4402C25.4568 19.8738 25.4917 20.3183 25.4917 20.7708C25.4917 21.5043 25.401 22.2169 25.2306 22.8977C26.4575 23.9502 27.2359 25.511 27.2359 27.2492C27.2359 30.4096 24.6654 32.9801 21.505 32.9801C19.1339 32.9801 17.0937 31.5319 16.2246 29.4738C15.0296 29.401 13.9003 29.087 12.8847 28.5797C13.5256 32.7658 17.1415 35.9701 21.505 35.9701C26.3219 35.9701 30.2259 32.0661 30.2259 27.2492C30.2259 23.8296 28.2575 20.8684 25.391 19.4402Z" fill="#312938"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
3
assets/images/menu.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 17V19H1V17H21ZM21 12H1V10H21V12ZM21 5H1V3H21V5Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 180 B |
3
assets/images/notif.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M77.9219 103.359C77.9219 111.953 71.0469 119 62.4531 119C53.8594 119 46.8125 111.953 46.8125 103.359C46.8125 102.672 46.8125 102.156 46.9844 101.641H9V87.8906H21.0312V51.9688C21.0312 28.25 40.2812 9 64 9C87.7188 9 106.969 28.25 106.969 51.9688V87.8906H119V101.641H77.9219V103.359ZM64 22.75C47.8438 22.75 34.7812 35.8125 34.7812 51.9688V87.8906H93.2188V51.9688C93.2188 35.8125 80.1562 22.75 64 22.75Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 532 B |
|
@ -1,69 +1,3 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
<path d="M13.7842 18.8721C13.7841 20.5907 12.4091 22 10.6904 22C8.97183 21.9999 7.56261 20.5907 7.5625 18.8721C7.5625 18.7347 7.56238 18.6314 7.59668 18.5283H0V15.7783H2.40625V8.59375C2.40625 3.85 6.25625 0 11 0C15.7437 0 19.5938 3.85 19.5938 8.59375V15.7783H22V18.5283H13.7842V18.8721ZM11 2.75C7.76875 2.75 5.15625 5.3625 5.15625 8.59375V15.7783H16.8438V8.59375C16.8438 5.3625 14.2312 2.75 11 2.75Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
version="1.1"
|
|
||||||
id="Capa_1"
|
|
||||||
x="0px"
|
|
||||||
y="0px"
|
|
||||||
width="510px"
|
|
||||||
height="510px"
|
|
||||||
viewBox="0 0 510 510"
|
|
||||||
style="enable-background:new 0 0 510 510;"
|
|
||||||
xml:space="preserve"
|
|
||||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
|
||||||
sodipodi:docname="notification_logo_tilt_white.svg"><metadata
|
|
||||||
id="metadata42"><rdf:RDF><cc:Work
|
|
||||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
|
||||||
id="defs40" /><sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1920"
|
|
||||||
inkscape:window-height="1090"
|
|
||||||
id="namedview38"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="0.4627451"
|
|
||||||
inkscape:cx="-849.27966"
|
|
||||||
inkscape:cy="255"
|
|
||||||
inkscape:window-x="-12"
|
|
||||||
inkscape:window-y="58"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="notifications"
|
|
||||||
inkscape:object-paths="true" /><g
|
|
||||||
id="g3"
|
|
||||||
transform="matrix(0.87658593,0,0,0.87658593,31.470588,31.470588)"><g
|
|
||||||
id="notifications"
|
|
||||||
transform="rotate(-20,255,255)"><path
|
|
||||||
d="m 233.56017,502.19654 c 28.05,0 51,-22.95 51,-51 h -102 c 0,28.05 22.95,51 51,51 z m 165.75,-153 v -140.25 c 0,-79.05 -53.55,-142.8 -127.5,-160.65 v -17.85 c 0,-20.4 -17.85,-38.2499996 -38.25,-38.2499996 -20.4,0 -38.25,17.8499996 -38.25,38.2499996 v 17.85 c -73.95,17.85 -127.499999,81.6 -127.499999,160.65 v 140.25 l -51,51 v 25.5 H 450.31017 v -25.5 z"
|
|
||||||
id="path6"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="opacity:1;fill:#ffffff;fill-opacity:0;stroke:#000000;stroke-width:19.39342117;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></g></g><g
|
|
||||||
id="g8" /><g
|
|
||||||
id="g10" /><g
|
|
||||||
id="g12" /><g
|
|
||||||
id="g14" /><g
|
|
||||||
id="g16" /><g
|
|
||||||
id="g18" /><g
|
|
||||||
id="g20" /><g
|
|
||||||
id="g22" /><g
|
|
||||||
id="g24" /><g
|
|
||||||
id="g26" /><g
|
|
||||||
id="g28" /><g
|
|
||||||
id="g30" /><g
|
|
||||||
id="g32" /><g
|
|
||||||
id="g34" /><g
|
|
||||||
id="g36" /></svg>
|
|
||||||
|
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 519 B |
BIN
assets/images/passphrase_dark.png
Normal file
After Width: | Height: | Size: 56 KiB |
22
assets/images/passphrase_key.svg
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<svg width="158" height="158" viewBox="0 0 158 158" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_3076_287)">
|
||||||
|
<path d="M59.8674 111.213C61.104 109.782 62.8874 109.123 64.6415 109.237L69.6321 103.461C69.1122 101.951 69.369 100.216 70.4903 98.9183C71.6101 97.6223 73.2894 97.1164 74.8608 97.4098L79.8316 91.6568L65.7827 79.5181L42.7631 106.16C41.9574 107.093 41.5571 108.305 41.6467 109.532L41.9828 114.163L48.3733 119.684L53.4019 119.732C54.767 119.746 56.0685 119.159 56.9607 118.127L58.6055 116.223C58.2383 114.504 58.6308 112.644 59.8674 111.213Z" fill="url(#paint0_linear_3076_287)"/>
|
||||||
|
<path d="M115.362 82.4834C126.257 69.8745 124.867 50.823 112.258 39.9285C99.6491 29.0339 80.5975 30.4236 69.703 43.0325C69.1902 43.6261 68.7318 44.2453 68.2752 44.866L68.1857 44.7886L56.0469 58.8375C52.6951 62.7168 53.1228 68.5796 57.002 71.9314L88.6121 99.2435C92.4913 102.595 98.3541 102.168 101.706 98.2884L113.845 84.2395L113.755 84.1621C114.303 83.6203 114.849 83.077 115.362 82.4834ZM104.671 48.709C108.551 52.0608 108.978 57.9236 105.626 61.8029C102.275 65.6821 96.4118 66.1098 92.5325 62.758C88.6532 59.4061 88.2256 53.5434 91.5774 49.6641C94.9292 45.7849 100.792 45.3572 104.671 48.709Z" fill="url(#paint1_linear_3076_287)"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_3076_287" x1="72.8481" y1="85.54" x2="45.4677" y2="117.229" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#E5A505"/>
|
||||||
|
<stop offset="0.01" stop-color="#E9A804"/>
|
||||||
|
<stop offset="0.06" stop-color="#F4B102"/>
|
||||||
|
<stop offset="0.129" stop-color="#FBB600"/>
|
||||||
|
<stop offset="0.323" stop-color="#FDB700"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_3076_287" x1="91.8949" y1="31.3914" x2="84.3571" y2="99.6065" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FEDE00"/>
|
||||||
|
<stop offset="1" stop-color="#FFD000"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_3076_287">
|
||||||
|
<rect width="111.4" height="111.4" fill="white" transform="translate(73.146) rotate(40.8281)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/images/passphrase_light.png
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
assets/images/payjoin.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assets/images/qr-cake.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
assets/images/receive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/seed_verified_dark.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
assets/images/seed_verified_light.png
Normal file
After Width: | Height: | Size: 83 KiB |
86
assets/images/seed_warning_dark.svg
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<svg width="260" height="298" viewBox="0 0 260 298" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M119.655 6.27832C126.055 3.53578 133.272 3.45033 139.723 6.02148L140.345 6.27832L243.044 50.293C252.699 54.431 258.96 63.925 258.96 74.4297V128.542C258.96 175.815 236.309 220.2 198.085 247.94L197.18 248.593L145.264 285.676C136.276 292.096 124.25 292.197 115.167 285.978L114.736 285.676L62.8203 248.593C24.0499 220.899 1.04004 176.187 1.04004 128.542V74.4297C1.04004 64.0891 7.10644 54.7283 16.5059 50.4912L16.9561 50.293L119.655 6.27832Z" stroke="#708BF4" stroke-opacity="0.05" stroke-width="2.08"/>
|
||||||
|
<path d="M120.451 17.2793C126.358 14.7477 133.02 14.6687 138.975 17.042L139.549 17.2793L234.349 57.9082C243.261 61.7279 249.04 70.491 249.04 80.1875V130.138C249.04 173.775 228.131 214.745 192.848 240.352L192.012 240.954L144.089 275.185C135.792 281.111 124.692 281.204 116.308 275.463L115.911 275.185L67.9883 240.954C32.2001 215.391 10.96 174.118 10.96 130.138V80.1875C10.9601 70.6424 16.56 62.0019 25.2363 58.0908L25.6514 57.9082L120.451 17.2793Z" stroke="#708BF4" stroke-opacity="0.15" stroke-width="1.92"/>
|
||||||
|
<path d="M121.294 28.3906C126.68 26.0825 132.754 26.0099 138.183 28.1738L138.706 28.3906L225.605 65.6328C233.731 69.1153 239 77.1057 239 85.9463V131.733C239 171.381 220.152 208.625 188.301 232.109L186.774 233.218L142.846 264.596C135.282 269.999 125.161 270.083 117.517 264.849L117.154 264.596L73.2256 233.218C40.4513 209.807 21 172.01 21 131.733V85.9463C21 77.2438 26.1053 69.3657 34.0156 65.7998L34.3945 65.6328L121.294 28.3906Z" stroke="#708BF4" stroke-opacity="0.5" stroke-width="2"/>
|
||||||
|
<path d="M77.8584 226.327L117.794 254.853C125.096 260.068 134.904 260.068 142.206 254.853L182.141 226.327C212.176 204.874 230 170.238 230 133.329V91.7045C230 83.3039 224.994 75.7116 217.272 72.4024L138.272 38.5453C132.99 36.2813 127.01 36.2813 121.728 38.5453L42.7277 72.4024C35.0063 75.7116 30 83.3039 30 91.7045V133.329C30 170.238 47.8247 204.874 77.8584 226.327Z" fill="black"/>
|
||||||
|
<path d="M77.8584 226.327L117.794 254.853C125.096 260.068 134.904 260.068 142.206 254.853L182.141 226.327C212.176 204.874 230 170.238 230 133.329V91.7045C230 83.3039 224.994 75.7116 217.272 72.4024L138.272 38.5453C132.99 36.2813 127.01 36.2813 121.728 38.5453L42.7277 72.4024C35.0063 75.7116 30 83.3039 30 91.7045V133.329C30 170.238 47.8247 204.874 77.8584 226.327Z" fill="url(#paint0_linear_4659_24215)"/>
|
||||||
|
<path d="M123.479 42.6299C127.513 40.9009 132.063 40.8476 136.13 42.4688L136.521 42.6299L215.521 76.4873C221.609 79.0961 225.556 85.0816 225.556 91.7041V133.329C225.556 168.248 208.955 201.051 180.902 221.734L179.559 222.711L139.623 251.236C134.047 255.22 126.615 255.344 120.923 251.609L120.377 251.236L80.4414 222.711C51.5757 202.092 34.4443 168.802 34.4443 133.329V91.7041C34.4445 85.2886 38.1486 79.4713 43.9141 76.7422L44.4785 76.4873L123.479 42.6299Z" stroke="url(#paint1_linear_4659_24215)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6299C127.513 40.9009 132.063 40.8476 136.13 42.4688L136.521 42.6299L215.521 76.4873C221.609 79.0961 225.556 85.0816 225.556 91.7041V133.329C225.556 168.248 208.955 201.051 180.902 221.734L179.559 222.711L139.623 251.236C134.047 255.22 126.615 255.344 120.923 251.609L120.377 251.236L80.4414 222.711C51.5757 202.092 34.4443 168.802 34.4443 133.329V91.7041C34.4445 85.2886 38.1486 79.4713 43.9141 76.7422L44.4785 76.4873L123.479 42.6299Z" stroke="url(#paint2_linear_4659_24215)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6299C127.513 40.9009 132.063 40.8476 136.13 42.4688L136.521 42.6299L215.521 76.4873C221.609 79.0961 225.556 85.0816 225.556 91.7041V133.329C225.556 168.248 208.955 201.051 180.902 221.734L179.559 222.711L139.623 251.236C134.047 255.22 126.615 255.344 120.923 251.609L120.377 251.236L80.4414 222.711C51.5757 202.092 34.4443 168.802 34.4443 133.329V91.7041C34.4445 85.2886 38.1486 79.4713 43.9141 76.7422L44.4785 76.4873L123.479 42.6299Z" stroke="url(#paint3_linear_4659_24215)" stroke-width="8.88889"/>
|
||||||
|
<g filter="url(#filter0_i_4659_24215)">
|
||||||
|
<path d="M77.8584 226.327L117.794 254.853C125.096 260.068 134.904 260.068 142.206 254.853L182.141 226.327C212.176 204.874 230 170.238 230 133.329V91.7045C230 83.3039 224.994 75.7116 217.272 72.4024L138.272 38.5453C132.99 36.2813 127.01 36.2813 121.728 38.5453L42.7277 72.4024C35.0063 75.7116 30 83.3039 30 91.7045V133.329C30 170.238 47.8247 204.874 77.8584 226.327Z" fill="black" fill-opacity="0.01"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter1_ii_4659_24215)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.25C163.158 154.25 175.75 141.658 175.75 126.125C175.75 110.592 163.158 98 147.625 98C132.092 98 119.5 110.592 119.5 126.125C119.5 131.628 121.081 136.763 123.813 141.098L85.6611 179.25L104.393 197.982L113.232 189.143L103.339 179.25L113.25 169.339L123.143 179.232L131.982 170.393L122.089 160.5L132.652 149.937C136.987 152.669 142.122 154.25 147.625 154.25ZM147.625 141.75C156.254 141.75 163.25 134.754 163.25 126.125C163.25 117.496 156.254 110.5 147.625 110.5C138.996 110.5 132 117.496 132 126.125C132 134.754 138.996 141.75 147.625 141.75Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.25C163.158 154.25 175.75 141.658 175.75 126.125C175.75 110.592 163.158 98 147.625 98C132.092 98 119.5 110.592 119.5 126.125C119.5 131.628 121.081 136.763 123.813 141.098L85.6611 179.25L104.393 197.982L113.232 189.143L103.339 179.25L113.25 169.339L123.143 179.232L131.982 170.393L122.089 160.5L132.652 149.937C136.987 152.669 142.122 154.25 147.625 154.25ZM147.625 141.75C156.254 141.75 163.25 134.754 163.25 126.125C163.25 117.496 156.254 110.5 147.625 110.5C138.996 110.5 132 117.496 132 126.125C132 134.754 138.996 141.75 147.625 141.75Z" fill="url(#paint4_linear_4659_24215)"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.25C163.158 154.25 175.75 141.658 175.75 126.125C175.75 110.592 163.158 98 147.625 98C132.092 98 119.5 110.592 119.5 126.125C119.5 131.628 121.081 136.763 123.813 141.098L85.6611 179.25L104.393 197.982L113.232 189.143L103.339 179.25L113.25 169.339L123.143 179.232L131.982 170.393L122.089 160.5L132.652 149.937C136.987 152.669 142.122 154.25 147.625 154.25ZM147.625 141.75C156.254 141.75 163.25 134.754 163.25 126.125C163.25 117.496 156.254 110.5 147.625 110.5C138.996 110.5 132 117.496 132 126.125C132 134.754 138.996 141.75 147.625 141.75Z" fill="url(#paint5_linear_4659_24215)"/>
|
||||||
|
</g>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" fill="#D9D9D9"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" fill="url(#paint6_linear_4659_24215)"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" stroke="#312938" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" stroke="url(#paint7_linear_4659_24215)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" stroke="url(#paint8_linear_4659_24215)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M189.907 212.209H189.952M189.907 198.907V185.604" stroke="#312938" stroke-width="8.86825" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_4659_24215" x="30" y="36.8477" width="200" height="221.917" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="plus-lighter" in2="shape" result="effect1_innerShadow_4659_24215"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_ii_4659_24215" x="85.6611" y="98" width="90.0889" height="99.9814" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.4 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_4659_24215"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="-2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect1_innerShadow_4659_24215" result="effect2_innerShadow_4659_24215"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_4659_24215" x1="130" y1="35" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#19233C"/>
|
||||||
|
<stop offset="1" stop-color="#1647C3"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4659_24215" x1="130" y1="35" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.42" stop-color="#2077F8"/>
|
||||||
|
<stop offset="0.700262" stop-color="#000F4D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_4659_24215" x1="130" y1="35" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_4659_24215" x1="130" y1="35" x2="130" y2="263.571" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D8E3FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_4659_24215" x1="130.705" y1="98" x2="130.705" y2="197.982" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#6DA8FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_4659_24215" x1="130.705" y1="98" x2="130.705" y2="197.982" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#6891FE"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_4659_24215" x1="190" y1="159" x2="190.533" y2="242.2" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FFC414"/>
|
||||||
|
<stop offset="1" stop-color="#FF9500"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_4659_24215" x1="190" y1="159" x2="190" y2="230.082" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#5C486E"/>
|
||||||
|
<stop offset="1" stop-color="#312938"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_4659_24215" x1="190" y1="159" x2="190" y2="230.082" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#EBD4FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
111
assets/images/seed_warning_light.svg
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<svg width="260" height="298" viewBox="0 0 260 298" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M119.655 6.2793C126.055 3.53675 133.272 3.4513 139.723 6.02246L140.345 6.2793L243.044 50.2939C252.699 54.432 258.96 63.9259 258.96 74.4307V128.543C258.96 175.816 236.309 220.201 198.085 247.941L197.18 248.594L145.264 285.677C136.276 292.097 124.25 292.198 115.167 285.979L114.736 285.677L62.8203 248.594C24.0499 220.9 1.04004 176.188 1.04004 128.543V74.4307C1.04004 64.09 7.10644 54.7293 16.5059 50.4922L16.9561 50.2939L119.655 6.2793Z" stroke="#4A98DC" stroke-opacity="0.05" stroke-width="2.08"/>
|
||||||
|
<path d="M120.451 17.2803C126.358 14.7487 133.02 14.6696 138.975 17.043L139.549 17.2803L234.349 57.9092C243.261 61.7289 249.04 70.492 249.04 80.1885V130.139C249.04 173.775 228.131 214.746 192.848 240.353L192.012 240.955L144.089 275.186C135.792 281.112 124.692 281.205 116.308 275.464L115.911 275.186L67.9883 240.955C32.2001 215.392 10.96 174.119 10.96 130.139V80.1885C10.9601 70.6434 16.56 62.0028 25.2363 58.0918L25.6514 57.9092L120.451 17.2803Z" stroke="#4B98DC" stroke-opacity="0.15" stroke-width="1.92"/>
|
||||||
|
<path d="M121.294 28.3916C126.68 26.0835 132.754 26.0109 138.183 28.1748L138.706 28.3916L225.605 65.6338C233.731 69.1163 239 77.1066 239 85.9473V131.734C239 171.382 220.152 208.626 188.301 232.11L186.774 233.219L142.846 264.597C135.282 270 125.161 270.084 117.517 264.85L117.154 264.597L73.2256 233.219C40.4513 209.808 21 172.011 21 131.734V85.9473C21 77.2448 26.1053 69.3666 34.0156 65.8008L34.3945 65.6338L121.294 28.3916Z" stroke="#4895DB" stroke-opacity="0.35" stroke-width="2"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="black"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint0_linear_5093_13165)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint1_linear_5093_13165)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint2_linear_5093_13165)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint3_linear_5093_13165)"/>
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="url(#paint4_radial_5093_13165)" fill-opacity="0.3"/>
|
||||||
|
<path d="M123.479 42.6309C127.513 40.9019 132.063 40.8486 136.13 42.4697L136.521 42.6309L215.521 76.4883C221.609 79.097 225.556 85.0825 225.556 91.7051V133.33C225.556 168.249 208.955 201.052 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.221 126.615 255.345 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7051C34.4445 85.2895 38.1486 79.4723 43.9141 76.7432L44.4785 76.4883L123.479 42.6309Z" stroke="url(#paint5_linear_5093_13165)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6309C127.513 40.9019 132.063 40.8486 136.13 42.4697L136.521 42.6309L215.521 76.4883C221.609 79.097 225.556 85.0825 225.556 91.7051V133.33C225.556 168.249 208.955 201.052 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.221 126.615 255.345 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7051C34.4445 85.2895 38.1486 79.4723 43.9141 76.7432L44.4785 76.4883L123.479 42.6309Z" stroke="url(#paint6_linear_5093_13165)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6309C127.513 40.9019 132.063 40.8486 136.13 42.4697L136.521 42.6309L215.521 76.4883C221.609 79.097 225.556 85.0825 225.556 91.7051V133.33C225.556 168.249 208.955 201.052 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.221 126.615 255.345 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7051C34.4445 85.2895 38.1486 79.4723 43.9141 76.7432L44.4785 76.4883L123.479 42.6309Z" stroke="url(#paint7_linear_5093_13165)" stroke-width="8.88889"/>
|
||||||
|
<path d="M123.479 42.6309C127.513 40.9019 132.063 40.8486 136.13 42.4697L136.521 42.6309L215.521 76.4883C221.609 79.097 225.556 85.0825 225.556 91.7051V133.33C225.556 168.249 208.955 201.052 180.902 221.735L179.559 222.712L139.623 251.237C134.047 255.221 126.615 255.345 120.923 251.61L120.377 251.237L80.4414 222.712C51.5757 202.093 34.4443 168.803 34.4443 133.33V91.7051C34.4445 85.2895 38.1486 79.4723 43.9141 76.7432L44.4785 76.4883L123.479 42.6309Z" stroke="url(#paint8_linear_5093_13165)" stroke-width="8.88889"/>
|
||||||
|
<g filter="url(#filter0_i_5093_13165)">
|
||||||
|
<path d="M77.8584 226.328L117.794 254.854C125.096 260.069 134.904 260.069 142.206 254.854L182.141 226.328C212.176 204.875 230 170.239 230 133.33V91.7054C230 83.3049 224.994 75.7126 217.272 72.4034L138.272 38.5462C132.99 36.2823 127.01 36.2823 121.728 38.5463L42.7277 72.4034C35.0063 75.7126 30 83.3049 30 91.7054V133.33C30 170.239 47.8247 204.875 77.8584 226.328Z" fill="black" fill-opacity="0.01"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter1_ii_5093_13165)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.251C163.158 154.251 175.75 141.659 175.75 126.126C175.75 110.593 163.158 98.001 147.625 98.001C132.092 98.001 119.5 110.593 119.5 126.126C119.5 131.629 121.081 136.764 123.813 141.099L85.6611 179.251L104.393 197.983L113.232 189.144L103.339 179.251L113.25 169.34L123.143 179.233L131.982 170.394L122.089 160.501L132.652 149.938C136.987 152.67 142.122 154.251 147.625 154.251ZM147.625 141.751C156.254 141.751 163.25 134.755 163.25 126.126C163.25 117.497 156.254 110.501 147.625 110.501C138.996 110.501 132 117.497 132 126.126C132 134.755 138.996 141.751 147.625 141.751Z" fill="black"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.251C163.158 154.251 175.75 141.659 175.75 126.126C175.75 110.593 163.158 98.001 147.625 98.001C132.092 98.001 119.5 110.593 119.5 126.126C119.5 131.629 121.081 136.764 123.813 141.099L85.6611 179.251L104.393 197.983L113.232 189.144L103.339 179.251L113.25 169.34L123.143 179.233L131.982 170.394L122.089 160.501L132.652 149.938C136.987 152.67 142.122 154.251 147.625 154.251ZM147.625 141.751C156.254 141.751 163.25 134.755 163.25 126.126C163.25 117.497 156.254 110.501 147.625 110.501C138.996 110.501 132 117.497 132 126.126C132 134.755 138.996 141.751 147.625 141.751Z" fill="url(#paint9_linear_5093_13165)"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.251C163.158 154.251 175.75 141.659 175.75 126.126C175.75 110.593 163.158 98.001 147.625 98.001C132.092 98.001 119.5 110.593 119.5 126.126C119.5 131.629 121.081 136.764 123.813 141.099L85.6611 179.251L104.393 197.983L113.232 189.144L103.339 179.251L113.25 169.34L123.143 179.233L131.982 170.394L122.089 160.501L132.652 149.938C136.987 152.67 142.122 154.251 147.625 154.251ZM147.625 141.751C156.254 141.751 163.25 134.755 163.25 126.126C163.25 117.497 156.254 110.501 147.625 110.501C138.996 110.501 132 117.497 132 126.126C132 134.755 138.996 141.751 147.625 141.751Z" fill="url(#paint10_linear_5093_13165)"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.625 154.251C163.158 154.251 175.75 141.659 175.75 126.126C175.75 110.593 163.158 98.001 147.625 98.001C132.092 98.001 119.5 110.593 119.5 126.126C119.5 131.629 121.081 136.764 123.813 141.099L85.6611 179.251L104.393 197.983L113.232 189.144L103.339 179.251L113.25 169.34L123.143 179.233L131.982 170.394L122.089 160.501L132.652 149.938C136.987 152.67 142.122 154.251 147.625 154.251ZM147.625 141.751C156.254 141.751 163.25 134.755 163.25 126.126C163.25 117.497 156.254 110.501 147.625 110.501C138.996 110.501 132 117.497 132 126.126C132 134.755 138.996 141.751 147.625 141.751Z" fill="url(#paint11_linear_5093_13165)"/>
|
||||||
|
</g>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" fill="#D9D9D9"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" fill="url(#paint12_linear_5093_13165)"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" stroke="#312938" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M158.882 230.082H221.118C227.963 230.082 232.227 222.658 228.779 216.746L197.66 163.4C194.238 157.533 185.762 157.533 182.34 163.4L151.221 216.746C147.773 222.658 152.037 230.082 158.882 230.082Z" stroke="url(#paint13_linear_5093_13165)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M189.907 212.209H189.952M189.907 198.907V185.604" stroke="#312938" stroke-width="8.86825" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_5093_13165" x="30" y="36.8486" width="200" height="221.917" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_5093_13165"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_ii_5093_13165" x="85.6611" y="98.001" width="90.0889" height="99.9814" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.3 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_5093_13165"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="-2"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect1_innerShadow_5093_13165" result="effect2_innerShadow_5093_13165"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#002A52"/>
|
||||||
|
<stop offset="1" stop-color="#0652DF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#19233C"/>
|
||||||
|
<stop offset="1" stop-color="#144CD8"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#19233C"/>
|
||||||
|
<stop offset="1" stop-color="#1647C3"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FAFAFA"/>
|
||||||
|
<stop offset="1" stop-color="#72AAFF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="paint4_radial_5093_13165" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(130 149.287) rotate(90) scale(97.381 85.2083)">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient id="paint5_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.42" stop-color="#2077F8"/>
|
||||||
|
<stop offset="0.700262" stop-color="#000F4D"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#C1F2FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D8E3FF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#718CF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_5093_13165" x1="130" y1="35.001" x2="130" y2="263.572" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#68BEEF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#2C71CC"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint9_linear_5093_13165" x1="130.705" y1="98.001" x2="130.705" y2="197.983" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#6DA8FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint10_linear_5093_13165" x1="130.705" y1="98.001" x2="130.705" y2="197.983" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#68BEEF"/>
|
||||||
|
<stop offset="1" stop-color="#0047A3"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint11_linear_5093_13165" x1="130.705" y1="98.001" x2="130.705" y2="197.983" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#68BEEF"/>
|
||||||
|
<stop offset="0.700262" stop-color="#2C71CC"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint12_linear_5093_13165" x1="190" y1="159" x2="190.533" y2="242.2" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FFC414"/>
|
||||||
|
<stop offset="1" stop-color="#FF9500"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint13_linear_5093_13165" x1="190" y1="159" x2="190" y2="230.082" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#5C486E"/>
|
||||||
|
<stop offset="1" stop-color="#312938"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 378 B |
BIN
assets/images/send2.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/swap.png
Normal file
After Width: | Height: | Size: 909 B |
76
assets/images/tor_logo.svg
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 150.5 91.1" enable-background="new 0 0 150.5 91.1" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g id="layer3_22_" transform="translate(-92,-63.999774)">
|
||||||
|
<g id="layer5_22_">
|
||||||
|
<g id="path2554_38_">
|
||||||
|
<path fill="#68B044" d="M176.9,70.8l-2.4,9.6c3.4-6.8,8.9-11.9,15.2-16.4c-4.6,5.3-8.8,10.6-11.3,16
|
||||||
|
c4.3-6.1,10.1-9.4,16.6-11.7c-8.7,7.7-15.6,16.1-20.8,24.4l-4.2-1.8C170.7,84.2,173.2,77.4,176.9,70.8L176.9,70.8z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2534_13_">
|
||||||
|
<path fill="#F5F8DE" d="M165.8,89.1l7.9,3.3c0,2-0.2,8.2,1.1,10c13.2,17,11,51.2-2.7,52c-20.8,0-28.8-14.1-28.8-27.1
|
||||||
|
c0-11.9,14.2-19.7,22.7-26.7C168.3,98.7,167.9,94.5,165.8,89.1L165.8,89.1z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2536_23_">
|
||||||
|
<path fill="#7E4798" d="M173.7,92.3l2.9,1.5c-0.3,1.9,0.1,6.1,2,7.1c8.4,5.2,16.2,10.8,19.3,16.5c11,19.9-7.7,38.4-24,36.6
|
||||||
|
c8.8-6.5,11.4-19.9,8.1-34.6c-1.3-5.7-3.4-10.9-7.1-16.8C173.3,99.9,173.9,96.3,173.7,92.3L173.7,92.3z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="layer4_22_">
|
||||||
|
<g id="path2540_23_">
|
||||||
|
<path fill="#010101" d="M170.5,101.8c-0.6,3.1-1.3,8.7-4,10.8c-1.1,0.8-2.3,1.6-3.5,2.4c-4.9,3.3-9.7,6.4-11.9,14.3
|
||||||
|
c-0.5,1.7-0.1,3.5,0.3,5.2c1.2,4.9,4.6,10.1,7.3,13.2c0,0.1,0.5,0.5,0.5,0.6c2.2,2.6,2.9,3.4,11.3,5.3l-0.2,0.9
|
||||||
|
c-5.1-1.3-9.2-2.6-11.9-5.6c0-0.1-0.5-0.5-0.5-0.5c-2.8-3.2-6.3-8.6-7.5-13.7c-0.5-2-0.9-3.6-0.3-5.7
|
||||||
|
c2.3-8.2,7.3-11.5,12.3-14.9c1.1-0.7,2.5-1.4,3.6-2.3C168.3,110.3,169.4,105.6,170.5,101.8L170.5,101.8z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2542_23_">
|
||||||
|
<path fill="#010101" d="M172.7,114.8c0.1,3.5-0.3,5.3,0.6,7.8c0.5,1.5,2.4,3.5,2.9,5.5c0.7,2.6,1.5,5.5,1.5,7.3
|
||||||
|
c0,2-0.1,5.8-1,9.8c-0.7,3.3-2.2,6.2-4.8,7.8c-2.7-0.5-5.8-1.5-7.6-3.1c-3.6-3.1-6.7-8.3-7.1-12.8c-0.3-3.7,3.1-9.2,7.9-11.9
|
||||||
|
c4-2.4,5-5,5.9-9.4c-1.2,3.8-2.4,6.9-6.3,9c-5.7,3-8.6,7.9-8.3,12.7c0.4,6.1,2.8,10.2,7.6,13.5c2,1.4,5.8,2.9,8.2,3.3v-0.3
|
||||||
|
c1.8-0.3,4.1-3.3,5.3-7.2c1-3.6,1.4-8.1,1.3-11c-0.1-1.7-0.8-5.3-2.2-8.6c-0.7-1.8-1.9-3.6-2.6-4.9
|
||||||
|
C173.1,120.8,173.1,118,172.7,114.8z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2544_23_">
|
||||||
|
<path fill="#010101" d="M172.1,128.5c0.1,2.4,1,5.4,1.4,8.5c0.3,2.3,0.2,4.6,0.1,6.6c-0.1,2.3-0.8,6.5-1.9,8.6
|
||||||
|
c-1-0.5-1.4-1-2.1-1.8c-0.8-1.1-1.4-2.3-1.9-3.6c-0.4-1-0.9-2.2-1.1-3.5c-0.3-2-0.2-5.2,2.1-8.4c1.8-2.6,2.2-2.8,2.8-5.7
|
||||||
|
c-0.8,2.6-1.4,2.9-3.3,5.1c-2.1,2.4-2.4,6-2.4,8.9c0,1.2,0.5,2.6,1,3.8c0.5,1.3,1,2.7,1.7,3.7c1.1,1.6,2.5,2.6,3.2,2.7
|
||||||
|
c0,0,0,0,0,0c0,0,0,0,0,0v-0.1c1.3-1.5,2.1-2.9,2.4-4.4c0.3-1.8,0.4-3.5,0.6-5.6c0.2-1.8,0.1-4.1-0.4-6.5
|
||||||
|
C173.7,133.8,172.6,130.7,172.1,128.5L172.1,128.5z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2550_23_">
|
||||||
|
<path fill="#010101" d="M172.5,99c0.1,3.5,0.3,10,1.3,12.6c0.3,0.9,2.8,4.7,4.5,9.4c1.2,3.2,1.5,6.2,1.7,7.1
|
||||||
|
c0.8,3.8-0.2,10.3-1.5,16.4c-0.7,3.3-3,7.4-5.6,9l-0.5,0.9c1.5-0.1,5.1-3.6,6.4-8.1c2.2-7.5,3-11,2-19.4
|
||||||
|
c-0.1-0.8-0.5-3.6-1.8-6.5c-1.9-4.5-4.6-8.8-4.9-9.7C173.4,109.3,172.6,103.1,172.5,99L172.5,99z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2552_23_">
|
||||||
|
<path fill="#010101" d="M173.7,92.6c-0.2,3.6-0.2,6.4,0.4,9.1c0.7,2.9,4.5,7.1,6.1,11.9c3,9.2,2.2,21.2,0.1,30.5
|
||||||
|
c-0.8,3.3-4.6,8.1-8.5,9.6l2.8,0.7c1.5-0.1,5.5-3.8,7.1-8c2.5-6.7,3-14.6,2-23c-0.1-0.8-1.4-8-2.7-11
|
||||||
|
c-1.8-4.5-4.7-7.7-5.7-10.5c-0.8-2.1-1.1-7.7-0.6-8.8L173.7,92.6z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="path2528_18_">
|
||||||
|
<path fill="#7E4798" d="M3.8,8.8h54.1c2,0,3.8,1.7,3.8,3.8v16c0,2.1-1.8,3.8-3.8,3.8H46.8c-2.5,0-3.6,1.4-3.6,3v52.3
|
||||||
|
c0,1.8-1.4,3.1-3.1,3.1H21.7c-1.7,0-3-1.3-3-3.1V34.9c0-1.6-1.5-2.6-2.6-2.6H3.8c-2.1,0-3.8-1.7-3.8-3.8v-16
|
||||||
|
C0,10.5,1.7,8.8,3.8,8.8z"/>
|
||||||
|
</g>
|
||||||
|
<g id="path2532_18_">
|
||||||
|
<path fill="#7E4798" d="M142.6,30h4.8c1.8,0,3.2,1.4,3.2,3.1v17.1c0,2.2,0.1,3.1-2.6,3.1c-5.3,0-7.7,2.8-7.7,5.9v28.9
|
||||||
|
c0,1.3-1.3,2.5-2.8,2.5h-17.2c-1.5,0-2.8-1.1-2.8-2.5V55.2c0-0.6,0-1.4,0.1-1.9c0.9-12.2,10.5-21.9,22.6-23.2
|
||||||
|
C140.5,30.1,141.9,30,142.6,30L142.6,30z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#010101" d="M101.7,46.3c-2.9-2.6-6.5-4.8-10.3-6.9c-1.7-0.9-6.9-5-5.1-10.8l-13.1-5.4l-0.9,0.7
|
||||||
|
c4.4,7.9,2.1,12.1-0.1,13.5c-4.4,3-10.8,6.8-13.9,10.1c-6.1,6.3-7.9,12.3-7.3,20.1c0.6,10.1,7.9,18.5,17.8,21.8
|
||||||
|
c4.3,1.4,8.3,1.6,12.7,1.6c7.1,0,14.5-1.9,19.8-6.3c5.7-4.7,9-11.8,9-19.1C110.3,58.3,107.2,51.3,101.7,46.3z M99.8,83.2
|
||||||
|
c-4.9,4-13.7,6.8-18.4,6.6c-5.2-0.3-10.3-1.1-14.8-3.3c-7.9-3.8-13.1-12.1-13.5-18.8C52.4,54,59,50.1,65.1,45.1
|
||||||
|
c3.4-2.8,8.2-4.2,10.9-9.2c0.5-1.1,0.8-3.5,0.2-6c-0.3-0.9-1.5-3.9-2-4.6l9.8,4.3c-1.2,4.5,2.5,9.2,5.5,10.9
|
||||||
|
c3,1.7,7.7,4.9,10.6,7.5c5.1,4.5,7.7,10.9,7.7,17.6C107.8,72.3,105,78.9,99.8,83.2z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/images/usdtbsc_icon.png
Normal file
After Width: | Height: | Size: 920 B |
Before Width: | Height: | Size: 10 KiB |
BIN
assets/images/wallet_group_confirmed_dark.png
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
assets/images/wallet_group_confirmed_light.png
Normal file
After Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 6.9 KiB |
BIN
assets/images/wallet_group_empty_dark.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
assets/images/wallet_group_empty_light.png
Normal file
After Width: | Height: | Size: 164 KiB |
Before Width: | Height: | Size: 7 KiB |
BIN
assets/images/wallet_group_options_dark.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
assets/images/wallet_group_options_light.png
Normal file
After Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 50 KiB |
BIN
assets/images/wallet_type_wallet_dark.png
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
assets/images/wallet_type_wallet_light.png
Normal file
After Width: | Height: | Size: 184 KiB |
BIN
assets/images/wallets.png
Normal file
After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 116 KiB |
215
assets/images/welcome_dark_theme.svg
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
<svg width="375" height="304" viewBox="0 0 375 304" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="-40" width="475" height="304" fill="url(#paint0_linear_4656_21674)"/>
|
||||||
|
<g filter="url(#filter0_df_4656_21674)">
|
||||||
|
<circle cx="298.5" cy="121.5" r="2.5" fill="#E0E7FA"/>
|
||||||
|
</g>
|
||||||
|
<g opacity="0.5" filter="url(#filter1_df_4656_21674)">
|
||||||
|
<ellipse cx="261" cy="64.5" rx="1" ry="2.5" fill="#E0E7FA"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter2_df_4656_21674)">
|
||||||
|
<path d="M95.5 59L96.3061 65.6939L103 66.5L96.3061 67.3061L95.5 74L94.6939 67.3061L88 66.5L94.6939 65.6939L95.5 59Z" fill="#D7E2F7"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter3_df_4656_21674)">
|
||||||
|
<path d="M38.5 156L39.3061 162.694L46 163.5L39.3061 164.306L38.5 171L37.6939 164.306L31 163.5L37.6939 162.694L38.5 156Z" fill="#D7E2F7"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter4_df_4656_21674)">
|
||||||
|
<path d="M336.5 79L337.306 85.6939L344 86.5L337.306 87.3061L336.5 94L335.694 87.3061L329 86.5L335.694 85.6939L336.5 79Z" fill="#D7E2F7"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter5_df_4656_21674)">
|
||||||
|
<path d="M75.5 123.5L76.1449 128.855L81.5 129.5L76.1449 130.145L75.5 135.5L74.8551 130.145L69.5 129.5L74.8551 128.855L75.5 123.5Z" fill="#D7E2F7"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter6_df_4656_21674)">
|
||||||
|
<circle cx="271.5" cy="216.5" r="2.5" fill="#E0E7FA"/>
|
||||||
|
</g>
|
||||||
|
<g filter="url(#filter7_df_4656_21674)">
|
||||||
|
<path d="M316.5 171L317.844 182.156L329 183.5L317.844 184.844L316.5 196L315.156 184.844L304 183.5L315.156 182.156L316.5 171Z" fill="#D7E2F7"/>
|
||||||
|
</g>
|
||||||
|
<line x1="316.5" y1="161" x2="316.5" y2="207" stroke="url(#paint1_linear_4656_21674)"/>
|
||||||
|
<line x1="293" y1="183.5" x2="339" y2="183.5" stroke="url(#paint2_linear_4656_21674)"/>
|
||||||
|
<g opacity="0.2">
|
||||||
|
<g filter="url(#filter8_df_4656_21674)">
|
||||||
|
<path d="M54.5 77L55.8435 88.1565L67 89.5L55.8435 90.8435L54.5 102L53.1565 90.8435L42 89.5L53.1565 88.1565L54.5 77Z" fill="#D7E2F7"/>
|
||||||
|
</g>
|
||||||
|
<line x1="54.5" y1="67" x2="54.5" y2="113" stroke="url(#paint3_linear_4656_21674)"/>
|
||||||
|
<line x1="31" y1="89.5" x2="77" y2="89.5" stroke="url(#paint4_linear_4656_21674)"/>
|
||||||
|
</g>
|
||||||
|
<g opacity="0.5" filter="url(#filter9_df_4656_21674)">
|
||||||
|
<ellipse cx="102" cy="173.5" rx="1" ry="2.5" fill="#E0E7FA"/>
|
||||||
|
</g>
|
||||||
|
<path d="M176.165 126.986C174.967 129.623 174.3 132.551 174.3 135.636C174.3 147.197 183.672 156.569 195.232 156.569C200.746 156.569 205.761 154.436 209.5 150.951C206.208 158.196 198.909 163.235 190.433 163.235C178.872 163.235 169.5 153.863 169.5 142.302C169.5 136.255 172.065 130.808 176.165 126.986Z" fill="#D9D9D9"/>
|
||||||
|
<path d="M176.165 126.986C174.967 129.623 174.3 132.551 174.3 135.636C174.3 147.197 183.672 156.569 195.232 156.569C200.746 156.569 205.761 154.436 209.5 150.951C206.208 158.196 198.909 163.235 190.433 163.235C178.872 163.235 169.5 153.863 169.5 142.302C169.5 136.255 172.065 130.808 176.165 126.986Z" fill="url(#paint5_linear_4656_21674)"/>
|
||||||
|
<path d="M176.165 126.986C174.967 129.623 174.3 132.551 174.3 135.636C174.3 147.197 183.672 156.569 195.232 156.569C200.746 156.569 205.761 154.436 209.5 150.951C206.208 158.196 198.909 163.235 190.433 163.235C178.872 163.235 169.5 153.863 169.5 142.302C169.5 136.255 172.065 130.808 176.165 126.986Z" fill="url(#paint6_linear_4656_21674)"/>
|
||||||
|
<g opacity="0.5" filter="url(#filter10_f_4656_21674)">
|
||||||
|
<path d="M176.165 126.986C174.967 129.623 174.3 132.551 174.3 135.636C174.3 147.197 183.672 156.569 195.232 156.569C200.746 156.569 205.761 154.436 209.5 150.951C206.208 158.196 198.909 163.235 190.433 163.235C178.872 163.235 169.5 153.863 169.5 142.302C169.5 136.255 172.065 130.808 176.165 126.986Z" fill="#D9D9D9"/>
|
||||||
|
<path d="M176.165 126.986C174.967 129.623 174.3 132.551 174.3 135.636C174.3 147.197 183.672 156.569 195.232 156.569C200.746 156.569 205.761 154.436 209.5 150.951C206.208 158.196 198.909 163.235 190.433 163.235C178.872 163.235 169.5 153.863 169.5 142.302C169.5 136.255 172.065 130.808 176.165 126.986Z" fill="url(#paint7_linear_4656_21674)"/>
|
||||||
|
<path d="M176.165 126.986C174.967 129.623 174.3 132.551 174.3 135.636C174.3 147.197 183.672 156.569 195.232 156.569C200.746 156.569 205.761 154.436 209.5 150.951C206.208 158.196 198.909 163.235 190.433 163.235C178.872 163.235 169.5 153.863 169.5 142.302C169.5 136.255 172.065 130.808 176.165 126.986Z" fill="url(#paint8_linear_4656_21674)"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_df_4656_21674" x="284.5" y="107.5" width="28" height="28" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="5.25"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="2" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter1_df_4656_21674" x="248.5" y="50.5" width="25" height="28" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="5.25"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="2" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter2_df_4656_21674" x="81.1" y="52.1" width="28.8" height="28.8" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="0.6" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="3.15"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.3" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter3_df_4656_21674" x="24.1" y="149.1" width="28.8" height="28.8" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="0.6" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="3.15"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.3" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter4_df_4656_21674" x="322.1" y="72.1" width="28.8" height="28.8" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="0.6" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="3.15"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.3" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter5_df_4656_21674" x="63.98" y="117.98" width="23.04" height="23.04" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="0.48" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="2.52"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.24" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter6_df_4656_21674" x="257.5" y="202.5" width="28" height="28" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="5.25"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="2" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter7_df_4656_21674" x="292.5" y="159.5" width="48" height="48" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="5.25"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter8_df_4656_21674" x="30.5" y="65.5" width="48" height="48" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="5.25"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter9_df_4656_21674" x="89.5" y="159.5" width="25" height="28" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feMorphology radius="1" operator="dilate" in="SourceAlpha" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feOffset/>
|
||||||
|
<feGaussianBlur stdDeviation="5.25"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="out"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0"/>
|
||||||
|
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_4656_21674"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_4656_21674" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="2" result="effect2_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<filter id="filter10_f_4656_21674" x="156.1" y="113.586" width="66.8" height="63.049" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feGaussianBlur stdDeviation="6.7" result="effect1_foregroundBlur_4656_21674"/>
|
||||||
|
</filter>
|
||||||
|
<linearGradient id="paint0_linear_4656_21674" x1="198" y1="22.9607" x2="198" y2="268.181" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#142040"/>
|
||||||
|
<stop offset="0.644231" stop-color="#14234B"/>
|
||||||
|
<stop offset="1" stop-color="#1B284A" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_4656_21674" x1="315.5" y1="161" x2="315.5" y2="207" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
<stop offset="0.466346" stop-color="#D7E2F7"/>
|
||||||
|
<stop offset="1" stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_4656_21674" x1="293" y1="184.5" x2="339" y2="184.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
<stop offset="0.466346" stop-color="#D7E2F7"/>
|
||||||
|
<stop offset="1" stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_4656_21674" x1="53.5" y1="67" x2="53.5" y2="113" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
<stop offset="0.466346" stop-color="#D7E2F7"/>
|
||||||
|
<stop offset="1" stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_4656_21674" x1="31" y1="90.5" x2="77" y2="90.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
<stop offset="0.466346" stop-color="#D7E2F7"/>
|
||||||
|
<stop offset="1" stop-color="#D7E2F7" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_4656_21674" x1="189.5" y1="126.986" x2="189.5" y2="163.235" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D7E2F7"/>
|
||||||
|
<stop offset="1" stop-color="#7891C1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint6_linear_4656_21674" x1="189.5" y1="126.986" x2="195.774" y2="163.063" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#7891C1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint7_linear_4656_21674" x1="189.5" y1="126.986" x2="189.5" y2="163.235" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#D7E2F7"/>
|
||||||
|
<stop offset="1" stop-color="#7891C1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint8_linear_4656_21674" x1="189.5" y1="126.986" x2="195.774" y2="163.063" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="1" stop-color="#7891C1"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 97 KiB |
14
assets/images/welcome_light_theme.svg
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<svg width="375" height="304" viewBox="0 0 375 304" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="-40" y="-27" width="475" height="331" fill="url(#paint0_linear_4656_21863)"/>
|
||||||
|
<rect x="285" y="163" width="101" height="49" rx="24.5" fill="#EFEFF8"/>
|
||||||
|
<circle cx="331" cy="173" r="31" fill="#EFEFF8"/>
|
||||||
|
<rect x="-30" y="108" width="115" height="49" rx="24.5" fill="#EFEFF8"/>
|
||||||
|
<circle cx="16" cy="118" r="31" fill="#EFEFF8"/>
|
||||||
|
<rect x="251" y="193" width="30" height="19" rx="9.5" fill="#EFEFF8"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_4656_21863" x1="197.5" y1="-27" x2="197.5" y2="304" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#68BEEF"/>
|
||||||
|
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 745 B |
BIN
assets/images/welcome_wallet_dark.png
Normal file
After Width: | Height: | Size: 136 KiB |
BIN
assets/images/welcome_wallet_light.png
Normal file
After Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 420 KiB |
|
@ -1,4 +1,4 @@
|
||||||
Background sync improvements
|
Add built-in Tor support (experimental)
|
||||||
Payment notifications
|
Ledger improvements
|
||||||
UI/UX improvements
|
UI/UX improvements
|
||||||
Bug fixes
|
Bug fixes
|
|
@ -1,5 +1,9 @@
|
||||||
Background sync improvements
|
Add built-in Tor support (experimental)
|
||||||
Payment notifications
|
Add dEuro investments
|
||||||
WalletConnect enhancements
|
Solana fixes/enhancements
|
||||||
|
Polygon fixes/enhancements
|
||||||
|
WalletConnect improvements
|
||||||
|
Ledger improvements
|
||||||
|
Payjoin improvements
|
||||||
UI/UX improvements
|
UI/UX improvements
|
||||||
Bug fixes
|
Bug fixes
|
|
@ -2,22 +2,37 @@ import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
|
||||||
String addressFromOutputScript(Script script, BasedUtxoNetwork network) {
|
String addressFromOutputScript(Script script, BasedUtxoNetwork network) {
|
||||||
try {
|
try {
|
||||||
switch (script.getAddressType()) {
|
return addressFromScript(script, network).toAddress(network);
|
||||||
case P2pkhAddressType.p2pkh:
|
|
||||||
return P2pkhAddress.fromScriptPubkey(script: script).toAddress(network);
|
|
||||||
case P2shAddressType.p2pkInP2sh:
|
|
||||||
return P2shAddress.fromScriptPubkey(script: script).toAddress(network);
|
|
||||||
case SegwitAddresType.p2wpkh:
|
|
||||||
return P2wpkhAddress.fromScriptPubkey(script: script).toAddress(network);
|
|
||||||
case P2shAddressType.p2pkhInP2sh:
|
|
||||||
return P2shAddress.fromScriptPubkey(script: script).toAddress(network);
|
|
||||||
case SegwitAddresType.p2wsh:
|
|
||||||
return P2wshAddress.fromScriptPubkey(script: script).toAddress(network);
|
|
||||||
case SegwitAddresType.p2tr:
|
|
||||||
return P2trAddress.fromScriptPubkey(script: script).toAddress(network);
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BitcoinBaseAddress addressFromScript(Script script,
|
||||||
|
[BasedUtxoNetwork network = BitcoinNetwork.mainnet]) {
|
||||||
|
final addressType = script.getAddressType();
|
||||||
|
if (addressType == null) {
|
||||||
|
throw ArgumentError("Invalid script");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (addressType) {
|
||||||
|
case P2pkhAddressType.p2pkh:
|
||||||
|
return P2pkhAddress.fromScriptPubkey(
|
||||||
|
script: script, network: BitcoinNetwork.mainnet);
|
||||||
|
case P2shAddressType.p2pkhInP2sh:
|
||||||
|
case P2shAddressType.p2pkInP2sh:
|
||||||
|
return P2shAddress.fromScriptPubkey(
|
||||||
|
script: script, network: BitcoinNetwork.mainnet);
|
||||||
|
case SegwitAddresType.p2wpkh:
|
||||||
|
return P2wpkhAddress.fromScriptPubkey(
|
||||||
|
script: script, network: BitcoinNetwork.mainnet);
|
||||||
|
case SegwitAddresType.p2wsh:
|
||||||
|
return P2wshAddress.fromScriptPubkey(
|
||||||
|
script: script, network: BitcoinNetwork.mainnet);
|
||||||
|
case SegwitAddresType.p2tr:
|
||||||
|
return P2trAddress.fromScriptPubkey(
|
||||||
|
script: script, network: BitcoinNetwork.mainnet);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ArgumentError("Invalid script");
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
}) : _txCount = txCount,
|
}) : _txCount = txCount,
|
||||||
_balance = balance,
|
_balance = balance,
|
||||||
_name = name,
|
_name = name,
|
||||||
_isUsed = isUsed;
|
_isUsed = Observable(isUsed);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
|
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
|
||||||
|
@ -27,7 +28,7 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
int _txCount;
|
int _txCount;
|
||||||
int _balance;
|
int _balance;
|
||||||
String _name;
|
String _name;
|
||||||
bool _isUsed;
|
final Observable<bool> _isUsed;
|
||||||
BasedUtxoNetwork? network;
|
BasedUtxoNetwork? network;
|
||||||
|
|
||||||
int get txCount => _txCount;
|
int get txCount => _txCount;
|
||||||
|
@ -40,9 +41,9 @@ abstract class BaseBitcoinAddressRecord {
|
||||||
|
|
||||||
set balance(int value) => _balance = value;
|
set balance(int value) => _balance = value;
|
||||||
|
|
||||||
bool get isUsed => _isUsed;
|
bool get isUsed => _isUsed.value;
|
||||||
|
|
||||||
void setAsUsed() => _isUsed = true;
|
void setAsUsed() => _isUsed.value = true;
|
||||||
void setNewName(String label) => _name = label;
|
void setNewName(String label) => _name = label;
|
||||||
|
|
||||||
int get hashCode => address.hashCode;
|
int get hashCode => address.hashCode;
|
||||||
|
|
|
@ -3,11 +3,17 @@ import 'package:cw_core/output_info.dart';
|
||||||
import 'package:cw_core/unspent_coin_type.dart';
|
import 'package:cw_core/unspent_coin_type.dart';
|
||||||
|
|
||||||
class BitcoinTransactionCredentials {
|
class BitcoinTransactionCredentials {
|
||||||
BitcoinTransactionCredentials(this.outputs,
|
BitcoinTransactionCredentials(
|
||||||
{required this.priority, this.feeRate, this.coinTypeToSpendFrom = UnspentCoinType.any});
|
this.outputs, {
|
||||||
|
required this.priority,
|
||||||
|
this.feeRate,
|
||||||
|
this.coinTypeToSpendFrom = UnspentCoinType.any,
|
||||||
|
this.payjoinUri,
|
||||||
|
});
|
||||||
|
|
||||||
final List<OutputInfo> outputs;
|
final List<OutputInfo> outputs;
|
||||||
final BitcoinTransactionPriority? priority;
|
final BitcoinTransactionPriority? priority;
|
||||||
final int? feeRate;
|
final int? feeRate;
|
||||||
final UnspentCoinType coinTypeToSpendFrom;
|
final UnspentCoinType coinTypeToSpendFrom;
|
||||||
|
final String? payjoinUri;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,22 +3,33 @@ import 'dart:convert';
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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/address_from_output.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_bitcoin/bitcoin_transaction_credentials.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.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_derivations.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/payjoin/manager.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/storage.dart';
|
||||||
|
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/signer.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/transaction_builder.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/v0_deserialize.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/v0_finalizer.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
import 'package:cw_core/payjoin_session.dart';
|
||||||
|
import 'package:cw_core/pending_transaction.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';
|
||||||
import 'package:cw_core/wallet_keys_file.dart';
|
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_bitcoin/psbt.dart';
|
||||||
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
@ -31,6 +42,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required Box<PayjoinSession> payjoinBox,
|
||||||
required EncryptionFileUtils encryptionFileUtils,
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
Uint8List? seedBytes,
|
Uint8List? seedBytes,
|
||||||
String? mnemonic,
|
String? mnemonic,
|
||||||
|
@ -71,8 +83,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
// String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
// String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
||||||
// String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
|
// String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
|
||||||
// final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
// final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
||||||
walletAddresses = BitcoinWalletAddresses(
|
|
||||||
walletInfo,
|
payjoinManager = PayjoinManager(PayjoinStorage(payjoinBox), this);
|
||||||
|
walletAddresses = BitcoinWalletAddresses(walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
@ -84,7 +97,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
masterHd:
|
masterHd:
|
||||||
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
||||||
isHardwareWallet: walletInfo.isHardwareWallet,
|
isHardwareWallet: walletInfo.isHardwareWallet,
|
||||||
);
|
payjoinManager: payjoinManager);
|
||||||
|
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
this.walletAddresses.isEnabledAutoGenerateSubaddress =
|
this.walletAddresses.isEnabledAutoGenerateSubaddress =
|
||||||
|
@ -100,6 +113,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required Box<PayjoinSession> payjoinBox,
|
||||||
required EncryptionFileUtils encryptionFileUtils,
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
String? passphrase,
|
String? passphrase,
|
||||||
String? addressPageType,
|
String? addressPageType,
|
||||||
|
@ -122,9 +136,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
break;
|
break;
|
||||||
case DerivationType.electrum:
|
case DerivationType.electrum:
|
||||||
default:
|
default:
|
||||||
seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
seedBytes =
|
||||||
|
await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BitcoinWallet(
|
return BitcoinWallet(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
passphrase: passphrase ?? "",
|
passphrase: passphrase ?? "",
|
||||||
|
@ -141,6 +157,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
addressPageType: addressPageType,
|
addressPageType: addressPageType,
|
||||||
networkParam: network,
|
networkParam: network,
|
||||||
|
payjoinBox: payjoinBox,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +165,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
required String name,
|
required String name,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required Box<PayjoinSession> payjoinBox,
|
||||||
required String password,
|
required String password,
|
||||||
required EncryptionFileUtils encryptionFileUtils,
|
required EncryptionFileUtils encryptionFileUtils,
|
||||||
required bool alwaysScan,
|
required bool alwaysScan,
|
||||||
|
@ -204,7 +222,8 @@ 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, passphrase: passphrase ?? "");
|
seedBytes =
|
||||||
|
await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
|
||||||
break;
|
break;
|
||||||
case DerivationType.bip39:
|
case DerivationType.bip39:
|
||||||
default:
|
default:
|
||||||
|
@ -234,7 +253,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
addressPageType: snp?.addressPageType,
|
addressPageType: snp?.addressPageType,
|
||||||
networkParam: network,
|
networkParam: network,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
);
|
payjoinBox: payjoinBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
LedgerConnection? _ledgerConnection;
|
LedgerConnection? _ledgerConnection;
|
||||||
|
@ -248,19 +267,30 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<BtcTransaction> buildHardwareWalletTransaction({
|
Future<void> close({bool shouldCleanup = false}) async {
|
||||||
|
payjoinManager.cleanupSessions();
|
||||||
|
super.close(shouldCleanup: shouldCleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final PayjoinManager payjoinManager;
|
||||||
|
|
||||||
|
bool get isPayjoinAvailable => unspentCoinsInfo.values
|
||||||
|
.where((element) =>
|
||||||
|
element.walletId == id && element.isSending && !element.isFrozen)
|
||||||
|
.isNotEmpty;
|
||||||
|
|
||||||
|
Future<PsbtV2> buildPsbt({
|
||||||
required List<BitcoinBaseOutput> outputs,
|
required List<BitcoinBaseOutput> outputs,
|
||||||
required BigInt fee,
|
required BigInt fee,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required List<UtxoWithAddress> utxos,
|
required List<UtxoWithAddress> utxos,
|
||||||
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
||||||
|
required Uint8List masterFingerprint,
|
||||||
String? memo,
|
String? memo,
|
||||||
bool enableRBF = false,
|
bool enableRBF = false,
|
||||||
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
||||||
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
||||||
}) async {
|
}) async {
|
||||||
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint();
|
|
||||||
|
|
||||||
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
|
||||||
for (final utxo in utxos) {
|
for (final utxo in utxos) {
|
||||||
final rawTx =
|
final rawTx =
|
||||||
|
@ -278,13 +308,128 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
final psbt = PSBTTransactionBuild(
|
return PSBTTransactionBuild(
|
||||||
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF)
|
||||||
|
.psbt;
|
||||||
|
}
|
||||||
|
|
||||||
final rawHex = await _bitcoinLedgerApp!.signPsbt(psbt: psbt.psbt);
|
@override
|
||||||
|
Future<BtcTransaction> buildHardwareWalletTransaction({
|
||||||
|
required List<BitcoinBaseOutput> outputs,
|
||||||
|
required BigInt fee,
|
||||||
|
required BasedUtxoNetwork network,
|
||||||
|
required List<UtxoWithAddress> utxos,
|
||||||
|
required Map<String, PublicKeyWithDerivationPath> publicKeys,
|
||||||
|
String? memo,
|
||||||
|
bool enableRBF = false,
|
||||||
|
BitcoinOrdering inputOrdering = BitcoinOrdering.bip69,
|
||||||
|
BitcoinOrdering outputOrdering = BitcoinOrdering.bip69,
|
||||||
|
}) async {
|
||||||
|
final masterFingerprint = await _bitcoinLedgerApp!.getMasterFingerprint();
|
||||||
|
|
||||||
|
final psbt = await buildPsbt(
|
||||||
|
outputs: outputs,
|
||||||
|
fee: fee,
|
||||||
|
network: network,
|
||||||
|
utxos: utxos,
|
||||||
|
publicKeys: publicKeys,
|
||||||
|
masterFingerprint: masterFingerprint,
|
||||||
|
memo: memo,
|
||||||
|
enableRBF: enableRBF,
|
||||||
|
inputOrdering: inputOrdering,
|
||||||
|
outputOrdering: outputOrdering,
|
||||||
|
);
|
||||||
|
|
||||||
|
final rawHex = await _bitcoinLedgerApp!.signPsbt(psbt: psbt);
|
||||||
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
|
credentials = credentials as BitcoinTransactionCredentials;
|
||||||
|
|
||||||
|
final tx = (await super.createTransaction(credentials))
|
||||||
|
as PendingBitcoinTransaction;
|
||||||
|
|
||||||
|
final payjoinUri = credentials.payjoinUri;
|
||||||
|
if (payjoinUri == null) return tx;
|
||||||
|
|
||||||
|
final transaction = await buildPsbt(
|
||||||
|
utxos: tx.utxos,
|
||||||
|
outputs: tx.outputs
|
||||||
|
.map((e) => BitcoinOutput(
|
||||||
|
address: addressFromScript(e.scriptPubKey),
|
||||||
|
value: e.amount,
|
||||||
|
isSilentPayment: e.isSilentPayment,
|
||||||
|
isChange: e.isChange,
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
fee: BigInt.from(tx.fee),
|
||||||
|
network: network,
|
||||||
|
memo: credentials.outputs.first.memo,
|
||||||
|
outputOrdering: BitcoinOrdering.none,
|
||||||
|
enableRBF: true,
|
||||||
|
publicKeys: tx.publicKeys!,
|
||||||
|
masterFingerprint: Uint8List(0));
|
||||||
|
|
||||||
|
final originalPsbt = await signPsbt(
|
||||||
|
base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys());
|
||||||
|
|
||||||
|
tx.commitOverride = () async {
|
||||||
|
final sender = await payjoinManager.initSender(
|
||||||
|
payjoinUri, originalPsbt, int.parse(tx.feeRate));
|
||||||
|
payjoinManager.spawnNewSender(
|
||||||
|
sender: sender, pjUrl: payjoinUri, amount: BigInt.from(tx.amount));
|
||||||
|
};
|
||||||
|
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<UtxoWithPrivateKey> getUtxoWithPrivateKeys() => unspentCoins
|
||||||
|
.where((e) => (e.isSending && !e.isFrozen))
|
||||||
|
.map((unspent) => UtxoWithPrivateKey.fromUnspent(unspent, this))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Future<void> commitPsbt(String finalizedPsbt) {
|
||||||
|
final psbt = PsbtV2()..deserializeV0(base64.decode(finalizedPsbt));
|
||||||
|
|
||||||
|
final btcTx =
|
||||||
|
BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract()));
|
||||||
|
|
||||||
|
return PendingBitcoinTransaction(
|
||||||
|
btcTx,
|
||||||
|
type,
|
||||||
|
electrumClient: electrumClient,
|
||||||
|
amount: 0,
|
||||||
|
fee: 0,
|
||||||
|
feeRate: "",
|
||||||
|
network: network,
|
||||||
|
hasChange: true,
|
||||||
|
).commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> signPsbt(
|
||||||
|
String preProcessedPsbt, List<UtxoWithPrivateKey> utxos) async {
|
||||||
|
final psbt = PsbtV2()..deserializeV0(base64Decode(preProcessedPsbt));
|
||||||
|
|
||||||
|
await psbt.signWithUTXO(utxos, (txDigest, utxo, key, sighash) {
|
||||||
|
return utxo.utxo.isP2tr()
|
||||||
|
? key.signTapRoot(
|
||||||
|
txDigest,
|
||||||
|
sighash: sighash,
|
||||||
|
tweak: utxo.utxo.isSilentPayment != true,
|
||||||
|
)
|
||||||
|
: key.signInput(txDigest, sigHash: sighash);
|
||||||
|
}, (txId, vout) async {
|
||||||
|
final txHex = await electrumClient.getTransactionHex(hash: txId);
|
||||||
|
final output = BtcTransaction.fromRaw(txHex).outputs[vout];
|
||||||
|
return TaprootAmountScriptPair(output.amount, output.scriptPubKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
psbt.finalizeV0();
|
||||||
|
return base64Encode(psbt.asPsbtV0());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> signMessage(String message, {String? address = null}) async {
|
Future<String> signMessage(String message, {String? address = null}) async {
|
||||||
if (walletInfo.isHardwareWallet) {
|
if (walletInfo.isHardwareWallet) {
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:blockchain_utils/bip/bip/bip32/bip32.dart';
|
import 'package:blockchain_utils/bip/bip/bip32/bip32.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/manager.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/unspent_coin_type.dart';
|
import 'package:cw_core/unspent_coin_type.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:payjoin_flutter/receive.dart' as payjoin;
|
||||||
|
|
||||||
part 'bitcoin_wallet_addresses.g.dart';
|
part 'bitcoin_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
@ -17,6 +20,7 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
required super.sideHd,
|
required super.sideHd,
|
||||||
required super.network,
|
required super.network,
|
||||||
required super.isHardwareWallet,
|
required super.isHardwareWallet,
|
||||||
|
required this.payjoinManager,
|
||||||
super.initialAddresses,
|
super.initialAddresses,
|
||||||
super.initialRegularAddressIndex,
|
super.initialRegularAddressIndex,
|
||||||
super.initialChangeAddressIndex,
|
super.initialChangeAddressIndex,
|
||||||
|
@ -25,6 +29,13 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
super.masterHd,
|
super.masterHd,
|
||||||
}) : super(walletInfo);
|
}) : super(walletInfo);
|
||||||
|
|
||||||
|
final PayjoinManager payjoinManager;
|
||||||
|
|
||||||
|
payjoin.Receiver? currentPayjoinReceiver;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
String? payjoinEndpoint = null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getAddress(
|
String getAddress(
|
||||||
{required int index,
|
{required int index,
|
||||||
|
@ -45,4 +56,33 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
|
|
||||||
return generateP2WPKHAddress(hd: hd, index: index, network: network);
|
return generateP2WPKHAddress(hd: hd, index: index, network: network);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> initPayjoin() async {
|
||||||
|
try {
|
||||||
|
await payjoinManager.initPayjoin();
|
||||||
|
currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
|
||||||
|
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
|
||||||
|
|
||||||
|
payjoinManager.resumeSessions();
|
||||||
|
} catch (e) {
|
||||||
|
printV(e);
|
||||||
|
// Ignore Connectivity errors
|
||||||
|
if (!e.toString().contains("error sending request for url")) rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> newPayjoinReceiver() async {
|
||||||
|
try {
|
||||||
|
currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
|
||||||
|
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
|
||||||
|
|
||||||
|
payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!);
|
||||||
|
} catch (e) {
|
||||||
|
printV(e);
|
||||||
|
// Ignore Connectivity errors
|
||||||
|
if (!e.toString().contains("error sending request for url")) rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ 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';
|
||||||
|
import 'package:cw_core/payjoin_session.dart';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
@ -21,10 +22,12 @@ class BitcoinWalletService extends WalletService<
|
||||||
BitcoinRestoreWalletFromSeedCredentials,
|
BitcoinRestoreWalletFromSeedCredentials,
|
||||||
BitcoinRestoreWalletFromWIFCredentials,
|
BitcoinRestoreWalletFromWIFCredentials,
|
||||||
BitcoinRestoreWalletFromHardware> {
|
BitcoinRestoreWalletFromHardware> {
|
||||||
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource, this.alwaysScan, this.isDirect);
|
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource,
|
||||||
|
this.payjoinSessionSource, this.alwaysScan, this.isDirect);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
|
final Box<PayjoinSession> payjoinSessionSource;
|
||||||
final bool alwaysScan;
|
final bool alwaysScan;
|
||||||
final bool isDirect;
|
final bool isDirect;
|
||||||
|
|
||||||
|
@ -55,6 +58,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
passphrase: credentials.passphrase,
|
passphrase: credentials.passphrase,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
payjoinBox: payjoinSessionSource,
|
||||||
network: network,
|
network: network,
|
||||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
@ -79,6 +83,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
payjoinBox: payjoinSessionSource,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
@ -92,6 +97,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
name: name,
|
name: name,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
payjoinBox: payjoinSessionSource,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
@ -126,6 +132,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
name: currentName,
|
name: currentName,
|
||||||
walletInfo: currentWalletInfo,
|
walletInfo: currentWalletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
payjoinBox: payjoinSessionSource,
|
||||||
alwaysScan: alwaysScan,
|
alwaysScan: alwaysScan,
|
||||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
@ -147,7 +154,6 @@ class BitcoinWalletService extends WalletService<
|
||||||
credentials.walletInfo?.network = network.value;
|
credentials.walletInfo?.network = network.value;
|
||||||
credentials.walletInfo?.derivationInfo?.derivationPath =
|
credentials.walletInfo?.derivationInfo?.derivationPath =
|
||||||
credentials.hwAccountData.derivationPath;
|
credentials.hwAccountData.derivationPath;
|
||||||
|
|
||||||
final wallet = await BitcoinWallet(
|
final wallet = await BitcoinWallet(
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
xpub: credentials.hwAccountData.xpub,
|
xpub: credentials.hwAccountData.xpub,
|
||||||
|
@ -155,6 +161,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
networkParam: network,
|
networkParam: network,
|
||||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
payjoinBox: payjoinSessionSource,
|
||||||
);
|
);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
await wallet.init();
|
await wallet.init();
|
||||||
|
@ -182,6 +189,7 @@ class BitcoinWalletService extends WalletService<
|
||||||
mnemonic: credentials.mnemonic,
|
mnemonic: credentials.mnemonic,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
payjoinBox: payjoinSessionSource,
|
||||||
network: network,
|
network: network,
|
||||||
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'dart:typed_data';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ class ElectrumClient {
|
||||||
static const aliveTimerDuration = Duration(seconds: 4);
|
static const aliveTimerDuration = Duration(seconds: 4);
|
||||||
|
|
||||||
bool get isConnected => _isConnected;
|
bool get isConnected => _isConnected;
|
||||||
Socket? socket;
|
ProxySocket? socket;
|
||||||
void Function(ConnectionStatus)? onConnectionStatusChange;
|
void Function(ConnectionStatus)? onConnectionStatusChange;
|
||||||
int _id;
|
int _id;
|
||||||
final Map<String, SocketTask> _tasks;
|
final Map<String, SocketTask> _tasks;
|
||||||
|
@ -72,18 +74,11 @@ class ElectrumClient {
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
socket = null;
|
socket = null;
|
||||||
|
|
||||||
|
final ssl = !(useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum")));
|
||||||
try {
|
try {
|
||||||
if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
|
socket = await ProxyWrapper().getSocksSocket(ssl, host, port, connectionTimeout: connectionTimeout);
|
||||||
socket = await Socket.connect(host, port, timeout: connectionTimeout);
|
|
||||||
} else {
|
|
||||||
socket = await SecureSocket.connect(
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
timeout: connectionTimeout,
|
|
||||||
onBadCertificate: (_) => true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
printV("connect: $e");
|
||||||
if (e is HandshakeException) {
|
if (e is HandshakeException) {
|
||||||
useSSL = !(useSSL ?? false);
|
useSSL = !(useSSL ?? false);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +100,6 @@ class ElectrumClient {
|
||||||
|
|
||||||
// use ping to determine actual connection status since we could've just not timed out yet:
|
// use ping to determine actual connection status since we could've just not timed out yet:
|
||||||
// _setConnectionStatus(ConnectionStatus.connected);
|
// _setConnectionStatus(ConnectionStatus.connected);
|
||||||
|
|
||||||
socket!.listen(
|
socket!.listen(
|
||||||
(Uint8List event) {
|
(Uint8List event) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
import 'package:cw_core/format_amount.dart';
|
import 'package:cw_core/format_amount.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
@ -49,7 +50,6 @@ import 'package:mobx/mobx.dart';
|
||||||
import 'package:rxdart/subjects.dart';
|
import 'package:rxdart/subjects.dart';
|
||||||
import 'package:sp_scanner/sp_scanner.dart';
|
import 'package:sp_scanner/sp_scanner.dart';
|
||||||
import 'package:hex/hex.dart';
|
import 'package:hex/hex.dart';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
|
|
||||||
part 'electrum_wallet.g.dart';
|
part 'electrum_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -493,10 +493,9 @@ abstract class ElectrumWalletBase
|
||||||
Future<void> updateFeeRates() async {
|
Future<void> updateFeeRates() async {
|
||||||
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
|
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
|
||||||
try {
|
try {
|
||||||
final response = await http
|
final response = await ProxyWrapper()
|
||||||
.get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
|
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
|
||||||
.timeout(Duration(seconds: 5));
|
.timeout(Duration(seconds: 15));
|
||||||
|
|
||||||
final result = json.decode(response.body) as Map<String, dynamic>;
|
final result = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
|
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
|
||||||
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
|
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
|
||||||
|
@ -1176,9 +1175,7 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return PendingBitcoinTransaction(
|
return PendingBitcoinTransaction(transaction, type,
|
||||||
transaction,
|
|
||||||
type,
|
|
||||||
electrumClient: electrumClient,
|
electrumClient: electrumClient,
|
||||||
amount: estimatedTx.amount,
|
amount: estimatedTx.amount,
|
||||||
fee: estimatedTx.fee,
|
fee: estimatedTx.fee,
|
||||||
|
@ -1188,7 +1185,8 @@ abstract class ElectrumWalletBase
|
||||||
isSendAll: estimatedTx.isSendAll,
|
isSendAll: estimatedTx.isSendAll,
|
||||||
hasTaprootInputs: hasTaprootInputs,
|
hasTaprootInputs: hasTaprootInputs,
|
||||||
utxos: estimatedTx.utxos,
|
utxos: estimatedTx.utxos,
|
||||||
)..addListener((transaction) async {
|
publicKeys: estimatedTx.publicKeys)
|
||||||
|
..addListener((transaction) async {
|
||||||
transactionHistory.addOne(transaction);
|
transactionHistory.addOne(transaction);
|
||||||
if (estimatedTx.spendsSilentPayment) {
|
if (estimatedTx.spendsSilentPayment) {
|
||||||
transactionHistory.transactions.values.forEach((tx) {
|
transactionHistory.transactions.values.forEach((tx) {
|
||||||
|
@ -1879,20 +1877,17 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
|
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
|
||||||
try {
|
try {
|
||||||
final blockHash = await http.get(
|
final blockHash = await ProxyWrapper()
|
||||||
Uri.parse(
|
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block-height/$height"))
|
||||||
"https://mempool.cakewallet.com/api/v1/block-height/$height",
|
.timeout(Duration(seconds: 15));
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (blockHash.statusCode == 200 &&
|
if (blockHash.statusCode == 200 &&
|
||||||
blockHash.body.isNotEmpty &&
|
blockHash.body.isNotEmpty &&
|
||||||
jsonDecode(blockHash.body) != null) {
|
jsonDecode(blockHash.body) != null) {
|
||||||
final blockResponse = await http.get(
|
final blockResponse = await ProxyWrapper()
|
||||||
Uri.parse(
|
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block/${blockHash}"))
|
||||||
"https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
|
.timeout(Duration(seconds: 15));
|
||||||
),
|
|
||||||
);
|
|
||||||
if (blockResponse.statusCode == 200 &&
|
if (blockResponse.statusCode == 200 &&
|
||||||
blockResponse.body.isNotEmpty &&
|
blockResponse.body.isNotEmpty &&
|
||||||
jsonDecode(blockResponse.body)['timestamp'] != null) {
|
jsonDecode(blockResponse.body)['timestamp'] != null) {
|
||||||
|
@ -1965,6 +1960,11 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isMine(Script script) {
|
||||||
|
final derivedAddress = addressFromOutputScript(script, network);
|
||||||
|
return addressesSet.contains(derivedAddress);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async {
|
Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -144,27 +144,32 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
return silentAddress.toString();
|
return silentAddress.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
String receiveAddress;
|
final typeMatchingAddresses = _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList();
|
||||||
|
final typeMatchingReceiveAddresses = typeMatchingAddresses.where((addr) => !addr.isUsed).toList();
|
||||||
|
|
||||||
final typeMatchingReceiveAddresses =
|
if (!isEnabledAutoGenerateSubaddress) {
|
||||||
receiveAddresses.where(_isAddressPageTypeMatch).where((addr) => !addr.isUsed);
|
if (previousAddressRecord != null &&
|
||||||
|
previousAddressRecord!.type == addressPageType) {
|
||||||
if ((isEnabledAutoGenerateSubaddress && receiveAddresses.isEmpty) ||
|
return previousAddressRecord!.address;
|
||||||
typeMatchingReceiveAddresses.isEmpty) {
|
|
||||||
receiveAddress = generateNewAddress().address;
|
|
||||||
} else {
|
|
||||||
final previousAddressMatchesType =
|
|
||||||
previousAddressRecord != null && previousAddressRecord!.type == addressPageType;
|
|
||||||
|
|
||||||
if (previousAddressMatchesType &&
|
|
||||||
typeMatchingReceiveAddresses.first.address != addressesByReceiveType.first.address) {
|
|
||||||
receiveAddress = previousAddressRecord!.address;
|
|
||||||
} else {
|
|
||||||
receiveAddress = typeMatchingReceiveAddresses.first.address;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return receiveAddress;
|
if (typeMatchingAddresses.isNotEmpty) {
|
||||||
|
return typeMatchingAddresses.first.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateNewAddress().address;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeMatchingAddresses.isEmpty || typeMatchingReceiveAddresses.isEmpty) {
|
||||||
|
return generateNewAddress().address;
|
||||||
|
}
|
||||||
|
|
||||||
|
final prev = previousAddressRecord;
|
||||||
|
if (prev != null && prev.type == addressPageType && !prev.isUsed) {
|
||||||
|
return prev.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeMatchingReceiveAddresses.first.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
|
|
|
@ -464,7 +464,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
final oldBox = await CakeHive.openBox<MwebUtxo>(oldBoxName);
|
final oldBox = await CakeHive.openBox<MwebUtxo>(oldBoxName);
|
||||||
mwebUtxosBox = await CakeHive.openBox<MwebUtxo>(newBoxName);
|
mwebUtxosBox = await CakeHive.openBox<MwebUtxo>(newBoxName);
|
||||||
for (final key in oldBox.keys) {
|
for (final key in oldBox.keys) {
|
||||||
await mwebUtxosBox.put(key, oldBox.get(key)!);
|
final value = oldBox.get(key);
|
||||||
|
await oldBox.delete(key);
|
||||||
|
await mwebUtxosBox.put(key, value!);
|
||||||
}
|
}
|
||||||
oldBox.deleteFromDisk();
|
oldBox.deleteFromDisk();
|
||||||
|
|
||||||
|
|
310
cw_bitcoin/lib/payjoin/manager.dart
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/payjoin_persister.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/payjoin_receive_worker.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/payjoin_send_worker.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/storage.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/signer.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/utils.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:payjoin_flutter/common.dart';
|
||||||
|
import 'package:payjoin_flutter/receive.dart';
|
||||||
|
import 'package:payjoin_flutter/send.dart';
|
||||||
|
import 'package:payjoin_flutter/src/config.dart' as pj_config;
|
||||||
|
import 'package:payjoin_flutter/uri.dart' as PayjoinUri;
|
||||||
|
|
||||||
|
class PayjoinManager {
|
||||||
|
PayjoinManager(this._payjoinStorage, this._wallet);
|
||||||
|
|
||||||
|
final PayjoinStorage _payjoinStorage;
|
||||||
|
final BitcoinWalletBase _wallet;
|
||||||
|
final Map<String, PayjoinPollerSession> _activePollers = {};
|
||||||
|
|
||||||
|
static const List<String> ohttpRelayUrls = [
|
||||||
|
'https://pj.bobspacebkk.com',
|
||||||
|
'https://ohttp.achow101.com',
|
||||||
|
'https://ohttp.cakewallet.com',
|
||||||
|
];
|
||||||
|
|
||||||
|
static String randomOhttpRelayUrl() =>
|
||||||
|
ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)];
|
||||||
|
|
||||||
|
static const payjoinDirectoryUrl = 'https://payjo.in';
|
||||||
|
|
||||||
|
Future<void> initPayjoin() => pj_config.PConfig.initializeApp();
|
||||||
|
|
||||||
|
Future<void> resumeSessions() async {
|
||||||
|
final allSessions = _payjoinStorage.readAllOpenSessions(_wallet.id);
|
||||||
|
|
||||||
|
final spawnedSessions = allSessions.map((session) {
|
||||||
|
if (session.isSenderSession) {
|
||||||
|
printV("Resuming Payjoin Sender Session ${session.pjUri!}");
|
||||||
|
return _spawnSender(
|
||||||
|
sender: Sender.fromJson(json: session.sender!),
|
||||||
|
pjUri: session.pjUri!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final receiver = Receiver.fromJson(json: session.receiver!);
|
||||||
|
printV("Resuming Payjoin Receiver Session ${receiver.id()}");
|
||||||
|
return spawnReceiver(receiver: receiver);
|
||||||
|
});
|
||||||
|
|
||||||
|
printV("Resumed ${spawnedSessions.length} Payjoin Sessions");
|
||||||
|
await Future.wait(spawnedSessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Sender> initSender(
|
||||||
|
String pjUriString, String originalPsbt, int networkFeesSatPerVb) async {
|
||||||
|
try {
|
||||||
|
final pjUri =
|
||||||
|
(await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported();
|
||||||
|
final minFeeRateSatPerKwu = BigInt.from(networkFeesSatPerVb * 250);
|
||||||
|
final senderBuilder = await SenderBuilder.fromPsbtAndUri(
|
||||||
|
psbtBase64: originalPsbt,
|
||||||
|
pjUri: pjUri,
|
||||||
|
);
|
||||||
|
final persister = PayjoinSenderPersister.impl();
|
||||||
|
final newSender =
|
||||||
|
await senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
|
||||||
|
final senderToken = await newSender.persist(persister: persister);
|
||||||
|
|
||||||
|
return Sender.load(token: senderToken, persister: persister);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Error initializing Payjoin Sender: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> spawnNewSender({
|
||||||
|
required Sender sender,
|
||||||
|
required String pjUrl,
|
||||||
|
required BigInt amount,
|
||||||
|
bool isTestnet = false,
|
||||||
|
}) async {
|
||||||
|
final pjUri = Uri.parse(pjUrl).queryParameters['pj']!;
|
||||||
|
await _payjoinStorage.insertSenderSession(
|
||||||
|
sender, pjUri, _wallet.id, amount);
|
||||||
|
|
||||||
|
return _spawnSender(isTestnet: isTestnet, sender: sender, pjUri: pjUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _spawnSender({
|
||||||
|
required Sender sender,
|
||||||
|
required String pjUri,
|
||||||
|
bool isTestnet = false,
|
||||||
|
}) async {
|
||||||
|
final completer = Completer();
|
||||||
|
final receivePort = ReceivePort();
|
||||||
|
|
||||||
|
receivePort.listen((message) async {
|
||||||
|
if (message is Map<String, dynamic>) {
|
||||||
|
try {
|
||||||
|
switch (message['type'] as PayjoinSenderRequestTypes) {
|
||||||
|
case PayjoinSenderRequestTypes.requestPosted:
|
||||||
|
return;
|
||||||
|
case PayjoinSenderRequestTypes.psbtToSign:
|
||||||
|
final proposalPsbt = message['psbt'] as String;
|
||||||
|
final utxos = _wallet.getUtxoWithPrivateKeys();
|
||||||
|
final finalizedPsbt = await _wallet.signPsbt(proposalPsbt, utxos);
|
||||||
|
final txId = getTxIdFromPsbtV0(finalizedPsbt);
|
||||||
|
_wallet.commitPsbt(finalizedPsbt);
|
||||||
|
|
||||||
|
_cleanupSession(pjUri);
|
||||||
|
await _payjoinStorage.markSenderSessionComplete(pjUri, txId);
|
||||||
|
completer.complete();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_cleanupSession(pjUri);
|
||||||
|
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, e.toString());
|
||||||
|
completer.complete();
|
||||||
|
}
|
||||||
|
} else if (message is PayjoinSessionError) {
|
||||||
|
_cleanupSession(pjUri);
|
||||||
|
if (message is UnrecoverableError) {
|
||||||
|
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, message.message);
|
||||||
|
completer.complete();
|
||||||
|
} else if (message is RecoverableError) {
|
||||||
|
completer.complete();
|
||||||
|
} else {
|
||||||
|
completer.completeError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final isolate = await Isolate.spawn(
|
||||||
|
PayjoinSenderWorker.run,
|
||||||
|
[receivePort.sendPort, sender.toJson(), pjUri],
|
||||||
|
);
|
||||||
|
|
||||||
|
_activePollers[pjUri] = PayjoinPollerSession(isolate, receivePort);
|
||||||
|
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Receiver> getUnusedReceiver(String address,
|
||||||
|
[bool isTestnet = false]) async {
|
||||||
|
final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id);
|
||||||
|
|
||||||
|
if (session != null) {
|
||||||
|
await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
|
||||||
|
|
||||||
|
return Receiver.fromJson(json: session.receiver!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return initReceiver(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Receiver> initReceiver(String address, [bool isTestnet = false]) async {
|
||||||
|
final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
|
||||||
|
ohttpRelay: await randomOhttpRelayUrl(),
|
||||||
|
payjoinDirectory: payjoinDirectoryUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
final newReceiver = await NewReceiver.create(
|
||||||
|
address: address,
|
||||||
|
network: isTestnet ? Network.testnet : Network.bitcoin,
|
||||||
|
directory: payjoinDirectoryUrl,
|
||||||
|
ohttpKeys: ohttpKeys,
|
||||||
|
);
|
||||||
|
final persister = PayjoinReceiverPersister.impl();
|
||||||
|
final receiverToken = await newReceiver.persist(persister: persister);
|
||||||
|
final receiver = await Receiver.load(persister: persister, token: receiverToken);
|
||||||
|
|
||||||
|
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
|
||||||
|
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> spawnReceiver({
|
||||||
|
required Receiver receiver,
|
||||||
|
bool isTestnet = false,
|
||||||
|
}) async {
|
||||||
|
final completer = Completer();
|
||||||
|
final receivePort = ReceivePort();
|
||||||
|
|
||||||
|
SendPort? mainToIsolateSendPort;
|
||||||
|
List<UtxoWithPrivateKey> utxos = [];
|
||||||
|
String rawAmount = '0';
|
||||||
|
|
||||||
|
receivePort.listen((message) async {
|
||||||
|
if (message is Map<String, dynamic>) {
|
||||||
|
try {
|
||||||
|
switch (message['type'] as PayjoinReceiverRequestTypes) {
|
||||||
|
case PayjoinReceiverRequestTypes.processOriginalTx:
|
||||||
|
final tx = message['tx'] as String;
|
||||||
|
rawAmount = getOutputAmountFromTx(tx, _wallet);
|
||||||
|
break;
|
||||||
|
case PayjoinReceiverRequestTypes.checkIsOwned:
|
||||||
|
(_wallet.walletAddresses as BitcoinWalletAddresses)
|
||||||
|
.newPayjoinReceiver();
|
||||||
|
_payjoinStorage.markReceiverSessionInProgress(receiver.id());
|
||||||
|
|
||||||
|
final inputScript = message['input_script'] as Uint8List;
|
||||||
|
final isOwned =
|
||||||
|
_wallet.isMine(Script.fromRaw(byteData: inputScript));
|
||||||
|
mainToIsolateSendPort?.send({
|
||||||
|
'requestId': message['requestId'],
|
||||||
|
'result': isOwned,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PayjoinReceiverRequestTypes.checkIsReceiverOutput:
|
||||||
|
final outputScript = message['output_script'] as Uint8List;
|
||||||
|
final isReceiverOutput =
|
||||||
|
_wallet.isMine(Script.fromRaw(byteData: outputScript));
|
||||||
|
mainToIsolateSendPort?.send({
|
||||||
|
'requestId': message['requestId'],
|
||||||
|
'result': isReceiverOutput,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PayjoinReceiverRequestTypes.getCandidateInputs:
|
||||||
|
utxos = _wallet.getUtxoWithPrivateKeys();
|
||||||
|
if (utxos.isEmpty) {
|
||||||
|
await _wallet.updateAllUnspents();
|
||||||
|
utxos = _wallet.getUtxoWithPrivateKeys();
|
||||||
|
}
|
||||||
|
mainToIsolateSendPort?.send({
|
||||||
|
'requestId': message['requestId'],
|
||||||
|
'result': utxos,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PayjoinReceiverRequestTypes.processPsbt:
|
||||||
|
final psbt = message['psbt'] as String;
|
||||||
|
final signedPsbt = await _wallet.signPsbt(psbt, utxos);
|
||||||
|
mainToIsolateSendPort?.send({
|
||||||
|
'requestId': message['requestId'],
|
||||||
|
'result': signedPsbt,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PayjoinReceiverRequestTypes.proposalSent:
|
||||||
|
_cleanupSession(receiver.id());
|
||||||
|
final psbt = message['psbt'] as String;
|
||||||
|
await _payjoinStorage.markReceiverSessionComplete(
|
||||||
|
receiver.id(), getTxIdFromPsbtV0(psbt), rawAmount);
|
||||||
|
completer.complete();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_cleanupSession(receiver.id());
|
||||||
|
await _payjoinStorage.markReceiverSessionUnrecoverable(
|
||||||
|
receiver.id(), e.toString());
|
||||||
|
completer.completeError(e);
|
||||||
|
}
|
||||||
|
} else if (message is PayjoinSessionError) {
|
||||||
|
_cleanupSession(receiver.id());
|
||||||
|
if (message is UnrecoverableError) {
|
||||||
|
await _payjoinStorage.markReceiverSessionUnrecoverable(
|
||||||
|
receiver.id(), message.message);
|
||||||
|
completer.complete();
|
||||||
|
} else if (message is RecoverableError) {
|
||||||
|
completer.complete();
|
||||||
|
} else {
|
||||||
|
completer.completeError(message);
|
||||||
|
}
|
||||||
|
} else if (message is SendPort) {
|
||||||
|
mainToIsolateSendPort = message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final isolate = await Isolate.spawn(
|
||||||
|
PayjoinReceiverWorker.run,
|
||||||
|
[receivePort.sendPort, receiver.toJson()],
|
||||||
|
);
|
||||||
|
|
||||||
|
_activePollers[receiver.id()] = PayjoinPollerSession(isolate, receivePort);
|
||||||
|
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupSessions() {
|
||||||
|
final sessionIds = _activePollers.keys.toList();
|
||||||
|
for (final sessionId in sessionIds) {
|
||||||
|
_cleanupSession(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cleanupSession(String sessionId) {
|
||||||
|
_activePollers[sessionId]?.close();
|
||||||
|
_activePollers.remove(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PayjoinPollerSession {
|
||||||
|
final Isolate isolate;
|
||||||
|
final ReceivePort port;
|
||||||
|
|
||||||
|
PayjoinPollerSession(this.isolate, this.port);
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
isolate.kill();
|
||||||
|
port.close();
|
||||||
|
}
|
||||||
|
}
|
66
cw_bitcoin/lib/payjoin/payjoin_persister.dart
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import 'package:payjoin_flutter/src/generated/api/receive.dart';
|
||||||
|
import 'package:payjoin_flutter/src/generated/api/send.dart';
|
||||||
|
|
||||||
|
class PayjoinSenderPersister implements DartSenderPersister {
|
||||||
|
static DartSenderPersister impl() {
|
||||||
|
final impl = PayjoinSenderPersister();
|
||||||
|
return DartSenderPersister(
|
||||||
|
save: (sender) => impl.save(sender: sender),
|
||||||
|
load: (token) => impl.load(token: token),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, FfiSender> _store = {};
|
||||||
|
|
||||||
|
Future<SenderToken> save({required FfiSender sender}) async {
|
||||||
|
final token = sender.key();
|
||||||
|
_store[token.toBytes().toString()] = sender;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<FfiSender> load({required SenderToken token}) async {
|
||||||
|
final sender = _store[token.toBytes().toString()];
|
||||||
|
if (sender == null) {
|
||||||
|
throw Exception('Sender not found for the provided token.');
|
||||||
|
}
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() => _store.clear();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isDisposed => _store.isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PayjoinReceiverPersister implements DartReceiverPersister {
|
||||||
|
static DartReceiverPersister impl() {
|
||||||
|
final impl = PayjoinReceiverPersister();
|
||||||
|
return DartReceiverPersister(
|
||||||
|
save: (receiver) => impl.save(receiver: receiver),
|
||||||
|
load: (token) => impl.load(token: token),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, FfiReceiver> _store = {};
|
||||||
|
|
||||||
|
Future<ReceiverToken> save({required FfiReceiver receiver}) async {
|
||||||
|
final token = receiver.key();
|
||||||
|
_store[token.toBytes().toString()] = receiver;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<FfiReceiver> load({required ReceiverToken token}) async {
|
||||||
|
final receiver = _store[token.toBytes().toString()];
|
||||||
|
if (receiver == null) {
|
||||||
|
throw Exception('Receiver not found for the provided token.');
|
||||||
|
}
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() => _store.clear();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isDisposed => _store.isEmpty;
|
||||||
|
}
|
222
cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/manager.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/signer.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
|
import 'package:payjoin_flutter/bitcoin_ffi.dart';
|
||||||
|
import 'package:payjoin_flutter/common.dart';
|
||||||
|
import 'package:payjoin_flutter/receive.dart';
|
||||||
|
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
|
||||||
|
import 'package:http/http.dart' as very_insecure_http_do_not_use; // for errors
|
||||||
|
|
||||||
|
enum PayjoinReceiverRequestTypes {
|
||||||
|
processOriginalTx,
|
||||||
|
proposalSent,
|
||||||
|
getCandidateInputs,
|
||||||
|
checkIsOwned,
|
||||||
|
checkIsReceiverOutput,
|
||||||
|
processPsbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PayjoinReceiverWorker {
|
||||||
|
final SendPort sendPort;
|
||||||
|
final pendingRequests = <String, Completer<dynamic>>{};
|
||||||
|
|
||||||
|
PayjoinReceiverWorker._(this.sendPort);
|
||||||
|
static final client = ProxyWrapper().getHttpIOClient();
|
||||||
|
static Future<void> run(List<Object> args) async {
|
||||||
|
await pj.core.init();
|
||||||
|
|
||||||
|
final sendPort = args[0] as SendPort;
|
||||||
|
final receiverJson = args[1] as String;
|
||||||
|
|
||||||
|
final worker = PayjoinReceiverWorker._(sendPort);
|
||||||
|
final receivePort = ReceivePort();
|
||||||
|
|
||||||
|
sendPort.send(receivePort.sendPort);
|
||||||
|
receivePort.listen(worker.handleMessage);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final receiver = Receiver.fromJson(json: receiverJson);
|
||||||
|
|
||||||
|
final uncheckedProposal =
|
||||||
|
await worker.receiveUncheckedProposal(receiver);
|
||||||
|
|
||||||
|
final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast();
|
||||||
|
sendPort.send({
|
||||||
|
'type': PayjoinReceiverRequestTypes.processOriginalTx,
|
||||||
|
'tx': BytesUtils.toHexString(originalTx),
|
||||||
|
});
|
||||||
|
|
||||||
|
final payjoinProposal = await worker.processPayjoinProposal(
|
||||||
|
uncheckedProposal,
|
||||||
|
);
|
||||||
|
final psbt = await worker.sendFinalProposal(payjoinProposal);
|
||||||
|
sendPort.send({
|
||||||
|
'type': PayjoinReceiverRequestTypes.proposalSent,
|
||||||
|
'psbt': psbt,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (e is HttpException ||
|
||||||
|
(e is very_insecure_http_do_not_use.ClientException &&
|
||||||
|
e.message.contains("Software caused connection abort"))) {
|
||||||
|
sendPort.send(PayjoinSessionError.recoverable(e.toString()));
|
||||||
|
} else {
|
||||||
|
sendPort.send(PayjoinSessionError.unrecoverable(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMessage(dynamic message) async {
|
||||||
|
if (message is Map<String, dynamic>) {
|
||||||
|
final requestId = message['requestId'] as String?;
|
||||||
|
if (requestId != null && pendingRequests.containsKey(requestId)) {
|
||||||
|
pendingRequests[requestId]!.complete(message['result']);
|
||||||
|
pendingRequests.remove(requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> _sendRequest(PayjoinReceiverRequestTypes type,
|
||||||
|
[Map<String, dynamic> data = const {}]) async {
|
||||||
|
final completer = Completer<dynamic>();
|
||||||
|
final requestId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
|
pendingRequests[requestId] = completer;
|
||||||
|
|
||||||
|
sendPort.send({
|
||||||
|
...data,
|
||||||
|
'type': type,
|
||||||
|
'requestId': requestId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<UncheckedProposal> receiveUncheckedProposal(Receiver session) async {
|
||||||
|
while (true) {
|
||||||
|
printV("Polling for Proposal (${session.id()})");
|
||||||
|
final extractReq = await session.extractReq(
|
||||||
|
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
|
||||||
|
);
|
||||||
|
final request = extractReq.$1;
|
||||||
|
|
||||||
|
final url = Uri.parse(request.url.asString());
|
||||||
|
final httpRequest = await client.post(url,
|
||||||
|
headers: {'Content-Type': request.contentType}, body: request.body);
|
||||||
|
|
||||||
|
final proposal = await session.processRes(
|
||||||
|
body: httpRequest.bodyBytes, ctx: extractReq.$2);
|
||||||
|
if (proposal != null) return proposal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> sendFinalProposal(PayjoinProposal finalProposal) async {
|
||||||
|
final req = await finalProposal.extractReq(
|
||||||
|
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
|
||||||
|
);
|
||||||
|
final proposalReq = req.$1;
|
||||||
|
final proposalCtx = req.$2;
|
||||||
|
|
||||||
|
final request = await client.post(
|
||||||
|
Uri.parse(proposalReq.url.asString()),
|
||||||
|
headers: {"Content-Type": proposalReq.contentType},
|
||||||
|
body: proposalReq.body,
|
||||||
|
);
|
||||||
|
|
||||||
|
await finalProposal.processRes(
|
||||||
|
res: request.bodyBytes,
|
||||||
|
ohttpContext: proposalCtx,
|
||||||
|
);
|
||||||
|
|
||||||
|
return await finalProposal.psbt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PayjoinProposal> processPayjoinProposal(
|
||||||
|
UncheckedProposal proposal) async {
|
||||||
|
await proposal.extractTxToScheduleBroadcast();
|
||||||
|
// TODO Handle this. send to the main port on a timer?
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Receive Check 1: can broadcast
|
||||||
|
final pj1 = await proposal.assumeInteractiveReceiver();
|
||||||
|
|
||||||
|
// Receive Check 2: original PSBT has no receiver-owned inputs
|
||||||
|
final pj2 = await pj1.checkInputsNotOwned(
|
||||||
|
isOwned: (inputScript) async {
|
||||||
|
final result = await _sendRequest(
|
||||||
|
PayjoinReceiverRequestTypes.checkIsOwned,
|
||||||
|
{'input_script': inputScript},
|
||||||
|
);
|
||||||
|
return result as bool;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// Receive Check 3: sender inputs have not been seen before (prevent probing attacks)
|
||||||
|
final pj3 = await pj2.checkNoInputsSeenBefore(isKnown: (input) => false);
|
||||||
|
|
||||||
|
// Identify receiver outputs
|
||||||
|
final pj4 = await pj3.identifyReceiverOutputs(
|
||||||
|
isReceiverOutput: (outputScript) async {
|
||||||
|
final result = await _sendRequest(
|
||||||
|
PayjoinReceiverRequestTypes.checkIsReceiverOutput,
|
||||||
|
{'output_script': outputScript},
|
||||||
|
);
|
||||||
|
return result as bool;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final pj5 = await pj4.commitOutputs();
|
||||||
|
|
||||||
|
final listUnspent =
|
||||||
|
await _sendRequest(PayjoinReceiverRequestTypes.getCandidateInputs);
|
||||||
|
final unspent = listUnspent as List<UtxoWithPrivateKey>;
|
||||||
|
if (unspent.isEmpty) throw RecoverableError('No unspent outputs available');
|
||||||
|
|
||||||
|
final selectedUtxo = await _inputPairFromUtxo(unspent[0]);
|
||||||
|
final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]);
|
||||||
|
final pj7 = await pj6.commitInputs();
|
||||||
|
|
||||||
|
// Finalize proposal
|
||||||
|
final payjoinProposal = await pj7.finalizeProposal(
|
||||||
|
processPsbt: (String psbt) async {
|
||||||
|
final result = await _sendRequest(
|
||||||
|
PayjoinReceiverRequestTypes.processPsbt, {'psbt': psbt});
|
||||||
|
return result as String;
|
||||||
|
},
|
||||||
|
// TODO set maxFeeRateSatPerVb
|
||||||
|
maxFeeRateSatPerVb: BigInt.from(10000),
|
||||||
|
);
|
||||||
|
return payjoinProposal;
|
||||||
|
} catch (e) {
|
||||||
|
printV('Error occurred while finalizing proposal: $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<InputPair> _inputPairFromUtxo(UtxoWithPrivateKey utxo) async {
|
||||||
|
final txout = TxOut(
|
||||||
|
value: utxo.utxo.value,
|
||||||
|
scriptPubkey: Uint8List.fromList(
|
||||||
|
utxo.ownerDetails.address.toScriptPubKey().toBytes()),
|
||||||
|
);
|
||||||
|
|
||||||
|
final psbtin =
|
||||||
|
PsbtInput(witnessUtxo: txout, redeemScript: null, witnessScript: null);
|
||||||
|
|
||||||
|
final previousOutput =
|
||||||
|
OutPoint(txid: utxo.utxo.txHash, vout: utxo.utxo.vout);
|
||||||
|
|
||||||
|
final txin = TxIn(
|
||||||
|
previousOutput: previousOutput,
|
||||||
|
scriptSig: await Script.newInstance(rawOutputScript: []),
|
||||||
|
witness: [],
|
||||||
|
sequence: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
return InputPair.newInstance(txin: txin, psbtin: psbtin);
|
||||||
|
}
|
||||||
|
}
|
120
cw_bitcoin/lib/payjoin/payjoin_send_worker.dart
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
|
||||||
|
import 'package:cw_bitcoin/payjoin/manager.dart';
|
||||||
|
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
|
import 'package:payjoin_flutter/common.dart';
|
||||||
|
import 'package:payjoin_flutter/send.dart';
|
||||||
|
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
|
||||||
|
import 'package:payjoin_flutter/src/generated/api/send/error.dart' as pj_error;
|
||||||
|
import 'package:payjoin_flutter/uri.dart' as pj_uri;
|
||||||
|
|
||||||
|
enum PayjoinSenderRequestTypes {
|
||||||
|
requestPosted,
|
||||||
|
psbtToSign;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PayjoinSenderWorker {
|
||||||
|
final SendPort sendPort;
|
||||||
|
final pendingRequests = <String, Completer<dynamic>>{};
|
||||||
|
final String pjUrl;
|
||||||
|
|
||||||
|
PayjoinSenderWorker._(this.sendPort, this.pjUrl);
|
||||||
|
|
||||||
|
static Future<void> run(List<Object> args) async {
|
||||||
|
await pj.core.init();
|
||||||
|
|
||||||
|
final sendPort = args[0] as SendPort;
|
||||||
|
final senderJson = args[1] as String;
|
||||||
|
final pjUrl = args[2] as String;
|
||||||
|
|
||||||
|
final sender = Sender.fromJson(json: senderJson);
|
||||||
|
final worker = PayjoinSenderWorker._(sendPort, pjUrl);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final proposalPsbt = await worker.runSender(sender);
|
||||||
|
sendPort.send({
|
||||||
|
'type': PayjoinSenderRequestTypes.psbtToSign,
|
||||||
|
'psbt': proposalPsbt,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
sendPort.send(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final client = ProxyWrapper().getHttpIOClient();
|
||||||
|
|
||||||
|
/// Run a payjoin sender (V2 protocol first, fallback to V1).
|
||||||
|
Future<String> runSender(Sender sender) async {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await _runSenderV2(sender);
|
||||||
|
} catch (e) {
|
||||||
|
printV(e);
|
||||||
|
if (e is pj_error.FfiCreateRequestError) {
|
||||||
|
return await _runSenderV1(sender);
|
||||||
|
} else if (e is HttpException) {
|
||||||
|
printV(e);
|
||||||
|
throw Exception(PayjoinSessionError.recoverable(e.toString()));
|
||||||
|
} else {
|
||||||
|
throw Exception(PayjoinSessionError.unrecoverable(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to send payjoin using the V2 of the protocol.
|
||||||
|
Future<String> _runSenderV2(Sender sender) async {
|
||||||
|
try {
|
||||||
|
final postRequest = await sender.extractV2(
|
||||||
|
ohttpProxyUrl:
|
||||||
|
await pj_uri.Url.fromStr(PayjoinManager.randomOhttpRelayUrl()),
|
||||||
|
);
|
||||||
|
|
||||||
|
final postResult = await _postRequest(postRequest.$1);
|
||||||
|
final getContext =
|
||||||
|
await postRequest.$2.processResponse(response: postResult);
|
||||||
|
|
||||||
|
sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted, "pj": pjUrl});
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
printV('Polling V2 Proposal Request (${pjUrl})');
|
||||||
|
|
||||||
|
final getRequest = await getContext.extractReq(
|
||||||
|
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
|
||||||
|
);
|
||||||
|
final getRes = await _postRequest(getRequest.$1);
|
||||||
|
final proposalPsbt = await getContext.processResponse(
|
||||||
|
response: getRes,
|
||||||
|
ohttpCtx: getRequest.$2,
|
||||||
|
);
|
||||||
|
printV("$proposalPsbt");
|
||||||
|
if (proposalPsbt != null) return proposalPsbt;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to send payjoin using the V1 of the protocol.
|
||||||
|
Future<String> _runSenderV1(Sender sender) async {
|
||||||
|
try {
|
||||||
|
final postRequest = await sender.extractV1();
|
||||||
|
final response = await _postRequest(postRequest.$1);
|
||||||
|
|
||||||
|
sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted});
|
||||||
|
|
||||||
|
return await postRequest.$2.processResponse(response: response);
|
||||||
|
} catch (e, stack) {
|
||||||
|
throw PayjoinSessionError.unrecoverable('Send V1 payjoin error: $e, $stack');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<int>> _postRequest(Request req) async {
|
||||||
|
final httpRequest = await client.post(Uri.parse(req.url.asString()),
|
||||||
|
headers: {'Content-Type': req.contentType}, body: req.body);
|
||||||
|
|
||||||
|
return httpRequest.bodyBytes;
|
||||||
|
}
|
||||||
|
}
|
16
cw_bitcoin/lib/payjoin/payjoin_session_errors.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
class PayjoinSessionError {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const PayjoinSessionError._(this.message);
|
||||||
|
|
||||||
|
factory PayjoinSessionError.recoverable(String message) = RecoverableError;
|
||||||
|
factory PayjoinSessionError.unrecoverable(String message) = UnrecoverableError;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecoverableError extends PayjoinSessionError {
|
||||||
|
const RecoverableError(super.message) : super._();
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnrecoverableError extends PayjoinSessionError {
|
||||||
|
const UnrecoverableError(super.message) : super._();
|
||||||
|
}
|
104
cw_bitcoin/lib/payjoin/storage.dart
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import 'package:cw_core/payjoin_session.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:payjoin_flutter/receive.dart';
|
||||||
|
import 'package:payjoin_flutter/send.dart';
|
||||||
|
|
||||||
|
class PayjoinStorage {
|
||||||
|
PayjoinStorage(this._payjoinSessionSources);
|
||||||
|
|
||||||
|
final Box<PayjoinSession> _payjoinSessionSources;
|
||||||
|
|
||||||
|
static const String _receiverPrefix = 'pj_recv_';
|
||||||
|
static const String _senderPrefix = 'pj_send_';
|
||||||
|
|
||||||
|
Future<void> insertReceiverSession(
|
||||||
|
Receiver receiver,
|
||||||
|
String walletId,
|
||||||
|
) =>
|
||||||
|
_payjoinSessionSources.put(
|
||||||
|
"$_receiverPrefix${receiver.id()}",
|
||||||
|
PayjoinSession(
|
||||||
|
walletId: walletId,
|
||||||
|
receiver: receiver.toJson(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
PayjoinSession? getUnusedActiveReceiverSession(String walletId) =>
|
||||||
|
_payjoinSessionSources.values
|
||||||
|
.where((session) =>
|
||||||
|
session.walletId == walletId &&
|
||||||
|
session.status == PayjoinSessionStatus.created.name &&
|
||||||
|
!session.isSenderSession)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
Future<void> markReceiverSessionComplete(
|
||||||
|
String sessionId, String txId, String amount) async {
|
||||||
|
final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!;
|
||||||
|
|
||||||
|
session.status = PayjoinSessionStatus.success.name;
|
||||||
|
session.txId = txId;
|
||||||
|
session.rawAmount = amount;
|
||||||
|
await session.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> markReceiverSessionUnrecoverable(
|
||||||
|
String sessionId, String reason) async {
|
||||||
|
final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!;
|
||||||
|
|
||||||
|
session.status = PayjoinSessionStatus.unrecoverable.name;
|
||||||
|
session.error = reason;
|
||||||
|
await session.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> markReceiverSessionInProgress(String sessionId) async {
|
||||||
|
final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!;
|
||||||
|
|
||||||
|
session.status = PayjoinSessionStatus.inProgress.name;
|
||||||
|
session.inProgressSince = DateTime.now();
|
||||||
|
await session.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> insertSenderSession(
|
||||||
|
Sender sender,
|
||||||
|
String pjUrl,
|
||||||
|
String walletId,
|
||||||
|
BigInt amount,
|
||||||
|
) =>
|
||||||
|
_payjoinSessionSources.put(
|
||||||
|
"$_senderPrefix$pjUrl",
|
||||||
|
PayjoinSession(
|
||||||
|
walletId: walletId,
|
||||||
|
pjUri: pjUrl,
|
||||||
|
sender: sender.toJson(),
|
||||||
|
status: PayjoinSessionStatus.inProgress.name,
|
||||||
|
inProgressSince: DateTime.now(),
|
||||||
|
rawAmount: amount.toString(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<void> markSenderSessionComplete(String pjUrl, String txId) async {
|
||||||
|
final session = _payjoinSessionSources.get("$_senderPrefix$pjUrl")!;
|
||||||
|
|
||||||
|
session.status = PayjoinSessionStatus.success.name;
|
||||||
|
session.txId = txId;
|
||||||
|
await session.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> markSenderSessionUnrecoverable(String pjUrl, String reason) async {
|
||||||
|
final session = _payjoinSessionSources.get("$_senderPrefix$pjUrl")!;
|
||||||
|
|
||||||
|
session.status = PayjoinSessionStatus.unrecoverable.name;
|
||||||
|
session.error = reason;
|
||||||
|
await session.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PayjoinSession> readAllOpenSessions(String walletId) =>
|
||||||
|
_payjoinSessionSources.values
|
||||||
|
.where((session) =>
|
||||||
|
session.walletId == walletId &&
|
||||||
|
![
|
||||||
|
PayjoinSessionStatus.success.name,
|
||||||
|
PayjoinSessionStatus.unrecoverable.name
|
||||||
|
].contains(session.status))
|
||||||
|
.toList();
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:grpc/grpc.dart';
|
import 'package:grpc/grpc.dart';
|
||||||
import 'package:cw_bitcoin/exceptions.dart';
|
import 'package:cw_bitcoin/exceptions.dart';
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
@ -25,6 +26,8 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||||
this.hasTaprootInputs = false,
|
this.hasTaprootInputs = false,
|
||||||
this.isMweb = false,
|
this.isMweb = false,
|
||||||
this.utxos = const [],
|
this.utxos = const [],
|
||||||
|
this.publicKeys,
|
||||||
|
this.commitOverride,
|
||||||
}) : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
|
}) : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
|
||||||
|
|
||||||
final WalletType type;
|
final WalletType type;
|
||||||
|
@ -43,6 +46,8 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||||
String? idOverride;
|
String? idOverride;
|
||||||
String? hexOverride;
|
String? hexOverride;
|
||||||
List<String>? outputAddresses;
|
List<String>? outputAddresses;
|
||||||
|
final Map<String, PublicKeyWithDerivationPath>? publicKeys;
|
||||||
|
Future<void> Function()? commitOverride;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get id => idOverride ?? _tx.txId();
|
String get id => idOverride ?? _tx.txId();
|
||||||
|
@ -129,6 +134,10 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> commit() async {
|
Future<void> commit() async {
|
||||||
|
if (commitOverride != null) {
|
||||||
|
return commitOverride?.call();
|
||||||
|
}
|
||||||
|
|
||||||
if (isMweb) {
|
if (isMweb) {
|
||||||
await _ltcCommit();
|
await _ltcCommit();
|
||||||
} else {
|
} else {
|
||||||
|
|
263
cw_bitcoin/lib/psbt/signer.dart
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||||
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
|
import 'package:ledger_bitcoin/psbt.dart';
|
||||||
|
import 'package:ledger_bitcoin/src/utils/buffer_writer.dart';
|
||||||
|
|
||||||
|
extension PsbtSigner on PsbtV2 {
|
||||||
|
Uint8List extractUnsignedTX({bool getSegwit = true}) {
|
||||||
|
final tx = BufferWriter()..writeUInt32(getGlobalTxVersion());
|
||||||
|
|
||||||
|
final isSegwit = getInputWitnessUtxo(0) != null;
|
||||||
|
if (isSegwit && getSegwit) {
|
||||||
|
tx.writeSlice(Uint8List.fromList([0, 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
final inputCount = getGlobalInputCount();
|
||||||
|
tx.writeVarInt(inputCount);
|
||||||
|
|
||||||
|
for (var i = 0; i < inputCount; i++) {
|
||||||
|
tx
|
||||||
|
..writeSlice(getInputPreviousTxid(i))
|
||||||
|
..writeUInt32(getInputOutputIndex(i))
|
||||||
|
..writeVarSlice(Uint8List(0))
|
||||||
|
..writeUInt32(getInputSequence(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
final outputCount = getGlobalOutputCount();
|
||||||
|
tx.writeVarInt(outputCount);
|
||||||
|
for (var i = 0; i < outputCount; i++) {
|
||||||
|
tx.writeUInt64(getOutputAmount(i));
|
||||||
|
tx.writeVarSlice(getOutputScript(i));
|
||||||
|
}
|
||||||
|
tx.writeUInt32(getGlobalFallbackLocktime() ?? 0);
|
||||||
|
return tx.buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signWithUTXO(
|
||||||
|
List<UtxoWithPrivateKey> utxos, UTXOSignerCallBack signer,
|
||||||
|
[UTXOGetterCallBack? getTaprootPair]) async {
|
||||||
|
final raw = BytesUtils.toHexString(extractUnsignedTX(getSegwit: false));
|
||||||
|
final tx = BtcTransaction.fromRaw(raw);
|
||||||
|
|
||||||
|
/// when the transaction is taproot and we must use getTaproot transaction
|
||||||
|
/// digest we need all of inputs amounts and owner script pub keys
|
||||||
|
List<BigInt> taprootAmounts = [];
|
||||||
|
List<Script> taprootScripts = [];
|
||||||
|
|
||||||
|
if (utxos.any((e) => e.utxo.isP2tr())) {
|
||||||
|
for (final input in tx.inputs) {
|
||||||
|
final utxo = utxos.firstWhereOrNull(
|
||||||
|
(u) => u.utxo.txHash == input.txId && u.utxo.vout == input.txIndex);
|
||||||
|
|
||||||
|
if (utxo == null) {
|
||||||
|
final trPair = await getTaprootPair!.call(input.txId, input.txIndex);
|
||||||
|
taprootAmounts.add(trPair.value);
|
||||||
|
taprootScripts.add(trPair.script);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
taprootAmounts.add(utxo.utxo.value);
|
||||||
|
taprootScripts.add(_findLockingScript(utxo, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < tx.inputs.length; i++) {
|
||||||
|
final utxo = utxos.firstWhereOrNull((e) =>
|
||||||
|
e.utxo.txHash == tx.inputs[i].txId &&
|
||||||
|
e.utxo.vout == tx.inputs[i].txIndex); // ToDo: More robust verify
|
||||||
|
if (utxo == null) continue;
|
||||||
|
|
||||||
|
/// We receive the owner's ScriptPubKey
|
||||||
|
final script = _findLockingScript(utxo, false);
|
||||||
|
|
||||||
|
final int sighash = utxo.utxo.isP2tr()
|
||||||
|
? BitcoinOpCodeConst.TAPROOT_SIGHASH_ALL
|
||||||
|
: BitcoinOpCodeConst.SIGHASH_ALL;
|
||||||
|
|
||||||
|
/// We generate transaction digest for current input
|
||||||
|
final digest = _generateTransactionDigest(
|
||||||
|
script, i, utxo.utxo, tx, taprootAmounts, taprootScripts);
|
||||||
|
|
||||||
|
/// now we need sign the transaction digest
|
||||||
|
final sig = signer(digest, utxo, utxo.privateKey, sighash);
|
||||||
|
|
||||||
|
if (utxo.utxo.isP2tr()) {
|
||||||
|
setInputTapKeySig(i, Uint8List.fromList(BytesUtils.fromHexString(sig)));
|
||||||
|
} else {
|
||||||
|
setInputPartialSig(
|
||||||
|
i,
|
||||||
|
Uint8List.fromList(BytesUtils.fromHexString(utxo.public().toHex())),
|
||||||
|
Uint8List.fromList(BytesUtils.fromHexString(sig)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> _generateTransactionDigest(
|
||||||
|
Script scriptPubKeys,
|
||||||
|
int input,
|
||||||
|
BitcoinUtxo utxo,
|
||||||
|
BtcTransaction transaction,
|
||||||
|
List<BigInt> taprootAmounts,
|
||||||
|
List<Script> tapRootPubKeys) {
|
||||||
|
if (utxo.isSegwit()) {
|
||||||
|
if (utxo.isP2tr()) {
|
||||||
|
return transaction.getTransactionTaprootDigset(
|
||||||
|
txIndex: input,
|
||||||
|
scriptPubKeys: tapRootPubKeys,
|
||||||
|
amounts: taprootAmounts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return transaction.getTransactionSegwitDigit(
|
||||||
|
txInIndex: input, script: scriptPubKeys, amount: utxo.value);
|
||||||
|
}
|
||||||
|
return transaction.getTransactionDigest(
|
||||||
|
txInIndex: input, script: scriptPubKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
Script _findLockingScript(UtxoWithAddress utxo, bool isTaproot) {
|
||||||
|
if (utxo.isMultiSig()) {
|
||||||
|
throw Exception("MultiSig is not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
final senderPub = utxo.public();
|
||||||
|
switch (utxo.utxo.scriptType) {
|
||||||
|
case PubKeyAddressType.p2pk:
|
||||||
|
return senderPub.toRedeemScript();
|
||||||
|
case SegwitAddresType.p2wsh:
|
||||||
|
if (isTaproot) {
|
||||||
|
return senderPub.toP2wshAddress().toScriptPubKey();
|
||||||
|
}
|
||||||
|
return senderPub.toP2wshRedeemScript();
|
||||||
|
case P2pkhAddressType.p2pkh:
|
||||||
|
return senderPub.toP2pkhAddress().toScriptPubKey();
|
||||||
|
case SegwitAddresType.p2wpkh:
|
||||||
|
if (isTaproot) {
|
||||||
|
return senderPub.toP2wpkhAddress().toScriptPubKey();
|
||||||
|
}
|
||||||
|
return senderPub.toP2pkhAddress().toScriptPubKey();
|
||||||
|
case SegwitAddresType.p2tr:
|
||||||
|
return senderPub
|
||||||
|
.toTaprootAddress(tweak: utxo.utxo.isSilentPayment != true)
|
||||||
|
.toScriptPubKey();
|
||||||
|
case SegwitAddresType.mweb:
|
||||||
|
return Script(script: []);
|
||||||
|
case P2shAddressType.p2pkhInP2sh:
|
||||||
|
if (isTaproot) {
|
||||||
|
return senderPub.toP2pkhInP2sh().toScriptPubKey();
|
||||||
|
}
|
||||||
|
return senderPub.toP2pkhAddress().toScriptPubKey();
|
||||||
|
case P2shAddressType.p2wpkhInP2sh:
|
||||||
|
if (isTaproot) {
|
||||||
|
return senderPub.toP2wpkhInP2sh().toScriptPubKey();
|
||||||
|
}
|
||||||
|
return senderPub.toP2pkhAddress().toScriptPubKey();
|
||||||
|
case P2shAddressType.p2wshInP2sh:
|
||||||
|
if (isTaproot) {
|
||||||
|
return senderPub.toP2wshInP2sh().toScriptPubKey();
|
||||||
|
}
|
||||||
|
return senderPub.toP2wshRedeemScript();
|
||||||
|
case P2shAddressType.p2pkInP2sh:
|
||||||
|
if (isTaproot) {
|
||||||
|
return senderPub.toP2pkInP2sh().toScriptPubKey();
|
||||||
|
}
|
||||||
|
return senderPub.toRedeemScript();
|
||||||
|
}
|
||||||
|
throw Exception("invalid bitcoin address type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef UTXOSignerCallBack = String Function(List<int> trDigest,
|
||||||
|
UtxoWithAddress utxo, ECPrivate privateKey, int sighash);
|
||||||
|
|
||||||
|
typedef UTXOGetterCallBack = Future<TaprootAmountScriptPair> Function(
|
||||||
|
String txId, int vout);
|
||||||
|
|
||||||
|
class TaprootAmountScriptPair {
|
||||||
|
final BigInt value;
|
||||||
|
final Script script;
|
||||||
|
|
||||||
|
const TaprootAmountScriptPair(this.value, this.script);
|
||||||
|
}
|
||||||
|
|
||||||
|
class UtxoWithPrivateKey extends UtxoWithAddress {
|
||||||
|
final ECPrivate privateKey;
|
||||||
|
|
||||||
|
UtxoWithPrivateKey({
|
||||||
|
required super.utxo,
|
||||||
|
required super.ownerDetails,
|
||||||
|
required this.privateKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory UtxoWithPrivateKey.fromUtxo(
|
||||||
|
UtxoWithAddress input, List<ECPrivateInfo> inputPrivateKeyInfos) {
|
||||||
|
ECPrivateInfo? key;
|
||||||
|
|
||||||
|
if (inputPrivateKeyInfos.isEmpty) {
|
||||||
|
throw Exception("No private keys generated.");
|
||||||
|
} else {
|
||||||
|
key = inputPrivateKeyInfos.firstWhereOrNull((element) {
|
||||||
|
final elemPubkey = element.privkey.getPublic().toHex();
|
||||||
|
if (elemPubkey == input.public().toHex()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == null) {
|
||||||
|
throw Exception("${input.utxo.txHash} No Key found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return UtxoWithPrivateKey(
|
||||||
|
utxo: input.utxo,
|
||||||
|
ownerDetails: input.ownerDetails,
|
||||||
|
privateKey: key.privkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory UtxoWithPrivateKey.fromUnspent(
|
||||||
|
BitcoinUnspent input, BitcoinWalletBase wallet) {
|
||||||
|
final address =
|
||||||
|
RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);
|
||||||
|
|
||||||
|
final newHd =
|
||||||
|
input.bitcoinAddressRecord.isHidden ? wallet.sideHd : wallet.hd;
|
||||||
|
|
||||||
|
ECPrivate privkey;
|
||||||
|
if (input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
|
||||||
|
final unspentAddress =
|
||||||
|
input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
|
||||||
|
privkey = wallet.walletAddresses.silentAddress!.b_spend.tweakAdd(
|
||||||
|
BigintUtils.fromBytes(
|
||||||
|
BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
privkey = generateECPrivate(
|
||||||
|
hd: newHd,
|
||||||
|
index: input.bitcoinAddressRecord.index,
|
||||||
|
network: BitcoinNetwork.mainnet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UtxoWithPrivateKey(
|
||||||
|
utxo: BitcoinUtxo(
|
||||||
|
txHash: input.hash,
|
||||||
|
value: BigInt.from(input.value),
|
||||||
|
vout: input.vout,
|
||||||
|
scriptType: input.bitcoinAddressRecord.type,
|
||||||
|
isSilentPayment:
|
||||||
|
input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
|
||||||
|
),
|
||||||
|
ownerDetails: UtxoAddressDetails(
|
||||||
|
publicKey: privkey.getPublic().toHex(),
|
||||||
|
address: address,
|
||||||
|
),
|
||||||
|
privateKey: privkey);
|
||||||
|
}
|
||||||
|
}
|
41
cw_bitcoin/lib/psbt/utils.dart
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||||
|
import 'package:cw_bitcoin/psbt/v0_deserialize.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:ledger_bitcoin/psbt.dart';
|
||||||
|
|
||||||
|
String getTxIdFromPsbtV0(String psbt) {
|
||||||
|
final psbtV2 = PsbtV2()..deserializeV0(base64.decode(psbt));
|
||||||
|
|
||||||
|
return BtcTransaction.fromRaw(
|
||||||
|
BytesUtils.toHexString(psbtV2.extractUnsignedTX(false)))
|
||||||
|
.txId();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getOutputAmountFromPsbt(String psbtV0, BitcoinWalletBase wallet) {
|
||||||
|
printV(psbtV0);
|
||||||
|
final psbt = PsbtV2()..deserializeV0(base64.decode(psbtV0));
|
||||||
|
int amount = 0;
|
||||||
|
for (var i = 0; i < psbt.getGlobalOutputCount(); i++) {
|
||||||
|
final script = psbt.getOutputScript(i);
|
||||||
|
if (wallet.isMine(Script.fromRaw(byteData: script))) {
|
||||||
|
amount += psbt.getOutputAmount(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return amount.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getOutputAmountFromTx(String originalTx, BitcoinWalletBase wallet) {
|
||||||
|
final tx = BtcTransaction.fromRaw(originalTx);
|
||||||
|
BigInt amount = BigInt.zero;
|
||||||
|
for (final output in tx.outputs) {
|
||||||
|
if (wallet.isMine(output.scriptPubKey)) {
|
||||||
|
amount += output.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printV(amount);
|
||||||
|
return amount.toString();
|
||||||
|
}
|
52
cw_bitcoin/lib/psbt/v0_deserialize.dart
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:ledger_bitcoin/psbt.dart';
|
||||||
|
import 'package:ledger_bitcoin/src/psbt/map_extension.dart';
|
||||||
|
import 'package:ledger_bitcoin/src/utils/buffer_reader.dart';
|
||||||
|
import 'package:ledger_bitcoin/src/utils/uint8list_extension.dart' as ext;
|
||||||
|
|
||||||
|
extension PsbtSigner on PsbtV2 {
|
||||||
|
|
||||||
|
void deserializeV0(Uint8List psbt) {
|
||||||
|
final bufferReader = BufferReader(psbt);
|
||||||
|
if (!listEquals(bufferReader.readSlice(5), Uint8List.fromList([0x70, 0x73, 0x62, 0x74, 0xff]))) {
|
||||||
|
throw Exception("Invalid magic bytes");
|
||||||
|
}
|
||||||
|
while (_readKeyPair(globalMap, bufferReader)) {}
|
||||||
|
|
||||||
|
final tx = BtcTransaction.fromRaw(BytesUtils.toHexString(globalMap['00']!));
|
||||||
|
|
||||||
|
setGlobalInputCount(tx.inputs.length);
|
||||||
|
setGlobalOutputCount(tx.outputs.length);
|
||||||
|
setGlobalTxVersion(Uint8List.fromList(tx.version).readUint32LE(0));
|
||||||
|
|
||||||
|
for (var i = 0; i < getGlobalInputCount(); i++) {
|
||||||
|
inputMaps.insert(i, <String, Uint8List>{});
|
||||||
|
while (_readKeyPair(inputMaps[i], bufferReader)) {}
|
||||||
|
final input = tx.inputs[i];
|
||||||
|
setInputOutputIndex(i, input.txIndex);
|
||||||
|
setInputPreviousTxId(i, Uint8List.fromList(BytesUtils.fromHexString(input.txId).reversed.toList()));
|
||||||
|
setInputSequence(i, Uint8List.fromList(input.sequence).readUint32LE(0));
|
||||||
|
}
|
||||||
|
for (var i = 0; i < getGlobalOutputCount(); i++) {
|
||||||
|
outputMaps.insert(i, <String, Uint8List>{});
|
||||||
|
while (_readKeyPair(outputMaps[i], bufferReader)) {}
|
||||||
|
final output = tx.outputs[i];
|
||||||
|
setOutputAmount(i, output.amount.toInt());
|
||||||
|
setOutputScript(i, Uint8List.fromList(output.scriptPubKey.toBytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _readKeyPair(Map<String, Uint8List> map, BufferReader bufferReader) {
|
||||||
|
final keyLen = bufferReader.readVarInt();
|
||||||
|
if (keyLen == 0) return false;
|
||||||
|
|
||||||
|
final keyType = bufferReader.readUInt8();
|
||||||
|
final keyData = bufferReader.readSlice(keyLen - 1);
|
||||||
|
final value = bufferReader.readVarSlice();
|
||||||
|
|
||||||
|
map.set(keyType, keyData, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
143
cw_bitcoin/lib/psbt/v0_finalizer.dart
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
import "dart:typed_data";
|
||||||
|
|
||||||
|
import "package:ledger_bitcoin/src/psbt/constants.dart";
|
||||||
|
import "package:ledger_bitcoin/src/psbt/psbtv2.dart";
|
||||||
|
import "package:ledger_bitcoin/src/utils/buffer_writer.dart";
|
||||||
|
|
||||||
|
/// This roughly implements the "input finalizer" role of BIP370 (PSBTv2
|
||||||
|
/// https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki). However
|
||||||
|
/// the role is documented in BIP174 (PSBTv0
|
||||||
|
/// https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki).
|
||||||
|
///
|
||||||
|
/// Verify that all inputs have a signature, and set inputFinalScriptwitness
|
||||||
|
/// and/or inputFinalScriptSig depending on the type of the spent outputs. Clean
|
||||||
|
/// fields that aren't useful anymore, partial signatures, redeem script and
|
||||||
|
/// derivation paths.
|
||||||
|
///
|
||||||
|
/// @param psbt The psbt with all signatures added as partial sigs, either
|
||||||
|
/// through PSBT_IN_PARTIAL_SIG or PSBT_IN_TAP_KEY_SIG
|
||||||
|
extension InputFinalizer on PsbtV2 {
|
||||||
|
void finalizeV0() {
|
||||||
|
|
||||||
|
// First check that each input has a signature
|
||||||
|
for (var i = 0; i < getGlobalInputCount(); i++) {
|
||||||
|
if (_isFinalized(i)) continue;
|
||||||
|
|
||||||
|
final legacyPubkeys = getInputKeyDatas(i, PSBTIn.partialSig);
|
||||||
|
final taprootSig = getInputTapKeySig(i);
|
||||||
|
if (legacyPubkeys.isEmpty && taprootSig == null) {
|
||||||
|
continue;
|
||||||
|
// throw Exception('No signature for input $i present');
|
||||||
|
}
|
||||||
|
if (legacyPubkeys.isNotEmpty) {
|
||||||
|
if (legacyPubkeys.length > 1) {
|
||||||
|
throw Exception(
|
||||||
|
'Expected exactly one signature, got ${legacyPubkeys.length}');
|
||||||
|
}
|
||||||
|
if (taprootSig != null) {
|
||||||
|
throw Exception('Both taproot and non-taproot signatures present.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final isSegwitV0 = getInputWitnessUtxo(i) != null;
|
||||||
|
final redeemScript = getInputRedeemScript(i);
|
||||||
|
final isWrappedSegwit = redeemScript != null;
|
||||||
|
final signature = getInputPartialSig(i, legacyPubkeys[0]);
|
||||||
|
if (signature == null) {
|
||||||
|
throw Exception('Expected partial signature for input $i');
|
||||||
|
}
|
||||||
|
if (isSegwitV0) {
|
||||||
|
final witnessBuf = BufferWriter()
|
||||||
|
..writeVarInt(2)
|
||||||
|
..writeVarInt(signature.length)
|
||||||
|
..writeSlice(signature)
|
||||||
|
..writeVarInt(legacyPubkeys[0].length)
|
||||||
|
..writeSlice(legacyPubkeys[0]);
|
||||||
|
setInputFinalScriptwitness(i, witnessBuf.buffer());
|
||||||
|
if (isWrappedSegwit) {
|
||||||
|
if (redeemScript.isEmpty) {
|
||||||
|
throw Exception(
|
||||||
|
"Expected non-empty redeemscript. Can't finalize intput $i");
|
||||||
|
}
|
||||||
|
final scriptSigBuf = BufferWriter()
|
||||||
|
..writeUInt8(redeemScript.length) // Push redeemScript length
|
||||||
|
..writeSlice(redeemScript);
|
||||||
|
setInputFinalScriptsig(i, scriptSigBuf.buffer());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Legacy input
|
||||||
|
final scriptSig = BufferWriter();
|
||||||
|
_writePush(scriptSig, signature);
|
||||||
|
_writePush(scriptSig, legacyPubkeys[0]);
|
||||||
|
setInputFinalScriptsig(i, scriptSig.buffer());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Taproot input
|
||||||
|
final signature = getInputTapKeySig(i);
|
||||||
|
if (signature == null) {
|
||||||
|
throw Exception("No taproot signature found");
|
||||||
|
}
|
||||||
|
if (signature.length != 64 && signature.length != 65) {
|
||||||
|
throw Exception("Unexpected length of schnorr signature.");
|
||||||
|
}
|
||||||
|
final witnessBuf = BufferWriter()
|
||||||
|
..writeVarInt(1)
|
||||||
|
..writeVarSlice(signature);
|
||||||
|
setInputFinalScriptwitness(i, witnessBuf.buffer());
|
||||||
|
}
|
||||||
|
clearFinalizedInput(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes fields that are no longer neccesary from the psbt.
|
||||||
|
///
|
||||||
|
/// Note, the spec doesn't say anything about removing ouput fields
|
||||||
|
/// like PSBT_OUT_BIP32_DERIVATION_PATH and others, so we keep them
|
||||||
|
/// without actually knowing why. I think we should remove them too.
|
||||||
|
void clearFinalizedInput(int inputIndex) {
|
||||||
|
final keyTypes = [
|
||||||
|
PSBTIn.bip32Derivation,
|
||||||
|
PSBTIn.partialSig,
|
||||||
|
PSBTIn.tapBip32Derivation,
|
||||||
|
PSBTIn.tapKeySig,
|
||||||
|
];
|
||||||
|
final witnessUtxoAvailable = getInputWitnessUtxo(inputIndex) != null;
|
||||||
|
final nonWitnessUtxoAvailable = getInputNonWitnessUtxo(inputIndex) != null;
|
||||||
|
if (witnessUtxoAvailable && nonWitnessUtxoAvailable) {
|
||||||
|
// Remove NON_WITNESS_UTXO for segwit v0 as it's only needed while signing.
|
||||||
|
// Segwit v1 doesn't have NON_WITNESS_UTXO set.
|
||||||
|
// See https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#cite_note-7
|
||||||
|
keyTypes.add(PSBTIn.nonWitnessUTXO);
|
||||||
|
}
|
||||||
|
deleteInputEntries(inputIndex, keyTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes a script push operation to buf, which looks different
|
||||||
|
/// depending on the size of the data. See
|
||||||
|
/// https://en.bitcoin.it/wiki/Script#finalants
|
||||||
|
///
|
||||||
|
/// [buf] the BufferWriter to write to
|
||||||
|
/// [data] the Buffer to be pushed.
|
||||||
|
void _writePush(BufferWriter buf, Uint8List data) {
|
||||||
|
if (data.length <= 75) {
|
||||||
|
buf.writeUInt8(data.length);
|
||||||
|
} else if (data.length <= 256) {
|
||||||
|
buf.writeUInt8(76);
|
||||||
|
buf.writeUInt8(data.length);
|
||||||
|
} else if (data.length <= 256 * 256) {
|
||||||
|
buf.writeUInt8(77);
|
||||||
|
final b = ByteData(2)..setUint16(0, data.length, Endian.little);
|
||||||
|
buf.writeSlice(b.buffer.asUint8List());
|
||||||
|
}
|
||||||
|
buf.writeSlice(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFinalized(int i) {
|
||||||
|
if (getInputFinalScriptsig(i) != null) return true;
|
||||||
|
try {
|
||||||
|
getInputFinalScriptwitness(i);
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,34 +5,39 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
|
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "47.0.0"
|
version: "76.0.0"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.3.3"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
|
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.7.0"
|
version: "6.11.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.0"
|
version: "2.7.0"
|
||||||
asn1lib:
|
asn1lib:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: asn1lib
|
name: asn1lib
|
||||||
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
|
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.8"
|
version: "1.5.9"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -80,7 +85,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: cake-update-v9
|
ref: cake-update-v9
|
||||||
resolved-ref: "86969a14e337383e14965f5fb45a72a63e5009bc"
|
resolved-ref: bb4318511312a454fd91bf49042e25ecc855e4ac
|
||||||
url: "https://github.com/cake-tech/bitcoin_base"
|
url: "https://github.com/cake-tech/bitcoin_base"
|
||||||
source: git
|
source: git
|
||||||
version: "4.7.0"
|
version: "4.7.0"
|
||||||
|
@ -121,50 +126,58 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.2"
|
||||||
|
build_cli_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_cli_annotations
|
||||||
|
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_config
|
name: build_config
|
||||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.2"
|
||||||
build_daemon:
|
build_daemon:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_daemon
|
name: build_daemon
|
||||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.4"
|
||||||
build_resolvers:
|
build_resolvers:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_resolvers
|
name: build_resolvers
|
||||||
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.10"
|
version: "2.4.4"
|
||||||
build_runner:
|
build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.13"
|
version: "2.4.15"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.10"
|
version: "8.0.0"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -177,10 +190,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
|
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.4"
|
version: "8.10.1"
|
||||||
cake_backup:
|
cake_backup:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -288,10 +301,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.4"
|
version: "2.3.8"
|
||||||
dart_varuint_bitcoin:
|
dart_varuint_bitcoin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -377,6 +390,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
flutter_rust_bridge:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_rust_bridge
|
||||||
|
sha256: "5a5c7a5deeef2cc2ffe6076a33b0429f4a20ceac22a397297aed2b1eb067e611"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.9.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -386,15 +407,23 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_web_bluetooth
|
name: flutter_web_bluetooth
|
||||||
sha256: "1363831def5eed1e1064d1eca04e8ccb35446e8f758579c3c519e156b77926da"
|
sha256: ad26a1b3fef95b86ea5f63793b9a0cdc1a33490f35d754e4e711046cae3ebbf8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
freezed_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: freezed_annotation
|
||||||
|
sha256: c87ff004c8aa6af2d531668b46a4ea379f7191dc6dfa066acd53d506da6e044b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
frontend_server_client:
|
frontend_server_client:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -415,18 +444,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: google_identity_services_web
|
name: google_identity_services_web
|
||||||
sha256: "55580f436822d64c8ff9a77e37d61f5fb1e6c7ec9d632a43ee324e2a05c3c6c9"
|
sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.3"
|
version: "0.3.3+1"
|
||||||
googleapis_auth:
|
googleapis_auth:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: googleapis_auth
|
name: googleapis_auth
|
||||||
sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938
|
sha256: b81fe352cc4a330b3710d2b7ad258d9bcef6f909bb759b306bf42973a7d046db
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.0"
|
version: "2.0.0"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -439,10 +468,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: grpc
|
name: grpc
|
||||||
sha256: "5b99b7a420937d4361ece68b798c9af8e04b5bc128a7859f2a4be87427694813"
|
sha256: "30e1edae6846b163a64f6d8716e3443980fe1f7d2d1f086f011d24ea186f2582"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.4"
|
||||||
hex:
|
hex:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -463,18 +492,18 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: hive_generator
|
name: hive_generator
|
||||||
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
|
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.3"
|
version: "2.0.1"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.4.0"
|
||||||
http2:
|
http2:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -495,10 +524,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http_parser
|
name: http_parser
|
||||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.1.2"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -559,7 +588,7 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "packages/ledger-bitcoin"
|
path: "packages/ledger-bitcoin"
|
||||||
ref: HEAD
|
ref: trunk
|
||||||
resolved-ref: e93254f3ff3f996fb91f65a1e7ceffb9f510b4c8
|
resolved-ref: e93254f3ff3f996fb91f65a1e7ceffb9f510b4c8
|
||||||
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
url: "https://github.com/cake-tech/ledger-flutter-plus-plugins"
|
||||||
source: git
|
source: git
|
||||||
|
@ -568,10 +597,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: ledger_flutter_plus
|
name: ledger_flutter_plus
|
||||||
sha256: "1c03f3c4a9754b5f0170a9eb9552ec54fa86e985f8ee71a255ee2c5629b53d31"
|
sha256: "531da5daba5731d9eca2732881ef2f039b97bf8aa3564e7098dfa99a9b07a8e6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.3"
|
||||||
ledger_litecoin:
|
ledger_litecoin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -597,6 +626,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
macros:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: macros
|
||||||
|
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3-main.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -641,10 +678,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: mobx_codegen
|
name: mobx_codegen
|
||||||
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
|
sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.7.1"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -666,10 +703,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_config
|
name: package_config
|
||||||
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
|
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.2.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -690,10 +727,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
|
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.15"
|
version: "2.2.17"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -726,6 +763,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
payjoin_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: da83a23f3a011cb49eb3b6513cd485b3fb8867ff
|
||||||
|
resolved-ref: da83a23f3a011cb49eb3b6513cd485b3fb8867ff
|
||||||
|
url: "https://github.com/OmarHatem28/payjoin-flutter"
|
||||||
|
source: git
|
||||||
|
version: "0.23.0"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -778,26 +824,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: provider
|
name: provider
|
||||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.2"
|
version: "6.1.5"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
|
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.2.0"
|
||||||
pubspec_parse:
|
pubspec_parse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pubspec_parse
|
name: pubspec_parse
|
||||||
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
|
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.5.0"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -826,18 +872,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
|
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.2"
|
version: "2.5.3"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
|
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.6"
|
version: "2.4.10"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -882,18 +928,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf
|
name: shelf
|
||||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.4.2"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_web_socket
|
name: shelf_web_socket
|
||||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "3.0.0"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -902,27 +948,37 @@ packages:
|
||||||
socks5_proxy:
|
socks5_proxy:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: socks5_proxy
|
path: "."
|
||||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||||
url: "https://pub.dev"
|
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||||
source: hosted
|
url: "https://github.com/LacticWhale/socks_dart"
|
||||||
version: "1.0.6"
|
source: git
|
||||||
|
version: "2.1.0"
|
||||||
|
socks_socket:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||||
|
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
|
||||||
|
url: "https://github.com/sneurlax/socks_socket"
|
||||||
|
source: git
|
||||||
|
version: "1.1.1"
|
||||||
source_gen:
|
source_gen:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.6"
|
version: "1.5.0"
|
||||||
source_helper:
|
source_helper:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_helper
|
name: source_helper
|
||||||
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.5"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -992,10 +1048,19 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: timing
|
name: timing
|
||||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.1"
|
||||||
|
tor_binary:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: cb811c610871a9517d47134b87c2f590c15c96c5
|
||||||
|
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
|
||||||
|
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
|
||||||
|
source: git
|
||||||
|
version: "4.7.14"
|
||||||
tuple:
|
tuple:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1016,10 +1081,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: universal_ble
|
name: universal_ble
|
||||||
sha256: "1fad089150a29db82b3b7d60327e18c5ad6b3a5bb509defc1c690b0a76b9c098"
|
sha256: "35d210e93a5938c6a6d1fd3c710cf4ac90b1bdd1b11c8eb2beeb32600672e6e6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.0"
|
version: "0.17.0"
|
||||||
universal_platform:
|
universal_platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1072,18 +1137,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket
|
name: web_socket
|
||||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.6"
|
version: "1.0.1"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
|
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.3"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1117,5 +1182,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.5.0 <4.0.0"
|
dart: ">=3.6.0 <4.0.0"
|
||||||
flutter: ">=3.24.0"
|
flutter: ">=3.27.0"
|
||||||
|
|
|
@ -40,23 +40,32 @@ dependencies:
|
||||||
bech32:
|
bech32:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bech32.git
|
url: https://github.com/cake-tech/bech32.git
|
||||||
|
payjoin_flutter:
|
||||||
|
git:
|
||||||
|
url: https://github.com/OmarHatem28/payjoin-flutter
|
||||||
|
ref: da83a23f3a011cb49eb3b6513cd485b3fb8867ff #cake-v2
|
||||||
ledger_flutter_plus: ^1.4.1
|
ledger_flutter_plus: ^1.4.1
|
||||||
ledger_bitcoin:
|
ledger_bitcoin:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||||
path: packages/ledger-bitcoin
|
path: packages/ledger-bitcoin
|
||||||
|
ref: trunk
|
||||||
ledger_litecoin:
|
ledger_litecoin:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||||
path: packages/ledger-litecoin
|
path: packages/ledger-litecoin
|
||||||
|
socks_socket:
|
||||||
|
git:
|
||||||
|
url: https://github.com/sneurlax/socks_socket
|
||||||
|
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.15
|
||||||
build_resolvers: ^2.0.9
|
build_resolvers: ^2.4.4
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
|
@ -7,7 +7,7 @@ homepage: https://cakewallet.com
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.19.0 <3.0.0'
|
sdk: '>=2.19.0 <3.0.0'
|
||||||
flutter: ">=1.17.0"
|
flutter: ">=1.20.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
@ -33,9 +33,9 @@ dependencies:
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.15
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
|
@ -111,7 +111,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
CryptoCurrency.zano,
|
CryptoCurrency.zano,
|
||||||
CryptoCurrency.ton,
|
CryptoCurrency.ton,
|
||||||
CryptoCurrency.flip,
|
CryptoCurrency.flip,
|
||||||
CryptoCurrency.deuro
|
CryptoCurrency.deuro,
|
||||||
|
CryptoCurrency.usdtbsc,
|
||||||
];
|
];
|
||||||
|
|
||||||
static const havenCurrencies = [
|
static const havenCurrencies = [
|
||||||
|
@ -232,7 +233,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static const ton = CryptoCurrency(title: 'TON', fullName: 'Toncoin', raw: 95, name: 'ton', iconPath: 'assets/images/ton_icon.png', decimals: 8);
|
static const ton = CryptoCurrency(title: 'TON', fullName: 'Toncoin', raw: 95, name: 'ton', iconPath: 'assets/images/ton_icon.png', decimals: 8);
|
||||||
static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/images/zano_icon.png', decimals: 12);
|
static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/images/zano_icon.png', decimals: 12);
|
||||||
static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18);
|
static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18);
|
||||||
static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Digital Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png', decimals: 18);
|
static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Decentralized Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png', decimals: 18);
|
||||||
|
static const usdtbsc = CryptoCurrency(title: 'USDT', tag: 'BSC', fullName: 'USDT Binance coin', raw: 99, name: 'usdtbsc', iconPath: 'assets/images/usdtbsc_icon.png', decimals: 18);
|
||||||
|
|
||||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||||
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
|
|
||||||
// FIXME: Hardcoded values; Works only for monero
|
// FIXME: Hardcoded values; Works only for monero
|
||||||
|
|
||||||
|
@ -234,10 +234,14 @@ int getHavenHeightByDate({required DateTime date}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> getHavenCurrentHeight() async {
|
Future<int> getHavenCurrentHeight() async {
|
||||||
final response = await http.get(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'));
|
final req = await ProxyWrapper().getHttpClient()
|
||||||
|
.getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'))
|
||||||
|
.timeout(Duration(seconds: 15));
|
||||||
|
final response = await req.close();
|
||||||
|
final stringResponse = await response.transform(utf8.decoder).join();
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final info = jsonDecode(response.body);
|
final info = jsonDecode(stringResponse);
|
||||||
return info['data']['height'] as int;
|
return info['data']['height'] as int;
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to load current blockchain height');
|
throw Exception('Failed to load current blockchain height');
|
||||||
|
@ -269,13 +273,13 @@ const bitcoinDates = {
|
||||||
};
|
};
|
||||||
|
|
||||||
Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
|
Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
|
||||||
final response = await http.get(
|
final req = await ProxyWrapper().getHttpClient()
|
||||||
Uri.parse(
|
.getUrl(Uri.parse("https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}"))
|
||||||
"https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}",
|
.timeout(Duration(seconds: 15));
|
||||||
),
|
final response = await req.close();
|
||||||
);
|
final stringResponse = await response.transform(utf8.decoder).join();
|
||||||
|
|
||||||
return jsonDecode(response.body)['height'] as int;
|
return jsonDecode(stringResponse)['height'] as int;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getBitcoinHeightByDate({required DateTime date}) {
|
int getBitcoinHeightByDate({required DateTime date}) {
|
||||||
|
|
|
@ -21,3 +21,4 @@ const HARDWARE_WALLET_TYPE_TYPE_ID = 19;
|
||||||
const MWEB_UTXO_TYPE_ID = 20;
|
const MWEB_UTXO_TYPE_ID = 20;
|
||||||
const HAVEN_SEED_STORE_TYPE_ID = 21;
|
const HAVEN_SEED_STORE_TYPE_ID = 21;
|
||||||
const ZANO_ASSET_TYPE_ID = 22;
|
const ZANO_ASSET_TYPE_ID = 22;
|
||||||
|
const PAYJOIN_SESSION_TYPE_ID = 23;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:cw_core/keyable.dart';
|
import 'package:cw_core/keyable.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
||||||
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:cw_core/hive_type_ids.dart';
|
import 'package:cw_core/hive_type_ids.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:http/io_client.dart' as ioc;
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'package:convert/convert.dart';
|
import 'package:convert/convert.dart';
|
||||||
|
|
||||||
|
@ -184,23 +184,17 @@ class Node extends HiveObject with Keyable {
|
||||||
final body = {'jsonrpc': '2.0', 'id': '0', 'method': "getinfo"};
|
final body = {'jsonrpc': '2.0', 'id': '0', 'method': "getinfo"};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final authenticatingClient = HttpClient();
|
|
||||||
authenticatingClient.badCertificateCallback =
|
|
||||||
((X509Certificate cert, String host, int port) => true);
|
|
||||||
|
|
||||||
final http.Client client = ioc.IOClient(authenticatingClient);
|
|
||||||
|
|
||||||
final jsonBody = json.encode(body);
|
final jsonBody = json.encode(body);
|
||||||
|
|
||||||
final response = await client.post(
|
final response = await ProxyWrapper().post(
|
||||||
rpcUri,
|
clearnetUri: rpcUri,
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: jsonBody,
|
body: jsonBody,
|
||||||
);
|
);
|
||||||
|
|
||||||
printV("node check response: ${response.body}");
|
|
||||||
|
|
||||||
final resBody = json.decode(response.body) as Map<String, dynamic>;
|
final resBody = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
return resBody['result']['height'] != null;
|
return resBody['result']['height'] != null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
printV("error: $e");
|
printV("error: $e");
|
||||||
|
@ -218,11 +212,7 @@ class Node extends HiveObject with Keyable {
|
||||||
final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName};
|
final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final authenticatingClient = HttpClient();
|
final client = ProxyWrapper().getHttpIOClient();
|
||||||
authenticatingClient.badCertificateCallback =
|
|
||||||
((X509Certificate cert, String host, int port) => true);
|
|
||||||
|
|
||||||
final http.Client client = ioc.IOClient(authenticatingClient);
|
|
||||||
|
|
||||||
final jsonBody = json.encode(body);
|
final jsonBody = json.encode(body);
|
||||||
|
|
||||||
|
@ -242,15 +232,15 @@ class Node extends HiveObject with Keyable {
|
||||||
return !(response['offline'] as bool);
|
return !(response['offline'] as bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
printV("node check response: ${response.body}");
|
final responseString = await response.body;
|
||||||
|
|
||||||
if ((response.body.contains("400 Bad Request") // Some other generic error
|
if ((responseString.contains("400 Bad Request") // Some other generic error
|
||||||
||
|
||
|
||||||
response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|
responseString.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|
||||||
||
|
||
|
||||||
response.headers["location"] != null // Generic reverse proxy
|
response.headers["location"] != null // Generic reverse proxy
|
||||||
||
|
||
|
||||||
response.body
|
responseString
|
||||||
.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
|
.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
|
||||||
) &&
|
) &&
|
||||||
!(useSSL ?? false)) {
|
!(useSSL ?? false)) {
|
||||||
|
@ -277,15 +267,16 @@ class Node extends HiveObject with Keyable {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> requestNodeWithProxy() async {
|
Future<bool> requestNodeWithProxy() async {
|
||||||
if (!isValidProxyAddress /* && !Tor.instance.enabled*/) {
|
if (!isValidProxyAddress && !CakeTor.instance.enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String? proxy = socksProxyAddress;
|
String? proxy = socksProxyAddress;
|
||||||
|
|
||||||
// if ((proxy?.isEmpty ?? true) && Tor.instance.enabled) {
|
if ((proxy?.isEmpty ?? true) && CakeTor.instance.enabled) {
|
||||||
// proxy = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
|
proxy = "${InternetAddress.loopbackIPv4.address}:${CakeTor.instance.port}";
|
||||||
// }
|
}
|
||||||
|
printV("proxy: $proxy");
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -305,13 +296,9 @@ class Node extends HiveObject with Keyable {
|
||||||
// you try to communicate with it
|
// you try to communicate with it
|
||||||
Future<bool> requestElectrumServer() async {
|
Future<bool> requestElectrumServer() async {
|
||||||
try {
|
try {
|
||||||
final Socket socket;
|
final ProxySocket socket;
|
||||||
if (useSSL == true) {
|
socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, uri.host, uri.port);
|
||||||
socket = await SecureSocket.connect(uri.host, uri.port,
|
|
||||||
timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
|
|
||||||
} else {
|
|
||||||
socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
return true;
|
return true;
|
||||||
|
@ -322,8 +309,8 @@ class Node extends HiveObject with Keyable {
|
||||||
|
|
||||||
Future<bool> requestNanoNode() async {
|
Future<bool> requestNanoNode() async {
|
||||||
try {
|
try {
|
||||||
final response = await http.post(
|
final response = await ProxyWrapper().post(
|
||||||
uri,
|
clearnetUri: uri,
|
||||||
headers: {"Content-Type": "application/json", "nano-app": "cake-wallet"},
|
headers: {"Content-Type": "application/json", "nano-app": "cake-wallet"},
|
||||||
body: jsonEncode(
|
body: jsonEncode(
|
||||||
{
|
{
|
||||||
|
@ -332,7 +319,8 @@ class Node extends HiveObject with Keyable {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final data = await jsonDecode(response.body);
|
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
if (response.statusCode != 200 ||
|
if (response.statusCode != 200 ||
|
||||||
data["error"] != null ||
|
data["error"] != null ||
|
||||||
data["balance"] == null ||
|
data["balance"] == null ||
|
||||||
|
@ -348,13 +336,14 @@ class Node extends HiveObject with Keyable {
|
||||||
|
|
||||||
Future<bool> requestEthereumServer() async {
|
Future<bool> requestEthereumServer() async {
|
||||||
try {
|
try {
|
||||||
final response = await http.get(
|
final req = await ProxyWrapper().getHttpClient()
|
||||||
uri,
|
.getUrl(uri,)
|
||||||
headers: {'Content-Type': 'application/json'},
|
.timeout(Duration(seconds: 15));
|
||||||
);
|
final response = await req.close();
|
||||||
|
|
||||||
return response.statusCode >= 200 && response.statusCode < 300;
|
return response.statusCode >= 200 && response.statusCode < 300;
|
||||||
} catch (_) {
|
} catch (err) {
|
||||||
|
printV("Failed to request ethereum server: $err");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,7 +451,7 @@ class DaemonRpc {
|
||||||
|
|
||||||
/// Perform a JSON-RPC call with Digest Authentication.
|
/// Perform a JSON-RPC call with Digest Authentication.
|
||||||
Future<Map<String, dynamic>> call(String method, Map<String, dynamic> params) async {
|
Future<Map<String, dynamic>> call(String method, Map<String, dynamic> params) async {
|
||||||
final http.Client client = http.Client();
|
final client = ProxyWrapper().getHttpIOClient();
|
||||||
final DigestAuth digestAuth = DigestAuth(username, password);
|
final DigestAuth digestAuth = DigestAuth(username, password);
|
||||||
|
|
||||||
// Initial request to get the `WWW-Authenticate` header.
|
// Initial request to get the `WWW-Authenticate` header.
|
||||||
|
|
67
cw_core/lib/payjoin_session.dart
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import 'package:cw_core/hive_type_ids.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
part 'payjoin_session.g.dart';
|
||||||
|
|
||||||
|
@HiveType(typeId: PAYJOIN_SESSION_TYPE_ID)
|
||||||
|
class PayjoinSession extends HiveObject {
|
||||||
|
PayjoinSession({
|
||||||
|
required this.walletId,
|
||||||
|
this.receiver,
|
||||||
|
this.sender,
|
||||||
|
this.pjUri,
|
||||||
|
this.status = "created",
|
||||||
|
this.inProgressSince,
|
||||||
|
this.rawAmount,
|
||||||
|
}) {
|
||||||
|
if (receiver == null) {
|
||||||
|
assert(sender != null);
|
||||||
|
assert(pjUri != null);
|
||||||
|
} else {
|
||||||
|
assert(receiver != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const typeId = PAYJOIN_SESSION_TYPE_ID;
|
||||||
|
static const boxName = 'PayjoinSessions';
|
||||||
|
|
||||||
|
@HiveField(0)
|
||||||
|
final String walletId;
|
||||||
|
|
||||||
|
@HiveField(1)
|
||||||
|
final String? sender;
|
||||||
|
|
||||||
|
@HiveField(2)
|
||||||
|
final String? receiver;
|
||||||
|
|
||||||
|
@HiveField(3)
|
||||||
|
final String? pjUri;
|
||||||
|
|
||||||
|
@HiveField(4)
|
||||||
|
String status;
|
||||||
|
|
||||||
|
@HiveField(5)
|
||||||
|
DateTime? inProgressSince;
|
||||||
|
|
||||||
|
@HiveField(6)
|
||||||
|
String? txId;
|
||||||
|
|
||||||
|
@HiveField(7)
|
||||||
|
String? rawAmount;
|
||||||
|
|
||||||
|
@HiveField(8)
|
||||||
|
String? error;
|
||||||
|
|
||||||
|
bool get isSenderSession => sender != null;
|
||||||
|
|
||||||
|
BigInt get amount => BigInt.parse(rawAmount ?? "0");
|
||||||
|
set amount(BigInt amount) => rawAmount = amount.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PayjoinSessionStatus {
|
||||||
|
created,
|
||||||
|
inProgress,
|
||||||
|
success,
|
||||||
|
unrecoverable,
|
||||||
|
}
|
|
@ -1,20 +1,19 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:http/http.dart';
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||||
import 'package:on_chain/solana/solana.dart';
|
import 'package:on_chain/solana/solana.dart';
|
||||||
|
|
||||||
class SolanaRPCHTTPService implements SolanaJSONRPCService {
|
class SolanaRPCHTTPService implements SolanaJSONRPCService {
|
||||||
SolanaRPCHTTPService(
|
SolanaRPCHTTPService(
|
||||||
{required this.url, Client? client, this.defaultRequestTimeout = const Duration(seconds: 30)})
|
{required this.url,
|
||||||
: client = client ?? Client();
|
this.defaultRequestTimeout = const Duration(seconds: 30)});
|
||||||
@override
|
@override
|
||||||
final String url;
|
final String url;
|
||||||
final Client client;
|
|
||||||
final Duration defaultRequestTimeout;
|
final Duration defaultRequestTimeout;
|
||||||
|
|
||||||
@override
|
Future<Map<String, dynamic>> call(SolanaRequestDetails params,
|
||||||
Future<Map<String, dynamic>> call(SolanaRequestDetails params, [Duration? timeout]) async {
|
[Duration? timeout]) async {
|
||||||
final response = await client.post(
|
final response = await ProxyWrapper().post(
|
||||||
Uri.parse(url),
|
clearnetUri: Uri.parse(url),
|
||||||
body: params.toRequestBody(),
|
body: params.toRequestBody(),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
29
cw_core/lib/utils/proxy_logger/abstract.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:http/http.dart' as very_insecure_http_do_not_use;
|
||||||
|
|
||||||
|
enum RequestNetwork {
|
||||||
|
clearnet,
|
||||||
|
tor,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RequestMethod {
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
put,
|
||||||
|
delete,
|
||||||
|
|
||||||
|
newHttpClient,
|
||||||
|
newHttpIOClient,
|
||||||
|
newProxySocket,
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ProxyLogger {
|
||||||
|
void log({
|
||||||
|
required Uri? uri,
|
||||||
|
required RequestMethod method,
|
||||||
|
required Uint8List body,
|
||||||
|
required very_insecure_http_do_not_use.Response? response,
|
||||||
|
required RequestNetwork network,
|
||||||
|
required String? error,
|
||||||
|
});
|
||||||
|
}
|
63
cw_core/lib/utils/proxy_logger/memory_proxy_logger.dart
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:cw_core/utils/proxy_logger/abstract.dart';
|
||||||
|
import 'package:http/http.dart' as very_insecure_http_do_not_use;
|
||||||
|
|
||||||
|
class MemoryProxyLoggerEntry {
|
||||||
|
MemoryProxyLoggerEntry({
|
||||||
|
required this.trace,
|
||||||
|
required this.uri,
|
||||||
|
required this.body,
|
||||||
|
required this.network,
|
||||||
|
required this.method,
|
||||||
|
required this.response,
|
||||||
|
required this.error,
|
||||||
|
}) : time = DateTime.now();
|
||||||
|
|
||||||
|
final StackTrace trace;
|
||||||
|
final Uri? uri;
|
||||||
|
final Uint8List body;
|
||||||
|
final RequestNetwork network;
|
||||||
|
final very_insecure_http_do_not_use.Response? response;
|
||||||
|
final RequestMethod method;
|
||||||
|
final String? error;
|
||||||
|
final DateTime time;
|
||||||
|
@override
|
||||||
|
String toString() => """MemoryProxyLoggerEntry(
|
||||||
|
uri: $uri,
|
||||||
|
body: $body,
|
||||||
|
network: $network,
|
||||||
|
method: $method,
|
||||||
|
response:
|
||||||
|
code: ${response?.statusCode},
|
||||||
|
headers: ${response?.headers},
|
||||||
|
body: ${response?.body},
|
||||||
|
error: $error,
|
||||||
|
time: $time,
|
||||||
|
trace: ${trace}
|
||||||
|
);""";
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemoryProxyLogger implements ProxyLogger {
|
||||||
|
static List<MemoryProxyLoggerEntry> logs = [];
|
||||||
|
@override
|
||||||
|
void log({
|
||||||
|
required Uri? uri,
|
||||||
|
required RequestMethod method,
|
||||||
|
required Uint8List body,
|
||||||
|
required very_insecure_http_do_not_use.Response? response,
|
||||||
|
required RequestNetwork network,
|
||||||
|
required String? error,
|
||||||
|
}) {
|
||||||
|
final trace = StackTrace.current;
|
||||||
|
logs.add(MemoryProxyLoggerEntry(
|
||||||
|
method: method,
|
||||||
|
trace: trace,
|
||||||
|
uri: uri,
|
||||||
|
body: body,
|
||||||
|
network: network,
|
||||||
|
response: response,
|
||||||
|
error: error,),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
cw_core/lib/utils/proxy_logger/silent_logger.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:cw_core/utils/proxy_logger/abstract.dart';
|
||||||
|
import 'package:http/http.dart' as very_insecure_http_do_not_use;
|
||||||
|
|
||||||
|
// we are not doing anything
|
||||||
|
class SilentProxyLogger implements ProxyLogger {
|
||||||
|
@override
|
||||||
|
void log({
|
||||||
|
required Uri? uri,
|
||||||
|
required RequestMethod method,
|
||||||
|
required Uint8List body,
|
||||||
|
required very_insecure_http_do_not_use.Response? response,
|
||||||
|
required RequestNetwork network,
|
||||||
|
required String? error,
|
||||||
|
}) {}
|
||||||
|
}
|