mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Compare commits
29 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 |
254 changed files with 7426 additions and 1901 deletions
10
.github/workflows/automated_integration_test.yml
vendored
10
.github/workflows/automated_integration_test.yml
vendored
|
@ -55,7 +55,7 @@ jobs:
|
|||
- name: Flutter action
|
||||
uses: subosito/flutter-action@v1
|
||||
with:
|
||||
flutter-version: "3.27.4"
|
||||
flutter-version: "3.27.0"
|
||||
channel: stable
|
||||
|
||||
- name: Install package dependencies
|
||||
|
@ -153,8 +153,8 @@ jobs:
|
|||
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> 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 changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> 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 wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> 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 twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> 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 anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> 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 moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/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 exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> 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
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
|
||||
|
2
.github/workflows/no_print_in_dart.yaml
vendored
2
.github/workflows/no_print_in_dart.yaml
vendored
|
@ -15,5 +15,5 @@ jobs:
|
|||
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
|
||||
echo "$GIT_GREP_OUT"
|
||||
echo "There are .dart files which use print() statements"
|
||||
echo "Please use printV from package: cw_core/utils/print_verbose.dart"
|
||||
echo "Please use printV from package:cw_core/utils/print_verbose.dart"
|
||||
exit 1
|
||||
|
|
15
.github/workflows/pr_test_build_android.yml
vendored
15
.github/workflows/pr_test_build_android.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
|||
PR_test_build:
|
||||
runs-on: linux-amd64
|
||||
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:
|
||||
STORE_PASS: test@cake_wallet
|
||||
KEY_PASS: test@cake_wallet
|
||||
|
@ -98,8 +98,8 @@ jobs:
|
|||
else
|
||||
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||
fi
|
||||
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> 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 wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> 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 twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> 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 anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> 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 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 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 exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> 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
|
||||
run: |
|
||||
flutter --version
|
||||
flutter clean
|
||||
rm -rf .dart_tool
|
||||
rm pubspec.lock
|
||||
flutter pub get
|
||||
./model_generator.sh async
|
||||
|
||||
- name: Generate key properties
|
||||
|
|
10
.github/workflows/pr_test_build_linux.yml
vendored
10
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
|||
PR_test_build:
|
||||
runs-on: linux-amd64
|
||||
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:
|
||||
STORE_PASS: test@cake_wallet
|
||||
KEY_PASS: test@cake_wallet
|
||||
|
@ -91,8 +91,8 @@ jobs:
|
|||
else
|
||||
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||
fi
|
||||
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowCakeWalletApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> 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 wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> 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 twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> 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 anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> 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 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 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 exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||
|
|
18
Dockerfile
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
|
||||
# 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
|
||||
|
||||
# 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
|
||||
# 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
|
||||
ENV ANDROID_PLATFORM_VERSION=35
|
||||
ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0
|
||||
|
@ -164,9 +164,12 @@ RUN (addgroup kvm || true) && \
|
|||
ENV PATH=${HOME}/.cargo/bin:${PATH}
|
||||
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \
|
||||
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; \
|
||||
do \
|
||||
rustup target add --toolchain stable $target; \
|
||||
rustup target add --toolchain $toolchain $target; \
|
||||
done \
|
||||
done
|
||||
|
||||
# Download and install Flutter
|
||||
|
@ -175,8 +178,11 @@ ENV FLUTTER_HOME=${HOME}/sdks/flutter/${FLUTTER_VERSION}
|
|||
ENV FLUTTER_ROOT=$FLUTTER_HOME
|
||||
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} \
|
||||
&& yes | flutter doctor --android-licenses \
|
||||
RUN git clone --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} && \
|
||||
cd ${FLUTTER_HOME} && \
|
||||
git fetch -a
|
||||
|
||||
RUN yes | flutter doctor --android-licenses \
|
||||
&& flutter doctor \
|
||||
&& chown -R root:root ${FLUTTER_HOME}
|
||||
|
||||
|
|
10
assets/images/history.svg
Normal file
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 |
3
assets/images/notif.svg
Normal file
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 |
BIN
assets/images/qr-cake.png
Normal file
BIN
assets/images/qr-cake.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 72 KiB |
76
assets/images/tor_logo.svg
Normal file
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
BIN
assets/images/usdtbsc_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 920 B |
|
@ -1,3 +1,4 @@
|
|||
New themes and UI/UX improvements
|
||||
Ledger flow enhancements
|
||||
Add built-in Tor support (experimental)
|
||||
Ledger improvements
|
||||
UI/UX improvements
|
||||
Bug fixes
|
|
@ -1,4 +1,9 @@
|
|||
New themes and UI/UX improvements
|
||||
Payjoin enhancements
|
||||
Ledger flow enhancements
|
||||
Add built-in Tor support (experimental)
|
||||
Add dEuro investments
|
||||
Solana fixes/enhancements
|
||||
Polygon fixes/enhancements
|
||||
WalletConnect improvements
|
||||
Ledger improvements
|
||||
Payjoin improvements
|
||||
UI/UX improvements
|
||||
Bug fixes
|
|
@ -266,6 +266,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
|||
derivationPath: walletInfo.derivationInfo!.derivationPath!);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close({bool shouldCleanup = false}) async {
|
||||
payjoinManager.cleanupSessions();
|
||||
super.close(shouldCleanup: shouldCleanup);
|
||||
}
|
||||
|
||||
late final PayjoinManager payjoinManager;
|
||||
|
||||
bool get isPayjoinAvailable => unspentCoinsInfo.values
|
||||
|
|
|
@ -31,12 +31,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
|
||||
final PayjoinManager payjoinManager;
|
||||
|
||||
@observable
|
||||
payjoin.Receiver? currentPayjoinReceiver;
|
||||
|
||||
@computed
|
||||
String? get payjoinEndpoint =>
|
||||
currentPayjoinReceiver?.pjUriBuilder().build().pjEndpoint();
|
||||
@observable
|
||||
String? payjoinEndpoint = null;
|
||||
|
||||
@override
|
||||
String getAddress(
|
||||
|
@ -59,16 +57,32 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
|||
return generateP2WPKHAddress(hd: hd, index: index, network: network);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> initPayjoin() async {
|
||||
currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress);
|
||||
try {
|
||||
await payjoinManager.initPayjoin();
|
||||
currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
|
||||
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
|
||||
|
||||
payjoinManager.resumeSessions();
|
||||
payjoinManager.resumeSessions();
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
// Ignore Connectivity errors
|
||||
if (!e.toString().contains("error sending request for url")) rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> newPayjoinReceiver() async {
|
||||
currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress);
|
||||
try {
|
||||
currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
|
||||
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
|
||||
|
||||
printV("Initializing new Payjoin Receiver");
|
||||
payjoinManager.spawnNewReceiver(receiver: currentPayjoinReceiver!);
|
||||
payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!);
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
// Ignore Connectivity errors
|
||||
if (!e.toString().contains("error sending request for url")) rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import 'dart:typed_data';
|
|||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_amount_format.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:rxdart/rxdart.dart';
|
||||
|
||||
|
@ -42,7 +44,7 @@ class ElectrumClient {
|
|||
static const aliveTimerDuration = Duration(seconds: 4);
|
||||
|
||||
bool get isConnected => _isConnected;
|
||||
Socket? socket;
|
||||
ProxySocket? socket;
|
||||
void Function(ConnectionStatus)? onConnectionStatusChange;
|
||||
int _id;
|
||||
final Map<String, SocketTask> _tasks;
|
||||
|
@ -72,18 +74,11 @@ class ElectrumClient {
|
|||
} catch (_) {}
|
||||
socket = null;
|
||||
|
||||
final ssl = !(useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum")));
|
||||
try {
|
||||
if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
|
||||
socket = await Socket.connect(host, port, timeout: connectionTimeout);
|
||||
} else {
|
||||
socket = await SecureSocket.connect(
|
||||
host,
|
||||
port,
|
||||
timeout: connectionTimeout,
|
||||
onBadCertificate: (_) => true,
|
||||
);
|
||||
}
|
||||
socket = await ProxyWrapper().getSocksSocket(ssl, host, port, connectionTimeout: connectionTimeout);
|
||||
} catch (e) {
|
||||
printV("connect: $e");
|
||||
if (e is HandshakeException) {
|
||||
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:
|
||||
// _setConnectionStatus(ConnectionStatus.connected);
|
||||
|
||||
socket!.listen(
|
||||
(Uint8List event) {
|
||||
try {
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||
import 'dart:isolate';
|
||||
|
||||
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_core/format_amount.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:sp_scanner/sp_scanner.dart';
|
||||
import 'package:hex/hex.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
part 'electrum_wallet.g.dart';
|
||||
|
||||
|
@ -493,10 +493,9 @@ abstract class ElectrumWalletBase
|
|||
Future<void> updateFeeRates() async {
|
||||
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
|
||||
try {
|
||||
final response = await http
|
||||
.get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
|
||||
.timeout(Duration(seconds: 5));
|
||||
|
||||
final response = await ProxyWrapper()
|
||||
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
|
||||
.timeout(Duration(seconds: 15));
|
||||
final result = json.decode(response.body) as Map<String, dynamic>;
|
||||
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
|
||||
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
|
||||
|
@ -1176,20 +1175,18 @@ abstract class ElectrumWalletBase
|
|||
}
|
||||
});
|
||||
|
||||
return PendingBitcoinTransaction(
|
||||
transaction,
|
||||
type,
|
||||
electrumClient: electrumClient,
|
||||
amount: estimatedTx.amount,
|
||||
fee: estimatedTx.fee,
|
||||
feeRate: feeRateInt.toString(),
|
||||
network: network,
|
||||
hasChange: estimatedTx.hasChange,
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: hasTaprootInputs,
|
||||
utxos: estimatedTx.utxos,
|
||||
publicKeys: estimatedTx.publicKeys
|
||||
)..addListener((transaction) async {
|
||||
return PendingBitcoinTransaction(transaction, type,
|
||||
electrumClient: electrumClient,
|
||||
amount: estimatedTx.amount,
|
||||
fee: estimatedTx.fee,
|
||||
feeRate: feeRateInt.toString(),
|
||||
network: network,
|
||||
hasChange: estimatedTx.hasChange,
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: hasTaprootInputs,
|
||||
utxos: estimatedTx.utxos,
|
||||
publicKeys: estimatedTx.publicKeys)
|
||||
..addListener((transaction) async {
|
||||
transactionHistory.addOne(transaction);
|
||||
if (estimatedTx.spendsSilentPayment) {
|
||||
transactionHistory.transactions.values.forEach((tx) {
|
||||
|
@ -1880,20 +1877,17 @@ abstract class ElectrumWalletBase
|
|||
|
||||
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
|
||||
try {
|
||||
final blockHash = await http.get(
|
||||
Uri.parse(
|
||||
"https://mempool.cakewallet.com/api/v1/block-height/$height",
|
||||
),
|
||||
);
|
||||
final blockHash = await ProxyWrapper()
|
||||
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block-height/$height"))
|
||||
.timeout(Duration(seconds: 15));
|
||||
|
||||
if (blockHash.statusCode == 200 &&
|
||||
blockHash.body.isNotEmpty &&
|
||||
jsonDecode(blockHash.body) != null) {
|
||||
final blockResponse = await http.get(
|
||||
Uri.parse(
|
||||
"https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
|
||||
),
|
||||
);
|
||||
final blockResponse = await ProxyWrapper()
|
||||
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block/${blockHash}"))
|
||||
.timeout(Duration(seconds: 15));
|
||||
|
||||
if (blockResponse.statusCode == 200 &&
|
||||
blockResponse.body.isNotEmpty &&
|
||||
jsonDecode(blockResponse.body)['timestamp'] != null) {
|
||||
|
|
|
@ -6,6 +6,7 @@ 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';
|
||||
|
@ -16,6 +17,7 @@ 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 {
|
||||
|
@ -31,11 +33,13 @@ class PayjoinManager {
|
|||
'https://ohttp.cakewallet.com',
|
||||
];
|
||||
|
||||
static Future<PayjoinUri.Url> randomOhttpRelayUrl() => PayjoinUri.Url.fromStr(
|
||||
ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)]);
|
||||
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);
|
||||
|
||||
|
@ -43,13 +47,13 @@ class PayjoinManager {
|
|||
if (session.isSenderSession) {
|
||||
printV("Resuming Payjoin Sender Session ${session.pjUri!}");
|
||||
return _spawnSender(
|
||||
sender: Sender.fromJson(session.sender!),
|
||||
sender: Sender.fromJson(json: session.sender!),
|
||||
pjUri: session.pjUri!,
|
||||
);
|
||||
}
|
||||
final receiver = Receiver.fromJson(session.receiver!);
|
||||
final receiver = Receiver.fromJson(json: session.receiver!);
|
||||
printV("Resuming Payjoin Receiver Session ${receiver.id()}");
|
||||
return _spawnReceiver(receiver: receiver);
|
||||
return spawnReceiver(receiver: receiver);
|
||||
});
|
||||
|
||||
printV("Resumed ${spawnedSessions.length} Payjoin Sessions");
|
||||
|
@ -66,7 +70,12 @@ class PayjoinManager {
|
|||
psbtBase64: originalPsbt,
|
||||
pjUri: pjUri,
|
||||
);
|
||||
return senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
|
||||
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');
|
||||
}
|
||||
|
@ -112,15 +121,13 @@ class PayjoinManager {
|
|||
}
|
||||
} catch (e) {
|
||||
_cleanupSession(pjUri);
|
||||
printV(e);
|
||||
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
|
||||
completer.completeError(e);
|
||||
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, e.toString());
|
||||
completer.complete();
|
||||
}
|
||||
} else if (message is PayjoinSessionError) {
|
||||
_cleanupSession(pjUri);
|
||||
if (message is UnrecoverableError) {
|
||||
printV(message.message);
|
||||
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
|
||||
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, message.message);
|
||||
completer.complete();
|
||||
} else if (message is RecoverableError) {
|
||||
completer.complete();
|
||||
|
@ -140,42 +147,41 @@ class PayjoinManager {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
Future<Receiver> initReceiver(String address,
|
||||
Future<Receiver> getUnusedReceiver(String address,
|
||||
[bool isTestnet = false]) async {
|
||||
try {
|
||||
final payjoinDirectory =
|
||||
await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
|
||||
final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id);
|
||||
|
||||
final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
|
||||
ohttpRelay: await randomOhttpRelayUrl(),
|
||||
payjoinDirectory: payjoinDirectory,
|
||||
);
|
||||
if (session != null) {
|
||||
await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
|
||||
|
||||
final receiver = await Receiver.create(
|
||||
address: address,
|
||||
network: isTestnet ? Network.testnet : Network.bitcoin,
|
||||
directory: payjoinDirectory,
|
||||
ohttpKeys: ohttpKeys,
|
||||
ohttpRelay: await randomOhttpRelayUrl(),
|
||||
);
|
||||
|
||||
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
|
||||
|
||||
return receiver;
|
||||
} catch (e) {
|
||||
throw Exception('Error initializing Payjoin Receiver: $e');
|
||||
return Receiver.fromJson(json: session.receiver!);
|
||||
}
|
||||
|
||||
return initReceiver(address);
|
||||
}
|
||||
|
||||
Future<void> spawnNewReceiver({
|
||||
required Receiver receiver,
|
||||
bool isTestnet = false,
|
||||
}) async {
|
||||
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 _spawnReceiver(isTestnet: isTestnet, receiver: receiver);
|
||||
|
||||
return receiver;
|
||||
}
|
||||
|
||||
Future<void> _spawnReceiver({
|
||||
Future<void> spawnReceiver({
|
||||
required Receiver receiver,
|
||||
bool isTestnet = false,
|
||||
}) async {
|
||||
|
@ -195,7 +201,8 @@ class PayjoinManager {
|
|||
rawAmount = getOutputAmountFromTx(tx, _wallet);
|
||||
break;
|
||||
case PayjoinReceiverRequestTypes.checkIsOwned:
|
||||
(_wallet.walletAddresses as BitcoinWalletAddresses).newPayjoinReceiver();
|
||||
(_wallet.walletAddresses as BitcoinWalletAddresses)
|
||||
.newPayjoinReceiver();
|
||||
_payjoinStorage.markReceiverSessionInProgress(receiver.id());
|
||||
|
||||
final inputScript = message['input_script'] as Uint8List;
|
||||
|
@ -219,6 +226,10 @@ class PayjoinManager {
|
|||
|
||||
case PayjoinReceiverRequestTypes.getCandidateInputs:
|
||||
utxos = _wallet.getUtxoWithPrivateKeys();
|
||||
if (utxos.isEmpty) {
|
||||
await _wallet.updateAllUnspents();
|
||||
utxos = _wallet.getUtxoWithPrivateKeys();
|
||||
}
|
||||
mainToIsolateSendPort?.send({
|
||||
'requestId': message['requestId'],
|
||||
'result': utxos,
|
||||
|
|
66
cw_bitcoin/lib/payjoin/payjoin_persister.dart
Normal file
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;
|
||||
}
|
|
@ -4,14 +4,16 @@ 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:http/http.dart' as http;
|
||||
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,
|
||||
|
@ -27,7 +29,7 @@ class PayjoinReceiverWorker {
|
|||
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();
|
||||
|
||||
|
@ -41,11 +43,10 @@ class PayjoinReceiverWorker {
|
|||
receivePort.listen(worker.handleMessage);
|
||||
|
||||
try {
|
||||
final httpClient = http.Client();
|
||||
final receiver = Receiver.fromJson(receiverJson);
|
||||
final receiver = Receiver.fromJson(json: receiverJson);
|
||||
|
||||
final uncheckedProposal =
|
||||
await worker.receiveUncheckedProposal(httpClient, receiver);
|
||||
await worker.receiveUncheckedProposal(receiver);
|
||||
|
||||
final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast();
|
||||
sendPort.send({
|
||||
|
@ -56,14 +57,14 @@ class PayjoinReceiverWorker {
|
|||
final payjoinProposal = await worker.processPayjoinProposal(
|
||||
uncheckedProposal,
|
||||
);
|
||||
final psbt = await worker.sendFinalProposal(httpClient, payjoinProposal);
|
||||
final psbt = await worker.sendFinalProposal(payjoinProposal);
|
||||
sendPort.send({
|
||||
'type': PayjoinReceiverRequestTypes.proposalSent,
|
||||
'psbt': psbt,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e is HttpException ||
|
||||
(e is http.ClientException &&
|
||||
(e is very_insecure_http_do_not_use.ClientException &&
|
||||
e.message.contains("Software caused connection abort"))) {
|
||||
sendPort.send(PayjoinSessionError.recoverable(e.toString()));
|
||||
} else {
|
||||
|
@ -97,15 +98,16 @@ class PayjoinReceiverWorker {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
Future<UncheckedProposal> receiveUncheckedProposal(
|
||||
http.Client httpClient, Receiver session) async {
|
||||
Future<UncheckedProposal> receiveUncheckedProposal(Receiver session) async {
|
||||
while (true) {
|
||||
printV("Polling for Proposal (${session.id()})");
|
||||
final extractReq = await session.extractReq();
|
||||
final extractReq = await session.extractReq(
|
||||
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
|
||||
);
|
||||
final request = extractReq.$1;
|
||||
|
||||
final url = Uri.parse(request.url.asString());
|
||||
final httpRequest = await httpClient.post(url,
|
||||
final httpRequest = await client.post(url,
|
||||
headers: {'Content-Type': request.contentType}, body: request.body);
|
||||
|
||||
final proposal = await session.processRes(
|
||||
|
@ -114,13 +116,14 @@ class PayjoinReceiverWorker {
|
|||
}
|
||||
}
|
||||
|
||||
Future<String> sendFinalProposal(
|
||||
http.Client httpClient, PayjoinProposal finalProposal) async {
|
||||
final req = await finalProposal.extractV2Req();
|
||||
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 httpClient.post(
|
||||
final request = await client.post(
|
||||
Uri.parse(proposalReq.url.asString()),
|
||||
headers: {"Content-Type": proposalReq.contentType},
|
||||
body: proposalReq.body,
|
||||
|
@ -171,7 +174,7 @@ class PayjoinReceiverWorker {
|
|||
final listUnspent =
|
||||
await _sendRequest(PayjoinReceiverRequestTypes.getCandidateInputs);
|
||||
final unspent = listUnspent as List<UtxoWithPrivateKey>;
|
||||
if (unspent.isEmpty) throw Exception('No unspent outputs available');
|
||||
if (unspent.isEmpty) throw RecoverableError('No unspent outputs available');
|
||||
|
||||
final selectedUtxo = await _inputPairFromUtxo(unspent[0]);
|
||||
final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]);
|
||||
|
@ -214,6 +217,6 @@ class PayjoinReceiverWorker {
|
|||
sequence: 0,
|
||||
);
|
||||
|
||||
return InputPair.newInstance(txin, psbtin);
|
||||
return InputPair.newInstance(txin: txin, psbtin: psbtin);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,12 @@ 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:http/http.dart' as http;
|
||||
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,
|
||||
|
@ -29,7 +31,7 @@ class PayjoinSenderWorker {
|
|||
final senderJson = args[1] as String;
|
||||
final pjUrl = args[2] as String;
|
||||
|
||||
final sender = Sender.fromJson(senderJson);
|
||||
final sender = Sender.fromJson(json: senderJson);
|
||||
final worker = PayjoinSenderWorker._(sendPort, pjUrl);
|
||||
|
||||
try {
|
||||
|
@ -42,19 +44,17 @@ class PayjoinSenderWorker {
|
|||
sendPort.send(e);
|
||||
}
|
||||
}
|
||||
final client = ProxyWrapper().getHttpIOClient();
|
||||
|
||||
/// Run a payjoin sender (V2 protocol first, fallback to V1).
|
||||
Future<String> runSender(Sender sender) async {
|
||||
final httpClient = http.Client();
|
||||
|
||||
try {
|
||||
return await _runSenderV2(sender, httpClient);
|
||||
return await _runSenderV2(sender);
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
if (e is PayjoinException &&
|
||||
// TODO condition on error type instead of message content
|
||||
e.message?.contains('parse receiver public key') == true) {
|
||||
return await _runSenderV1(sender, httpClient);
|
||||
if (e is pj_error.FfiCreateRequestError) {
|
||||
return await _runSenderV1(sender);
|
||||
} else if (e is HttpException) {
|
||||
printV(e);
|
||||
throw Exception(PayjoinSessionError.recoverable(e.toString()));
|
||||
|
@ -65,13 +65,14 @@ class PayjoinSenderWorker {
|
|||
}
|
||||
|
||||
/// Attempt to send payjoin using the V2 of the protocol.
|
||||
Future<String> _runSenderV2(Sender sender, http.Client httpClient) async {
|
||||
Future<String> _runSenderV2(Sender sender) async {
|
||||
try {
|
||||
final postRequest = await sender.extractV2(
|
||||
ohttpProxyUrl: await PayjoinManager.randomOhttpRelayUrl(),
|
||||
ohttpProxyUrl:
|
||||
await pj_uri.Url.fromStr(PayjoinManager.randomOhttpRelayUrl()),
|
||||
);
|
||||
|
||||
final postResult = await _postRequest(httpClient, postRequest.$1);
|
||||
final postResult = await _postRequest(postRequest.$1);
|
||||
final getContext =
|
||||
await postRequest.$2.processResponse(response: postResult);
|
||||
|
||||
|
@ -83,7 +84,7 @@ class PayjoinSenderWorker {
|
|||
final getRequest = await getContext.extractReq(
|
||||
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
|
||||
);
|
||||
final getRes = await _postRequest(httpClient, getRequest.$1);
|
||||
final getRes = await _postRequest(getRequest.$1);
|
||||
final proposalPsbt = await getContext.processResponse(
|
||||
response: getRes,
|
||||
ohttpCtx: getRequest.$2,
|
||||
|
@ -97,20 +98,20 @@ class PayjoinSenderWorker {
|
|||
}
|
||||
|
||||
/// Attempt to send payjoin using the V1 of the protocol.
|
||||
Future<String> _runSenderV1(Sender sender, http.Client httpClient) async {
|
||||
Future<String> _runSenderV1(Sender sender) async {
|
||||
try {
|
||||
final postRequest = await sender.extractV1();
|
||||
final response = await _postRequest(httpClient, postRequest.$1);
|
||||
final response = await _postRequest(postRequest.$1);
|
||||
|
||||
sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted});
|
||||
|
||||
return await postRequest.$2.processResponse(response: response);
|
||||
} catch (e) {
|
||||
throw PayjoinSessionError.unrecoverable('Send V1 payjoin error: $e');
|
||||
} catch (e, stack) {
|
||||
throw PayjoinSessionError.unrecoverable('Send V1 payjoin error: $e, $stack');
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<int>> _postRequest(http.Client client, Request req) async {
|
||||
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);
|
||||
|
||||
|
|
|
@ -23,6 +23,14 @@ class PayjoinStorage {
|
|||
),
|
||||
);
|
||||
|
||||
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}")!;
|
||||
|
@ -76,10 +84,11 @@ class PayjoinStorage {
|
|||
await session.save();
|
||||
}
|
||||
|
||||
Future<void> markSenderSessionUnrecoverable(String pjUrl) async {
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,34 +5,39 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "47.0.0"
|
||||
version: "76.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.3"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "6.11.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.7.0"
|
||||
asn1lib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: asn1lib
|
||||
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
|
||||
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.8"
|
||||
version: "1.5.9"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -121,10 +126,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
build_cli_annotations:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -137,42 +142,42 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.2"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.0.4"
|
||||
build_resolvers:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
||||
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
version: "2.4.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.10"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -185,10 +190,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
|
||||
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.4"
|
||||
version: "8.10.1"
|
||||
cake_backup:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -296,10 +301,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
||||
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.3.8"
|
||||
dart_varuint_bitcoin:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -389,10 +394,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_rust_bridge
|
||||
sha256: "3292ad6085552987b8b3b9a7e5805567f4013372d302736b702801acb001ee00"
|
||||
sha256: "5a5c7a5deeef2cc2ffe6076a33b0429f4a20ceac22a397297aed2b1eb067e611"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.1"
|
||||
version: "2.9.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -402,10 +407,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flutter_web_bluetooth
|
||||
sha256: "1363831def5eed1e1064d1eca04e8ccb35446e8f758579c3c519e156b77926da"
|
||||
sha256: ad26a1b3fef95b86ea5f63793b9a0cdc1a33490f35d754e4e711046cae3ebbf8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -415,10 +420,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
|
||||
sha256: c87ff004c8aa6af2d531668b46a4ea379f7191dc6dfa066acd53d506da6e044b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.4"
|
||||
version: "3.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -439,18 +444,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: google_identity_services_web
|
||||
sha256: "55580f436822d64c8ff9a77e37d61f5fb1e6c7ec9d632a43ee324e2a05c3c6c9"
|
||||
sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.3"
|
||||
version: "0.3.3+1"
|
||||
googleapis_auth:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: googleapis_auth
|
||||
sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938
|
||||
sha256: b81fe352cc4a330b3710d2b7ad258d9bcef6f909bb759b306bf42973a7d046db
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
version: "2.0.0"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -463,10 +468,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: grpc
|
||||
sha256: "5b99b7a420937d4361ece68b798c9af8e04b5bc128a7859f2a4be87427694813"
|
||||
sha256: "30e1edae6846b163a64f6d8716e3443980fe1f7d2d1f086f011d24ea186f2582"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
version: "4.0.4"
|
||||
hex:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -487,18 +492,18 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: hive_generator
|
||||
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
|
||||
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
version: "2.0.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
http2:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -519,10 +524,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -592,10 +597,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: ledger_flutter_plus
|
||||
sha256: "1c03f3c4a9754b5f0170a9eb9552ec54fa86e985f8ee71a255ee2c5629b53d31"
|
||||
sha256: "531da5daba5731d9eca2732881ef2f039b97bf8aa3564e7098dfa99a9b07a8e6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
version: "1.5.3"
|
||||
ledger_litecoin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -621,6 +626,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -665,10 +678,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobx_codegen
|
||||
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
|
||||
sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.7.1"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -690,10 +703,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.2.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -714,10 +727,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
|
||||
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.15"
|
||||
version: "2.2.17"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -754,11 +767,11 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "6a3eb32fb9467ac12e7b75d3de47de4ca44fd88c"
|
||||
resolved-ref: "6a3eb32fb9467ac12e7b75d3de47de4ca44fd88c"
|
||||
url: "https://github.com/konstantinullrich/payjoin-flutter"
|
||||
ref: da83a23f3a011cb49eb3b6513cd485b3fb8867ff
|
||||
resolved-ref: da83a23f3a011cb49eb3b6513cd485b3fb8867ff
|
||||
url: "https://github.com/OmarHatem28/payjoin-flutter"
|
||||
source: git
|
||||
version: "0.21.0"
|
||||
version: "0.23.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -811,26 +824,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
version: "6.1.5"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.5.0"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -859,18 +872,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
|
||||
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
version: "2.5.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
|
||||
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.6"
|
||||
version: "2.4.10"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -915,18 +928,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
version: "1.4.2"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -935,27 +948,37 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.6"
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
||||
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.5"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -973,14 +996,6 @@ packages:
|
|||
url: "https://github.com/cake-tech/sp_scanner"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sprintf
|
||||
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1033,10 +1048,19 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1057,10 +1081,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: universal_ble
|
||||
sha256: "1fad089150a29db82b3b7d60327e18c5ad6b3a5bb509defc1c690b0a76b9c098"
|
||||
sha256: "35d210e93a5938c6a6d1fd3c710cf4ac90b1bdd1b11c8eb2beeb32600672e6e6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.15.0"
|
||||
version: "0.17.0"
|
||||
universal_platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1077,14 +1101,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1121,18 +1137,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.0.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1166,5 +1182,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.2.2"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
|
|
|
@ -42,8 +42,8 @@ dependencies:
|
|||
url: https://github.com/cake-tech/bech32.git
|
||||
payjoin_flutter:
|
||||
git:
|
||||
url: https://github.com/konstantinullrich/payjoin-flutter
|
||||
ref: 6a3eb32fb9467ac12e7b75d3de47de4ca44fd88c #cake-v1
|
||||
url: https://github.com/OmarHatem28/payjoin-flutter
|
||||
ref: da83a23f3a011cb49eb3b6513cd485b3fb8867ff #cake-v2
|
||||
ledger_flutter_plus: ^1.4.1
|
||||
ledger_bitcoin:
|
||||
git:
|
||||
|
@ -54,14 +54,18 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||
path: packages/ledger-litecoin
|
||||
socks_socket:
|
||||
git:
|
||||
url: https://github.com/sneurlax/socks_socket
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_resolvers: ^2.0.9
|
||||
build_runner: ^2.4.15
|
||||
build_resolvers: ^2.4.4
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -7,7 +7,7 @@ homepage: https://cakewallet.com
|
|||
|
||||
environment:
|
||||
sdk: '>=2.19.0 <3.0.0'
|
||||
flutter: ">=1.17.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -33,9 +33,9 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -111,7 +111,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
CryptoCurrency.zano,
|
||||
CryptoCurrency.ton,
|
||||
CryptoCurrency.flip,
|
||||
CryptoCurrency.deuro
|
||||
CryptoCurrency.deuro,
|
||||
CryptoCurrency.usdtbsc,
|
||||
];
|
||||
|
||||
static const havenCurrencies = [
|
||||
|
@ -233,6 +234,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
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 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 =
|
||||
[...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:intl/intl.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
// FIXME: Hardcoded values; Works only for monero
|
||||
|
||||
|
@ -234,10 +234,14 @@ int getHavenHeightByDate({required DateTime date}) {
|
|||
}
|
||||
|
||||
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) {
|
||||
final info = jsonDecode(response.body);
|
||||
final info = jsonDecode(stringResponse);
|
||||
return info['data']['height'] as int;
|
||||
} else {
|
||||
throw Exception('Failed to load current blockchain height');
|
||||
|
@ -269,13 +273,13 @@ const bitcoinDates = {
|
|||
};
|
||||
|
||||
Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
|
||||
final response = await http.get(
|
||||
Uri.parse(
|
||||
"https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}",
|
||||
),
|
||||
);
|
||||
final req = await ProxyWrapper().getHttpClient()
|
||||
.getUrl(Uri.parse("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}) {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'dart:io';
|
||||
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 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:http/io_client.dart' as ioc;
|
||||
import 'dart:math' as math;
|
||||
import 'package:convert/convert.dart';
|
||||
|
||||
|
@ -184,23 +184,17 @@ class Node extends HiveObject with Keyable {
|
|||
final body = {'jsonrpc': '2.0', 'id': '0', 'method': "getinfo"};
|
||||
|
||||
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 response = await client.post(
|
||||
rpcUri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: rpcUri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonBody,
|
||||
);
|
||||
|
||||
printV("node check response: ${response.body}");
|
||||
|
||||
final resBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
return resBody['result']['height'] != null;
|
||||
} catch (e) {
|
||||
printV("error: $e");
|
||||
|
@ -218,11 +212,7 @@ class Node extends HiveObject with Keyable {
|
|||
final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName};
|
||||
|
||||
try {
|
||||
final authenticatingClient = HttpClient();
|
||||
authenticatingClient.badCertificateCallback =
|
||||
((X509Certificate cert, String host, int port) => true);
|
||||
|
||||
final http.Client client = ioc.IOClient(authenticatingClient);
|
||||
final client = ProxyWrapper().getHttpIOClient();
|
||||
|
||||
final jsonBody = json.encode(body);
|
||||
|
||||
|
@ -242,15 +232,15 @@ class Node extends HiveObject with Keyable {
|
|||
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.body
|
||||
responseString
|
||||
.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
|
||||
) &&
|
||||
!(useSSL ?? false)) {
|
||||
|
@ -277,15 +267,16 @@ class Node extends HiveObject with Keyable {
|
|||
}
|
||||
|
||||
Future<bool> requestNodeWithProxy() async {
|
||||
if (!isValidProxyAddress /* && !Tor.instance.enabled*/) {
|
||||
if (!isValidProxyAddress && !CakeTor.instance.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String? proxy = socksProxyAddress;
|
||||
|
||||
// if ((proxy?.isEmpty ?? true) && Tor.instance.enabled) {
|
||||
// proxy = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
|
||||
// }
|
||||
if ((proxy?.isEmpty ?? true) && CakeTor.instance.enabled) {
|
||||
proxy = "${InternetAddress.loopbackIPv4.address}:${CakeTor.instance.port}";
|
||||
}
|
||||
printV("proxy: $proxy");
|
||||
if (proxy == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -305,13 +296,9 @@ class Node extends HiveObject with Keyable {
|
|||
// you try to communicate with it
|
||||
Future<bool> requestElectrumServer() async {
|
||||
try {
|
||||
final Socket socket;
|
||||
if (useSSL == true) {
|
||||
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));
|
||||
}
|
||||
final ProxySocket socket;
|
||||
socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, uri.host, uri.port);
|
||||
|
||||
|
||||
socket.destroy();
|
||||
return true;
|
||||
|
@ -322,8 +309,8 @@ class Node extends HiveObject with Keyable {
|
|||
|
||||
Future<bool> requestNanoNode() async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: {"Content-Type": "application/json", "nano-app": "cake-wallet"},
|
||||
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 ||
|
||||
data["error"] != null ||
|
||||
data["balance"] == null ||
|
||||
|
@ -348,13 +336,14 @@ class Node extends HiveObject with Keyable {
|
|||
|
||||
Future<bool> requestEthereumServer() async {
|
||||
try {
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
);
|
||||
final req = await ProxyWrapper().getHttpClient()
|
||||
.getUrl(uri,)
|
||||
.timeout(Duration(seconds: 15));
|
||||
final response = await req.close();
|
||||
|
||||
return response.statusCode >= 200 && response.statusCode < 300;
|
||||
} catch (_) {
|
||||
} catch (err) {
|
||||
printV("Failed to request ethereum server: $err");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +451,7 @@ class DaemonRpc {
|
|||
|
||||
/// Perform a JSON-RPC call with Digest Authentication.
|
||||
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);
|
||||
|
||||
// Initial request to get the `WWW-Authenticate` header.
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import 'dart:convert';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:on_chain/solana/solana.dart';
|
||||
|
||||
class SolanaRPCHTTPService implements SolanaJSONRPCService {
|
||||
SolanaRPCHTTPService(
|
||||
{required this.url, Client? client, this.defaultRequestTimeout = const Duration(seconds: 30)})
|
||||
: client = client ?? Client();
|
||||
{required this.url,
|
||||
this.defaultRequestTimeout = const Duration(seconds: 30)});
|
||||
@override
|
||||
final String url;
|
||||
final Client client;
|
||||
final Duration defaultRequestTimeout;
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> call(SolanaRequestDetails params, [Duration? timeout]) async {
|
||||
final response = await client.post(
|
||||
Uri.parse(url),
|
||||
Future<Map<String, dynamic>> call(SolanaRequestDetails params,
|
||||
[Duration? timeout]) async {
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: Uri.parse(url),
|
||||
body: params.toRequestBody(),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
29
cw_core/lib/utils/proxy_logger/abstract.dart
Normal file
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
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
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,
|
||||
}) {}
|
||||
}
|
47
cw_core/lib/utils/proxy_socket/abstract.dart
Normal file
47
cw_core/lib/utils/proxy_socket/abstract.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:cw_core/utils/proxy_socket/insecure.dart';
|
||||
import 'package:cw_core/utils/proxy_socket/secure.dart';
|
||||
import 'package:cw_core/utils/proxy_socket/socks.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:socks_socket/socks_socket.dart';
|
||||
|
||||
class ProxyAddress {
|
||||
final String host;
|
||||
final int port;
|
||||
|
||||
ProxyAddress({required this.host, required this.port});
|
||||
}
|
||||
|
||||
abstract class ProxySocket {
|
||||
static Future<ProxySocket> connect(bool sslEnabled, ProxyAddress address, {Duration? connectionTimeout}) async {
|
||||
if (CakeTor.instance.started) {
|
||||
var socksSocket = await SOCKSSocket.create(
|
||||
proxyHost: InternetAddress.loopbackIPv4.address,
|
||||
proxyPort: CakeTor.instance.port,
|
||||
sslEnabled: sslEnabled,
|
||||
);
|
||||
await socksSocket.connect();
|
||||
await socksSocket.connectTo(address.host, address.port);
|
||||
return ProxySocketSocks(socksSocket);
|
||||
}
|
||||
if (sslEnabled == false) {
|
||||
return ProxySocketInsecure(await Socket.connect(address.host, address.port, timeout: connectionTimeout));
|
||||
} else {
|
||||
return ProxySocketSecure(await SecureSocket.connect(
|
||||
address.host,
|
||||
address.port,
|
||||
timeout: connectionTimeout,
|
||||
onBadCertificate: (_) => true,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> close();
|
||||
Future<void> destroy();
|
||||
Future<void> write(String data);
|
||||
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function (Object error)? onError, Function ()? onDone, bool cancelOnError = true});
|
||||
ProxyAddress get address;
|
||||
}
|
34
cw_core/lib/utils/proxy_socket/insecure.dart
Normal file
34
cw_core/lib/utils/proxy_socket/insecure.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:io';
|
||||
|
||||
class ProxySocketInsecure implements ProxySocket {
|
||||
final Socket socket;
|
||||
|
||||
ProxySocketInsecure(this.socket);
|
||||
|
||||
ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort);
|
||||
|
||||
@override
|
||||
Future<void> close() => socket.close();
|
||||
|
||||
@override
|
||||
Future<void> destroy() async => socket.destroy();
|
||||
|
||||
@override
|
||||
Future<void> write(String data) async => socket.write(data);
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
|
||||
return socket.listen(
|
||||
(data) {
|
||||
onData(Uint8List.fromList(data));
|
||||
},
|
||||
onError: onError,
|
||||
onDone: onDone,
|
||||
cancelOnError: cancelOnError,
|
||||
);
|
||||
}
|
||||
}
|
34
cw_core/lib/utils/proxy_socket/secure.dart
Normal file
34
cw_core/lib/utils/proxy_socket/secure.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
||||
|
||||
class ProxySocketSecure implements ProxySocket {
|
||||
final SecureSocket socket;
|
||||
|
||||
ProxySocketSecure(this.socket);
|
||||
|
||||
ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort);
|
||||
|
||||
@override
|
||||
Future<void> close() => socket.close();
|
||||
|
||||
@override
|
||||
Future<void> destroy() async => socket.destroy();
|
||||
|
||||
@override
|
||||
Future<void> write(String data) async => socket.write(data);
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
|
||||
return socket.listen(
|
||||
(data) {
|
||||
onData(Uint8List.fromList(data));
|
||||
},
|
||||
onError: onError,
|
||||
onDone: onDone,
|
||||
cancelOnError: cancelOnError,
|
||||
);
|
||||
}
|
||||
}
|
36
cw_core/lib/utils/proxy_socket/socks.dart
Normal file
36
cw_core/lib/utils/proxy_socket/socks.dart
Normal file
|
@ -0,0 +1,36 @@
|
|||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
||||
import 'package:socks_socket/socks_socket.dart';
|
||||
|
||||
class ProxySocketSocks implements ProxySocket {
|
||||
final SOCKSSocket socket;
|
||||
|
||||
ProxySocketSocks(this.socket);
|
||||
|
||||
@override
|
||||
ProxyAddress get address => ProxyAddress(host: socket.proxyHost, port: socket.proxyPort);
|
||||
|
||||
@override
|
||||
Future<void> close() => socket.close();
|
||||
|
||||
@override
|
||||
Future<void> destroy() => close();
|
||||
|
||||
@override
|
||||
Future<void> write(String data) async => socket.write(data);
|
||||
|
||||
@override
|
||||
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
|
||||
return socket.listen(
|
||||
(data) {
|
||||
onData(Uint8List.fromList(data));
|
||||
},
|
||||
onError: onError,
|
||||
onDone: onDone,
|
||||
cancelOnError: cancelOnError,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
447
cw_core/lib/utils/proxy_wrapper.dart
Normal file
447
cw_core/lib/utils/proxy_wrapper.dart
Normal file
|
@ -0,0 +1,447 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:cw_core/utils/proxy_logger/abstract.dart';
|
||||
import 'package:cw_core/utils/proxy_socket/abstract.dart';
|
||||
import 'package:cw_core/utils/tor/abstract.dart';
|
||||
import 'package:cw_core/utils/tor/android.dart';
|
||||
import 'package:cw_core/utils/tor/disabled.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:socks5_proxy/socks_client.dart';
|
||||
import 'package:http/io_client.dart' as ioc;
|
||||
|
||||
class ProxyWrapper {
|
||||
static final ProxyWrapper _proxyWrapper = ProxyWrapper._internal();
|
||||
static ProxyLogger? logger;
|
||||
|
||||
factory ProxyWrapper() {
|
||||
return _proxyWrapper;
|
||||
}
|
||||
|
||||
ProxyWrapper._internal();
|
||||
Future<ProxySocket> getSocksSocket(bool sslEnabled, String host, int port, {Duration? connectionTimeout}) async {
|
||||
logger?.log(
|
||||
uri: Uri(
|
||||
scheme: sslEnabled ? "https" : "http",
|
||||
host: host,
|
||||
port: port,
|
||||
),
|
||||
method: RequestMethod.newProxySocket,
|
||||
body: Uint8List(0),
|
||||
response: null,
|
||||
network: requestNetwork(),
|
||||
error: null
|
||||
);
|
||||
return ProxySocket.connect(sslEnabled, ProxyAddress(host: host, port: port), connectionTimeout: connectionTimeout);
|
||||
}
|
||||
|
||||
RequestNetwork requestNetwork() {
|
||||
return CakeTor.instance.started ? RequestNetwork.tor : RequestNetwork.clearnet;
|
||||
}
|
||||
|
||||
ioc.IOClient getHttpIOClient({int? portOverride, bool internal = false}) {
|
||||
if (!internal) {
|
||||
logger?.log(
|
||||
uri: null,
|
||||
method: RequestMethod.newHttpIOClient,
|
||||
body: Uint8List(0),
|
||||
response: null,
|
||||
network: requestNetwork(),
|
||||
error: null,
|
||||
);
|
||||
}
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
final httpClient = ProxyWrapper().getHttpClient(portOverride: portOverride, internal: true);
|
||||
return ioc.IOClient(httpClient);
|
||||
}
|
||||
|
||||
int getPort() => CakeTor.instance.port;
|
||||
|
||||
@Deprecated('Use ProxyWrapper().get/post/put methods instead, and provide proper clearnet and onion uri.')
|
||||
HttpClient getHttpClient({int? portOverride, bool internal = false}) {
|
||||
if (!internal) {
|
||||
logger?.log(
|
||||
uri: null,
|
||||
method: RequestMethod.newProxySocket,
|
||||
body: Uint8List(0),
|
||||
response: null,
|
||||
network: requestNetwork(),
|
||||
error: null
|
||||
);
|
||||
}
|
||||
if (CakeTor.instance.started) {
|
||||
// Assign connection factory.
|
||||
final client = HttpClient();
|
||||
SocksTCPClient.assignToHttpClient(client, [
|
||||
ProxySettings(
|
||||
InternetAddress.loopbackIPv4,
|
||||
CakeTor.instance.port,
|
||||
password: null,
|
||||
),
|
||||
]);
|
||||
return client;
|
||||
} else {
|
||||
return HttpClient();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Future<Response> _make({
|
||||
required RequestMethod method,
|
||||
required ioc.IOClient client,
|
||||
required Uri uri,
|
||||
required Map<String, String>? headers,
|
||||
String? body,
|
||||
}) async {
|
||||
Object? error;
|
||||
Response? resp;
|
||||
try {
|
||||
switch (method) {
|
||||
case RequestMethod.get:
|
||||
resp = await client. get(
|
||||
uri,
|
||||
headers: headers,
|
||||
);
|
||||
break;
|
||||
case RequestMethod.delete:
|
||||
resp = await client.delete(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
break;
|
||||
case RequestMethod.post:
|
||||
resp = await client.post(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
break;
|
||||
case RequestMethod.put:
|
||||
resp = await client.put(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
break;
|
||||
case RequestMethod.newHttpClient:
|
||||
case RequestMethod.newHttpIOClient:
|
||||
case RequestMethod.newProxySocket:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
return resp;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
rethrow;
|
||||
} finally {
|
||||
logger?.log(
|
||||
uri: uri,
|
||||
method: RequestMethod.get,
|
||||
body: utf8.encode(body ?? ''),
|
||||
response: resp,
|
||||
network: requestNetwork(),
|
||||
error: error?.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Response> get({
|
||||
Map<String, String>? headers,
|
||||
int? portOverride,
|
||||
Uri? clearnetUri,
|
||||
Uri? onionUri,
|
||||
}) async {
|
||||
ioc.IOClient? torClient;
|
||||
bool torEnabled = CakeTor.instance.started;
|
||||
|
||||
if (CakeTor.instance.started) {
|
||||
torEnabled = true;
|
||||
} else {
|
||||
torEnabled = false;
|
||||
}
|
||||
|
||||
// if tor is enabled, try to connect to the onion url first:
|
||||
if (torEnabled) {
|
||||
try {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
if (onionUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.get,
|
||||
client: torClient,
|
||||
uri: onionUri,
|
||||
headers: headers,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.get,
|
||||
client: torClient,
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return HttpOverrides.runZoned(
|
||||
() async {
|
||||
return await _make(
|
||||
method: RequestMethod.get,
|
||||
client: ioc.IOClient(),
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (_) {
|
||||
// we weren't able to get a response:
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("Unable to connect to server");
|
||||
}
|
||||
|
||||
|
||||
Future<Response> post({
|
||||
Map<String, String>? headers,
|
||||
int? portOverride,
|
||||
Uri? clearnetUri,
|
||||
Uri? onionUri,
|
||||
String? body,
|
||||
bool allowMitmMoneroBypassSSLCheck = false,
|
||||
}) async {
|
||||
HttpClient? torHttpClient;
|
||||
HttpClient cleatnetHttpClient = HttpClient();
|
||||
if (allowMitmMoneroBypassSSLCheck) {
|
||||
cleatnetHttpClient.badCertificateCallback =
|
||||
((X509Certificate cert, String host, int port) => true);
|
||||
}
|
||||
|
||||
ioc.IOClient clearnetClient = ioc.IOClient(cleatnetHttpClient);
|
||||
|
||||
|
||||
bool torEnabled = CakeTor.instance.started;
|
||||
|
||||
if (torEnabled) {
|
||||
try {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
torHttpClient = await getHttpClient(portOverride: portOverride);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
if (allowMitmMoneroBypassSSLCheck) {
|
||||
torHttpClient.badCertificateCallback =
|
||||
((X509Certificate cert, String host, int port) => true);
|
||||
}
|
||||
if (onionUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.post,
|
||||
client: ioc.IOClient(torHttpClient),
|
||||
uri: onionUri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.post,
|
||||
client: ioc.IOClient(torHttpClient),
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return HttpOverrides.runZoned(
|
||||
() async {
|
||||
return await _make(
|
||||
method: RequestMethod.post,
|
||||
client: clearnetClient,
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("Unable to connect to server");
|
||||
}
|
||||
|
||||
Future<Response> put({
|
||||
Map<String, String>? headers,
|
||||
int? portOverride,
|
||||
Uri? clearnetUri,
|
||||
Uri? onionUri,
|
||||
String? body,
|
||||
}) async {
|
||||
ioc.IOClient? torClient;
|
||||
bool torEnabled = CakeTor.instance.started;
|
||||
|
||||
if (torEnabled) {
|
||||
try {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
|
||||
} catch (_) {}
|
||||
|
||||
if (onionUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.put,
|
||||
client: torClient!,
|
||||
uri: onionUri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.put,
|
||||
client: torClient!,
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return HttpOverrides.runZoned(
|
||||
() async {
|
||||
return await _make(
|
||||
method: RequestMethod.put,
|
||||
client: ioc.IOClient(),
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (_) {
|
||||
// we weren't able to get a response:
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("Unable to connect to server");
|
||||
}
|
||||
|
||||
Future<Response> delete({
|
||||
Map<String, String>? headers,
|
||||
int? portOverride,
|
||||
Uri? clearnetUri,
|
||||
Uri? onionUri,
|
||||
}) async {
|
||||
ioc.IOClient? torClient;
|
||||
bool torEnabled = CakeTor.instance.started;
|
||||
|
||||
if (CakeTor.instance.started) {
|
||||
torEnabled = true;
|
||||
} else {
|
||||
torEnabled = false;
|
||||
}
|
||||
|
||||
// if tor is enabled, try to connect to the onion url first:
|
||||
if (torEnabled) {
|
||||
try {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
if (onionUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.delete,
|
||||
client: torClient,
|
||||
uri: onionUri,
|
||||
headers: headers,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return await _make(
|
||||
method: RequestMethod.delete,
|
||||
client: torClient,
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clearnetUri != null) {
|
||||
try {
|
||||
return HttpOverrides.runZoned(
|
||||
() async {
|
||||
return await _make(
|
||||
method: RequestMethod.delete,
|
||||
client: ioc.IOClient(),
|
||||
uri: clearnetUri,
|
||||
headers: headers,
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (_) {
|
||||
// we weren't able to get a response:
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception("Unable to connect to server");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CakeTor {
|
||||
static final CakeTorInstance instance = CakeTorInstance.getInstance();
|
||||
}
|
38
cw_core/lib/utils/tor/abstract.dart
Normal file
38
cw_core/lib/utils/tor/abstract.dart
Normal file
|
@ -0,0 +1,38 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/tor/android.dart';
|
||||
import 'package:cw_core/utils/tor/disabled.dart';
|
||||
import 'package:cw_core/utils/tor/tails.dart';
|
||||
|
||||
abstract class CakeTorInstance {
|
||||
bool get started;
|
||||
|
||||
int get port => -1;
|
||||
|
||||
bool get enabled => false;
|
||||
|
||||
bool get bootstrapped => false;
|
||||
|
||||
Future<void> start();
|
||||
Future<void> stop();
|
||||
|
||||
static CakeTorInstance getInstance() {
|
||||
if (Platform.isAndroid) {
|
||||
return CakeTorAndroid();
|
||||
}
|
||||
if (Platform.isLinux) {
|
||||
try {
|
||||
final os = File("/etc/os-release").readAsLinesSync();
|
||||
for (var line in os) {
|
||||
if (!line.startsWith("ID=")) continue;
|
||||
if (!line.contains("tails")) continue;
|
||||
return CakeTorTails();
|
||||
}
|
||||
} catch (e) {
|
||||
printV("Failed to identify linux version - /etc/os-release missing");
|
||||
}
|
||||
}
|
||||
return CakeTorDisabled();
|
||||
}
|
||||
}
|
73
cw_core/lib/utils/tor/android.dart
Normal file
73
cw_core/lib/utils/tor/android.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/tor/abstract.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:tor_binary/tor_binary_platform_interface.dart';
|
||||
|
||||
class CakeTorAndroid implements CakeTorInstance {
|
||||
@override
|
||||
bool get bootstrapped => _proc != null;
|
||||
|
||||
@override
|
||||
bool get enabled => _proc != null;
|
||||
|
||||
@override
|
||||
int get port => 42142;
|
||||
|
||||
@override
|
||||
Future<void> start() async {
|
||||
await _runEmbeddedTor();
|
||||
}
|
||||
|
||||
@override
|
||||
bool get started => _proc != null;
|
||||
|
||||
@override
|
||||
Future<void> stop() async {
|
||||
_proc?.kill();
|
||||
await _proc?.exitCode;
|
||||
_proc = null;
|
||||
}
|
||||
|
||||
static Process? _proc;
|
||||
|
||||
Future<void> _runEmbeddedTor() async {
|
||||
final dir = await getApplicationCacheDirectory();
|
||||
|
||||
final torBinPath = p.join((await TorBinaryPlatform.instance.getBinaryPath())!, "libtor.so");
|
||||
printV("torPath: $torBinPath");
|
||||
|
||||
if (started) {
|
||||
printV("Proxy is running");
|
||||
return;
|
||||
}
|
||||
|
||||
printV("Starting embedded tor");
|
||||
printV("app docs: $dir");
|
||||
final torrc = """
|
||||
SocksPort $port
|
||||
Log notice file ${p.join(dir.path, "tor.log")}
|
||||
RunAsDaemon 0
|
||||
DataDirectory ${p.join(dir.path, "tor-data")}
|
||||
""";
|
||||
final torrcPath = p.join(dir.absolute.path, "torrc");
|
||||
File(torrcPath).writeAsStringSync(torrc);
|
||||
|
||||
if (_proc != null) {
|
||||
try {
|
||||
_proc?.kill();
|
||||
await _proc?.exitCode;
|
||||
_proc = null;
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
}
|
||||
}
|
||||
printV("path: $torBinPath -f $torrcPath");
|
||||
_proc = await Process.start(torBinPath, ["-f", torrcPath]);
|
||||
_proc?.stdout.transform(utf8.decoder).forEach(printV);
|
||||
_proc?.stderr.transform(utf8.decoder).forEach(printV);
|
||||
}
|
||||
}
|
21
cw_core/lib/utils/tor/disabled.dart
Normal file
21
cw_core/lib/utils/tor/disabled.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:cw_core/utils/tor/abstract.dart';
|
||||
|
||||
class CakeTorDisabled implements CakeTorInstance {
|
||||
@override
|
||||
bool get bootstrapped => false;
|
||||
|
||||
@override
|
||||
bool get enabled => false;
|
||||
|
||||
@override
|
||||
int get port => -1;
|
||||
|
||||
@override
|
||||
Future<void> start() => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
bool get started => false;
|
||||
|
||||
@override
|
||||
Future<void> stop() => throw UnimplementedError();
|
||||
}
|
21
cw_core/lib/utils/tor/tails.dart
Normal file
21
cw_core/lib/utils/tor/tails.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:cw_core/utils/tor/abstract.dart';
|
||||
|
||||
class CakeTorTails implements CakeTorInstance {
|
||||
@override
|
||||
bool get bootstrapped => true;
|
||||
|
||||
@override
|
||||
bool get enabled => true;
|
||||
|
||||
@override
|
||||
int get port => 9150;
|
||||
|
||||
@override
|
||||
Future<void> start() async {}
|
||||
|
||||
@override
|
||||
bool get started => true;
|
||||
|
||||
@override
|
||||
Future<void> stop() async {}
|
||||
}
|
|
@ -26,18 +26,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.7.0"
|
||||
asn1lib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: asn1lib
|
||||
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
|
||||
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.8"
|
||||
version: "1.5.9"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -67,50 +67,50 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.2"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.0.4"
|
||||
build_resolvers:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
version: "2.4.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.2"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -123,10 +123,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
|
||||
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.4"
|
||||
version: "8.10.1"
|
||||
cake_backup:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -212,10 +212,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
|
||||
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
version: "2.3.8"
|
||||
decimal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -326,10 +326,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -342,10 +342,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -462,10 +462,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobx_codegen
|
||||
sha256: "990da80722f7d7c0017dec92040b31545d625b15d40204c36a1e63d167c73cdc"
|
||||
sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
version: "2.7.1"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -479,7 +479,7 @@ packages:
|
|||
description:
|
||||
path: "."
|
||||
ref: cake-update-v2
|
||||
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
|
||||
resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
|
||||
url: "https://github.com/cake-tech/on_chain.git"
|
||||
source: git
|
||||
version: "3.7.0"
|
||||
|
@ -487,10 +487,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.2.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -511,10 +511,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
|
||||
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.15"
|
||||
version: "2.2.17"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -583,26 +583,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
version: "6.1.5"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.5.0"
|
||||
rational:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -615,18 +615,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
version: "1.4.2"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -635,11 +635,21 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -716,10 +726,19 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
version: "1.0.1"
|
||||
tor_binary:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: cb811c610871a9517d47134b87c2f590c15c96c5
|
||||
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
|
||||
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
|
||||
source: git
|
||||
version: "4.7.14"
|
||||
tuple:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -780,18 +799,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.0.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -809,5 +828,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
|
|
|
@ -25,22 +25,29 @@ dependencies:
|
|||
url: https://github.com/cake-tech/cake_backup.git
|
||||
ref: main
|
||||
version: 1.0.0
|
||||
socks5_proxy: ^1.0.4
|
||||
socks5_proxy:
|
||||
git:
|
||||
url: https://github.com/LacticWhale/socks_dart
|
||||
ref: 27ad7c2efae8d7460325c74b90f660085cbd0685
|
||||
unorm_dart: ^0.3.0
|
||||
on_chain:
|
||||
git:
|
||||
url: https://github.com/cake-tech/on_chain.git
|
||||
ref: cake-update-v2
|
||||
# tor:
|
||||
# git:
|
||||
# url: https://github.com/cake-tech/tor.git
|
||||
# ref: main
|
||||
socks_socket:
|
||||
git:
|
||||
url: https://github.com/sneurlax/socks_socket
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
tor_binary:
|
||||
git:
|
||||
url: https://github.com/MrCyjaneK/flutter-tor_binary
|
||||
ref: cb811c610871a9517d47134b87c2f590c15c96c5
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_resolvers: ^2.0.9
|
||||
build_runner: ^2.4.15
|
||||
build_resolvers: ^2.4.4
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import 'package:path/path.dart' as p;
|
|||
import 'package:cw_core/exceptions.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_decred/amount_format.dart';
|
||||
import 'package:cw_decred/pending_transaction.dart';
|
||||
import 'package:cw_decred/transaction_credentials.dart';
|
||||
|
@ -307,9 +309,10 @@ abstract class DecredWalletBase
|
|||
persistantPeer = addr;
|
||||
await _libwallet.closeWallet(walletInfo.name);
|
||||
final network = isTestnet ? "testnet" : "mainnet";
|
||||
final dirPath = await pathForWalletDir(name: walletInfo.name, type: WalletType.decred);
|
||||
final config = {
|
||||
"name": walletInfo.name,
|
||||
"datadir": walletInfo.dirPath,
|
||||
"datadir": dirPath,
|
||||
"net": network,
|
||||
"unsyncedaddrs": true,
|
||||
};
|
||||
|
@ -611,7 +614,7 @@ abstract class DecredWalletBase
|
|||
}
|
||||
|
||||
await for (final entity in sourceDir.list(recursive: true)) {
|
||||
final relativePath = entity.path.substring(sourceDir.path.length+1);
|
||||
final relativePath = entity.path.substring(sourceDir.path.length + 1);
|
||||
final targetPath = p.join(targetDir.path, relativePath);
|
||||
|
||||
if (entity is File) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:cw_core/wallet_service.dart';
|
|||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
|
@ -57,42 +58,93 @@ class DecredWalletService extends WalletService<
|
|||
@override
|
||||
Future<DecredWallet> create(DecredNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||
await this.init();
|
||||
final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
|
||||
final network = isTestnet == true ? testnet : mainnet;
|
||||
final config = {
|
||||
"name": credentials.walletInfo!.name,
|
||||
"datadir": credentials.walletInfo!.dirPath,
|
||||
"datadir": dirPath,
|
||||
"pass": credentials.password!,
|
||||
"net": isTestnet == true ? testnet : mainnet,
|
||||
"net": network,
|
||||
"unsyncedaddrs": true,
|
||||
};
|
||||
await libwallet!.createWallet(jsonEncode(config));
|
||||
final di = DerivationInfo(
|
||||
derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
|
||||
credentials.walletInfo!.derivationInfo = di;
|
||||
credentials.walletInfo!.network = network;
|
||||
// ios will move our wallet directory when updating. Since we must
|
||||
// recalculate the new path every time we open the wallet, ensure this path
|
||||
// is not used. An older wallet will have a directory here which is a
|
||||
// condition for moving the wallet when opening, so this must be kept blank
|
||||
// going forward.
|
||||
credentials.walletInfo!.dirPath = "";
|
||||
credentials.walletInfo!.path = "";
|
||||
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
|
||||
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
void copyDirectorySync(Directory source, Directory destination) {
|
||||
/// create destination folder if not exist
|
||||
if (!destination.existsSync()) {
|
||||
destination.createSync(recursive: true);
|
||||
}
|
||||
|
||||
/// get all files from source (recursive: false is important here)
|
||||
source.listSync(recursive: false).forEach((entity) {
|
||||
final newPath = destination.path + Platform.pathSeparator + basename(entity.path);
|
||||
if (entity is File) {
|
||||
entity.rename(newPath);
|
||||
} else if (entity is Directory) {
|
||||
copyDirectorySync(entity, Directory(newPath));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> moveWallet(String fromPath, String toPath) async {
|
||||
final oldWalletDir = new Directory(fromPath);
|
||||
final newWalletDir = new Directory(toPath);
|
||||
copyDirectorySync(oldWalletDir, newWalletDir);
|
||||
// It would be ideal to delete the old directory here, but ios will error
|
||||
// sometimes with "OS Error: No such file or directory, errno = 2" even
|
||||
// after checking if it exists.
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DecredWallet> openWallet(String name, String password) async {
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
||||
final network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
|
||||
walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
|
||||
? testnet
|
||||
: mainnet;
|
||||
if (walletInfo.network == null || walletInfo.network == "") {
|
||||
walletInfo.network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
|
||||
walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
|
||||
? testnet
|
||||
: mainnet;
|
||||
}
|
||||
|
||||
await this.init();
|
||||
final walletDirExists = Directory(walletInfo.dirPath).existsSync();
|
||||
if (!walletDirExists) {
|
||||
walletInfo.dirPath = await pathForWalletDir(name: name, type: getType());
|
||||
|
||||
// Cake wallet version 4.27.0 and earlier gave a wallet dir that did not
|
||||
// match the name. Move those to the correct place.
|
||||
final dirPath = await pathForWalletDir(name: name, type: getType());
|
||||
if (walletInfo.path != "") {
|
||||
// On ios the stored dir no longer exists. We can only trust the basename.
|
||||
// dirPath may already be updated and lost the basename, so look at path.
|
||||
final randomBasename = basename(walletInfo.path);
|
||||
final oldDir = await pathForWalletDir(name: randomBasename, type: getType());
|
||||
if (oldDir != dirPath) {
|
||||
await this.moveWallet(oldDir, dirPath);
|
||||
}
|
||||
// Clear the path so this does not trigger again.
|
||||
walletInfo.dirPath = "";
|
||||
walletInfo.path = "";
|
||||
await walletInfo.save();
|
||||
}
|
||||
|
||||
final config = {
|
||||
"name": walletInfo.name,
|
||||
"datadir": walletInfo.dirPath,
|
||||
"net": network,
|
||||
"name": name,
|
||||
"datadir": dirPath,
|
||||
"net": walletInfo.network,
|
||||
"unsyncedaddrs": true,
|
||||
};
|
||||
await libwallet!.loadWallet(jsonEncode(config));
|
||||
|
@ -127,12 +179,11 @@ class DecredWalletService extends WalletService<
|
|||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
final newDirPath = await pathForWalletDir(name: newName, type: getType());
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
newWalletInfo.dirPath = newDirPath;
|
||||
newWalletInfo.network = network;
|
||||
newWalletInfo.dirPath = "";
|
||||
newWalletInfo.path = "";
|
||||
|
||||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
@ -141,18 +192,23 @@ class DecredWalletService extends WalletService<
|
|||
Future<DecredWallet> restoreFromSeed(DecredRestoreWalletFromSeedCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
await this.init();
|
||||
final network = isTestnet == true ? testnet : mainnet;
|
||||
final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
|
||||
final config = {
|
||||
"name": credentials.walletInfo!.name,
|
||||
"datadir": credentials.walletInfo!.dirPath,
|
||||
"datadir": dirPath,
|
||||
"pass": credentials.password!,
|
||||
"mnemonic": credentials.mnemonic,
|
||||
"net": isTestnet == true ? testnet : mainnet,
|
||||
"net": network,
|
||||
"unsyncedaddrs": true,
|
||||
};
|
||||
await libwallet!.createWallet(jsonEncode(config));
|
||||
final di = DerivationInfo(
|
||||
derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
|
||||
credentials.walletInfo!.derivationInfo = di;
|
||||
credentials.walletInfo!.network = network;
|
||||
credentials.walletInfo!.dirPath = "";
|
||||
credentials.walletInfo!.path = "";
|
||||
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
|
||||
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
|
||||
await wallet.init();
|
||||
|
@ -165,17 +221,22 @@ class DecredWalletService extends WalletService<
|
|||
Future<DecredWallet> restoreFromKeys(DecredRestoreWalletFromPubkeyCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
await this.init();
|
||||
final network = isTestnet == true ? testnet : mainnet;
|
||||
final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
|
||||
final config = {
|
||||
"name": credentials.walletInfo!.name,
|
||||
"datadir": credentials.walletInfo!.dirPath,
|
||||
"datadir": dirPath,
|
||||
"pubkey": credentials.pubkey,
|
||||
"net": isTestnet == true ? testnet : mainnet,
|
||||
"net": network,
|
||||
"unsyncedaddrs": true,
|
||||
};
|
||||
await libwallet!.createWatchOnlyWallet(jsonEncode(config));
|
||||
final di = DerivationInfo(
|
||||
derivationPath: isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath);
|
||||
credentials.walletInfo!.derivationInfo = di;
|
||||
credentials.walletInfo!.network = network;
|
||||
credentials.walletInfo!.dirPath = "";
|
||||
credentials.walletInfo!.path = "";
|
||||
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
|
||||
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
|
||||
await wallet.init();
|
||||
|
|
|
@ -91,26 +91,26 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
version: "2.4.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.2"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -666,11 +666,21 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
socks_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
url: "https://github.com/sneurlax/socks_socket"
|
||||
source: git
|
||||
version: "1.1.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -751,6 +761,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -848,5 +867,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.2.2"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
|
|
|
@ -19,8 +19,8 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.1.11
|
||||
build_resolvers: ^2.0.9
|
||||
build_runner: ^2.4.15
|
||||
build_resolvers: ^2.4.4
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^2.0.1
|
||||
ffigen: ^16.1.0
|
||||
|
|
170
cw_ethereum/lib/deuro/deuro_savings.dart
Normal file
170
cw_ethereum/lib/deuro/deuro_savings.dart
Normal file
|
@ -0,0 +1,170 @@
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_ethereum/deuro/deuro_savings_contract.dart';
|
||||
import 'package:cw_ethereum/ethereum_wallet.dart';
|
||||
import 'package:cw_evm/contract/erc20.dart';
|
||||
import 'package:cw_evm/evm_chain_exceptions.dart';
|
||||
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
||||
import 'package:cw_evm/pending_evm_chain_transaction.dart';
|
||||
import 'package:web3dart/crypto.dart';
|
||||
import 'package:web3dart/web3dart.dart';
|
||||
|
||||
const String savingsGatewayAddress = "0x073493d73258C4BEb6542e8dd3e1b2891C972303";
|
||||
|
||||
const String dEuroAddress = "0xbA3f535bbCcCcA2A154b573Ca6c5A49BAAE0a3ea";
|
||||
const String frontendCode = "0x00000000000000000000000000000000000000000043616b652057616c6c6574";
|
||||
|
||||
class DEuro {
|
||||
final SavingsGateway _savingsGateway;
|
||||
final ERC20 _dEuro;
|
||||
final EthereumWallet _wallet;
|
||||
|
||||
DEuro(EthereumWallet wallet)
|
||||
: _wallet = wallet,
|
||||
_savingsGateway = _getSavingsGateway(wallet.getWeb3Client()!),
|
||||
_dEuro = _getDEuroToken(wallet.getWeb3Client()!);
|
||||
|
||||
static SavingsGateway _getSavingsGateway(Web3Client client) => SavingsGateway(
|
||||
address: EthereumAddress.fromHex(savingsGatewayAddress),
|
||||
client: client,
|
||||
);
|
||||
|
||||
static ERC20 _getDEuroToken(Web3Client client) => ERC20(
|
||||
address: EthereumAddress.fromHex(dEuroAddress),
|
||||
client: client,
|
||||
);
|
||||
|
||||
EthereumAddress get _address => EthereumAddress.fromHex(_wallet.walletAddresses.primaryAddress);
|
||||
|
||||
Future<BigInt> get savingsBalance async =>
|
||||
(await _savingsGateway.savings(accountOwner: _address)).saved;
|
||||
|
||||
Future<BigInt> get accruedInterest => _savingsGateway.accruedInterest(accountOwner: _address);
|
||||
|
||||
Future<BigInt> get interestRate => _savingsGateway.currentRatePPM();
|
||||
|
||||
Future<BigInt> get approvedBalance => _dEuro.allowance(_address, _savingsGateway.self.address);
|
||||
|
||||
Future<void> _checkEthBalanceForGasFees(EVMChainTransactionPriority priority) async {
|
||||
final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address);
|
||||
final currentBalance = ethBalance.getInWei;
|
||||
|
||||
final gasFeesModel = await _wallet.calculateActualEstimatedFeeForCreateTransaction(
|
||||
amount: BigInt.zero,
|
||||
contractAddress: _savingsGateway.self.address.hexEip55,
|
||||
receivingAddressHex: _savingsGateway.self.address.hexEip55,
|
||||
priority: priority,
|
||||
data: _savingsGateway.self.abi.functions[17]
|
||||
.encodeCall([BigInt.zero, hexToBytes(frontendCode)]),
|
||||
);
|
||||
|
||||
final estimatedGasFee = BigInt.from(gasFeesModel.estimatedGasFee);
|
||||
final requiredBalance = estimatedGasFee;
|
||||
|
||||
if (currentBalance < requiredBalance) {
|
||||
throw DeuroGasFeeException(
|
||||
requiredGasFee: requiredBalance,
|
||||
currentBalance: currentBalance,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<PendingEVMChainTransaction> depositSavings(
|
||||
BigInt amount, EVMChainTransactionPriority priority) async {
|
||||
try {
|
||||
await _checkEthBalanceForGasFees(priority);
|
||||
|
||||
final signedTransaction = await _savingsGateway.save(
|
||||
(amount: amount, frontendCode: hexToBytes(frontendCode)),
|
||||
credentials: _wallet.evmChainPrivateKey,
|
||||
);
|
||||
|
||||
final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction(
|
||||
amount: amount,
|
||||
contractAddress: _savingsGateway.self.address.hexEip55,
|
||||
receivingAddressHex: _savingsGateway.self.address.hexEip55,
|
||||
priority: priority,
|
||||
data: _savingsGateway.self.abi.functions[17].encodeCall([amount, hexToBytes(frontendCode)]),
|
||||
);
|
||||
|
||||
final sendTransaction = () => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction);
|
||||
|
||||
return PendingEVMChainTransaction(
|
||||
sendTransaction: sendTransaction,
|
||||
signedTransaction: signedTransaction,
|
||||
fee: BigInt.from(fee.estimatedGasFee),
|
||||
amount: amount.toString(),
|
||||
exponent: 18,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e.toString().contains('insufficient funds for gas')) {
|
||||
final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address);
|
||||
throw DeuroGasFeeException(
|
||||
currentBalance: ethBalance.getInWei,
|
||||
);
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<PendingEVMChainTransaction> withdrawSavings(
|
||||
BigInt amount, EVMChainTransactionPriority priority) async {
|
||||
try {
|
||||
await _checkEthBalanceForGasFees(priority);
|
||||
|
||||
final signedTransaction = await _savingsGateway.withdraw(
|
||||
(target: _address, amount: amount, frontendCode: hexToBytes(frontendCode)),
|
||||
credentials: _wallet.evmChainPrivateKey,
|
||||
);
|
||||
|
||||
final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction(
|
||||
amount: amount,
|
||||
contractAddress: _savingsGateway.self.address.hexEip55,
|
||||
receivingAddressHex: _savingsGateway.self.address.hexEip55,
|
||||
priority: priority,
|
||||
data: _savingsGateway.self.abi.functions[17].encodeCall([amount, hexToBytes(frontendCode)]),
|
||||
);
|
||||
|
||||
final sendTransaction = () => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction);
|
||||
|
||||
return PendingEVMChainTransaction(
|
||||
sendTransaction: sendTransaction,
|
||||
signedTransaction: signedTransaction,
|
||||
fee: BigInt.from(fee.estimatedGasFee),
|
||||
amount: amount.toString(),
|
||||
exponent: 18);
|
||||
} catch (e) {
|
||||
if (e.toString().contains('insufficient funds for gas')) {
|
||||
final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address);
|
||||
throw DeuroGasFeeException(
|
||||
currentBalance: ethBalance.getInWei,
|
||||
);
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// Set an infinite approval to save gas in the future
|
||||
Future<PendingEVMChainTransaction> enableSavings(EVMChainTransactionPriority priority) async {
|
||||
try {
|
||||
await _checkEthBalanceForGasFees(priority);
|
||||
|
||||
return (await _wallet.createApprovalTransaction(
|
||||
BigInt.parse(
|
||||
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
radix: 16,
|
||||
),
|
||||
_savingsGateway.self.address.hexEip55,
|
||||
CryptoCurrency.deuro,
|
||||
priority,
|
||||
)) as PendingEVMChainTransaction;
|
||||
} catch (e) {
|
||||
if (e.toString().contains('insufficient funds for gas')) {
|
||||
final ethBalance = await _wallet.getWeb3Client()!.getBalance(_address);
|
||||
throw DeuroGasFeeException(
|
||||
currentBalance: ethBalance.getInWei,
|
||||
);
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
543
cw_ethereum/lib/deuro/deuro_savings_contract.dart
Normal file
543
cw_ethereum/lib/deuro/deuro_savings_contract.dart
Normal file
File diff suppressed because one or more lines are too long
|
@ -19,7 +19,7 @@ class EthereumClient extends EVMChainClient {
|
|||
Future<List<EVMChainTransactionModel>> fetchTransactions(String address,
|
||||
{String? contractAddress}) async {
|
||||
try {
|
||||
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
"chainid": "$chainId",
|
||||
"module": "account",
|
||||
"action": contractAddress != null ? "tokentx" : "txlist",
|
||||
|
@ -51,7 +51,7 @@ class EthereumClient extends EVMChainClient {
|
|||
@override
|
||||
Future<List<EVMChainTransactionModel>> fetchInternalTransactions(String address) async {
|
||||
try {
|
||||
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
"chainid": "$chainId",
|
||||
"module": "account",
|
||||
"action": "txlistinternal",
|
||||
|
|
|
@ -6,7 +6,7 @@ author: Cake Wallet
|
|||
homepage: https://cakewallet.com
|
||||
|
||||
environment:
|
||||
sdk: '>=2.18.2 <3.0.0'
|
||||
sdk: ^3.5.0
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
|
@ -29,7 +29,7 @@ dependency_overrides:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
|
||||
flutter:
|
||||
# assets:
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:developer';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_evm/evm_chain_transaction_model.dart';
|
||||
import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
||||
import 'package:cw_evm/evm_erc20_balance.dart';
|
||||
|
@ -12,13 +13,12 @@ import 'package:cw_evm/pending_evm_chain_transaction.dart';
|
|||
import 'package:cw_evm/.secrets.g.dart' as secrets;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hex/hex.dart' as hex;
|
||||
import 'package:http/http.dart';
|
||||
import 'package:web3dart/web3dart.dart';
|
||||
|
||||
import 'contract/erc20.dart';
|
||||
|
||||
abstract class EVMChainClient {
|
||||
final httpClient = Client();
|
||||
late final client = ProxyWrapper().getHttpIOClient();
|
||||
Web3Client? _client;
|
||||
|
||||
//! To be overridden by all child classes
|
||||
|
@ -47,7 +47,7 @@ abstract class EVMChainClient {
|
|||
}
|
||||
|
||||
_client =
|
||||
Web3Client(isModifiedNodeUri ? rpcUri!.toString() : node.uri.toString(), httpClient);
|
||||
Web3Client(isModifiedNodeUri ? rpcUri!.toString() : node.uri.toString(), client);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
|
@ -101,6 +101,7 @@ abstract class EVMChainClient {
|
|||
String? contractAddress,
|
||||
EtherAmount? gasPrice,
|
||||
EtherAmount? maxFeePerGas,
|
||||
Uint8List? data,
|
||||
}) async {
|
||||
try {
|
||||
if (contractAddress == null) {
|
||||
|
@ -108,7 +109,6 @@ abstract class EVMChainClient {
|
|||
sender: senderAddress,
|
||||
to: toAddress,
|
||||
value: value,
|
||||
// maxFeePerGas: maxFeePerGas,
|
||||
);
|
||||
|
||||
return estimatedGas.toInt();
|
||||
|
@ -124,7 +124,7 @@ abstract class EVMChainClient {
|
|||
final gasEstimate = await _client!.estimateGas(
|
||||
sender: senderAddress,
|
||||
to: EthereumAddress.fromHex(contractAddress),
|
||||
data: transfer.encodeCall([
|
||||
data: data ?? transfer.encodeCall([
|
||||
toAddress,
|
||||
value.getInWei,
|
||||
]),
|
||||
|
@ -137,6 +137,21 @@ abstract class EVMChainClient {
|
|||
}
|
||||
}
|
||||
|
||||
Uint8List getEncodedDataForApprovalTransaction({
|
||||
required EthereumAddress toAddress,
|
||||
required EtherAmount value,
|
||||
required EthereumAddress contractAddress,
|
||||
}) {
|
||||
final contract = DeployedContract(ethereumContractAbi, contractAddress);
|
||||
|
||||
final approve = contract.function('approve');
|
||||
|
||||
return approve.encodeCall([
|
||||
toAddress,
|
||||
value.getInWei,
|
||||
]);
|
||||
}
|
||||
|
||||
Future<PendingEVMChainTransaction> signTransaction({
|
||||
required Credentials privateKey,
|
||||
required String toAddress,
|
||||
|
@ -149,6 +164,7 @@ abstract class EVMChainClient {
|
|||
required int exponent,
|
||||
String? contractAddress,
|
||||
String? data,
|
||||
int? gasPrice,
|
||||
}) async {
|
||||
assert(currency == CryptoCurrency.eth ||
|
||||
currency == CryptoCurrency.maticpoly ||
|
||||
|
@ -164,6 +180,7 @@ abstract class EVMChainClient {
|
|||
data: data != null ? hexToBytes(data) : null,
|
||||
maxGas: estimatedGasUnits,
|
||||
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
|
||||
gasPrice: gasPrice != null ? EtherAmount.fromInt(EtherUnit.wei, gasPrice) : null,
|
||||
);
|
||||
|
||||
Uint8List signedTransaction;
|
||||
|
@ -198,6 +215,52 @@ abstract class EVMChainClient {
|
|||
);
|
||||
}
|
||||
|
||||
Future<PendingEVMChainTransaction> signApprovalTransaction({
|
||||
required Credentials privateKey,
|
||||
required String spender,
|
||||
required BigInt amount,
|
||||
required BigInt gasFee,
|
||||
required int estimatedGasUnits,
|
||||
required int maxFeePerGas,
|
||||
required EVMChainTransactionPriority priority,
|
||||
required int exponent,
|
||||
required String contractAddress,
|
||||
int? gasPrice,
|
||||
}) async {
|
||||
|
||||
final Transaction transaction = createTransaction(
|
||||
from: privateKey.address,
|
||||
to: EthereumAddress.fromHex(contractAddress),
|
||||
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
|
||||
amount: EtherAmount.zero(),
|
||||
maxGas: estimatedGasUnits,
|
||||
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
|
||||
gasPrice: gasPrice != null ? EtherAmount.fromInt(EtherUnit.wei, gasPrice) : null,
|
||||
);
|
||||
|
||||
final erc20 = ERC20(
|
||||
client: _client!,
|
||||
address: EthereumAddress.fromHex(contractAddress),
|
||||
chainId: chainId,
|
||||
);
|
||||
|
||||
final signedTransaction = await erc20.approve(
|
||||
EthereumAddress.fromHex(spender),
|
||||
amount,
|
||||
credentials: privateKey,
|
||||
transaction: transaction,
|
||||
);
|
||||
|
||||
return PendingEVMChainTransaction(
|
||||
signedTransaction: prepareSignedTransactionForSending(signedTransaction),
|
||||
amount: amount.toString(),
|
||||
fee: gasFee,
|
||||
sendTransaction: () => sendTransaction(signedTransaction),
|
||||
exponent: exponent,
|
||||
isInfiniteApproval: amount.toRadixString(16) == 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
);
|
||||
}
|
||||
|
||||
Transaction createTransaction({
|
||||
required EthereumAddress from,
|
||||
required EthereumAddress to,
|
||||
|
@ -293,7 +356,7 @@ abstract class EVMChainClient {
|
|||
},
|
||||
);
|
||||
|
||||
final response = await httpClient.get(
|
||||
final response = await client.get(
|
||||
uri,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
|
|
|
@ -22,3 +22,32 @@ class EVMChainTransactionFeesException implements Exception {
|
|||
@override
|
||||
String toString() => exceptionMessage;
|
||||
}
|
||||
|
||||
class DeuroGasFeeException implements Exception {
|
||||
final String exceptionMessage;
|
||||
final BigInt? requiredGasFee;
|
||||
final BigInt? currentBalance;
|
||||
|
||||
DeuroGasFeeException({
|
||||
this.requiredGasFee,
|
||||
this.currentBalance,
|
||||
}) : exceptionMessage = _buildMessage(requiredGasFee, currentBalance);
|
||||
|
||||
static String _buildMessage(BigInt? requiredGasFee, BigInt? currentBalance) {
|
||||
const baseMessage = 'Insufficient ETH for gas fees.';
|
||||
const addEthMessage = ' Please add ETH to your wallet to cover transaction fees.';
|
||||
|
||||
if (requiredGasFee != null) {
|
||||
final requiredEth = (requiredGasFee / BigInt.from(10).pow(18)).toStringAsFixed(8);
|
||||
final balanceInfo = currentBalance != null
|
||||
? ', Available: ${(currentBalance / BigInt.from(10).pow(18)).toStringAsFixed(8)} ETH'
|
||||
: '';
|
||||
return '$baseMessage Required: ~$requiredEth ETH$balanceInfo.$addEthMessage';
|
||||
}
|
||||
|
||||
return '$baseMessage$addEthMessage';
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => exceptionMessage;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bip32/bip32.dart' as bip32;
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
|
@ -197,8 +198,8 @@ abstract class EVMChainWalletBase
|
|||
for (var token in erc20Currencies) {
|
||||
bool isPotentialScam = false;
|
||||
|
||||
bool isWhitelisted =
|
||||
getDefaultTokenContractAddresses.any((element) => element == token.contractAddress);
|
||||
bool isWhitelisted = getDefaultTokenContractAddresses
|
||||
.any((element) => element.toLowerCase() == token.contractAddress.toLowerCase());
|
||||
|
||||
final tokenSymbol = token.title.toUpperCase();
|
||||
|
||||
|
@ -213,6 +214,16 @@ abstract class EVMChainWalletBase
|
|||
token.iconPath = null;
|
||||
await token.save();
|
||||
}
|
||||
|
||||
// For fixing wrongly classified tokens
|
||||
if (!isPotentialScam && token.isPotentialScam) {
|
||||
token.isPotentialScam = false;
|
||||
final iconPath = CryptoCurrency.all
|
||||
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
|
||||
.iconPath;
|
||||
token.iconPath = iconPath;
|
||||
await token.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,36 +266,72 @@ abstract class EVMChainWalletBase
|
|||
required String? contractAddress,
|
||||
required String receivingAddressHex,
|
||||
required TransactionPriority priority,
|
||||
Uint8List? data,
|
||||
}) async {
|
||||
try {
|
||||
if (priority is EVMChainTransactionPriority) {
|
||||
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||
|
||||
int maxFeePerGas;
|
||||
int adjustedGasPrice;
|
||||
|
||||
bool isPolygon = _client.chainId == 137;
|
||||
|
||||
if (gasBaseFee != null) {
|
||||
// MaxFeePerGas with EIP1559;
|
||||
maxFeePerGas = gasBaseFee! + priorityFee;
|
||||
} else {
|
||||
// MaxFeePerGas with gasPrice
|
||||
maxFeePerGas = gasPrice;
|
||||
maxFeePerGas = gasPrice + priorityFee;
|
||||
}
|
||||
|
||||
adjustedGasPrice = maxFeePerGas;
|
||||
|
||||
// Polygon has a minimum priority fee of 25 gwei
|
||||
if (isPolygon) {
|
||||
int minPriorityFee = 25;
|
||||
int minPriorityFeeWei =
|
||||
EtherAmount.fromInt(EtherUnit.gwei, minPriorityFee).getInWei.toInt();
|
||||
|
||||
// Calculate user selected priority-based additional fee on top of minimum
|
||||
int additionalPriorityFee = 0;
|
||||
switch (priority) {
|
||||
case EVMChainTransactionPriority.slow:
|
||||
// We use minimum priority fee only
|
||||
additionalPriorityFee = 0;
|
||||
break;
|
||||
case EVMChainTransactionPriority.medium:
|
||||
// We add 15 gwei on top of minimum
|
||||
additionalPriorityFee = EtherAmount.fromInt(EtherUnit.gwei, 15).getInWei.toInt();
|
||||
break;
|
||||
case EVMChainTransactionPriority.fast:
|
||||
// We add 35 gwei on top of minimum
|
||||
additionalPriorityFee = EtherAmount.fromInt(EtherUnit.gwei, 35).getInWei.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
int totalPriorityFee = minPriorityFeeWei + additionalPriorityFee;
|
||||
adjustedGasPrice = gasPrice + totalPriorityFee;
|
||||
maxFeePerGas = gasPrice + totalPriorityFee;
|
||||
}
|
||||
|
||||
final estimatedGas = await _client.getEstimatedGasUnitsForTransaction(
|
||||
contractAddress: contractAddress,
|
||||
senderAddress: _evmChainPrivateKey.address,
|
||||
value: EtherAmount.fromBigInt(EtherUnit.wei, amount!),
|
||||
gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice),
|
||||
gasPrice: EtherAmount.fromInt(EtherUnit.wei, adjustedGasPrice),
|
||||
toAddress: EthereumAddress.fromHex(receivingAddressHex),
|
||||
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
|
||||
data: data,
|
||||
);
|
||||
|
||||
final totalGasFee = estimatedGas * maxFeePerGas;
|
||||
final totalGasFee = estimatedGas * adjustedGasPrice;
|
||||
|
||||
return GasParamsHandler(
|
||||
estimatedGasUnits: estimatedGas,
|
||||
estimatedGasFee: totalGasFee,
|
||||
maxFeePerGas: maxFeePerGas,
|
||||
gasPrice: gasPrice,
|
||||
gasPrice: adjustedGasPrice,
|
||||
);
|
||||
}
|
||||
return GasParamsHandler.zero();
|
||||
|
@ -473,11 +520,46 @@ abstract class EVMChainWalletBase
|
|||
contractAddress:
|
||||
transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null,
|
||||
data: hexOpReturnMemo,
|
||||
gasPrice: maxFeePerGasForTransaction,
|
||||
);
|
||||
|
||||
return pendingEVMChainTransaction;
|
||||
}
|
||||
|
||||
Future<PendingTransaction> createApprovalTransaction(BigInt amount, String spender,
|
||||
CryptoCurrency token, EVMChainTransactionPriority priority) async {
|
||||
final CryptoCurrency transactionCurrency =
|
||||
balance.keys.firstWhere((element) => element.title == token.title);
|
||||
assert(transactionCurrency is Erc20Token);
|
||||
|
||||
final data = _client.getEncodedDataForApprovalTransaction(
|
||||
contractAddress: EthereumAddress.fromHex((transactionCurrency as Erc20Token).contractAddress),
|
||||
value: EtherAmount.fromBigInt(EtherUnit.wei, amount),
|
||||
toAddress: EthereumAddress.fromHex(spender),
|
||||
);
|
||||
|
||||
final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction(
|
||||
amount: amount,
|
||||
receivingAddressHex: spender,
|
||||
priority: priority,
|
||||
contractAddress: transactionCurrency.contractAddress,
|
||||
data: data,
|
||||
);
|
||||
|
||||
return _client.signApprovalTransaction(
|
||||
privateKey: _evmChainPrivateKey,
|
||||
spender: spender,
|
||||
amount: amount,
|
||||
priority: priority,
|
||||
gasFee: BigInt.from(gasFeesModel.estimatedGasFee),
|
||||
maxFeePerGas: gasFeesModel.maxFeePerGas,
|
||||
estimatedGasUnits: gasFeesModel.estimatedGasUnits,
|
||||
exponent: transactionCurrency.decimal,
|
||||
contractAddress: transactionCurrency.contractAddress,
|
||||
gasPrice: gasFeesModel.gasPrice,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _updateTransactions() async {
|
||||
try {
|
||||
if (_isTransactionUpdating) {
|
||||
|
|
|
@ -11,6 +11,7 @@ class PendingEVMChainTransaction with PendingTransaction {
|
|||
final BigInt fee;
|
||||
final String amount;
|
||||
final int exponent;
|
||||
final bool isInfiniteApproval;
|
||||
|
||||
PendingEVMChainTransaction({
|
||||
required this.sendTransaction,
|
||||
|
@ -18,10 +19,12 @@ class PendingEVMChainTransaction with PendingTransaction {
|
|||
required this.fee,
|
||||
required this.amount,
|
||||
required this.exponent,
|
||||
this.isInfiniteApproval = false,
|
||||
});
|
||||
|
||||
@override
|
||||
String get amountFormatted {
|
||||
if (isInfiniteApproval) return "∞";
|
||||
final _amount = (BigInt.parse(amount) / BigInt.from(pow(10, exponent))).toString();
|
||||
return _amount.substring(0, min(10, _amount.length));
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter-plus-plugins
|
||||
path: packages/ledger-ethereum
|
||||
ref: f4761cd5171d4c1e2e42fd3298261650539fb2db
|
||||
|
||||
dependency_overrides:
|
||||
web3dart:
|
||||
|
@ -41,9 +42,9 @@ dependency_overrides:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -5,13 +5,11 @@ class PendingTransactionDescription {
|
|||
required this.fee,
|
||||
required this.hash,
|
||||
required this.hex,
|
||||
required this.txKey,
|
||||
required this.pointerAddress});
|
||||
|
||||
final int amount;
|
||||
final int fee;
|
||||
final String hash;
|
||||
final String hex;
|
||||
final String txKey;
|
||||
final int pointerAddress;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:isolate';
|
||||
|
||||
|
@ -194,14 +195,12 @@ Future<PendingTransactionDescription> createTransactionSync(
|
|||
final rFee = pendingTx.fee();
|
||||
final rHash = pendingTx.txid('');
|
||||
final rHex = pendingTx.hex('');
|
||||
final rTxKey = rHash;
|
||||
|
||||
return PendingTransactionDescription(
|
||||
amount: rAmt,
|
||||
fee: rFee,
|
||||
hash: rHash,
|
||||
hex: rHex,
|
||||
txKey: rTxKey,
|
||||
pointerAddress: pendingTx.ffiAddress(),
|
||||
);
|
||||
}
|
||||
|
@ -246,7 +245,6 @@ Future<PendingTransactionDescription> createTransactionMultDest(
|
|||
fee: tx.fee(),
|
||||
hash: tx.txid(''),
|
||||
hex: tx.hex(''),
|
||||
txKey: tx.txid(''),
|
||||
pointerAddress: tx.ffiAddress(),
|
||||
);
|
||||
}
|
||||
|
@ -263,6 +261,7 @@ Future<String?> commitTransaction({required Wallet2PendingTransaction tx, requir
|
|||
filename: '',
|
||||
overwrite: false,
|
||||
);
|
||||
return null;
|
||||
});
|
||||
|
||||
String? error = (() {
|
||||
|
@ -285,11 +284,12 @@ Future<String?> commitTransaction({required Wallet2PendingTransaction tx, requir
|
|||
if (error != null && error != "no tx keys found for this txid") {
|
||||
throw CreationTransactionException(message: error);
|
||||
}
|
||||
if (useUR) {
|
||||
return Future.value(txCommit as String?);
|
||||
} else {
|
||||
return Future.value(null);
|
||||
}
|
||||
unawaited(() async {
|
||||
storeSync(force: true);
|
||||
await Future.delayed(Duration(seconds: 5));
|
||||
storeSync(force: true);
|
||||
}());
|
||||
return Future.value(txCommit);
|
||||
}
|
||||
|
||||
class Transaction {
|
||||
|
|
|
@ -116,12 +116,17 @@ String getSeedLegacy(String? language) {
|
|||
}
|
||||
|
||||
String getPassphrase() {
|
||||
return currentWallet!.getCacheAttribute(key: "cakewallet.passphrase");
|
||||
return currentWallet?.getCacheAttribute(key: "cakewallet.passphrase") ?? "";
|
||||
}
|
||||
|
||||
Map<int, Map<int, Map<int, String>>> addressCache = {};
|
||||
|
||||
String getAddress({int accountIndex = 0, int addressIndex = 0}) {
|
||||
// this is a workaround for when we switch the wallet pointer,
|
||||
// it should never reach UI but should be good enough to prevent gray screen
|
||||
// or other errors because of forced null check.
|
||||
if (currentWallet == null) return "<wallet not ready ($accountIndex:$addressIndex)>";
|
||||
|
||||
// printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}");
|
||||
// this could be a while loop, but I'm in favor of making it if to not cause freezes
|
||||
if (currentWallet!.numSubaddresses(accountIndex: accountIndex)-1 < addressIndex) {
|
||||
|
@ -146,7 +151,25 @@ int getUnlockedBalance({int accountIndex = 0}) =>
|
|||
|
||||
int getCurrentHeight() => currentWallet?.blockChainHeight() ?? 0;
|
||||
|
||||
int getNodeHeightSync() => currentWallet?.daemonBlockChainHeight() ?? 0;
|
||||
|
||||
int cachedNodeHeight = 0;
|
||||
bool isHeightRefreshing = false;
|
||||
int getNodeHeightSync() {
|
||||
if (isHeightRefreshing == false) {
|
||||
(() async {
|
||||
try {
|
||||
isHeightRefreshing = true;
|
||||
final wptrAddress = currentWallet!.ffiAddress();
|
||||
cachedNodeHeight = await Isolate.run(() async {
|
||||
return monero.Wallet_daemonBlockChainHeight(Pointer.fromAddress(wptrAddress));
|
||||
});
|
||||
} finally {
|
||||
isHeightRefreshing = false;
|
||||
}
|
||||
})();
|
||||
}
|
||||
return cachedNodeHeight;
|
||||
}
|
||||
|
||||
bool isConnectedSync() => currentWallet?.connected() != 0;
|
||||
|
||||
|
@ -202,7 +225,6 @@ Future<bool> setupNodeSync(
|
|||
}
|
||||
|
||||
void startRefreshSync() {
|
||||
currentWallet!.refreshAsync();
|
||||
currentWallet!.startRefresh();
|
||||
}
|
||||
|
||||
|
@ -228,7 +250,7 @@ void storeSync({bool force = false}) async {
|
|||
return monero.Wallet_synchronized(Pointer.fromAddress(addr));
|
||||
});
|
||||
if (lastStorePointer == addr &&
|
||||
lastStoreHeight + 5000 > currentWallet!.blockChainHeight() &&
|
||||
lastStoreHeight + 75000 > currentWallet!.blockChainHeight() &&
|
||||
!synchronized &&
|
||||
!force) {
|
||||
return;
|
||||
|
@ -255,13 +277,13 @@ void closeCurrentWallet() {
|
|||
currentWallet!.stop();
|
||||
}
|
||||
|
||||
String getSecretViewKey() => currentWallet!.secretViewKey();
|
||||
String getSecretViewKey() => currentWallet?.secretViewKey() ?? "";
|
||||
|
||||
String getPublicViewKey() => currentWallet!.publicViewKey();
|
||||
String getPublicViewKey() => currentWallet?.publicViewKey() ?? "";
|
||||
|
||||
String getSecretSpendKey() => currentWallet!.secretSpendKey();
|
||||
String getSecretSpendKey() => currentWallet?.secretSpendKey() ?? "";
|
||||
|
||||
String getPublicSpendKey() => currentWallet!.publicSpendKey();
|
||||
String getPublicSpendKey() => currentWallet?.publicSpendKey() ?? "";
|
||||
|
||||
class SyncListener {
|
||||
SyncListener(this.onNewBlock, this.onNewTransaction)
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:cw_core/pending_transaction.dart';
|
|||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
@ -207,6 +208,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
|
||||
@override
|
||||
Future<void> connectToNode({required Node node}) async {
|
||||
String socksProxy = node.socksProxyAddress ?? '';
|
||||
printV("bootstrapped: ${CakeTor.instance.bootstrapped}");
|
||||
printV(" enabled: ${CakeTor.instance.enabled}");
|
||||
printV(" port: ${CakeTor.instance.port}");
|
||||
printV(" started: ${CakeTor.instance.started}");
|
||||
if (CakeTor.instance.enabled) {
|
||||
socksProxy = "127.0.0.1:${CakeTor.instance.port}";
|
||||
}
|
||||
try {
|
||||
syncStatus = ConnectingSyncStatus();
|
||||
await monero_wallet.setupNodeSync(
|
||||
|
@ -216,7 +225,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
useSSL: node.isSSL,
|
||||
isLightWallet: false,
|
||||
// FIXME: hardcoded value
|
||||
socksProxyAddress: node.socksProxyAddress);
|
||||
socksProxyAddress: socksProxy);
|
||||
|
||||
await monero_wallet.setTrustedDaemon(node.trusted);
|
||||
syncStatus = ConnectedSyncStatus();
|
||||
|
|
|
@ -31,8 +31,6 @@ class PendingMoneroTransaction with PendingTransaction {
|
|||
@override
|
||||
String get hex => pendingTransactionDescription.hex;
|
||||
|
||||
String get txKey => pendingTransactionDescription.txKey;
|
||||
|
||||
@override
|
||||
String get amountFormatted => AmountConverter.amountIntToString(
|
||||
CryptoCurrency.xmr, pendingTransactionDescription.amount);
|
||||
|
|
|
@ -66,11 +66,11 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: cake-update-v2
|
||||
resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
|
||||
ref: cake-update-v4
|
||||
resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
|
||||
url: "https://github.com/cake-tech/blockchain_utils"
|
||||
source: git
|
||||
version: "3.3.0"
|
||||
version: "4.3.0"
|
||||
bluez:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -131,18 +131,18 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.10"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -599,10 +599,10 @@ packages:
|
|||
description:
|
||||
path: "."
|
||||
ref: cake-update-v2
|
||||
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
|
||||
resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
|
||||
url: "https://github.com/cake-tech/on_chain.git"
|
||||
source: git
|
||||
version: "3.7.0"
|
||||
version: "6.2.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -779,11 +779,21 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
socks_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
url: "https://github.com/sneurlax/socks_socket"
|
||||
source: git
|
||||
version: "1.1.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -860,10 +870,19 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -34,8 +34,8 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_resolvers: ^2.0.9
|
||||
build_runner: ^2.4.15
|
||||
build_resolvers: ^2.4.4
|
||||
mobx_codegen: ^2.0.7
|
||||
mockito: ^5.4.5
|
||||
hive_generator: ^2.0.1
|
||||
|
|
|
@ -3,11 +3,11 @@ import 'dart:convert';
|
|||
|
||||
import 'package:cw_core/nano_account_info_response.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_nano/nano_block_info_response.dart';
|
||||
import 'package:cw_core/n2_node.dart';
|
||||
import 'package:cw_nano/nano_balance.dart';
|
||||
import 'package:cw_nano/nano_transaction_model.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:nanoutil/nanoutil.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
@ -66,8 +66,8 @@ class NanoClient {
|
|||
}
|
||||
|
||||
Future<NanoBalance> getBalance(String address) async {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode(
|
||||
{
|
||||
|
@ -76,7 +76,8 @@ class NanoClient {
|
|||
},
|
||||
),
|
||||
);
|
||||
final data = await jsonDecode(response.body);
|
||||
|
||||
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
if (response.statusCode != 200 ||
|
||||
data["error"] != null ||
|
||||
data["balance"] == null ||
|
||||
|
@ -93,8 +94,8 @@ class NanoClient {
|
|||
|
||||
Future<AccountInfoResponse?> getAccountInfo(String address) async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode(
|
||||
{
|
||||
|
@ -104,8 +105,9 @@ class NanoClient {
|
|||
},
|
||||
),
|
||||
);
|
||||
final data = await jsonDecode(response.body);
|
||||
return AccountInfoResponse.fromJson(data as Map<String, dynamic>);
|
||||
|
||||
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
return AccountInfoResponse.fromJson(data);
|
||||
} catch (e) {
|
||||
printV("error while getting account info $e");
|
||||
return null;
|
||||
|
@ -114,8 +116,8 @@ class NanoClient {
|
|||
|
||||
Future<BlockContentsResponse?> getBlockContents(String block) async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode(
|
||||
{
|
||||
|
@ -125,7 +127,8 @@ class NanoClient {
|
|||
},
|
||||
),
|
||||
);
|
||||
final data = await jsonDecode(response.body);
|
||||
|
||||
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
return BlockContentsResponse.fromJson(data["contents"] as Map<String, dynamic>);
|
||||
} catch (e) {
|
||||
printV("error while getting block info $e");
|
||||
|
@ -181,8 +184,8 @@ class NanoClient {
|
|||
}
|
||||
|
||||
Future<String> requestWork(String hash) async {
|
||||
final response = await http.post(
|
||||
_powNode!.uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: _powNode!.uri,
|
||||
headers: getHeaders(_powNode!.uri.host),
|
||||
body: json.encode(
|
||||
{
|
||||
|
@ -191,8 +194,9 @@ class NanoClient {
|
|||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>;
|
||||
final decoded = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
if (decoded.containsKey("error")) {
|
||||
throw Exception("Received error ${decoded["error"]}");
|
||||
}
|
||||
|
@ -224,13 +228,13 @@ class NanoClient {
|
|||
"block": block,
|
||||
});
|
||||
|
||||
final processResponse = await http.post(
|
||||
_node!.uri,
|
||||
final processResponse = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: processBody,
|
||||
);
|
||||
|
||||
final Map<String, dynamic> decoded = json.decode(processResponse.body) as Map<String, dynamic>;
|
||||
final Map<String, dynamic> decoded = jsonDecode(processResponse.body) as Map<String, dynamic>;
|
||||
if (decoded.containsKey("error")) {
|
||||
throw Exception("Received error ${decoded["error"]}");
|
||||
}
|
||||
|
@ -423,12 +427,11 @@ class NanoClient {
|
|||
"subtype": "receive",
|
||||
"block": receiveBlock,
|
||||
});
|
||||
final processResponse = await http.post(
|
||||
_node!.uri,
|
||||
final processResponse = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: processBody,
|
||||
);
|
||||
|
||||
final Map<String, dynamic> decoded = json.decode(processResponse.body) as Map<String, dynamic>;
|
||||
if (decoded.containsKey("error")) {
|
||||
throw Exception("Received error ${decoded["error"]}");
|
||||
|
@ -440,16 +443,17 @@ class NanoClient {
|
|||
required String destinationAddress,
|
||||
required String privateKey,
|
||||
}) async {
|
||||
final receivableResponse = await http.post(_node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "receivable",
|
||||
"account": destinationAddress,
|
||||
"count": "-1",
|
||||
"source": true,
|
||||
}));
|
||||
|
||||
final receivableData = await jsonDecode(receivableResponse.body);
|
||||
final receivableResponse = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "receivable",
|
||||
"account": destinationAddress,
|
||||
"count": "-1",
|
||||
"source": true,
|
||||
}),
|
||||
);
|
||||
final receivableData = jsonDecode(receivableResponse.body) as Map<String, dynamic>;
|
||||
if (receivableData["blocks"] == "" || receivableData["blocks"] == null) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -492,15 +496,18 @@ class NanoClient {
|
|||
|
||||
Future<List<NanoTransactionModel>> fetchTransactions(String address) async {
|
||||
try {
|
||||
final response = await http.post(_node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "account_history",
|
||||
"account": address,
|
||||
"count": "100",
|
||||
// "raw": true,
|
||||
}));
|
||||
final data = await jsonDecode(response.body);
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: _node!.uri,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "account_history",
|
||||
"account": address,
|
||||
"count": "100",
|
||||
// "raw": true,
|
||||
}),
|
||||
);
|
||||
|
||||
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
final transactions = data["history"] is List ? data["history"] as List<dynamic> : [];
|
||||
|
||||
// Map the transactions list to NanoTransactionModel using the factory
|
||||
|
@ -516,13 +523,14 @@ class NanoClient {
|
|||
|
||||
Future<List<N2Node>> getN2Reps() async {
|
||||
final uri = Uri.parse(N2_REPS_ENDPOINT);
|
||||
final response = await http.post(
|
||||
uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: getHeaders(uri.host),
|
||||
body: jsonEncode({"action": "reps"}),
|
||||
);
|
||||
try {
|
||||
final List<N2Node> nodes = (json.decode(response.body) as List<dynamic>)
|
||||
|
||||
final List<N2Node> nodes = (jsonDecode(response.body) as List<dynamic>)
|
||||
.map((dynamic e) => N2Node.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
return nodes;
|
||||
|
@ -533,8 +541,8 @@ class NanoClient {
|
|||
|
||||
Future<int> getRepScore(String rep) async {
|
||||
final uri = Uri.parse(N2_REPS_ENDPOINT);
|
||||
final response = await http.post(
|
||||
uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: getHeaders(uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "rep_info",
|
||||
|
@ -542,7 +550,8 @@ class NanoClient {
|
|||
}),
|
||||
);
|
||||
try {
|
||||
final N2Node node = N2Node.fromJson(json.decode(response.body) as Map<String, dynamic>);
|
||||
|
||||
final N2Node node = N2Node.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
|
||||
return node.score ?? 100;
|
||||
} catch (error) {
|
||||
return 100;
|
||||
|
|
|
@ -5,34 +5,39 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "47.0.0"
|
||||
version: "76.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.3"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "6.11.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
version: "2.7.0"
|
||||
asn1lib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: asn1lib
|
||||
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
|
||||
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.8"
|
||||
version: "1.5.9"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -86,50 +91,50 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.2"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.0.4"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
||||
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
version: "2.4.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: "direct overridden"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e"
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.7+1"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -142,10 +147,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
|
||||
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.4"
|
||||
version: "8.10.1"
|
||||
cake_backup:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -238,10 +243,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
||||
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.3.8"
|
||||
decimal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -373,18 +378,18 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: hive_generator
|
||||
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
|
||||
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
version: "2.0.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -397,10 +402,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -473,6 +478,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -517,10 +530,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobx_codegen
|
||||
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
|
||||
sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.7.1"
|
||||
nanodart:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -551,7 +564,7 @@ packages:
|
|||
description:
|
||||
path: "."
|
||||
ref: cake-update-v2
|
||||
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
|
||||
resolved-ref: "01cbbacbb05d2113aafa8b7c4a2bb766f749d8d8"
|
||||
url: "https://github.com/cake-tech/on_chain.git"
|
||||
source: git
|
||||
version: "3.7.0"
|
||||
|
@ -559,10 +572,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.2.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -583,10 +596,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
|
||||
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.15"
|
||||
version: "2.2.17"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -663,26 +676,26 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: provider
|
||||
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
version: "6.1.5"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.5.0"
|
||||
rational:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -695,18 +708,18 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
|
||||
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
version: "2.5.3"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
|
||||
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.6"
|
||||
version: "2.4.10"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -751,18 +764,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
version: "1.4.2"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -771,27 +784,37 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
socks_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
url: "https://github.com/sneurlax/socks_socket"
|
||||
source: git
|
||||
version: "1.1.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.6"
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
||||
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.5"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -852,10 +875,19 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -916,18 +948,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.0.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -945,5 +977,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
|
|
|
@ -31,13 +31,12 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
build_runner_core: 7.2.7+1
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
|
|
@ -84,6 +84,6 @@ class DefaultPolygonErc20Tokens {
|
|||
.iconPath;
|
||||
} catch (_) {}
|
||||
|
||||
return Erc20Token.copyWith(token, iconPath, 'POLY');
|
||||
return Erc20Token.copyWith(token, iconPath, 'POL');
|
||||
}).toList();
|
||||
}
|
||||
|
|
|
@ -18,13 +18,20 @@ class PolygonClient extends EVMChainClient {
|
|||
EtherAmount? gasPrice,
|
||||
EtherAmount? maxFeePerGas,
|
||||
}) {
|
||||
EtherAmount? finalGasPrice = gasPrice;
|
||||
|
||||
if (gasPrice == null && maxFeePerGas != null) {
|
||||
// If we have EIP-1559 parameters but no legacy gasPrice, then use maxFeePerGas as gasPrice
|
||||
finalGasPrice = maxFeePerGas;
|
||||
}
|
||||
|
||||
return Transaction(
|
||||
from: from,
|
||||
to: to,
|
||||
value: amount,
|
||||
// data: data,
|
||||
data: data,
|
||||
maxGas: maxGas,
|
||||
// gasPrice: gasPrice,
|
||||
gasPrice: finalGasPrice,
|
||||
// maxFeePerGas: maxFeePerGas,
|
||||
// maxPriorityFeePerGas: maxPriorityFeePerGas,
|
||||
);
|
||||
|
@ -40,7 +47,7 @@ class PolygonClient extends EVMChainClient {
|
|||
Future<List<EVMChainTransactionModel>> fetchTransactions(String address,
|
||||
{String? contractAddress}) async {
|
||||
try {
|
||||
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
"chainid": "$chainId",
|
||||
"module": "account",
|
||||
"action": contractAddress != null ? "tokentx" : "txlist",
|
||||
|
@ -68,7 +75,7 @@ class PolygonClient extends EVMChainClient {
|
|||
@override
|
||||
Future<List<EVMChainTransactionModel>> fetchInternalTransactions(String address) async {
|
||||
try {
|
||||
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
|
||||
"chainid": "$chainId",
|
||||
"module": "account",
|
||||
"action": "txlistinternal",
|
||||
|
|
|
@ -45,7 +45,12 @@ class PolygonWallet extends EVMChainWallet {
|
|||
final initialErc20Tokens = DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
|
||||
|
||||
for (final token in initialErc20Tokens) {
|
||||
if (!evmChainErc20TokensBox.containsKey(token.contractAddress)) {
|
||||
if (evmChainErc20TokensBox.containsKey(token.contractAddress)) {
|
||||
final existingToken = evmChainErc20TokensBox.get(token.contractAddress);
|
||||
if (existingToken?.tag != token.tag) {
|
||||
evmChainErc20TokensBox.put(token.contractAddress, token);
|
||||
}
|
||||
} else {
|
||||
if (isMigration) token.enabled = false;
|
||||
evmChainErc20TokensBox.put(token.contractAddress, token);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ dev_dependencies:
|
|||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
|
|
|
@ -2,8 +2,10 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/solana_rpc_http_service.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_solana/pending_solana_transaction.dart';
|
||||
|
@ -11,14 +13,17 @@ import 'package:cw_solana/solana_balance.dart';
|
|||
import 'package:cw_solana/solana_exceptions.dart';
|
||||
import 'package:cw_solana/solana_transaction_model.dart';
|
||||
import 'package:cw_solana/spl_token.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:on_chain/solana/solana.dart';
|
||||
import 'package:on_chain/solana/src/instructions/associated_token_account/constant.dart';
|
||||
import 'package:on_chain/solana/src/models/pda/pda.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:on_chain/solana/src/rpc/models/models/confirmed_transaction_meta.dart';
|
||||
import '.secrets.g.dart' as secrets;
|
||||
|
||||
class SolanaWalletClient {
|
||||
final httpClient = http.Client();
|
||||
// Minimum amount in SOL to consider a transaction valid (to filter spam)
|
||||
static const double minValidAmount = 0.00000003;
|
||||
final httpClient = ProxyWrapper().getHttpClient();
|
||||
SolanaRPC? _provider;
|
||||
|
||||
bool connect(Node node) {
|
||||
|
@ -82,7 +87,8 @@ class SolanaWalletClient {
|
|||
}
|
||||
}
|
||||
|
||||
Future<SolanaBalance?> getSplTokenBalance(String mintAddress, String walletAddress) async {
|
||||
Future<SolanaBalance?> getSplTokenBalance(
|
||||
String mintAddress, String walletAddress) async {
|
||||
// Fetch the token accounts (a token can have multiple accounts for various uses)
|
||||
final tokenAccounts = await getSPLTokenAccounts(mintAddress, walletAddress);
|
||||
|
||||
|
@ -118,14 +124,16 @@ class SolanaWalletClient {
|
|||
),
|
||||
);
|
||||
|
||||
final fee = (feeForMessage?.toDouble() ?? 0.0) / SolanaUtils.lamportsPerSol;
|
||||
final fee =
|
||||
(feeForMessage?.toDouble() ?? 0.0) / SolanaUtils.lamportsPerSol;
|
||||
return fee;
|
||||
} catch (_) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
Future<double> getEstimatedFee(SolanaPublicKey publicKey, Commitment commitment) async {
|
||||
Future<double> getEstimatedFee(
|
||||
SolanaPublicKey publicKey, Commitment commitment) async {
|
||||
final message = await _getMessageForNativeTransaction(
|
||||
publicKey: publicKey,
|
||||
destinationAddress: publicKey.toAddress().address,
|
||||
|
@ -155,170 +163,88 @@ class SolanaWalletClient {
|
|||
if (meta == null || transaction == null) return null;
|
||||
|
||||
final int fee = meta.fee;
|
||||
final feeInSol = fee / SolanaUtils.lamportsPerSol;
|
||||
|
||||
final message = transaction.message;
|
||||
final instructions = message.compiledInstructions;
|
||||
|
||||
String sender = "";
|
||||
String receiver = "";
|
||||
|
||||
String signature = (txResponse.transaction?.signatures.isEmpty ?? true)
|
||||
? ""
|
||||
: Base58Encoder.encode(txResponse.transaction!.signatures.first);
|
||||
|
||||
|
||||
for (final instruction in instructions) {
|
||||
final programId = message.accountKeys[instruction.programIdIndex];
|
||||
|
||||
if (programId == SystemProgramConst.programId) {
|
||||
if (programId == SystemProgramConst.programId ||
|
||||
programId == ComputeBudgetConst.programId) {
|
||||
// For native solana transactions
|
||||
if (instruction.accounts.length < 2) continue;
|
||||
|
||||
if (txResponse.version == TransactionType.legacy) {
|
||||
// For legacy transfers, the fee payer (index 0) is the sender.
|
||||
sender = message.accountKeys[0].address;
|
||||
// Get the fee payer index based on transaction type
|
||||
// For legacy transfers, the first account is usually the fee payer
|
||||
// For versioned, the first account in instruction is usually the fee payer
|
||||
final feePayerIndex =
|
||||
txResponse.version == TransactionType.legacy ? 0 : instruction.accounts[0];
|
||||
|
||||
final senderPreBalance = meta.preBalances[0];
|
||||
final senderPostBalance = meta.postBalances[0];
|
||||
final feeForTx = fee / SolanaUtils.lamportsPerSol;
|
||||
final transactionModel = await _parseNativeTransaction(
|
||||
message: message,
|
||||
meta: meta,
|
||||
fee: fee,
|
||||
feeInSol: feeInSol,
|
||||
feePayerIndex: feePayerIndex,
|
||||
walletAddress: walletAddress,
|
||||
signature: signature,
|
||||
blockTime: blockTime,
|
||||
);
|
||||
|
||||
// The loss on the sender's account would include both the transfer amount and the fee.
|
||||
// So we would subtract the fee to calculate the actual amount that was transferred (in lamports).
|
||||
final transferLamports = (senderPreBalance - senderPostBalance) - BigInt.from(fee);
|
||||
|
||||
// Next, we attempt to find the receiver by comparing the balance changes.
|
||||
// (The index 0 is for the sender so we skip it.)
|
||||
bool foundReceiver = false;
|
||||
for (int i = 1; i < meta.preBalances.length; i++) {
|
||||
// The increase in balance on the receiver account should correspond to the transfer amount we calculated earlieer.
|
||||
final pre = meta.preBalances[i];
|
||||
final post = meta.postBalances[i];
|
||||
if ((post - pre) == transferLamports) {
|
||||
receiver = message.accountKeys[i].address;
|
||||
foundReceiver = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundReceiver) {
|
||||
// Optionally (and rarely), if no account shows the exact expected change,
|
||||
// we set the receiver address to unknown.
|
||||
receiver = "unknown";
|
||||
}
|
||||
|
||||
final amount = transferLamports / BigInt.from(1e9);
|
||||
|
||||
return SolanaTransactionModel(
|
||||
isOutgoingTx: sender == walletAddress,
|
||||
from: sender,
|
||||
to: receiver,
|
||||
id: signature,
|
||||
amount: amount.abs(),
|
||||
programId: SystemProgramConst.programId.address,
|
||||
tokenSymbol: 'SOL',
|
||||
blockTimeInInt: blockTime?.toInt() ?? 0,
|
||||
fee: feeForTx,
|
||||
);
|
||||
} else {
|
||||
if (instruction.accounts.length < 2) continue;
|
||||
final senderIndex = instruction.accounts[0];
|
||||
final receiverIndex = instruction.accounts[1];
|
||||
|
||||
sender = message.accountKeys[senderIndex].address;
|
||||
receiver = message.accountKeys[receiverIndex].address;
|
||||
|
||||
final feeForTx = fee / SolanaUtils.lamportsPerSol;
|
||||
|
||||
final preBalances = meta.preBalances;
|
||||
final postBalances = meta.postBalances;
|
||||
|
||||
final amountInString =
|
||||
(((preBalances[senderIndex] - postBalances[senderIndex]) / BigInt.from(1e9))
|
||||
.toDouble() -
|
||||
feeForTx)
|
||||
.toStringAsFixed(6);
|
||||
|
||||
final amount = double.parse(amountInString);
|
||||
|
||||
return SolanaTransactionModel(
|
||||
isOutgoingTx: sender == walletAddress,
|
||||
from: sender,
|
||||
to: receiver,
|
||||
id: signature,
|
||||
amount: amount.abs(),
|
||||
programId: SystemProgramConst.programId.address,
|
||||
tokenSymbol: 'SOL',
|
||||
blockTimeInInt: blockTime?.toInt() ?? 0,
|
||||
fee: feeForTx,
|
||||
);
|
||||
if (transactionModel != null) {
|
||||
return transactionModel;
|
||||
}
|
||||
} else if (programId == SPLTokenProgramConst.tokenProgramId) {
|
||||
// For SPL Token transactions
|
||||
if (instruction.accounts.length < 2) continue;
|
||||
|
||||
final preBalances = meta.preTokenBalances;
|
||||
final postBalances = meta.postTokenBalances;
|
||||
|
||||
double amount = 0.0;
|
||||
bool isOutgoing = false;
|
||||
String? mintAddress;
|
||||
|
||||
double userPreAmount = 0.0;
|
||||
if (preBalances != null && preBalances.isNotEmpty) {
|
||||
for (final preBal in preBalances) {
|
||||
if (preBal.owner?.address == walletAddress) {
|
||||
userPreAmount = preBal.uiTokenAmount.uiAmount ?? 0.0;
|
||||
|
||||
mintAddress = preBal.mint.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double userPostAmount = 0.0;
|
||||
if (postBalances != null && postBalances.isNotEmpty) {
|
||||
for (final postBal in postBalances) {
|
||||
if (postBal.owner?.address == walletAddress) {
|
||||
userPostAmount = postBal.uiTokenAmount.uiAmount ?? 0.0;
|
||||
|
||||
mintAddress ??= postBal.mint.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final diff = userPreAmount - userPostAmount;
|
||||
final rawAmount = diff.abs();
|
||||
|
||||
final amountInString = rawAmount.toStringAsFixed(6);
|
||||
amount = double.parse(amountInString);
|
||||
|
||||
isOutgoing = diff > 0;
|
||||
|
||||
if (mintAddress == null && instruction.accounts.length >= 4) {
|
||||
final mintIndex = instruction.accounts[3];
|
||||
mintAddress = message.accountKeys[mintIndex].address;
|
||||
}
|
||||
|
||||
final sender = message.accountKeys[instruction.accounts[0]].address;
|
||||
final receiver = message.accountKeys[instruction.accounts[1]].address;
|
||||
|
||||
String? tokenSymbol = splTokenSymbol;
|
||||
|
||||
if (tokenSymbol == null && mintAddress != null) {
|
||||
final token = await getTokenInfo(mintAddress);
|
||||
tokenSymbol = token?.symbol;
|
||||
}
|
||||
|
||||
return SolanaTransactionModel(
|
||||
isOutgoingTx: isOutgoing,
|
||||
from: sender,
|
||||
to: receiver,
|
||||
id: signature,
|
||||
amount: amount,
|
||||
programId: SPLTokenProgramConst.tokenProgramId.address,
|
||||
blockTimeInInt: blockTime?.toInt() ?? 0,
|
||||
tokenSymbol: tokenSymbol ?? '',
|
||||
fee: fee / SolanaUtils.lamportsPerSol,
|
||||
final transactionModel = await _parseSPLTokenTransaction(
|
||||
message: message,
|
||||
meta: meta,
|
||||
fee: fee,
|
||||
feeInSol: feeInSol,
|
||||
instruction: instruction,
|
||||
walletAddress: walletAddress,
|
||||
signature: signature,
|
||||
blockTime: blockTime,
|
||||
splTokenSymbol: splTokenSymbol,
|
||||
);
|
||||
|
||||
if (transactionModel != null) {
|
||||
return transactionModel;
|
||||
}
|
||||
} else if (programId == AssociatedTokenAccountProgramConst.associatedTokenProgramId) {
|
||||
// For ATA program, we need to check if this is a create account transaction
|
||||
// or if it's part of a normal token transfer
|
||||
|
||||
// We skip this transaction if this is the only instruction (this means that it's a create account transaction)
|
||||
if (instructions.length == 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// We look for a token transfer instruction in the same transaction
|
||||
bool hasTokenTransfer = false;
|
||||
for (final otherInstruction in instructions) {
|
||||
final otherProgramId = message.accountKeys[otherInstruction.programIdIndex];
|
||||
if (otherProgramId == SPLTokenProgramConst.tokenProgramId) {
|
||||
hasTokenTransfer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no token transfer instruction, it means this is just an ATA creation transaction
|
||||
if (!hasTokenTransfer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -330,6 +256,144 @@ class SolanaWalletClient {
|
|||
return null;
|
||||
}
|
||||
|
||||
Future<SolanaTransactionModel?> _parseNativeTransaction({
|
||||
required VersionedMessage message,
|
||||
required ConfirmedTransactionMeta meta,
|
||||
required int fee,
|
||||
required double feeInSol,
|
||||
required int feePayerIndex,
|
||||
required String walletAddress,
|
||||
required String signature,
|
||||
required BigInt? blockTime,
|
||||
}) async {
|
||||
// Calculate total balance changes across all accounts
|
||||
BigInt totalBalanceChange = BigInt.zero;
|
||||
String? sender;
|
||||
String? receiver;
|
||||
|
||||
for (int i = 0; i < meta.preBalances.length; i++) {
|
||||
final preBalance = meta.preBalances[i];
|
||||
final postBalance = meta.postBalances[i];
|
||||
final balanceChange = preBalance - postBalance;
|
||||
|
||||
if (balanceChange > BigInt.zero) {
|
||||
// This account sent funds
|
||||
sender = message.accountKeys[i].address;
|
||||
totalBalanceChange += balanceChange;
|
||||
} else if (balanceChange < BigInt.zero) {
|
||||
// This account received funds
|
||||
receiver = message.accountKeys[i].address;
|
||||
}
|
||||
}
|
||||
|
||||
// We subtract the fee from total balance change if the fee payer is the sender
|
||||
if (sender == message.accountKeys[feePayerIndex].address) {
|
||||
totalBalanceChange -= BigInt.from(fee);
|
||||
}
|
||||
|
||||
if (sender == null || receiver == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final amount = totalBalanceChange / BigInt.from(1e9);
|
||||
final amountInSol = amount.abs().toDouble();
|
||||
|
||||
// Skip transactions with very small amounts (likely spam)
|
||||
if (amountInSol < minValidAmount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SolanaTransactionModel(
|
||||
isOutgoingTx: sender == walletAddress,
|
||||
from: sender,
|
||||
to: receiver,
|
||||
id: signature,
|
||||
amount: amountInSol,
|
||||
programId: SystemProgramConst.programId.address,
|
||||
tokenSymbol: 'SOL',
|
||||
blockTimeInInt: blockTime?.toInt() ?? 0,
|
||||
fee: feeInSol,
|
||||
);
|
||||
}
|
||||
|
||||
Future<SolanaTransactionModel?> _parseSPLTokenTransaction({
|
||||
required VersionedMessage message,
|
||||
required ConfirmedTransactionMeta meta,
|
||||
required int fee,
|
||||
required double feeInSol,
|
||||
required CompiledInstruction instruction,
|
||||
required String walletAddress,
|
||||
required String signature,
|
||||
required BigInt? blockTime,
|
||||
String? splTokenSymbol,
|
||||
}) async {
|
||||
final preBalances = meta.preTokenBalances;
|
||||
final postBalances = meta.postTokenBalances;
|
||||
|
||||
double amount = 0.0;
|
||||
bool isOutgoing = false;
|
||||
String? mintAddress;
|
||||
|
||||
double userPreAmount = 0.0;
|
||||
if (preBalances != null && preBalances.isNotEmpty) {
|
||||
for (final preBal in preBalances) {
|
||||
if (preBal.owner?.address == walletAddress) {
|
||||
userPreAmount = preBal.uiTokenAmount.uiAmount ?? 0.0;
|
||||
|
||||
mintAddress = preBal.mint.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double userPostAmount = 0.0;
|
||||
if (postBalances != null && postBalances.isNotEmpty) {
|
||||
for (final postBal in postBalances) {
|
||||
if (postBal.owner?.address == walletAddress) {
|
||||
userPostAmount = postBal.uiTokenAmount.uiAmount ?? 0.0;
|
||||
|
||||
mintAddress ??= postBal.mint.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final diff = userPreAmount - userPostAmount;
|
||||
final rawAmount = diff.abs();
|
||||
|
||||
final amountInString = rawAmount.toStringAsFixed(6);
|
||||
amount = double.parse(amountInString);
|
||||
|
||||
isOutgoing = diff > 0;
|
||||
|
||||
if (mintAddress == null && instruction.accounts.length >= 4) {
|
||||
final mintIndex = instruction.accounts[3];
|
||||
mintAddress = message.accountKeys[mintIndex].address;
|
||||
}
|
||||
|
||||
final sender = message.accountKeys[instruction.accounts[0]].address;
|
||||
final receiver = message.accountKeys[instruction.accounts[1]].address;
|
||||
|
||||
String? tokenSymbol = splTokenSymbol;
|
||||
|
||||
if (tokenSymbol == null && mintAddress != null) {
|
||||
final token = await getTokenInfo(mintAddress);
|
||||
tokenSymbol = token?.symbol;
|
||||
}
|
||||
|
||||
return SolanaTransactionModel(
|
||||
isOutgoingTx: isOutgoing,
|
||||
from: sender,
|
||||
to: receiver,
|
||||
id: signature,
|
||||
amount: amount,
|
||||
programId: SPLTokenProgramConst.tokenProgramId.address,
|
||||
blockTimeInInt: blockTime?.toInt() ?? 0,
|
||||
tokenSymbol: tokenSymbol ?? '',
|
||||
fee: feeInSol,
|
||||
);
|
||||
}
|
||||
|
||||
/// Load the Address's transactions into the account
|
||||
Future<List<SolanaTransactionModel>> fetchTransactions(
|
||||
SolAddress address, {
|
||||
|
@ -369,23 +433,28 @@ class SolanaWalletClient {
|
|||
}
|
||||
}));
|
||||
|
||||
final versionedBatchResponses = batchResponses.whereType<VersionedTransactionResponse>();
|
||||
final versionedBatchResponses =
|
||||
batchResponses.whereType<VersionedTransactionResponse>();
|
||||
|
||||
final parsedTransactionsFutures = versionedBatchResponses.map((tx) => parseTransaction(
|
||||
txResponse: tx,
|
||||
splTokenSymbol: splTokenSymbol,
|
||||
walletAddress: walletAddress?.address ?? address.address,
|
||||
));
|
||||
final parsedTransactionsFutures =
|
||||
versionedBatchResponses.map((tx) => parseTransaction(
|
||||
txResponse: tx,
|
||||
splTokenSymbol: splTokenSymbol,
|
||||
walletAddress: walletAddress?.address ?? address.address,
|
||||
));
|
||||
|
||||
final parsedTransactions = await Future.wait(parsedTransactionsFutures);
|
||||
|
||||
transactions.addAll(parsedTransactions.whereType<SolanaTransactionModel>().toList());
|
||||
transactions.addAll(
|
||||
parsedTransactions.whereType<SolanaTransactionModel>().toList());
|
||||
|
||||
// Calling the callback after each batch is processed, therefore passing the current list of transactions.
|
||||
onUpdate(List<SolanaTransactionModel>.from(transactions));
|
||||
// Only update UI if we have new valid transactions
|
||||
if (parsedTransactions.isNotEmpty) {
|
||||
onUpdate(List<SolanaTransactionModel>.from(transactions));
|
||||
}
|
||||
|
||||
if (i + batchSize < signatures.length) {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,8 +515,8 @@ class SolanaWalletClient {
|
|||
}
|
||||
|
||||
Future<SPLToken?> fetchSPLTokenInfo(String mintAddress) async {
|
||||
final programAddress =
|
||||
MetaplexTokenMetaDataProgramUtils.findMetadataPda(mint: SolAddress(mintAddress));
|
||||
final programAddress = MetaplexTokenMetaDataProgramUtils.findMetadataPda(
|
||||
mint: SolAddress(mintAddress));
|
||||
|
||||
final token = await _provider!.request(
|
||||
SolanaRPCGetMetadataAccount(
|
||||
|
@ -468,8 +537,9 @@ class SolanaWalletClient {
|
|||
// iconPath = await _client.getIconImageFromTokenUri(metadata.uri);
|
||||
// } catch (_) {}
|
||||
|
||||
String filteredTokenSymbol =
|
||||
metadata.symbol.replaceFirst(RegExp('^\\\$'), '').replaceAll('\u0000', '');
|
||||
String filteredTokenSymbol = metadata.symbol
|
||||
.replaceFirst(RegExp('^\\\$'), '')
|
||||
.replaceAll('\u0000', '');
|
||||
|
||||
return SPLToken.fromMetadata(
|
||||
name: metadata.name,
|
||||
|
@ -585,7 +655,8 @@ class SolanaWalletClient {
|
|||
return message;
|
||||
}
|
||||
|
||||
Future<double> _getFeeFromCompiledMessage(Message message, Commitment commitment) async {
|
||||
Future<double> _getFeeFromCompiledMessage(
|
||||
Message message, Commitment commitment) async {
|
||||
final base64Message = base64Encode(message.serialize());
|
||||
|
||||
final fee = await getFeeForMessage(base64Message, commitment);
|
||||
|
@ -724,7 +795,8 @@ class SolanaWalletClient {
|
|||
required SolAddress mintAddress,
|
||||
required bool shouldCreateATA,
|
||||
}) async {
|
||||
final associatedTokenAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount(
|
||||
final associatedTokenAccount =
|
||||
AssociatedTokenAccountProgramUtils.associatedTokenAccount(
|
||||
mint: mintAddress,
|
||||
owner: ownerAddress,
|
||||
);
|
||||
|
@ -732,19 +804,24 @@ class SolanaWalletClient {
|
|||
SolanaAccountInfo? accountInfo;
|
||||
try {
|
||||
accountInfo = await _provider!.request(
|
||||
SolanaRPCGetAccountInfo(account: associatedTokenAccount.address),
|
||||
SolanaRPCGetAccountInfo(
|
||||
account: associatedTokenAccount.address,
|
||||
commitment: Commitment.confirmed,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
accountInfo = null;
|
||||
}
|
||||
|
||||
// If aacountInfo is null, signifies that the associatedTokenAccount has only been created locally and not been broadcasted to the blockchain.
|
||||
// If account exists, we return the associated token account
|
||||
if (accountInfo != null) return associatedTokenAccount;
|
||||
|
||||
if (!shouldCreateATA) return null;
|
||||
|
||||
final payerAddress = payerPrivateKey.publicKey().toAddress();
|
||||
|
||||
final createAssociatedTokenAccount = AssociatedTokenAccountProgram.associatedTokenAccount(
|
||||
payer: payerPrivateKey.publicKey().toAddress(),
|
||||
payer: payerAddress,
|
||||
associatedToken: associatedTokenAccount.address,
|
||||
owner: ownerAddress,
|
||||
mint: mintAddress,
|
||||
|
@ -753,19 +830,23 @@ class SolanaWalletClient {
|
|||
final blockhash = await _getLatestBlockhash(Commitment.confirmed);
|
||||
|
||||
final transaction = SolanaTransaction(
|
||||
payerKey: payerPrivateKey.publicKey().toAddress(),
|
||||
payerKey: payerAddress,
|
||||
instructions: [createAssociatedTokenAccount],
|
||||
recentBlockhash: blockhash,
|
||||
type: TransactionType.v0,
|
||||
);
|
||||
|
||||
transaction.sign([payerPrivateKey]);
|
||||
final serializedTransaction = await _signTransactionInternal(
|
||||
ownerPrivateKey: payerPrivateKey,
|
||||
transaction: transaction,
|
||||
);
|
||||
|
||||
await sendTransaction(
|
||||
serializedTransaction: transaction.serializeString(),
|
||||
serializedTransaction: serializedTransaction,
|
||||
commitment: Commitment.confirmed,
|
||||
);
|
||||
|
||||
// Delay for propagation on the blockchain for newly created associated token addresses
|
||||
// Wait for confirmation
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
return associatedTokenAccount;
|
||||
|
@ -786,7 +867,8 @@ class SolanaWalletClient {
|
|||
final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt();
|
||||
ProgramDerivedAddress? associatedSenderAccount;
|
||||
try {
|
||||
associatedSenderAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount(
|
||||
associatedSenderAccount =
|
||||
AssociatedTokenAccountProgramUtils.associatedTokenAccount(
|
||||
mint: mintAddress,
|
||||
owner: ownerPrivateKey.publicKey().toAddress(),
|
||||
);
|
||||
|
@ -921,7 +1003,8 @@ class SolanaWalletClient {
|
|||
if (uri.isEmpty || uri == '…') return null;
|
||||
|
||||
try {
|
||||
final response = await httpClient.get(Uri.parse(uri));
|
||||
final client = ProxyWrapper().getHttpIOClient();
|
||||
final response = await client.get(Uri.parse(uri));
|
||||
|
||||
final jsonResponse = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
|
|
|
@ -33,9 +33,9 @@ dev_dependencies:
|
|||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:developer';
|
|||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_tron/pending_tron_transaction.dart';
|
||||
import 'package:cw_tron/tron_abi.dart';
|
||||
import 'package:cw_tron/tron_balance.dart';
|
||||
|
@ -13,12 +14,12 @@ import 'package:cw_tron/tron_token.dart';
|
|||
import 'package:cw_tron/tron_transaction_model.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:http/http.dart';
|
||||
import '.secrets.g.dart' as secrets;
|
||||
import 'package:on_chain/on_chain.dart';
|
||||
|
||||
class TronClient {
|
||||
final httpClient = Client();
|
||||
late final client = ProxyWrapper().getHttpIOClient();
|
||||
|
||||
TronProvider? _provider;
|
||||
// This is an internal tracker, so we don't have to "refetch".
|
||||
int _nativeTxEstimatedFee = 0;
|
||||
|
@ -28,7 +29,7 @@ class TronClient {
|
|||
Future<List<TronTransactionModel>> fetchTransactions(String address,
|
||||
{String? contractAddress}) async {
|
||||
try {
|
||||
final response = await httpClient.get(
|
||||
final response = await client.get(
|
||||
Uri.https(
|
||||
"api.trongrid.io",
|
||||
"/v1/accounts/$address/transactions",
|
||||
|
@ -61,7 +62,7 @@ class TronClient {
|
|||
|
||||
Future<List<TronTRC20TransactionModel>> fetchTrc20ExcludedTransactions(String address) async {
|
||||
try {
|
||||
final response = await httpClient.get(
|
||||
final response = await client.get(
|
||||
Uri.https(
|
||||
"api.trongrid.io",
|
||||
"/v1/accounts/$address/transactions/trc20",
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:on_chain/tron/tron.dart';
|
||||
import '.secrets.g.dart' as secrets;
|
||||
|
||||
class TronHTTPProvider implements TronServiceProvider {
|
||||
TronHTTPProvider(
|
||||
{required this.url,
|
||||
http.Client? client,
|
||||
this.defaultRequestTimeout = const Duration(seconds: 30)})
|
||||
: client = client ?? http.Client();
|
||||
this.defaultRequestTimeout = const Duration(seconds: 30)});
|
||||
|
||||
@override
|
||||
final String url;
|
||||
final http.Client client;
|
||||
late final client = ProxyWrapper().getHttpIOClient();
|
||||
final Duration defaultRequestTimeout;
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> get(TronRequestDetails params, [Duration? timeout]) async {
|
||||
Future<Map<String, dynamic>> get(TronRequestDetails params,
|
||||
[Duration? timeout]) async {
|
||||
final response = await client.get(Uri.parse(params.url(url)), headers: {
|
||||
'Content-Type': 'application/json',
|
||||
if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
|
||||
|
@ -27,13 +27,16 @@ class TronHTTPProvider implements TronServiceProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> post(TronRequestDetails params, [Duration? timeout]) async {
|
||||
Future<Map<String, dynamic>> post(TronRequestDetails params,
|
||||
[Duration? timeout]) async {
|
||||
final response = await client
|
||||
.post(Uri.parse(params.url(url)),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
|
||||
if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey,
|
||||
if (url.contains("trongrid"))
|
||||
'TRON-PRO-API-KEY': secrets.tronGridApiKey,
|
||||
if (url.contains("nownodes"))
|
||||
'api-key': secrets.tronNowNodesApiKey,
|
||||
},
|
||||
body: params.toRequestBody())
|
||||
.timeout(timeout ?? defaultRequestTimeout);
|
||||
|
|
|
@ -31,9 +31,9 @@ dev_dependencies:
|
|||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
build_runner: ^2.3.3
|
||||
build_runner: ^2.4.15
|
||||
mobx_codegen: ^2.1.1
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
flutter:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
|
|
|
@ -110,7 +110,16 @@ int getUnlockedBalance({int accountIndex = 0}) =>
|
|||
|
||||
int getCurrentHeight() => wownero.Wallet_blockChainHeight(wptr!);
|
||||
|
||||
int getNodeHeightSync() => wownero.Wallet_daemonBlockChainHeight(wptr!);
|
||||
int cachedNodeHeight = 0;
|
||||
int getNodeHeightSync() {
|
||||
(() async {
|
||||
final wptrAddress = wptr!.address;
|
||||
cachedNodeHeight = await Isolate.run(() async {
|
||||
return wownero.Wallet_daemonBlockChainHeight(Pointer.fromAddress(wptrAddress));
|
||||
});
|
||||
})();
|
||||
return cachedNodeHeight;
|
||||
}
|
||||
|
||||
bool isConnectedSync() => wownero.Wallet_connected(wptr!) != 0;
|
||||
|
||||
|
@ -154,7 +163,7 @@ Future<bool> setupNodeSync(
|
|||
}
|
||||
|
||||
void startRefreshSync() {
|
||||
wownero.Wallet_refreshAsync(wptr!);
|
||||
// wownero.Wallet_refreshAsync(wptr!);
|
||||
wownero.Wallet_startRefresh(wptr!);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'package:cw_core/transaction_direction.dart';
|
|||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wownero_amount_format.dart';
|
||||
|
@ -183,6 +184,14 @@ abstract class WowneroWalletBase
|
|||
|
||||
@override
|
||||
Future<void> connectToNode({required Node node}) async {
|
||||
String socksProxy = node.socksProxyAddress ?? '';
|
||||
printV("bootstrapped: ${CakeTor.instance.bootstrapped}");
|
||||
printV(" enabled: ${CakeTor.instance.enabled}");
|
||||
printV(" port: ${CakeTor.instance.port}");
|
||||
printV(" started: ${CakeTor.instance.started}");
|
||||
if (CakeTor.instance.enabled) {
|
||||
socksProxy = "127.0.0.1:${CakeTor.instance.port}";
|
||||
}
|
||||
try {
|
||||
syncStatus = ConnectingSyncStatus();
|
||||
await wownero_wallet.setupNode(
|
||||
|
@ -192,7 +201,7 @@ abstract class WowneroWalletBase
|
|||
useSSL: node.isSSL,
|
||||
isLightWallet: false,
|
||||
// FIXME: hardcoded value
|
||||
socksProxyAddress: node.socksProxyAddress);
|
||||
socksProxyAddress: socksProxy);
|
||||
|
||||
wownero_wallet.setTrustedDaemon(node.trusted);
|
||||
syncStatus = ConnectedSyncStatus();
|
||||
|
|
|
@ -5,18 +5,23 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "47.0.0"
|
||||
version: "76.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.3"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "6.11.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -86,26 +91,26 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
||||
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
version: "2.4.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.10"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -214,10 +219,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
||||
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.3.8"
|
||||
decimal:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -336,10 +341,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: hive_generator
|
||||
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
|
||||
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
version: "2.0.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -428,6 +433,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -472,10 +485,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobx_codegen
|
||||
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
|
||||
sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.7.1"
|
||||
monero:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -670,27 +683,37 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
socks_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
url: "https://github.com/sneurlax/socks_socket"
|
||||
source: git
|
||||
version: "1.1.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.6"
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
||||
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.5"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -751,10 +774,19 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -844,5 +876,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
|
|
|
@ -31,10 +31,10 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_resolvers: ^2.0.9
|
||||
build_runner: ^2.4.15
|
||||
build_resolvers: ^2.4.4
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -5,18 +5,23 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "4897882604d919befd350648c7f91926a9d5de99e67b455bf0917cc2362f4bb8"
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "47.0.0"
|
||||
version: "76.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.3"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "690e335554a8385bc9d787117d9eb52c0c03ee207a607e593de3c9d71b1cfe80"
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "6.11.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -86,26 +91,26 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
||||
sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
version: "2.4.4"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
||||
sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.13"
|
||||
version: "2.4.15"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
||||
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.10"
|
||||
version: "8.0.0"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -214,10 +219,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
||||
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.3.8"
|
||||
decimal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -333,10 +338,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: hive_generator
|
||||
sha256: "81fd20125cb2ce8fd23623d7744ffbaf653aae93706c9bd3bf7019ea0ace3938"
|
||||
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
version: "2.0.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -433,6 +438,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -477,10 +490,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobx_codegen
|
||||
sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c
|
||||
sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.7.1"
|
||||
monero:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -667,27 +680,37 @@ packages:
|
|||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
path: "."
|
||||
ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
|
||||
url: "https://github.com/LacticWhale/socks_dart"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
socks_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
|
||||
url: "https://github.com/sneurlax/socks_socket"
|
||||
source: git
|
||||
version: "1.1.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.6"
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
||||
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.5"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -752,6 +775,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -841,5 +873,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
|
|
|
@ -30,10 +30,10 @@ dependencies:
|
|||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
build_runner: ^2.4.15
|
||||
mobx_codegen: ^2.1.1
|
||||
build_resolvers: ^2.0.9
|
||||
hive_generator: ^1.1.3
|
||||
build_resolvers: ^2.4.4
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -18,8 +18,8 @@ In order to build the latest version of Cake Wallet, simply run the following:
|
|||
git clone --branch main https://github.com/cake-tech/cake_wallet.git
|
||||
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
|
||||
cd cake_wallet
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 bash -x << EOF
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly bash -x << EOF
|
||||
set -x -e
|
||||
pushd scripts/android
|
||||
source ./app_env.sh cakewallet
|
||||
|
|
|
@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your iOS devi
|
|||
```txt
|
||||
macOS 15.3.1
|
||||
Xcode 16.2
|
||||
Flutter 3.27.4
|
||||
Flutter 3.27.0
|
||||
```
|
||||
|
||||
NOTE: Newer versions of macOS and Xcode may also work, but have not been confirmed to work by the Cake team.
|
||||
|
@ -43,9 +43,9 @@ To enable iOS build support for Xcode, perform the following:
|
|||
|
||||
### 3. Installing Flutter
|
||||
|
||||
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
Install Flutter, specifically version `3.27.0` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
|
||||
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
NOTE: as `3.27.0` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
|
||||
### 4. Installing Rust
|
||||
|
||||
|
@ -65,7 +65,7 @@ The output of this command should appear like this, indicating successful instal
|
|||
|
||||
```zsh
|
||||
Doctor summary (to see all details, run flutter doctor -v):
|
||||
[✓] Flutter (Channel stable, 3.27.4, on macOS 15.x.x)
|
||||
[✓] Flutter (Channel stable, 3.27.0, on macOS 15.x.x)
|
||||
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
|
||||
```
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ In order to build the latest version of Cake Wallet, simply run the following:
|
|||
git clone --branch main https://github.com/cake-tech/cake_wallet.git
|
||||
# NOTE: Replace `main` with the latest release tag available at https://github.com/cake-tech/cake_wallet/releases/latest.
|
||||
cd cake_wallet
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run --privileged -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.4-go1.24.1 bash -x << EOF
|
||||
# docker build -t ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly . # Uncomment to build the docker image yourself instead of pulling it from the registry
|
||||
docker run --privileged -v$(pwd):$(pwd) -w $(pwd) -i --rm ghcr.io/cake-tech/cake_wallet:debian12-flutter3.27.0-go1.24.1-ruststablenightly bash -x << EOF
|
||||
set -x -e
|
||||
pushd scripts
|
||||
./gen_android_manifest.sh
|
||||
|
|
|
@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your macOS de
|
|||
```txt
|
||||
macOS 15.3.1
|
||||
Xcode 16.2
|
||||
Flutter 3.27.4
|
||||
Flutter 3.27.0
|
||||
```
|
||||
|
||||
### 1. Installing dependencies
|
||||
|
@ -34,9 +34,9 @@ sudo xcodebuild -runFirstLaunch
|
|||
|
||||
### 3. Installing Flutter
|
||||
|
||||
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
Install Flutter, specifically version `3.27.0` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
|
||||
|
||||
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
NOTE: as `3.27.0` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
|
||||
### 4. Installing Rust
|
||||
|
||||
|
@ -56,7 +56,7 @@ The output of this command should appear like this, indicating successful instal
|
|||
|
||||
```zsh
|
||||
Doctor summary (to see all details, run flutter doctor -v):
|
||||
[✓] Flutter (Channel stable, 3.27.4, on macOS 15.x.x)
|
||||
[✓] Flutter (Channel stable, 3.27.0, on macOS 15.x.x)
|
||||
...
|
||||
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
|
||||
...
|
||||
|
|
|
@ -6,18 +6,18 @@ The following are the system requirements to build Cake Wallet for your Windows
|
|||
|
||||
```txt
|
||||
Windows 10 or later (64-bit), x86-64 based
|
||||
Flutter 3.27.4
|
||||
Flutter 3.27.0
|
||||
```
|
||||
|
||||
### 1. Installing Flutter
|
||||
|
||||
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/windows).
|
||||
Install Flutter, specifically version `3.27.0` by following the [official docs](https://docs.flutter.dev/get-started/install/windows).
|
||||
|
||||
In order for Flutter to function, you'll also need to enable Developer Mode:
|
||||
|
||||
Start Menu > search for "Run" > type `ms-settings:developers`, and turn on Developer Mode.
|
||||
|
||||
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
NOTE: as `3.27.0` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
|
||||
|
||||
### 2. Install Development Tools
|
||||
|
||||
|
|
|
@ -70,7 +70,10 @@ class WalletKeysAndSeedPageRobot {
|
|||
if (walletType == WalletType.bitcoin ||
|
||||
walletType == WalletType.litecoin ||
|
||||
walletType == WalletType.bitcoinCash) {
|
||||
commonTestCases.hasText(appStore.wallet!.seed!);
|
||||
final seedWords = appStore.wallet!.seed!.split(" ");
|
||||
for (var seedWord in seedWords) {
|
||||
commonTestCases.hasTextAtLestOnce(seedWord);
|
||||
}
|
||||
tester.printToConsole('$walletName wallet has seeds properly displayed');
|
||||
}
|
||||
|
||||
|
@ -78,10 +81,14 @@ class WalletKeysAndSeedPageRobot {
|
|||
walletType == WalletType.solana ||
|
||||
walletType == WalletType.tron) {
|
||||
if (hasSeed) {
|
||||
commonTestCases.hasText(appStore.wallet!.seed!);
|
||||
final seedWords = appStore.wallet!.seed!.split(" ");
|
||||
for (var seedWord in seedWords) {
|
||||
commonTestCases.hasTextAtLestOnce(seedWord);
|
||||
}
|
||||
tester.printToConsole('$walletName wallet has seeds properly displayed');
|
||||
}
|
||||
if (hasPrivateKey) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(appStore.wallet!.privateKey!);
|
||||
tester.printToConsole('$walletName wallet has private key properly displayed');
|
||||
}
|
||||
|
@ -89,14 +96,19 @@ class WalletKeysAndSeedPageRobot {
|
|||
|
||||
if (walletType == WalletType.nano || walletType == WalletType.banano) {
|
||||
if (hasSeed) {
|
||||
commonTestCases.hasText(appStore.wallet!.seed!);
|
||||
final seedWords = appStore.wallet!.seed!.split(" ");
|
||||
for (var seedWord in seedWords) {
|
||||
commonTestCases.hasTextAtLestOnce(seedWord);
|
||||
}
|
||||
tester.printToConsole('$walletName wallet has seeds properly displayed');
|
||||
}
|
||||
if (hasHexSeed) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(appStore.wallet!.hexSeed!);
|
||||
tester.printToConsole('$walletName wallet has hexSeed properly displayed');
|
||||
}
|
||||
if (hasPrivateKey) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(appStore.wallet!.privateKey!);
|
||||
tester.printToConsole('$walletName wallet has private key properly displayed');
|
||||
}
|
||||
|
@ -129,35 +141,39 @@ class WalletKeysAndSeedPageRobot {
|
|||
final hasSeedLegacy = Polyseed.isValidSeed(seed);
|
||||
|
||||
if (hasPublicSpendKey) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(keys.publicSpendKey);
|
||||
tester.printToConsole('$walletName wallet has public spend key properly displayed');
|
||||
}
|
||||
if (hasPrivateSpendKey) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(keys.privateSpendKey);
|
||||
tester.printToConsole('$walletName wallet has private spend key properly displayed');
|
||||
}
|
||||
if (hasPublicViewKey) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(keys.publicViewKey);
|
||||
tester.printToConsole('$walletName wallet has public view key properly displayed');
|
||||
}
|
||||
if (hasPrivateViewKey) {
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
|
||||
commonTestCases.hasText(keys.privateViewKey);
|
||||
tester.printToConsole('$walletName wallet has private view key properly displayed');
|
||||
}
|
||||
if (hasSeeds) {
|
||||
await commonTestCases.dragUntilVisible(
|
||||
'${walletName}_wallet_seed_item_key',
|
||||
'wallet_keys_page_credentials_list_view_key',
|
||||
);
|
||||
commonTestCases.hasText(seed);
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_seed');
|
||||
final seedWords = seed.split(" ");
|
||||
for (var seedWord in seedWords) {
|
||||
commonTestCases.hasTextAtLestOnce(seedWord);
|
||||
}
|
||||
tester.printToConsole('$walletName wallet has seeds properly displayed');
|
||||
}
|
||||
if (hasSeedLegacy) {
|
||||
await commonTestCases.dragUntilVisible(
|
||||
'${walletName}_wallet_seed_legacy_item_key',
|
||||
'wallet_keys_page_credentials_list_view_key',
|
||||
);
|
||||
commonTestCases.hasText(legacySeed);
|
||||
await commonTestCases.tapItemByKey('wallet_keys_page_seed_legacy');
|
||||
final seedWords = legacySeed.split(" ");
|
||||
for (var seedWord in seedWords) {
|
||||
commonTestCases.hasTextAtLestOnce(seedWord);
|
||||
}
|
||||
tester.printToConsole('$walletName wallet has legacy seeds properly displayed');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ PODS:
|
|||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- payjoin_flutter (0.20.0)
|
||||
- payjoin_flutter (0.23.0)
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- reown_yttrium (0.0.1):
|
||||
|
@ -235,7 +235,7 @@ SPEC CHECKSUMS:
|
|||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
payjoin_flutter: 6397d7b698cdad6453be4949ab6aca1863f6c5e5
|
||||
payjoin_flutter: d9d4c8aa16bd5dfedb9b21d0edc8199e0187d96e
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
reown_yttrium: c0e87e5965fa60a3559564cc35cffbba22976089
|
||||
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
|
||||
|
|
|
@ -6,8 +6,9 @@ import 'package:cake_wallet/anonpay/anonpay_status_response.dart';
|
|||
import 'package:cake_wallet/core/fiat_conversion_service.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
|
@ -20,17 +21,21 @@ class AnonPayApi {
|
|||
final WalletBase wallet;
|
||||
|
||||
static const anonpayRef = secrets.anonPayReferralCode;
|
||||
static const onionApiAuthority = 'tqzngtf2hybjbexznel6dhgsvbynjzezoybvtv6iofomx7gchqfssgqd.onion';
|
||||
static const clearNetAuthority = 'trocador.app';
|
||||
// static const onionApiAuthority = 'tqzngtf2hybjbexznel6dhgsvbynjzezoybvtv6iofomx7gchqfssgqd.onion';
|
||||
static const onionApiAuthority = clearNetAuthority;
|
||||
static const markup = secrets.trocadorExchangeMarkup;
|
||||
static const anonPayPath = '/anonpay';
|
||||
static const anonPayStatus = '/anonpay/status';
|
||||
static const coinPath = 'api/coin';
|
||||
static const apiKey = secrets.trocadorApiKey;
|
||||
static final apiKey = isMoneroOnly ? secrets.trocadorMoneroApiKey : secrets.trocadorApiKey;
|
||||
|
||||
Future<AnonpayStatusResponse> paymentStatus(String id) async {
|
||||
final authority = await _getAuthority();
|
||||
final response = await get(Uri.https(authority, "$anonPayStatus/$id"));
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: Uri.https(clearNetAuthority, "$anonPayStatus/$id"),
|
||||
onionUri: Uri.https(onionApiAuthority, "$anonPayStatus/$id"),
|
||||
);
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final status = responseJSON['Status'] as String;
|
||||
final fiatAmount = responseJSON['Fiat_Amount'] as double?;
|
||||
|
@ -69,9 +74,10 @@ class AnonPayApi {
|
|||
if (request.fiatEquivalent != null) {
|
||||
body['fiat_equiv'] = request.fiatEquivalent;
|
||||
}
|
||||
final authority = await _getAuthority();
|
||||
|
||||
final response = await get(Uri.https(authority, anonPayPath, body));
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: Uri.https(clearNetAuthority, anonPayPath, body),
|
||||
onionUri: Uri.https(onionApiAuthority, anonPayPath, body),
|
||||
);
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['ID'] as String;
|
||||
|
@ -146,17 +152,16 @@ class AnonPayApi {
|
|||
'name': cryptoCurrency.name,
|
||||
};
|
||||
|
||||
final String apiAuthority = await _getAuthority();
|
||||
final uri = Uri.https(apiAuthority, coinPath, params);
|
||||
|
||||
final response = await get(uri);
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: Uri.https(clearNetAuthority, coinPath, params),
|
||||
onionUri: Uri.https(onionApiAuthority, coinPath, params),
|
||||
);
|
||||
|
||||
final responseJSON = json.decode(response.body) as List<dynamic>;
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as List<dynamic>;
|
||||
|
||||
if (responseJSON.isEmpty) {
|
||||
throw Exception('No data');
|
||||
}
|
||||
|
@ -197,17 +202,4 @@ class AnonPayApi {
|
|||
return tag.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _getAuthority() async {
|
||||
try {
|
||||
if (useTorOnly) {
|
||||
return onionApiAuthority;
|
||||
}
|
||||
final uri = Uri.https(onionApiAuthority, '/anonpay');
|
||||
await get(uri);
|
||||
return onionApiAuthority;
|
||||
} catch (e) {
|
||||
return clearNetAuthority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_trasnaction.dart';
|
||||
|
@ -53,7 +53,11 @@ class AnyPayApi {
|
|||
final body = <String, dynamic>{
|
||||
'chain': chainByScheme(scheme),
|
||||
'currency': currencyByScheme(scheme).title};
|
||||
final response = await post(url, headers: headers, body: utf8.encode(json.encode(body)));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: url,
|
||||
headers: headers,
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
await ExceptionHandler.onError(FlutterErrorDetails(exception: response));
|
||||
|
@ -79,7 +83,12 @@ class AnyPayApi {
|
|||
'chain': chain,
|
||||
'currency': currency,
|
||||
'transactions': transactions.map((tx) => {'tx': tx.tx, 'tx_hash': tx.id, 'tx_key': tx.key}).toList()};
|
||||
final response = await post(Uri.parse(uri), headers: headers, body: utf8.encode(json.encode(body)));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: Uri.parse(uri),
|
||||
headers: headers,
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
throw Exception(decodedBody['message'] as String? ?? 'Unexpected response\nError code: 400');
|
||||
|
|
|
@ -747,5 +747,6 @@ class CWBitcoin extends Bitcoin {
|
|||
final _wallet = wallet as ElectrumWallet;
|
||||
(_wallet.walletAddresses as BitcoinWalletAddresses).payjoinManager.cleanupSessions();
|
||||
(_wallet.walletAddresses as BitcoinWalletAddresses).currentPayjoinReceiver = null;
|
||||
(_wallet.walletAddresses as BitcoinWalletAddresses).payjoinEndpoint = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -17,7 +18,6 @@ import 'package:cw_core/utils/print_verbose.dart';
|
|||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class DFXBuyProvider extends BuyProvider {
|
||||
|
@ -100,12 +100,13 @@ class DFXBuyProvider extends BuyProvider {
|
|||
});
|
||||
|
||||
final uri = Uri.https(_baseUrl, _authPath);
|
||||
var response = await http.post(
|
||||
uri,
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: requestBody,
|
||||
);
|
||||
|
||||
|
||||
if (response.statusCode == 201) {
|
||||
final responseBody = jsonDecode(response.body);
|
||||
return responseBody['accessToken'] as String;
|
||||
|
@ -137,7 +138,9 @@ class DFXBuyProvider extends BuyProvider {
|
|||
final url = Uri.https(_baseUrl, '/v1/fiat');
|
||||
|
||||
try {
|
||||
final response = await http.get(url, headers: {'accept': 'application/json'});
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: url,
|
||||
headers: {'accept': 'application/json'});
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as List<dynamic>;
|
||||
|
@ -160,7 +163,7 @@ class DFXBuyProvider extends BuyProvider {
|
|||
final url = Uri.https(_baseUrl, '/v1/asset', {'blockchains': blockchain});
|
||||
|
||||
try {
|
||||
final response = await http.get(url, headers: {'accept': 'application/json'});
|
||||
final response = await ProxyWrapper().get(clearnetUri: url, headers: {'accept': 'application/json'});
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = jsonDecode(response.body);
|
||||
|
@ -271,7 +274,12 @@ class DFXBuyProvider extends BuyProvider {
|
|||
});
|
||||
|
||||
try {
|
||||
final response = await http.put(url, headers: headers, body: body);
|
||||
final response = await ProxyWrapper().put(
|
||||
clearnetUri: url,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
|
||||
final responseData = jsonDecode(response.body);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
|
|
|
@ -9,10 +9,10 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
|
|||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:developer';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class KryptonimBuyProvider extends BuyProvider {
|
||||
|
@ -74,9 +74,14 @@ class KryptonimBuyProvider extends BuyProvider {
|
|||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: url,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 401) {
|
||||
|
||||
return jsonDecode(response.body) as Map<String, dynamic>;
|
||||
} else {
|
||||
return {};
|
||||
|
|
|
@ -8,13 +8,13 @@ import 'package:cake_wallet/buy/payment_method.dart';
|
|||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:developer';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class MeldBuyProvider extends BuyProvider {
|
||||
|
@ -71,8 +71,8 @@ class MeldBuyProvider extends BuyProvider {
|
|||
final url = Uri.https(_baseUrl, path, params);
|
||||
|
||||
try {
|
||||
final response = await http.get(
|
||||
url,
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: url,
|
||||
headers: {
|
||||
'Authorization': _isProduction ? '' : _testApiKey,
|
||||
'Meld-Version': '2023-12-19',
|
||||
|
@ -81,6 +81,7 @@ class MeldBuyProvider extends BuyProvider {
|
|||
},
|
||||
);
|
||||
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as List<dynamic>;
|
||||
final paymentMethods =
|
||||
|
@ -130,7 +131,12 @@ class MeldBuyProvider extends BuyProvider {
|
|||
});
|
||||
|
||||
try {
|
||||
final response = await http.post(url, headers: headers, body: body);
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: url,
|
||||
headers: headers,
|
||||
body: body,
|
||||
);
|
||||
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
|
|
@ -16,12 +16,12 @@ import 'package:cake_wallet/palette.dart';
|
|||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class MoonPayProvider extends BuyProvider {
|
||||
|
@ -98,9 +98,12 @@ class MoonPayProvider extends BuyProvider {
|
|||
Future<String> getMoonpaySignature(String query) async {
|
||||
final uri = Uri.https(_cIdBaseUrl, "/api/moonpay");
|
||||
|
||||
final response = await post(uri,
|
||||
headers: {'Content-Type': 'application/json', 'x-api-key': _exchangeHelperApiKey},
|
||||
body: json.encode({'query': query}));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: {'Content-Type': 'application/json', 'x-api-key': _exchangeHelperApiKey},
|
||||
body: json.encode({'query': query}),
|
||||
);
|
||||
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return (jsonDecode(response.body) as Map<String, dynamic>)['signature'] as String;
|
||||
|
@ -120,7 +123,11 @@ class MoonPayProvider extends BuyProvider {
|
|||
final url = Uri.https(_baseUrl, path, params);
|
||||
|
||||
try {
|
||||
final response = await get(url, headers: {'accept': 'application/json'});
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: url,
|
||||
headers: {'accept': 'application/json'},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return jsonDecode(response.body) as Map<String, dynamic>;
|
||||
} else {
|
||||
|
@ -191,7 +198,7 @@ class MoonPayProvider extends BuyProvider {
|
|||
final path = '$_currenciesPath/$formattedCryptoCurrency$quotePath';
|
||||
final url = Uri.https(_baseUrl, path, params);
|
||||
try {
|
||||
final response = await get(url);
|
||||
final response = await ProxyWrapper().get(clearnetUri: url);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
@ -306,7 +313,8 @@ class MoonPayProvider extends BuyProvider {
|
|||
Future<Order> findOrderById(String id) async {
|
||||
final url = _apiUrl + _transactionsSuffix + '/$id' + '?apiKey=' + _apiKey;
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final response = await ProxyWrapper().get(clearnetUri: uri);
|
||||
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(title: providerDescription, content: 'Transaction $id is not found!');
|
||||
|
|
|
@ -9,11 +9,12 @@ import 'package:cake_wallet/buy/payment_method.dart';
|
|||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/themes/core/theme_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class OnRamperBuyProvider extends BuyProvider {
|
||||
|
@ -66,8 +67,10 @@ class OnRamperBuyProvider extends BuyProvider {
|
|||
final url = Uri.https(_baseApiUrl, '$supported$defaultsAll', params);
|
||||
|
||||
try {
|
||||
final response =
|
||||
await http.get(url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
|
||||
final response = await ProxyWrapper().get(
|
||||
clearnetUri: url,
|
||||
headers: {'Authorization': _apiKey, 'accept': 'application/json'},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
@ -102,7 +105,7 @@ class OnRamperBuyProvider extends BuyProvider {
|
|||
|
||||
try {
|
||||
final response =
|
||||
await http.get(url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
|
||||
await ProxyWrapper().get(clearnetUri: url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
@ -132,7 +135,8 @@ class OnRamperBuyProvider extends BuyProvider {
|
|||
|
||||
try {
|
||||
final response =
|
||||
await http.get(url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
|
||||
await ProxyWrapper().get(clearnetUri: url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
|
||||
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
@ -195,7 +199,7 @@ class OnRamperBuyProvider extends BuyProvider {
|
|||
final headers = {'Authorization': _apiKey, 'accept': 'application/json'};
|
||||
|
||||
try {
|
||||
final response = await http.get(url, headers: headers);
|
||||
final response = await ProxyWrapper().get(clearnetUri: url, headers: headers);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body) as List<dynamic>;
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -18,7 +19,6 @@ import 'package:cw_core/utils/print_verbose.dart';
|
|||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class RobinhoodBuyProvider extends BuyProvider {
|
||||
|
@ -69,7 +69,8 @@ class RobinhoodBuyProvider extends BuyProvider {
|
|||
final uri = Uri.https(_apiBaseUrl, '$_assetsPath', {'applicationId': _applicationId});
|
||||
|
||||
try {
|
||||
final response = await http.get(uri, headers: {'accept': 'application/json'});
|
||||
final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'accept': 'application/json'});
|
||||
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
@ -122,12 +123,14 @@ class RobinhoodBuyProvider extends BuyProvider {
|
|||
|
||||
final uri = Uri.https(_cIdBaseUrl, "/api/robinhood");
|
||||
|
||||
var response = await http.post(uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json
|
||||
.encode({'valid_until': valid_until, 'wallet': walletAddress, 'signature': signature}));
|
||||
var response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode({'valid_until': valid_until, 'wallet': walletAddress, 'signature': signature}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
|
||||
return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String;
|
||||
} else {
|
||||
throw Exception('Provider currently unavailable. Status: ${response.statusCode}');
|
||||
|
@ -219,7 +222,8 @@ class RobinhoodBuyProvider extends BuyProvider {
|
|||
Uri.https('api.robinhood.com', '/catpay/v1/${cryptoCurrency.title}/quote/', queryParams);
|
||||
|
||||
try {
|
||||
final response = await http.get(uri, headers: {'accept': 'application/json'});
|
||||
final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'accept': 'application/json'});
|
||||
|
||||
final responseData = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:cake_wallet/buy/buy_exception.dart';
|
|||
import 'package:cake_wallet/buy/pairs_utils.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider_description.dart';
|
||||
|
@ -73,18 +73,21 @@ class WyreBuyProvider extends BuyProvider {
|
|||
'referrerAccountId': _accountId,
|
||||
'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest']
|
||||
};
|
||||
final response = await post(uri,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
'cache-control': 'no-cache'
|
||||
},
|
||||
body: json.encode(body));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
'cache-control': 'no-cache'
|
||||
},
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(title: providerDescription, content: 'Url $url is not found!');
|
||||
}
|
||||
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final urlFromResponse = responseJSON['url'] as String;
|
||||
return urlFromResponse;
|
||||
|
@ -101,18 +104,21 @@ class WyreBuyProvider extends BuyProvider {
|
|||
'country': _countryCode
|
||||
};
|
||||
final uri = Uri.parse(quoteUrl);
|
||||
final response = await post(uri,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
'cache-control': 'no-cache'
|
||||
},
|
||||
body: json.encode(body));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: {
|
||||
'Authorization': 'Bearer $_secretKey',
|
||||
'Content-Type': 'application/json',
|
||||
'cache-control': 'no-cache'
|
||||
},
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw BuyException(title: providerDescription, content: 'Quote is not found!');
|
||||
}
|
||||
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final sourceAmount = responseJSON['sourceAmount'] as double;
|
||||
final destAmount = responseJSON['destAmount'] as double;
|
||||
|
@ -125,8 +131,7 @@ class WyreBuyProvider extends BuyProvider {
|
|||
Future<Order> findOrderById(String id) async {
|
||||
final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
|
||||
final orderUri = Uri.parse(orderUrl);
|
||||
final orderResponse = await get(orderUri);
|
||||
|
||||
final orderResponse = await ProxyWrapper().get(clearnetUri: orderUri);
|
||||
if (orderResponse.statusCode != 200) {
|
||||
throw BuyException(title: providerDescription, content: 'Order $id is not found!');
|
||||
}
|
||||
|
@ -142,8 +147,7 @@ class WyreBuyProvider extends BuyProvider {
|
|||
|
||||
final transferUrl = baseApiUrl + _transferSuffix + transferId + _trackSuffix;
|
||||
final transferUri = Uri.parse(transferUrl);
|
||||
final transferResponse = await get(transferUri);
|
||||
|
||||
final transferResponse = await ProxyWrapper().get(clearnetUri: transferUri);
|
||||
if (transferResponse.statusCode != 200) {
|
||||
throw BuyException(title: providerDescription, content: 'Transfer $transferId is not found!');
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ import 'dart:convert';
|
|||
import 'package:cake_wallet/cake_pay/cake_pay_order.dart';
|
||||
import 'package:cake_wallet/cake_pay/cake_pay_user_credentials.dart';
|
||||
import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cake_wallet/entities/country.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class CakePayApi {
|
||||
static const testBaseUri = false;
|
||||
|
@ -32,12 +32,17 @@ class CakePayApi {
|
|||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Api-Key $apiKey',
|
||||
};
|
||||
final response = await http.post(uri, headers: headers, body: json.encode({'email': email}));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode({'email': email}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
if (bodyJson.containsKey('user') && bodyJson['user']['email'] != null) {
|
||||
|
@ -64,12 +69,17 @@ class CakePayApi {
|
|||
};
|
||||
final query = <String, String>{'email': email, 'otp': code};
|
||||
|
||||
final response = await http.post(uri, headers: headers, body: json.encode(query));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode(query),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
if (bodyJson.containsKey('error')) {
|
||||
|
@ -116,9 +126,14 @@ class CakePayApi {
|
|||
};
|
||||
|
||||
try {
|
||||
final response = await http.post(uri, headers: headers, body: json.encode(query));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode(query),
|
||||
);
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
|
||||
final responseBody = json.decode(response.body);
|
||||
if (responseBody is List) {
|
||||
throw '${responseBody[0]}';
|
||||
|
@ -127,6 +142,7 @@ class CakePayApi {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
final bodyJson = json.decode(response.body) as Map<String, dynamic>;
|
||||
return CakePayOrder.fromMap(bodyJson);
|
||||
} catch (e) {
|
||||
|
@ -145,7 +161,8 @@ class CakePayApi {
|
|||
'X-CSRFToken': CSRFToken,
|
||||
};
|
||||
|
||||
final response = await http.get(uri, headers: headers);
|
||||
final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
|
||||
|
||||
|
||||
printV('Response: ${response.statusCode}');
|
||||
|
||||
|
@ -168,7 +185,11 @@ class CakePayApi {
|
|||
};
|
||||
|
||||
try {
|
||||
final response = await http.post(uri, headers: headers, body: json.encode({'email': email}));
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode({'email': email}),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
|
@ -187,7 +208,7 @@ class CakePayApi {
|
|||
'Authorization': 'Api-Key $apiKey',
|
||||
};
|
||||
|
||||
final response = await http.get(uri, headers: headers);
|
||||
final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
|
@ -234,14 +255,15 @@ class CakePayApi {
|
|||
'Authorization': 'Api-Key $apiKey',
|
||||
};
|
||||
|
||||
var response = await http.get(uri, headers: headers);
|
||||
var response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
|
||||
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception(
|
||||
'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(utf8.decode(response.bodyBytes));
|
||||
final bodyJson = json.decode(response.body);
|
||||
|
||||
if (bodyJson is List<dynamic> && bodyJson.isEmpty) {
|
||||
return [];
|
||||
|
|
|
@ -38,9 +38,9 @@ class AddressValidator extends TextValidator {
|
|||
'|[0-9a-zA-Z]{105}|addr1[0-9a-zA-Z]{98}';
|
||||
case CryptoCurrency.btc:
|
||||
pattern =
|
||||
'${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${RegExp(r'(bc|tb)1q[ac-hj-np-z02-9]{25,39}}').pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}';
|
||||
'${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}';
|
||||
case CryptoCurrency.ltc:
|
||||
pattern = '^${RegExp(r'ltc1q[ac-hj-np-z02-9]{25,39}').pattern}\$|^${MwebAddress.regex.pattern}\$';
|
||||
pattern = '${P2wpkhAddress.regex.pattern}|${MwebAddress.regex.pattern}';
|
||||
case CryptoCurrency.nano:
|
||||
pattern = '[0-9a-zA-Z_]+';
|
||||
case CryptoCurrency.banano:
|
||||
|
@ -335,10 +335,6 @@ class AddressValidator extends TextValidator {
|
|||
}
|
||||
}
|
||||
|
||||
if (pattern != null) {
|
||||
return "$BEFORE_REGEX($pattern)$AFTER_REGEX";
|
||||
}
|
||||
|
||||
return null;
|
||||
return pattern != null ? "($pattern)" : null;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue